7

數據。 我有一個簡單的實體Gedmo 可記錄的日誌我使用Symfony2.2與StofDoctrineExtensionsBundle(等Gedmo DoctrineExtensions)不發生變化

/** 
* @ORM\Entity 
* @Gedmo\Loggable 
* @ORM\Table(name="person") 
*/ 
class Person { 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

[...] 

    /** 
    * @ORM\Column(type="datetime", nullable=true) 
    * @Assert\NotBlank() 
    * @Assert\Date() 
    * @Gedmo\Versioned 
    */ 
    protected $birthdate; 
} 

當更改現有對象的屬性,一個日誌條目表ext_log_entries完成。此日誌表中的條目僅包含更改的列。我可以通過讀取日誌:

$em = $this->getManager(); 
$repo = $em->getRepository('Gedmo\Loggable\Entity\LogEntry'); 
$person_repo = $em->getRepository('Acme\MainBundle\Entity\Person'); 

$person = $person_repo->find(1); 
$log = $repo->findBy(array('objectId' => $person->getId())); 
foreach ($log as $log_entry) { var_dump($log_entry->getData()); } 

但我不明白的是,爲什麼場birthdate總是包含在一個日誌條目,即使它沒有改變。這裏有三個日誌條目的例子:

array(9) { 
    ["salutation"]=> 
    string(4) "Herr" 
    ["firstname"]=> 
    string(3) "Max" 
    ["lastname"]=> 
    string(6) "Muster" 
    ["street"]=> 
    string(14) "Musterstraße 1" 
    ["zipcode"]=> 
    string(5) "00000" 
    ["city"]=> 
    string(12) "Musterhausen" 
    ["birthdate"]=> 
    object(DateTime)#655 (3) { 
    ["date"]=> 
    string(19) "1893-01-01 00:00:00" 
    ["timezone_type"]=> 
    int(3) 
    ["timezone"]=> 
    string(13) "Europe/Berlin" 
    } 
    ["email"]=> 
    string(17) "[email protected]" 
    ["phone"]=> 
    NULL 
} 

array(2) { 
    ["birthdate"]=> 
    object(DateTime)#659 (3) { 
    ["date"]=> 
    string(19) "1893-01-01 00:00:00" 
    ["timezone_type"]=> 
    int(3) 
    ["timezone"]=> 
    string(13) "Europe/Berlin" 
    } 
    ["phone"]=> 
    string(9) "123456789" 
} 

array(2) { 
    ["birthdate"]=> 
    object(DateTime)#662 (3) { 
    ["date"]=> 
    string(19) "1893-01-01 00:00:00" 
    ["timezone_type"]=> 
    int(3) 
    ["timezone"]=> 
    string(13) "Europe/Berlin" 
    } 
    ["phone"]=> 
    NULL 
} 

我想只記錄真正改變的數據。我還沒有看到任何選擇嗎?這似乎與事實有關,即birthdateDateTime對象,不是嗎?

編輯 它與DateTime對象無關。即使在其他實體中也會發生這種情況我已經包含另一個實體的簡單值:

/** 
* @ORM\Entity 
* @Gedmo\Loggable 
* @ORM\Entity(repositoryClass="Acme\MainBundle\Repository\ApplicationRepository") 
* @ORM\Table(name="application") 
*/ 
class Application { 

[...] 

    /** 
    * @ORM\Column(type="integer") 
    * @Assert\NotBlank(groups={"FormStepOne", "UserEditApplication"}) 
    * @Gedmo\Versioned 
    */ 
    protected $insurance_number; 
} 

當打開瀏覽器中編輯表單的儲蓄不加修飾,日誌表包含:

update 2013-04-26 11:32:42  Acme\MainBundle\Entity\Application a:1:{s:16:"insurance_number";s:7:"1234567";} 
update 2013-04-26 11:33:17  Acme\MainBundle\Entity\Application a:1:{s:16:"insurance_number";s:7:"1234567";} 

爲什麼?

回答

7

這可能與我在使用另一個擴展名(timestampable)時遇到的問題類似,即:在教條中使用的默認更改跟蹤策略(它試圖自動檢測更改)有時會將實體標記爲髒,當他們不是(對我來說,這發生在我的實體包含日期時間對象時,這是可以理解的,因爲這是一個從數據庫中拉出時需要構建的對象)。這不是一個錯誤或任何事情 - 它是預期的行爲,並且有一些方法。

可能是值得嘗試實現你想要記錄的實體的替代更改跟蹤政策,看是否能解決的事情 - 我猜想,除非實體狀態是髒的這種行爲(日誌)不踢,

http://docs.doctrine-project.org/en/latest/cookbook/implementing-the-notify-changetracking-policy.html

不要忘記更新您的實體:

YourBundle\Entity\YourThing: 
    type: entity 
    table: some_table 
    changeTrackingPolicy: NOTIFY 

看到這個線程:您可以通過實施變革手動跟蹤自己避免

https://github.com/Atlantic18/DoctrineExtensions/issues/333#issuecomment-16738878

+0

