جدول زمني لأول مرة تم تعيين حقل

0

انا املك state خاصية (حالة الجهاز) على كيان وأنا أقوم بتعيين حقول التاريخ والوقت بناءً على وقت انتقال الكيان إلى حالة معينة.

حالات المهمة: (مبسطة)

  • جديد
  • في تقدم
  • اكتمال

يمكن أن تنتقل المهمة مرة أخرى إلى in_progress بعد تعيينه على complete ، لكني أريد استخدام الطابع الزمني لتعيين $dateStarted الملكية فقط في المرة الأولى التي تنتقل إليه in_progress .

سيتم تعيين هذا الرمز دائمًا $dateStarted لآخر مرة $state التحولات إلى in_progress .

هل هناك طريقة لتكوين ذلك $dateStarted يتم تعيينها في المرة الأولى التي تنتقل فيها المهمة إلى in_progress ؟؟؟

/**
 * @var \DateTime
 *
 * @ORM\Column(type="datetime", nullable=true)
 * @Gedmo\Timestampable(on="change", field="state", value="in_progress")
 */
private $dateStarted;

2 الاجابة

2
افضل جواب

كما تقول Fyrye ، يمكنك استخدام رد اتصال دورة حياة مع وظيفة لتحديد موعدك مرة واحدة فقط. أستخدمها على هذا النحو:

/**
 * @ORM\PrePersist
 * @ORM\PreUpdate
 */
public function setTheStartDate()
{
    if ($this->getState() === 'in_progress' && $this->getDateStarted === null) {
        $this->setDateStarted(new \DateTime('now'));
    }
}

تأكد أيضًا من وجود التعليق التوضيحي التالي على صفك لتمكين عمليات الاسترداد لدورة الحياة:

* @ORM\HasLifecycleCallbacks()
:مؤلف
1
افضل جواب

كما ذكرت في تعليق ، Timestampable غير قادر على استخدام التعبيرات أو طريقة رد الاتصال لتقييم القيمة المتغيرة. بينما يمكنك استخدام رد اتصال دورة الحياة لتحقيق النتيجة المرجوة. تضيف عمليات الاسترداد لدورة الحياة طبقة إضافية من النفقات العامة والتعقيد إلى كيانك ، والتي يصعب تعقبها المشاكل التي تنشأ عنها وتوسيع التعليمات البرمجية الخاصة بك في المستقبل أكثر مملة. مثال واحد عند استخدام عمليات رد الاتصال Timestampable أو Lifecycle ؛ ال dateStarted لن يتم تعيينه حتى بعد مسح التغييرات على قاعدة البيانات. هذا يسبب الرجوع إلى dateStarted القيمة في منطق الأعمال الأخرى مستحيلة حتى تقوم بإرسالها إلى قاعدة البيانات.

لذلك يوصى بدلاً من ذلك بوضع منطق عملك في setState طريقة. القيام بذلك سيفرض المطلوب dateStarted قواعد المهمة. يسمح لك هذا أيضًا باستخدام منطق عمل إضافي ، مثل التأكد من عدم القفز من الدولة new إلى complete ، دون أن يتم تعيينه أولاً in_progress ، إلخ.

مثال: https://3v4l.org/s9PJu

class MyEntity
{

    const STATE_NEW = 'new';
    const STATE_IN_PROGRESS = 'in_progress';
    const STATE_COMPLETE = 'complete';
    const CONFIG_STATES = array(
        self::STATE_NEW,
        self::STATE_IN_PROGRESS,
        self::STATE_COMPLETE
    );

    /**
     * @var \DateTime|null
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $dateStarted;

    /**
     * @var string|null
     * @ORM\Column(type="string", nullable=true)
     */
    private $state = self::STATE_NEW;

    /**
     * @var string|null $state
     */
    public function setState($state = null)
    {
        $this->validateState($state);
        $this->updateStateDate($state);
        $this->state = $state;

        return $this;
    }

    public function getState()
    {
        return $this->state;
    }

    public function getDateStarted()
    {
        return $this->dateStarted;
    }

    /**
     * used to update the started date when the state changes to in_progress
     * @var string $state
     */
    protected function updateStateDate($state) 
    {
        if ($this->state !== $state && $state === self::STATE_IN_PROGRESS && $this->dateStarted === null) {
            $this->dateStarted = new \DateTime();
        }

        return $this;
    }

    protected function validateState($state)
    {
       if (!in_array($state, self::CONFIG_STATES, true)) {
            throw new \InvalidArgumentException(
                sprintf('Unknown state "%s". Expected one of: "%s"', 
                    $state, 
                    implode('", "', self::CONFIG_STATES)
                )
            );
        }
        if ($this->state === self::STATE_NEW && $state !== self::STATE_IN_PROGRESS) {
            throw new \InvalidArgumentException(
                sprintf('Invalid state "%s" specified, Expected: %s', 
                    $state, 
                    self::STATE_IN_PROGRESS
                )
            );
        }

        return $this;
    }
}

إستعمال:

//default state = "new", dateStarted = null
$entity = new \MyEntity;

//state = "in_progress",  dateStarted = \DateTime('now')
$entity->setState(MyEntity::STATE_IN_PROGRESS); 
//NOTE - $entity->getDateStarted()  will return a value now without first using $em->flush();

//only changes state to "complete", leaves the previously assigned date
$entity->setState(MyEntity::STATE_COMPLETE);

//only changes state to "in_progress", leaves the previously assigned date
$entity->setState(MyEntity::STATE_IN_PROGRESS);

أقترح أيضا ، إذا لم يتم ذلك بالفعل ، تحويل الخاص بك state حقل من سلسلة إلى كيان مرتبط. يمكنك بعد ذلك إزالة STATE الثوابت والتحقق من الداخل validateState ، نظرًا لأن قيد المفتاح الخارجي سيفرض تعيين دولة صالحًا.


كملاحظة أخيرة ، نظرًا لأنك تستخدم إطار عمل Symfony ، يمكنك بدلاً من ذلك استخدام قيود التحقق من صحة النموذج ونقل منطق عملك إلى تلك القيود / الاستدعاءات ، والتي سيتم التحقق منها عند إرسال النماذج وتغيير الكيان الخاص بك وعرض رسائل ودية وفقًا لذلك.

:مؤلف

أسئلة ذات صلة

فوق
قائمة طعام