【问题标题】:TYPO3 6.2 extbase repository object cloning not saving records properlyTYPO3 6.2 extbase 存储库对象克隆未正确保存记录
【发布时间】:2015-10-12 13:27:57
【问题描述】:

我有一个事件创建扩展,其中包含为用户创建事件的选项。这是使用 extbase 存储库方法实现的。在活动创建表单中,我有一个开始日期、结束日期和应该重复活动的工作日。

例如,如果我将开始日期设置为 13-10-2015 并将结束日期设置为 30-10-2015。并将工作日选择为“星期三”。因此该事件将在 13 到 30 之间的所有“星期三”重复。

当我创建一个非重复事件时,它会正常工作。但是对于重复发生的事件,我已经实现了extbase存储库的克隆方法。

if (!empty($endDateRecurring) && !empty($recurringWeekDays)) {
            $endDate = new \DateTime($endDateRecurring);
            $startDate = $newEvent->getDate();
            $startDate->setTime(0, 0);
            $datetimeDiff = $startDate->diff($endDate);

            for ( $event=1; $event <= $datetimeDiff->days; $event++ ) { 
                $checkDate = $newEvent->getDate()->add(new \DateInterval('P'.$event.'D'));
                $dayOfWeekNo = date('w',$checkDate->getTimestamp());

                if ( in_array( $dayOfWeekNo, $recurringWeekDays ) ) {               
                    $eventProperties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties( $newEvent );
                    \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty( $eventProperties, 'date', $eventProperties['date']->add(new \DateInterval('P1D') ) );

                    $eventCopy = $this->objectManager->create('\TYPO3\EventCreate\Domain\Model\Event');                 
                    foreach ( $eventProperties as $propertyName => $propertyValue ) {
                        if (\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($eventCopy,
                            $propertyName) && !in_array($propertyName, array('uid','pid'))) {
                                $propertyValue = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty( $newEvent, $propertyName );
                                \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty( $eventCopy, $propertyName, $propertyValue );
                            }
                    }
                    //TODO: cloning doesn't work because the id is already set and it thus doesn't add a new object to the repository.
                    //either create a new object and copy all content properties, or find another way to add more events to the db for recurring days.
                    $this->eventRepository->add($eventCopy);
                    $this->objectManger->get('Tx_Extbase_Persistence_Manager')->persistAll();
                }
            }
        }

这里的 $recurringWeekDays 是一个数组,其中包含选定的重复工作日 id(对于 Monday-1, Tuesday-2 像这样)。

问题是当有任意天数要插入时,只有一条记录插入到数据库中。在上述示例中,10 月 13 日至 30 日之间的 3 个星期三。但只插入了一条记录。

如果有人知道解决方案,请帮忙。

【问题讨论】:

    标签: php repository typo3 extbase typo3-6.2.x


    【解决方案1】:

    我猜想使用 objectManager 是个问题。尝试改变

    $eventCopy = $this->objectManager->create('\TYPO3\EventCreate\Domain\Model\Event');
    

    $eventCopy = new \TYPO3\EventCreate\Domain\Model\Event();
    

    这行得通吗?

    【讨论】:

    • 对不起,杰。它不工作...:(。我认为问题出在 $this->objectManger->get('Tx_Extbase_Persistence_Manager')->persistAll();。你能给我一个提示吗关于这个?
    • 我不认为这是问题所在。 persistAll() 只是强制存储库将所有更改(例如添加、更新或删除对象)保留在数据库中。否则,这只会​​在您的 Controller-Action 完成后完成。因此,在 for-loop 完成后立即运行 persistAll() 就足够了。
    • 您能否在使用\TYPO3\CMS\Core\Utility\GeneralUtility::devLog('uid: '.$eventCopy-&gt;getUid().', isDirty? '.($this-&gt;_isDirty() ? 'yes' : 'no'), 'myextensionkey'); 调用add() 之前调查您的$eventCopy uid 应该为null,并且对象被标记为脏,但确实如此吗?另一个问题:为什么要删除 pid-property?
    • 其实我不需要去掉pid。我刚刚在我的开发中添加了这个。我的问题是假设如果有 4 个条目,那么最后一个条目插入数据库 4 次(执行的循环数)。
    • 对象有一个内部 ID,这在 ORM 中用于向数据库中插入一条记录。如果您不重置此 ID,则 extbase 会将所有对象视为相同。您将需要设置_isDirty 并检查_memorizeCleanState()(请参阅ObjectMonitoringInterface)。从DomainObjectInterface 检查_isNew。完整参考:typo3.org/api/typo3cms/…
    【解决方案2】:

    再一次尝试作为我之前回答的讨论的结论:

    正如@pgame 所指出的,问题在于ORM 中使用的内部ID。在Persistence/ObjectStorage.php 中,我可以看到PHP 的spl_object_hash($object) 用于为存储中的对象生成内部ID。所以我们必须确保这个函数不会多次产生相同的哈希。

    由于它是在http://php.net/manual/de/function.spl-object-hash.php 中编写的,您可以在第一个用户注释中读到,此函数不是通过对象属性生成其哈希值,而是通过内部句柄来保证内存中的多个实例将具有不同的哈希值。但是一旦实例被销毁,哈希可能会被重用用于另一个实例。

    因此,我们必须确保在每次 for 迭代中,$eventCopy 的实例不会被下一个实例覆盖(并因此被破坏),因为它可能会在 ObjectStorage 中产生相同的哈希值。我建议创建一个数组$eventCopies 并将$eventCopy 的每个新实例推送到此。因此,通过 for 循环中的所有迭代,每个实例都将在此数组中保持活动状态。毕竟,您可以再次循环您的 $eventCopies 并将每个都添加到您的存储库中。

    这次可以吗?

    【讨论】:

    • 感谢您的提示。我会试试这个。
    • 嗯,我想到了这里的解释。我忘记了 ObjectStorage 会在内存中保留对 Object 的引用,所以当$eventCopy 被覆盖时它不应该被销毁。 ...因此我在这里的解决方案仍然不能解决问题。或者是吗? ...伙计,我现在正致力于为您的问题找到解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    • 2015-02-13
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多