即使這是一個老問題,我決定不實施我自己的通知功能,並讓這個蹩腳的行爲布萊恩:( – rabudde 2013-09-21 19:24:38

+1

@rabudde不是真的教條的錯 - 但PHP的蹩腳的對象比較 – calumbrodie 2013-09-23 12:42:20

+0

哦,當然,這可能也可能是PHP的錯,但是我不能想象,如果我爲基於PHP的應用程序編寫一個bundle /插件,我自己來比較對象會很困難,但我不會破解Gedmo bundle但是,謝謝你的回答。 – rabudde 2013-09-23 13:22:46

0

對於\DateTime我仍然在,但你的問題還有第二部分的工作是一種方式,解決了我的問題,我Numeric屬性:

/** 
* @ORM\Entity 
* @Gedmo\Loggable 
* @ORM\Entity(repositoryClass="Acme\MainBundle\Repository\ApplicationRepository") 
* @ORM\Table(name="application") 
*/ 
class Application { 

[...] 

    /** 
    * @ORM\Column(type="integer") 
    * @Assert\NotBlank(groups={"FormStepOne", "UserEditApplication"}) 
    * @Gedmo\Versioned 
    */ 
    protected $insurance_number; 
} 

在這裏,您聲明insurance_number作爲整數屬性,但正如我們所知PHP沒有類型,並進行動態投射,這是與Gedmo Loggable衝突的事情。

要解決,只要確保您自己在Setter MethodBusiness Logic中進行了自己的顯式投射。這一個

$application->setInsuranceNumber($valueComeFromHtmlForm)


例如替換這個(業務邏輯)

$application->setInsuranceNumber((int)$valueComeFromHtmlForm)

然後,當你堅持你的對象,你不會看到任何記錄在你的日誌。

我認爲這是因爲LoggableDoctrine Change Tracker預計Integer並收到String (which is a 'not casted Integer')所以它標誌着財產髒。我們可以在Log RecordS表示新值爲String)中看到它。

0

我今天也遇到了這個問題並解決了它。 這是完整的解決方案,適用於所有字符串,浮點型,整型和DateTime值。

  1. 製作您自己的LoggableListener並使用它代替Gedmo Listener。

    <?php 
    
    namespace MyBundle\Loggable\Listener; 
    
    use Gedmo\Loggable\LoggableListener; 
    use Gedmo\Tool\Wrapper\AbstractWrapper; 
    
    class MyLoggableListener extends LoggableListener 
    { 
        protected function getObjectChangeSetData($ea, $object, $logEntry) 
        { 
         $om = $ea->getObjectManager(); 
         $wrapped = AbstractWrapper::wrap($object, $om); 
         $meta = $wrapped->getMetadata(); 
         $config = $this->getConfiguration($om, $meta->name); 
         $uow = $om->getUnitOfWork(); 
         $values = []; 
    
         foreach ($ea->getObjectChangeSet($uow, $object) as $field => $changes) { 
          if (empty($config['versioned']) || !in_array($field, $config['versioned'])) { 
           continue; 
          } 
    
          $oldValue = $changes[0]; 
          if ($meta->isSingleValuedAssociation($field) && $oldValue) { 
           if ($wrapped->isEmbeddedAssociation($field)) { 
            $value = $this->getObjectChangeSetData($ea, $oldValue, $logEntry); 
           } else { 
            $oid = spl_object_hash($oldValue); 
            $wrappedAssoc = AbstractWrapper::wrap($oldValue, $om); 
            $oldValue = $wrappedAssoc->getIdentifier(false); 
            if (!is_array($oldValue) && !$oldValue) { 
             $this->pendingRelatedObjects[$oid][] = [ 
              'log' => $logEntry, 
              'field' => $field, 
             ]; 
            } 
           } 
          } 
    
          $value = $changes[1]; 
          if ($meta->isSingleValuedAssociation($field) && $value) { 
           if ($wrapped->isEmbeddedAssociation($field)) { 
            $value = $this->getObjectChangeSetData($ea, $value, $logEntry); 
           } else { 
            $oid = spl_object_hash($value); 
            $wrappedAssoc = AbstractWrapper::wrap($value, $om); 
            $value = $wrappedAssoc->getIdentifier(false); 
            if (!is_array($value) && !$value) { 
             $this->pendingRelatedObjects[$oid][] = [ 
              'log' => $logEntry, 
              'field' => $field, 
             ]; 
            } 
           } 
          } 
    
          //fix for DateTime, integer and float entries 
          if ($value == $oldValue) { 
           continue; 
          } 
    
          $values[$field] = $value; 
         } 
    
         return $values; 
        } 
    } 
    
  2. 對於Symfony的應用程序,註冊聽衆中config.yml文件。

    stof_doctrine_extensions: 
        orm: 
         default: 
          loggable: true 
        class: 
         loggable: MyBundle\Loggable\Listener\MyLoggableListener 
    
  3. 如果您使用的日期時間字段中的實體,但在數據庫中存儲你只有日期,那麼你還需要在所有制定者復位時間的一部分。

    public function setDateValue(DateTime $dateValue = null) 
    { 
        $dateValue->setTime(0, 0, 0); 
        $this->dateValue = $dateValue; 
        return $this; 
    } 
    

這應該做的工作。