【问题标题】:DRY: how to use this code in several entities accross Symfony2 project? Traits?DRY:如何在 Symfony2 项目的多个实体中使用此代码?特质?
【发布时间】:2015-01-23 12:26:57
【问题描述】:

我有这段重复的代码,将在我的 Symfony2 项目中的多个实体中使用,所以如果可能的话,当然可以应用某种 DRY,我正在考虑 PHP Traits

private static $preDeletedEntities;// static array that will contain entities due to deletion.
private static $deletedEntities;// static array that will contain entities that were deleted (well, at least the SQL was thrown).

/**
 * This callback will be called on the preRemove event
 * @ORM\PreRemove
 */
public function entityDueToDeletion()
{
    // This entity is due to be deleted though not deleted yet.
    self::$preDeletedEntities[] = $this->getId();
}

/**
 * This callback will be called in the postRemove event
 * @ORM\PostRemove
 */
public function entityDeleted()
{
    // The SQL to delete the entity has been issued. Could fail and trigger the rollback in which case the id doesn't get stored in the array.
    self::$deletedEntities[] = $this->getId();
}

public static function getDeletedEntities()
{
    return array_slice(self::$preDeletedEntities, 0, count(self::$deletedEntities));
}

public static function getNotDeletedEntities()
{
    return array_slice(self::$preDeletedEntities, count(self::$deletedEntities)+1, count(self::$preDeletedEntities));
}

public static function getFailedToDeleteEntity()
{
    if(count(self::$preDeletedEntities) == count(self::$deletedEntities)) {
        return NULL; // Everything went ok
    }

    return self::$preDeletedEntities[count(self::$deletedEntities)]; // We return the id of the entity that failed.
}

public static function prepareArrays()
{
    self::$preDeletedEntities = array();
    self::$deletedEntities = array();
}

这是我想到的代码:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\HasLifecycleCallbacks()
 */
trait DeleteLifeCycleCallbacksTrait
{
    // write things here
}

但是注释会应用于实体吗?可以吗?你会怎么做才能避免重复代码?

编辑:试图找到最佳方法

@Cerad 用户那里得到一些想法,因为正如文档所说,生命周期事件侦听器比简单的生命周期回调更强大,那么我将开始使用它们。

所以,首先,Lifecycle Callbacks|Listener|Suscribers 的目的是存储每个持久对象的 ID,以便我可以通过某种方式获取它并从控制器发送回视图。作为一个简单的视觉示例,假设我从视图向控制器发送了这个值数组(1, 2, 3, 4, 5),并且由于某种 X 原因,只有 1 ,4 和 5 被持久化(意味着从 DB 中完全删除)到 DB,对吗?

还可以说,我将在Producto 实体中使用事件侦听器。因此,无需测试并仅从示例中获取代码,Listener 的代码应该是这样的:

use Doctrine\ORM\Event\LifecycleEventArgs;
use Entity\Producto;

class StoreDeletedIds
{
    private $deletedItems = []; 

    public function postDelete(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        if ($entity instanceof Producto) {
            array_push($deletedItems, $entity->getId());
        }
    }
}

我的问题|对此的疑问是:

  • 上面的代码好还是不好?
  • 每次 Doctrine 调用侦听器时是否都会清理 $deletedItems
  • 如何返回 $deletedItems 以便在控制器上捕获它并发送回视图?
  • 我是否也需要定义订阅者?为什么?

这对我来说是新话题,所以我需要一些建议

【问题讨论】:

  • 在这种情况下我不会使用 trait。你有没有考虑过给它上课?还是服务?
  • @SergioCosta 不,实际上我不知道如何使用服务,使用一个类,我认为您的意思是稍后从实体本身扩展该类,对吗?
  • 看这里:symfony.com/doc/current/book/service_container.html 并尝试了解服务的工作原理。如果您有任何问题,请告诉我!
  • @SergioCosta 我知道服务是如何工作的,以及在这种情况下如何将它们构建到这个我应该通过 EntityManager 来访问它,我现在不知道这将如何在 DRY 方面帮助我,使用服务有什么优势以及如何从 Doctrine Entity 本身使用它
  • Doctrine and DRY 是矛盾的。

标签: php symfony lifecycle traits


【解决方案1】:

