public function testIfWillProperlyCreateAndSaveEmbedRefsFromPostData()
 {
     // POST data from real application
     $data = ['items' => [0 => ['title' => '', 'description' => '', 'hasText' => false, 'items' => [0 => ['filename' => '', 'file' => ['width' => 0, 'height' => 0, 'filename' => '', 'size' => 0, 'rootClass' => '', 'rootId' => '', 'contentType' => '', '_id' => '56336cccc79fda857b8b4b0e', '_key' => '', '_class' => 'Maslosoft\\Mangan\\Model\\Image', 'meta' => [], 'rawI18N' => []], 'basename' => '', 'relativeName' => '', 'icon' => '/css/filetypes/512/_blank.png', 'isImage' => false, 'iconSize' => 512, 'path' => '', 'url' => '/assets/get/56336cccc79fda857b8b4b06', 'type' => '', 'deleted' => false, 'title' => '', 'description' => '', 'id' => '56336cccc79fda857b8b4b06', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => ''], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b06', '_key' => '56336ccbc79fda857b8b4b00', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\PageAsset', 'meta' => [], 'parentId' => NULL], 1 => ['filename' => '', 'file' => ['width' => 0, 'height' => 0, 'filename' => '', 'size' => 0, 'rootClass' => '', 'rootId' => '', 'contentType' => '', '_id' => '56336cccc79fda857b8b4b0f', '_key' => '', '_class' => 'Maslosoft\\Mangan\\Model\\Image', 'meta' => [], 'rawI18N' => []], 'basename' => '', 'relativeName' => '', 'icon' => '/css/filetypes/512/_blank.png', 'isImage' => false, 'iconSize' => 512, 'path' => '', 'url' => '/assets/get/56336cccc79fda857b8b4b08', 'type' => '', 'deleted' => false, 'title' => '', 'description' => '', 'id' => '56336cccc79fda857b8b4b08', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => ''], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b08', '_key' => '56336cccc79fda857b8b4b01', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\PageAsset', 'meta' => [], 'parentId' => NULL], 2 => ['filename' => '', 'file' => ['width' => 0, 'height' => 0, 'filename' => '', 'size' => 0, 'rootClass' => '', 'rootId' => '', 'contentType' => '', '_id' => '56336cccc79fda857b8b4b10', '_key' => '', '_class' => 'Maslosoft\\Mangan\\Model\\Image', 'meta' => [], 'rawI18N' => []], 'basename' => '', 'relativeName' => '', 'icon' => '/css/filetypes/512/_blank.png', 'isImage' => false, 'iconSize' => 512, 'path' => '', 'url' => '/assets/get/56336cccc79fda857b8b4b0a', 'type' => '', 'deleted' => false, 'title' => '', 'description' => '', 'id' => '56336cccc79fda857b8b4b0a', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => ''], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b0a', '_key' => '56336cccc79fda857b8b4b02', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\PageAsset', 'meta' => [], 'parentId' => NULL]], 'assetsCount' => 0, 'id' => '56336cccc79fda857b8b4b0b', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => ''], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b0b', '_key' => '56336ccbc79fda857b8b4aff', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\AssetGroup', 'meta' => [], 'parentId' => ''], 1 => ['title' => 'Some title', 'description' => '', 'hasText' => true, 'items' => [], 'assetsCount' => 0, 'id' => '56336cccc79fda857b8b4b0c', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => 'Some title'], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b0c', '_key' => '56336cccc79fda857b8b4b03', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\AssetGroup', 'meta' => [], 'parentId' => '']], 'title' => '', 'description' => '', 'groupCount' => 0, 'assetsCount' => 0, 'id' => '56336cccc79fda857b8b4b0d', 'createUser' => NULL, 'createDate' => 0, 'updateUser' => NULL, 'updateDate' => 0, 'rawI18N' => ['title' => ['en' => ''], 'description' => ['en' => '']], '_id' => '56336cccc79fda857b8b4b0d', '_key' => '56336ccbc79fda857b8b4afe', '_class' => 'Maslosoft\\ManganTest\\Models\\DbRef\\AssetCollection', 'meta' => []];
     $model = SafeArray::toModel($data);
     $handler = function (ModelEvent $event) {
         $event->isValid = true;
         codecept_debug('EntityManager::EventBeforeSave');
     };
     Event::on($model, EntityManager::EventBeforeSave, $handler);
     $this->assertTrue($model instanceof AssetCollection);
     $this->assertSame(2, count($model->items));
     $this->assertTrue($model->items[0] instanceof AssetGroup);
     $this->assertTrue($model->items[1] instanceof AssetGroup);
     $this->assertSame(3, count($model->items[0]->items));
     $this->assertTrue($model->items[0]->items[0] instanceof PageAsset);
     $this->assertTrue($model->items[0]->items[1] instanceof PageAsset);
     $this->assertTrue($model->items[0]->items[2] instanceof PageAsset);
     codecept_debug(get_class($model->items[0]));
     /* @var $model AssetCollection */
     $saved = $model->save();
     $this->assertTrue($saved);
     $found = $model->findByPk($model->id);
     $this->assertNotNull($found);
     $this->assertTrue($found instanceof AssetCollection);
     $this->assertSame(2, count($found->items));
     $this->assertTrue($found->items[0] instanceof AssetGroup);
 }
