Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony Gedmo \Loggable记录不';我没有改变_Symfony_Doctrine Orm_Symfony 2.2_Doctrine Extensions_Stofdoctrineextensions - Fatal编程技术网

Symfony Gedmo \Loggable记录不';我没有改变

Symfony Gedmo \Loggable记录不';我没有改变,symfony,doctrine-orm,symfony-2.2,doctrine-extensions,stofdoctrineextensions,Symfony,Doctrine Orm,Symfony 2.2,Doctrine Extensions,Stofdoctrineextensions,我将Symfony2.2与StofDoctrineExtensionsBundle(以及Gedmo DoctrineExtensions)一起使用。 我有一个简单的实体 /** * @ORM\Entity * @Gedmo\Loggable * @ORM\Table(name="person") */ class Person { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\Generated

我将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\u log\u 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()); }
但我不明白的是,为什么字段
生日
总是包含在日志条目中,即使它没有更改。以下是三个日志条目的一些示例:

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@example.com"
  ["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
}
我只想记录真正更改的数据。有什么我还没看到的选择吗?这似乎与以下事实有关:
birthdate
是一个
DateTime
对象,不是吗

编辑 它与
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";}

为什么?

这可能与我在使用这些扩展中的另一个扩展(时间戳)时遇到的问题类似,即:条令中使用的默认更改跟踪策略(它尝试自动检测更改)有时会将实体标记为脏的,而不是脏的(对我来说,当我的实体包含一个datetime对象时发生了这种情况,这是可以理解的,因为这是一个从数据库中提取它时需要构造的对象)。这不是一个bug或任何东西——这是预期的行为,有一些方法可以解决

可能值得尝试在您想要记录的实体上实施一种替代的更改跟踪策略,看看这是否能解决问题-我想这种行为(记录)不会起作用,除非实体状态是脏的,您可以通过手动实施更改跟踪来避免:

不要忘记更新您的实体:

YourBundle\Entity\YourThing:
    type: entity
    table: some_table
    changeTrackingPolicy: NOTIFY
请参阅此线程:


对于
\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;
}
这里您将
insurance\u number
声明为整数属性,但我们知道
PHP
没有类型,并且执行动态强制转换,这与
Gedmo Loggable
冲突

要解决这个问题,只需确保在
Setter方法中或在
业务逻辑中执行显式强制转换

例如,替换此(业务逻辑):

$application->setInsuranceNumber($valueComeFromHtmlForm)

关于这一点:

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

然后,当您持久化对象时,您将不会在日志中看到任何记录


我认为这是因为
Loggable
document Change Tracker
期望
Integer
并接收
字符串(这是一个“非强制转换的整数”)
,因此它将属性标记为脏。我们可以在
Log Record
中看到它(
S
表示新值是字符串)

我今天也遇到了这个问题并解决了它。这里是完整的解决方案,适用于所有字符串、浮点、int和日期时间值

  • 制作您自己的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;
        }
    }
    
  • 若在实体中使用DateTime字段,但在数据库中只存储日期,那个么还需要在所有设置器中重置时间部分

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

  • 这应该可以完成任务。

    即使这是一个老问题,我也决定不实现自己的通知功能,让这种糟糕的行为继续下去:(@rabudde并不是信条的错——但PHP糟糕的对象比较当然,这也可能是PHP的错,对不起。但我无法想象,如果我为基于PHP的应用程序编写一个包/插件来比较对象会有那么难,但我不会侵入Gedmo包。但是谢谢你的回答,nev毫无疑问。
    public function setDateValue(DateTime $dateValue = null)
    {
        $dateValue->setTime(0, 0, 0);
        $this->dateValue = $dateValue;
        return $this;
    }