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); }
/** * 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); } }
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; } }
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); }
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; }
/** * @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; } }
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; }
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); }
/** * 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); }
/** * 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)); }
/** * 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; }
/** * 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); }
public static function destroyAllEvents() { parent::destroyEvents(); }
/** * 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); }