Example #2
0
 /**
  * NOTE: This must be called by class using this trait
  * TODO Move event initializer to some other global event init, as events now handle traits too.
  * @Ignored
  */
 public function initTree()
 {
     if ($this instanceof TrashInterface) {
         // Trash related events
         $onBeforeTrash = function (ModelEvent $event) {
             $event->isValid = true;
         };
         Event::on($this, TrashInterface::EventBeforeTrash, $onBeforeTrash);
         $onAfterTrash = function (ModelEvent $event) {
             foreach ($event->sender->children as $child) {
                 $child->trash();
             }
         };
         Event::on($this, TrashInterface::EventAfterTrash, $onAfterTrash);
         $onAfterRestore = function (ModelEvent $event) {
             // Root nodes does not have parentId
             if ($this->parentId) {
                 // Put node to root if parent does not exists
                 /**
                  * TODO Similar mechanism should be used to detect orphaned tree items.
                  * TODO Use exists here instead of raw finder.
                  * TODO investigate why rawfinder was used here.
                  */
                 if (!(new RawFinder($this))->findByPk(new MongoId($this->parentId))) {
                     $this->parentId = null;
                     (new EntityManager($this))->update(['parentId']);
                 }
             }
         };
         $onAfterRestore->bindTo($this);
         Event::on($this, TrashInterface::EventAfterRestore, $onAfterRestore);
     }
 }
Example #3
0
 public function __construct($scenario = 'insert', $lang = '')
 {
     parent::__construct($scenario, $lang);
     static $once = false;
     // Also check if has handler because of EventDestroyer
     if (!$once || !Event::hasHandler($this, TrashInterface::EventAfterTrash)) {
         (new ParentChildTrashHandlers())->registerParent($this, ChildDocument::class);
         $once = true;
     }
 }
Example #4
0
 public function setOwner(AnnotatedInterface $owner = null)
 {
     parent::setOwner($owner);
     $root = $this->getRoot();
     $onAfterDelete = function () {
         $this->_onAfterDelete();
     };
     $onAfterDelete->bindTo($this);
     Event::on($root, EntityManager::EventAfterDelete, $onAfterDelete);
 }
Example #5
0
 public static function ensureClass($model, $name, &$dbValue)
 {
     if (!is_array($dbValue) || !array_key_exists('_class', $dbValue) || empty($dbValue['_class'])) {
         $class = static::getClassName($model, $name);
     } else {
         $class = $dbValue['_class'];
     }
     if (!ClassChecker::exists($class)) {
         $event = new ClassNotFound($model);
         $event->notFound = $class;
         if (Event::hasHandler($model, NotFoundResolver::EventClassNotFound) && Event::handled($model, NotFoundResolver::EventClassNotFound, $event)) {
             $class = $event->replacement;
         } else {
             throw new ManganException(sprintf("Embedded model class `%s` not found in model `%s` field `%s`", $class, get_class($model), $name));
         }
     }
     $dbValue['_class'] = $class;
 }
