public function __construct($entityClass, $entityCollection, $conditions, $order, $limit, $offset) { // Convert boolean strings to boolean foreach ($conditions as &$condition) { if (is_scalar($condition) && (strtolower($condition) === 'true' || strtolower($condition) === 'false')) { $condition = StdObjectWrapper::toBool($condition); } } $this->entityClass = $entityClass; $this->collectionName = $entityCollection; $this->conditions = $conditions; $this->order = $order; $this->offset = $offset; $this->limit = $limit; $this->cursor = Entity::getInstance()->getDatabase()->find($this->collectionName, $this->conditions)->sort($this->order)->skip($this->offset)->limit($this->limit); }
/** * Add item to this entity collection<br> * NOTE: you need to call save() on parent entity to actually insert link into database * * @param array|\Webiny\Component\Entity\EntityAbstract $item * * @throws \Webiny\Component\Entity\EntityException * @return $this */ public function add($item) { if ($this->isInstanceOf($item, '\\Webiny\\Component\\Entity\\EntityAbstract')) { $item = [$item]; } /** * Validate items */ foreach ($item as $i) { if (!$this->isInstanceOf($i, $this->getEntity()) && !Entity::getInstance()->getDatabase()->isMongoId($i)) { throw new EntityException(EntityException::INVALID_MANY2MANY_VALUE, [$this->attribute, 'entity ID or instance of ' . $this->getEntity() . ' or null', get_class($i)]); } } /** * Assign items */ foreach ($item as $i) { $this->addedItems[] = $i; } return $this; }
/** * Unlink given item (only removes the aggregation record) and remove it from current loaded values * * @param Many2ManyAttribute $attribute * @param string|EntityAbstract $item * * @return bool */ public function unlink(Many2ManyAttribute $attribute, $item) { // Convert instance to entity ID if ($this->isInstanceOf($item, '\\Webiny\\Component\\Entity\\EntityAbstract')) { $item = $item->getId()->getValue(); } $sourceEntityId = $attribute->getParentEntity()->getId()->getValue(); if ($this->isNull($sourceEntityId) || $this->isNull($item)) { return; } $firstClassName = $this->extractClassName($attribute->getParentEntity()); $secondClassName = $this->extractClassName($attribute->getEntity()); $query = $this->arr([$firstClassName => $sourceEntityId, $secondClassName => $item])->sortKey()->val(); $res = Entity::getInstance()->getDatabase()->remove($attribute->getIntermediateCollection(), $query); return $res['n'] == 1; }
/** * (PHP 5 >= 5.0.0)<br/> * Retrieve an external iterator * @link http://php.net/manual/en/iteratoraggregate.getiterator.php * @return Traversable An instance of an object implementing <b>Iterator</b> or * <b>Traversable</b> */ public function getIterator() { if ($this->loaded) { return new \ArrayIterator($this->value); } $dbItems = []; foreach ($this->data as $data) { $instance = new $this->entityClass(); $data['__webiny_db__'] = true; $instance->populate($data); /** * Check if loaded instance is already in the pool and if yes - use the existing object */ if ($itemInPool = Entity::getInstance()->get($this->entityClass, $instance->id)) { $dbItems[] = $itemInPool; } else { $dbItems[] = Entity::getInstance()->add($instance); } } $this->value += $dbItems; $this->loaded = true; if ($this->randomize) { shuffle($this->value); } return new \ArrayIterator($this->value); }
private function cleanUpRecords($newValues) { if (!$this->parent->exists()) { return; } $newIds = []; foreach ($newValues as $nv) { if (isset($nv['id']) && $nv['id'] != '') { $newIds[] = Entity::getInstance()->getDatabase()->id($nv['id']); } } $attrValues = $this->getValue(); foreach ($attrValues as $r) { if (!in_array($r->id, $newIds)) { $r->delete(); } } }
/** * Perform validation against given value * * @param $value * * @throws ValidationException * @return $this */ protected function validate(&$value) { $mongoId = Entity::getInstance()->getDatabase()->isId($value); $abstractEntityClass = '\\Webiny\\Component\\Entity\\AbstractEntity'; if (!$this->isNull($value) && !is_array($value) && !$this->isInstanceOf($value, $abstractEntityClass) && !$mongoId) { $this->expected('entity ID, instance of ' . $abstractEntityClass . ' or null', gettype($value)); } return $this; }
/** * Perform validation against given value * * @param $value * * @throws ValidationException * @return $this */ public function validate(&$value) { if (!$this->isNull($value) && !$this->isInstanceOf($value, '\\Webiny\\Component\\Entity\\EntityAbstract') && !Entity::getInstance()->getDatabase()->isMongoId($value)) { throw new ValidationException(ValidationException::ATTRIBUTE_VALIDATION_FAILED, [$this->attribute, 'entity ID, instance of \\Webiny\\Component\\Entity\\EntityAbstract or null', gettype($value)]); } return $this; }
/** * Unlink given item (only removes the aggregation record) * * @param string|AbstractEntity $item * * @return bool */ protected function unlinkItem($item) { // Convert instance to entity ID if ($item instanceof AbstractEntity) { $item = $item->id; } $sourceEntityId = $this->getParentEntity()->id; if ($this->isNull($sourceEntityId) || $this->isNull($item)) { return false; } $firstClassName = $this->extractClassName($this->getParentEntity()); $secondClassName = $this->extractClassName($this->getEntity()); $query = $this->arr([$firstClassName => $sourceEntityId, $secondClassName => $item])->sortKey()->val(); $res = Entity::getInstance()->getDatabase()->delete($this->intermediateCollection, $query); return $res->getDeletedCount() == 1; }
/** * Normalize given value to be a valid array of entity instances * * @param mixed $value * * @return array * @throws ValidationException */ protected function normalizeValue($value) { if (is_null($value)) { return $value; } $entityClass = $this->getEntity(); $entityCollectionClass = '\\Webiny\\Component\\Entity\\EntityCollection'; // Validate Many2many attribute value if (!$this->isArray($value) && !$this->isArrayObject($value) && !$this->isInstanceOf($value, $entityCollectionClass)) { $exception = new ValidationException(ValidationException::DATA_TYPE, ['array, ArrayObject or EntityCollection', gettype($value)]); $exception->setAttribute($this->getName()); throw $exception; } /* @var $entityAttribute One2ManyAttribute */ $values = []; foreach ($value as $item) { $itemEntity = false; // $item can be an array of data, AbstractEntity or a simple mongo ID string if ($this->isInstanceOf($item, $entityClass)) { $itemEntity = $item; } elseif ($this->isArray($item) || $this->isArrayObject($item)) { $itemEntity = $entityClass::findById(isset($item['id']) ? $item['id'] : false); } elseif ($this->isString($item) && Entity::getInstance()->getDatabase()->isId($item)) { $itemEntity = $entityClass::findById($item); } // If instance was not found, create a new entity instance if (!$itemEntity) { $itemEntity = new $entityClass(); } // If $item is an array - use it to populate the entity instance if ($this->isArray($item) || $this->isArrayObject($item)) { $itemEntity->populate($item); } $values[] = $itemEntity; } return new EntityCollection($this->getEntity(), $values); }
/** * Test onSet, onGet, onToDb and onToArray callbacks as well as setAfterPopulate (only useful in combination with onSet callback) */ public function testOnCallbacks() { $entity = new Lib\EntityOnCallbacks(); $entity->populate(['char' => 'value', 'number' => 12])->save(); $this->assertEquals('get-db-get-set-12-value', $entity->char); Entity::getInstance()->reset(); $entity = Lib\EntityOnCallbacks::findOne(['number' => 12]); $this->assertEquals('get-db-get-set-12-value', $entity->char); $this->assertEquals(120, $entity->number); $array = $entity->toArray(); $this->assertEquals(['key' => 'value'], $array['char']); }
/** * Count total number of items in collection * * TODO: unittest * * @return mixed */ public function totalCount() { if (!isset($this->parameters['conditions'])) { return count($this->value); } if (!$this->totalCount) { $mongo = Entity::getInstance()->getDatabase(); $entity = $this->entityClass; $this->totalCount = $mongo->count($entity::getEntityCollection(), $this->parameters['conditions']); } return $this->totalCount; }
/** * Apply validator to given value * * @param string $validator * @param string $key * @param mixed $value * @param array $messages * * @throws ValidationException * @throws \Webiny\Component\StdLib\Exception\Exception */ protected function applyValidator($validator, $key, $value, $messages = []) { try { if ($this->isString($validator)) { $params = $this->arr(explode(':', $validator)); $vName = ''; $validatorParams = [$this, $value, $params->removeFirst($vName)->val()]; $validator = Entity::getInstance()->getValidator($vName); if (!$validator) { throw new ValidationException('Validator does not exist'); } $validator->validate(...$validatorParams); } elseif ($this->isCallable($validator)) { $vName = 'callable'; $validator($value, $this); } } catch (ValidationException $e) { $msg = isset($messages[$vName]) ? $messages[$vName] : $e->getMessage(); $ex = new ValidationException($msg); $ex->addError($key, $msg); throw $ex; } }
/** * Get entity database * @return \Webiny\Component\Mongo\Mongo */ public function getDatabase() { return Entity::getInstance()->getDatabase(); }
private function cleanUpRecords($newValues) { if (!$this->parent->exists()) { return; } $newIds = []; foreach ($newValues as $nv) { if (isset($nv['id']) && $nv['id'] != '') { $newIds[] = Entity::getInstance()->getDatabase()->id($nv['id']); } } $where = ['_id' => ['$nin' => $newIds]]; $where[$this->relatedAttribute] = $this->parent->id; $toRemove = call_user_func_array([$this->entityClass, 'find'], [$where]); foreach ($toRemove as $r) { $r->delete(); } }