以下@PeterPopelyshko评论这是我自带的解决方案,只需定义一个抽象类Model\DeleteLifeCycleCallbacks.php并将代码放入:

use Doctrine\ORM\Mapping as ORM; // not so sure if this is need here

abstract class DeleteLifeCycleCallbacks
{
    private static $preDeletedEntities;// static array that will contain entities due to deletion.
    private static $deletedEntities;// static array that will contain entities that were deleted (well, at least the SQL was thrown).

    /**
     * This callback will be called on the preRemove event
     * @ORM\PreRemove
     */
    public function entityDueToDeletion()
    {
        // This entity is due to be deleted though not deleted yet.
        self::$preDeletedEntities[] = $this->getId();
    }

    /**
     * This callback will be called in the postRemove event
     * @ORM\PostRemove
     */
    public function entityDeleted()
    {
        // The SQL to delete the entity has been issued. Could fail and trigger the rollback in which case the id doesn't get stored in the array.
        self::$deletedEntities[] = $this->getId();
    }

    public static function getDeletedEntities()
    {
        return array_slice(self::$preDeletedEntities, 0, count(self::$deletedEntities));
    }

    public static function getNotDeletedEntities()
    {
        return array_slice(self::$preDeletedEntities, count(self::$deletedEntities)+1, count(self::$preDeletedEntities));
    }

    public static function getFailedToDeleteEntity()
    {
        if(count(self::$preDeletedEntities) == count(self::$deletedEntities)) {
            return NULL; // Everything went ok
        }

        return self::$preDeletedEntities[count(self::$deletedEntities)]; // We return the id of the entity that failed.
    }

    public static function prepareArrays()
    {
        self::$preDeletedEntities = array();
        self::$deletedEntities = array();
    }
}

然后按如下方式使用:

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class Producto extends Model\DeleteLifeCycleCallbacks
{
    // entity methods and properties here
}

【讨论】:

  • 是这样,如果你需要在每个类中实现abstract方法,也要定义它们。
  • @PeterPopelyshko 现在我不需要那个,但对于任何寻找这样的东西的人来说都是一个好点,谢谢
  • 这种方法的问题在于它不是非常面向对象的。 Producto 是 DeleteLifeCycleCallback 吗?可能不是。基于“has”而不是“is”构建类层次结构可能会导致域模型出现问题。如果它对你有用,那么很好,但静态数组和方法是危险信号。
  • @Cerad,根本不工作,我仍在解决一些问题,因为$deletedEntities 永远不会返回 ID,即使它们已从数据库中删除(持久化),但无论如何,它们是什么红旗?您能告诉我您对改进代码和获得更好的 OOP 有什么建议吗?
  • 在不了解您的用例的情况下很难说。我倾向于避免使用实体回调,并且可能会从一个独立的订阅者对象开始:doctrine-orm.readthedocs.org/en/latest/reference/…。但同样,我无法通过扫描您的代码来准确判断您想要实现的目标。
【解决方案2】:

不要

业务逻辑不属于实体。

Traits 也无济于事,因为虽然复制代码是一件坏事,但滥用 Traits imo 更糟糕。

我曾经想知道我是否应该使用特征并在 codereview (https://codereview.stackexchange.com/a/74195/56686) 上发布了一个问题。我还没有在我的应用程序中偶然发现一个有效的特征用例。

提供服务

我建议您提供服务并将您的逻辑放在那里。 文档:http://symfony.com/doc/current/book/service_container.html

因为你不能从学说生命周期回调中调用 symfony 服务,你必须放弃那些。

您可能不想启动您选择的搜索引擎来寻找分步教程。

【讨论】:

  • 为什么你的意思是这是业务逻辑的一部分?不是,我想。我只是想返回哪些实体可以删除,哪些不能删除,我没有为此使用 Traits,而是用于实体上的重复代码,例如 ID 的 getter 和 setter。另一方面,你有做过这样的事情的经历吗?我还没有并且需要一些代码作为起点,你能用一些改进你的答案吗?
  • I'm just trying to return which entities could be deleted and which not 我认为这个业务逻辑不属于实体。如果你不想讨论这个,请加入我的 symfony2 聊天:chat.stackoverflow.com/rooms/68838/symfony2
  • 我同意这一点!实体应该只是一个数据保存对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多