Example #6
0
 /**
  * @staticvar boolean $once
  */
 private function attachTrashHandlers()
 {
     // @codeCoverageIgnoreStart
     static $once = true;
     if ($once) {
         $handler = function (ModelEvent $event) {
             // @codeCoverageIgnoreEnd
             /* @var $event ModelEvent */
             $model = $event->sender;
             $this->onDelete(new AfterDelete($model));
             $event->handled = true;
             $event->isValid = true;
             // @codeCoverageIgnoreStart
         };
         $handler->bindTo($this);
         Event::on(TrashableTrait::class, TrashInterface::EventAfterTrash, $handler);
         $once = false;
     }
 }
Example #7
0
 protected function fetchData()
 {
     $criteria = $this->configureFetch();
     /**
      * TODO Refactor this into SearchFinder class
      */
     $qb = new QueryBuilder();
     if ($criteria instanceof SearchCriteria) {
         $models = $criteria->getModels();
         if (!empty($models)) {
             $qb->add($models);
         }
     }
     $model = $this->getModel();
     if (!Event::handled($model, FinderInterface::EventBeforeFind)) {
         return [];
     }
     $modelCriteria = $model->getDbCriteria();
     $criteria->mergeWith($modelCriteria);
     if (!empty($model)) {
         $qb->add($model);
     }
     $qb->setCriteria($criteria);
     $rawResults = $qb->search($criteria->getSearch());
     $results = [];
     foreach ($rawResults as $data) {
         $model = SearchArray::toModel($data['_source']);
         if ($model instanceof IndexAwareInterface) {
             $model->setIndex($data['_index']);
         }
         if ($model instanceof ScoreAwareInterface) {
             $model->setScore($data['_score']);
         }
         $results[] = $model;
     }
     return $results;
 }
Example #8
0
 public function testIfEventWillStopPropagateAndAllowAlmostRevokedSave()
 {
     $model = new WithEmbeddedArrayI18NModel();
     $m1 = new ModelWithI18N();
     $m2 = new ModelWithI18NSecond();
     $model->pages[] = $m1;
     $model->page = $m2;
     $triggered = false;
     $triggered1 = false;
     $triggered2 = false;
     $beforeSave = function (ModelEvent $event) use(&$triggered) {
         $event->stopPropagation();
         $triggered = true;
         $event->isValid = false;
     };
     $beforeSave1 = function (ModelEvent $event) use(&$triggered1) {
         $triggered1 = true;
         $event->isValid = false;
     };
     $beforeSave2 = function (ModelEvent $event) use(&$triggered2) {
         $triggered2 = true;
         $event->isValid = false;
     };
     Event::on($model, EntityManagerInterface::EventBeforeSave, $beforeSave);
     Event::on($m1, EntityManagerInterface::EventBeforeSave, $beforeSave1);
     Event::on($m2, EntityManagerInterface::EventBeforeSave, $beforeSave2);
     $saved = $model->save();
     $this->assertFalse($saved);
     $this->assertFalse($triggered1);
     $this->assertFalse($triggered2);
 }
Example #9
0
 /**
  * Set available languages. This method accepts one parameter,
  * array contaning language codes prefably in short ISO form.
  * Example valid array and method calls:
  * ```php
  * $languages = ['en', 'pl', 'ru'];
  * $model->setLanguages($languages);
  * $model2->setLanguages(['en']);
  * ```
  * @param string[] $languages
  * @Ignored
  */
 public function setLanguages($languages)
 {
     $event = new ModelEvent($this);
     $event->data = $languages;
     if (!Event::valid($this, InternationalInterface::EventBeforeLanguagesSet, $event)) {
         return;
     }
     $this->_languages = $languages;
     Event::trigger($this, InternationalInterface::EventAfterLanguagesSet, $event);
 }
