مشاكل استخدام العقيدة ODM في عمليات الشيطان

أريد أن أتحدث عن تجربتي في استخدام Doctrine ODM في مشروع PHP صغير نسبيًا حيث تتركز قاعدة الكود الرئيسية في عمليات الخفي. وبشكل عام ، كيف ربطنا عقيدة ODM إلى Yii2. أحذرك على الفور - القصة ستكون مملة للغاية وعلى الأرجح مثيرة للاهتمام فقط لأولئك الذين واجهوا بالفعل مشاكل عند العمل مع Doctrine ODM في عمليات خفية.


أين سنقوم باللف


قبل حوالي 6 سنوات ، عهدوا إلي بالمهمة: قطع من قطعة واحدة متجانسة إلى Yii1قطعة من الرمز إلى خدمة منفصلة. سيتم التنفيذ قبل الانتهاء من سرد طلبك. لم يختر الإطار لفترة طويلة ، باستثناء Yiiأنني لم أكن أعرف أي شيء ، ثم أعلنوا عن إصدار وشيك Yii2، والذي بدا في ذلك الوقت أنيقًا جدًا / عصريًا / شبابيًا ، لكن المعرفة بالنسخة الأولى من هذا الإطار سمحت لنا بتخفيض عتبة الدخول إلى الإصدار الثاني. كان MongoDB أيضًا من المألوف ، والذي كنا على دراية به بالفعل وعملنا Yii1مع ملحق منفصل ، ولكن Yii2تم دعمه خارج الصندوق.


في البداية ، كانت الخدمة الدقيقة بسيطة للغاية: كان من الضروري استقبال الملفات من المستخدمين وتخزينها في تخزين مستمر ، والاحتفاظ بسجلات لهذه الملفات في قاعدة البيانات ، وإصدار معلومات تتعلق بهذه الملفات والارتباطات لهم استجابة للطلبات ذات الصلة من خلال واجهة برمجة التطبيقات.


بمرور الوقت ، بدأت هذه الخدمة الصغيرة في النمو: ظهرت معالجة الفيديو ، وفحص الفيروسات ، والتخزين الموزع عبر مناطق مختلفة (la CDN). مر الوقت بسرعة ، تطور المشروع بنشاط وحتى خضع لإعادة هيكلة ، ولكن في مرحلة ما ، بسبب الاتجاهات الجديدة والنمو المهني ، ظهر أيضًا شعور بعدم الراحة عند التفاعل مع هذا المشروع. أصبحت الرغبة في العمل في هذا المشروع أقل وأقل فكرت بجدية.


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


PHP 7- , . ActiveRecord Yii2 — "" , , phpdoc. MongoDB, - , - {user_id : '12'}


, . - , Yii2 . , , , , , .



, , MongoDB.
Symfony Doctrine ORM, Doctrine ODMORM MongoDB.


Yii2 Symfony , , :
- — , , .
- — ActiveRecord " " Yii2


, ActiveRecord Doctrine ODM, . , ORM .


. Doctrine DocumentManager ( EntityManager Doctrine ORM). " ".


Dependency Injection Container Yii2 , .


Yii2 DataProvider'a. -, CRUD- . " " . , Yii2. , , — , .


, Doctrine UnitOfWork , .



, : DI- , . - , Symfony .


, :


while (!$this->isShuttingDown()) {
    //  Task,  ,     
    //  MANAGED    ,
    //     
    $task = $this->taskProvider->getNextTask();
    try {
        //   -  , ,  
        $this->someService->runTask($task);
    } catch (SomeException $e) {
        //    :       
        //     MANAGED,      
        //       -     
        $this->switchTaskToError($task, $e);
    }
}

, - dirty ( flush() ), , , .


clear() "" . , , . clear() , , , $this->someService->runTask($task);



, ( , — ), . . , , . , , . .


:


while (!$this->isShuttingDown()) {
    //  ,  , 
    //   -  ,   
    //    detached,      , 
    //      
    $task = $this->taskProvider->getNextTask();
    try {
        //   -     
        $this->someService->runTask($task);
    } catch (SomeException $e) {
        //    ,  -   
        $this->switchTaskToError($task, $e);
    }
}

taskProvider someService , .


merge. runTask() :


public function runTask(Task $task) {
    $dm = $thic->dmFactory->createDocumentManager();
    $task = $dm->merge($task);
    ....
    $task->setStatus(Task::STATUS_OK);
    $dm->flush();
}

switchTaskToError() :


public function switchTaskToError(Task $task, Throwable $) {
    $dm = $this->dmFactory->createDocumentManager();
    $task = $dm->merge($task);
    $task->setStatus(Task::STATUS_ERROR);
    $task->setError($e->getMessage());
    $dm->flush();
}

, $dm .


, , - . , :


$tasks = $this->taskProvider->getProblemTasks();
$dm = $thic->dmFactory->createDocumentManager();
foreach ($tasks as $task) {
     $task = $dm->merge($task);
     $task->setState(..);
}
$dm->flush();

getProblemTasks , , "" , Task merge(). , merge() — .. , .


, , :


$dm = $thic->dmFactory->createDocumentManager();
$tasks = $this->taskProvider->getProblemTasks($dm);
foreach ($tasks as $task) {
     $task->setState(..);
}
$dm->flush();

.


JPA


, Doctrine JPA: , UnitOfWork, (managed, detached ..). JPA , , . , — . (Spring Framework ). JPA , , .


, , . - , , - (? ), ( ). , , .


, hibernate Doctrine.


Doctrine ODM


" doctrine" , - http , , , .


, . , . . , :


$session = $this->sessionManager->createNewSession();
try {
    $dm= $session->getDocumentManager();
    $tasks = $this->taskProvider->getProblemTasks();
    foreach ($tasks as $task) {
        $task->setState(..);
    }
    $dm->flush();
} finally {
    $this->sessionManager->close($session);
}

getProblemTasks


public function getProblemTasks(): array
{
    $repo = $this->sessionManager
                      ->getCurrentSession()
                      ->getDocumentManager()
                      ->getRepository(Task::class);

    return $repo->findBy(['status' => Task::STATUS_ERROR]);
}

, , , , .


:


public function switchTaskToError(Task $task, Throwable $) {
    //   ,  ,    
    $session $this->sessionManager->createNewSession();
    $dm = $session->getDocumentManager();
    try {
        $task = $dm->merge($task);
        $task->setStatus(Task::STATUS_ERROR);
        $task->setError($e->getMessage());
        $dm->flush();
    finally {
        $this->sessionManager->close($session);
    }
}

, , , wrap, , .


, 3 SessionManager


createNewSession — , "" .
getCurrentSession — .
close


, ( php-ds).


:
createNewSession — , .
getCurrentSession — , , .
close — .


, , , .


wrap, , :


public function switchTaskToError(Task $task, Throwable $) {
    $this->sessionManager->wrapBySession(function(DocumentManager $dm) use ($task, $e) {
        $task = $dm->merge($task);
        $task->setStatus(Task::STATUS_ERROR);
        $task->setError($e->getMessage());
        $dm->flush();
    });
}


بشكل عام ، تبين أن آلية الجلسة مريحة للغاية. على الأقل قام بحل جميع مشاكلنا. بالطبع ، سيكون من الجيد أيضًا إدارة الجلسات باستخدام نهج إعلاني ، كما هو الحال في إطار الربيع ، على سبيل المثال. سيقلل هذا بشكل كبير من النفقات العامة في شكل رمز زائدة ، ولكن في الوقت الحالي لا يمكنني حتى تخيل كيف يمكن القيام بذلك في PHP.


All Articles