Example #10
0
 /**
  * Restore trashed item
  * @return boolean
  * @throws Exception
  * @Ignored
  */
 public function restore()
 {
     if (!$this instanceof TrashInterface) {
         // When trying to restore normal document instead of trash item
         throw new Exception(sprintf('Restore can be performed only on `%s` instance', TrashInterface::class));
     }
     $em = new EntityManager($this->data);
     // Set scenario to `restore` for model, which is just about to be restored
     ScenarioManager::setScenario($this->data, TrashInterface::ScenarioRestore);
     if (!Event::valid($this->data, TrashInterface::EventBeforeRestore)) {
         return false;
     }
     $saved = $em->save();
     if (!$saved) {
         return false;
     }
     $finder = new Finder($this->data);
     $model = $finder->find(PkManager::prepareFromModel($this->data));
     if (!$model) {
         return false;
     }
     $eventAfter = new RestoreEvent();
     $eventAfter->setTrashed($this->data);
     $eventAfter->setTrash($this);
     if (!Event::valid($model, TrashInterface::EventAfterRestore, $eventAfter)) {
         return false;
     }
     $trashEm = new EntityManager($this);
     $this->data = null;
     // Use deleteOne, to avoid beforeDelete event,
     // which should be raised only when really removing document:
     // when emtying trash
     return $trashEm->deleteOne(PkManager::prepareFromModel($this));
 }
Example #11
0
 /**
  * Triggers a class-level event and checks if it's handled.
  * If don't have event handler returns true. If event handler is set, return true if `Event::handled`.
  * This method will cause invocation of event handlers that are attached to the named event
  * for the specified class and all its parent classes.
  * @param AnnotatedInterface $model the object specifying the class-level event.
  * @param string $name the event name.
  * @param ModelEvent $event the event parameter. If not set, a default [[Event]] object will be created.
  * @return bool|null True if handled, false otherway, null if not triggered
  */
 public static function handled(AnnotatedInterface $model, $name, $event = null)
 {
     if (Event::trigger($model, $name, $event)) {
         return $event->handled;
     }
     return true;
 }
Example #12
0
 /**
  * This method is invoked after deleting a record.
  * The default implementation raises the {@link onAfterDelete} event.
  * You may override this method to do postprocessing after the record is deleted.
  * Make sure you call the parent implementation so that the event is raised properly.
  * @since v1.0
  */
 private function _afterDelete()
 {
     $event = new ModelEvent($this->model);
     Event::trigger($this->model, EntityManagerInterface::EventAfterDelete, $event);
     (new Signal())->emit(new AfterDelete($this->model));
 }
 public function testIfWillTriggerAfterDelete()
 {
     $triggered = false;
     $model = new DocumentBaseAttributes();
     $afterDelete = function (ModelEvent $event) use(&$triggered) {
         $triggered = true;
     };
     Event::on($model, EntityManagerInterface::EventAfterDelete, $afterDelete);
     $saved = $model->save();
     $deleted = $model->delete();
     $this->assertTrue($deleted);
     $this->assertTrue($triggered);
     Event::off($model, EntityManagerInterface::EventAfterDelete, $afterDelete);
 }
Example #14
0
 public static function destroyAllEvents()
 {
     parent::destroyEvents();
 }
Example #15
0
 /**
  * Trigger before exists event
  * @return boolean
  */
 private function _beforeExists()
 {
     if (!Event::hasHandler($this->model, FinderInterface::EventBeforeExists)) {
         return true;
     }
     return Event::handled($this->model, FinderInterface::EventBeforeExists);
 }
 /**
  * Register event handlers for child item of parent-child relation.
  *
  * @param AnnotatedInterface $child
  * @param string $parentClass
  * @throws UnexpectedValueException
  */
 public function registerChild(AnnotatedInterface $child, $parentClass)
 {
     if (!ClassChecker::exists($parentClass)) {
         throw new UnexpectedValueException(sprintf('Class `%s` not found', $parentClass));
     }
     // Prevent restoring item if parent does not exists
     $beforeRestore = function (ModelEvent $event) use($child, $parentClass) {
         $model = $event->sender;
         if ($model instanceof $child) {
             $parent = new $parentClass();
             $criteria = new Criteria(null, $parent);
             $criteria->_id = $model->parentId;
             if (!$parent->exists($criteria)) {
                 $event->isValid = false;
                 return false;
             }
         }
         $event->isValid = true;
     };
     Event::on($child, TrashInterface::EventBeforeRestore, $beforeRestore);
 }