/** * If the $method is one of the MySQL. * * @see KObject::__call() */ public function __call($method, $arguments) { if (isset($arguments[0]) && $this->_parent_query->getRepository()->getDescription()->getProperty($method)) { $condition = isset($arguments[1]) ? $arguments[1] : 'AND'; $this->where($method, '=', $arguments[0], $condition); return $this; } return parent::__call($method, $arguments); }
/** * Summerize a story query. * * @param AnDomainQuery $query Query object * @param array $config Summerization configuration * * @return AnDomainEntityset */ protected function _buildAggregateQuery($query, $config) { $cases = array(); $config = KConfig::unbox($config); $config[] = array('WHEN @col(name) LIKE "avatar_edit" THEN IF(@col(subject.id) = @col(target.id), "", @col(id))', 'WHEN @col(name) LIKE "actor_follow" THEN @col(subject.id)'); foreach ($config as $component => $keys) { foreach ($keys as $name => $key) { if (!is_numeric($name)) { $names = explode(',', $name); $keys = explode(',', $key); foreach ($keys as $i => $key) { $keys[$i] = '@col(' . $key . '.id)'; } foreach ($names as $name) { $cases[] = 'WHEN CONCAT(@col(name),@col(component)) LIKE \'' . $name . $component . '\' THEN CONCAT(' . implode(',', $keys) . ')'; } } else { $cases[] = $key; } } } $cases = array_unique($cases); $keys = array(); //always group by date, name and component $date = '@col(name),@col(component),DATE(@col(creationTime))'; $keys[] = $date; if (!empty($cases)) { $case = 'CASE TRUE '; $case .= implode(' ', $cases) . ' '; $case .= 'ELSE CONCAT(@col(target.id),@col(subject.id),@col(object.id)) '; $case .= 'END'; $keys[] = $case; } else { $keys[] = '@col(target.id),@col(subject.id),@col(object.id)'; } $keys = implode(',', $keys); $comment_if = "IF(@col(comment.id) IS NOT NULL AND @col(object.id) IS NOT NULL , CONCAT_WS(',',{$date}, @col(object.id)), CONCAT_WS(',',{$keys}))"; //don't group if a story has a body or it has directly been commented on $bundle = "IF (@col(body) <> '' AND @col(body) IS NOT NULL,@col(id),{$comment_if}) AS bundle_key"; $query->select($bundle); $query->select('GROUP_CONCAT(DISTINCT @col(id)) AS ids'); $query->select('GROUP_CONCAT(DISTINCT @col(owner.id)) AS owner_ids'); $query->select('GROUP_CONCAT(DISTINCT @col(target.id)) AS target_ids'); $query->select('GROUP_CONCAT(DISTINCT @col(comment.id)) AS comment_ids'); $query->select('GROUP_CONCAT(DISTINCT @col(object.id)) AS object_ids'); $query->select('GROUP_CONCAT(DISTINCT @col(subject.id)) AS subject_ids'); $query->select(array('id' => 'MAX(@col(id))')); $query->select(array('creationTime' => 'MAX(@col(creationTime))')); $query->select(array('updateTime' => 'MAX(@col(updateTime))')); $viewer = get_viewer(); $query->group('bundle_key'); $query->order = array(); $query->order('modified_on', 'DESC'); }
/** * Delete record identified by $keys in the $resources * * @param AnDomainRepositoryAbstract $repository * @param array $keys * @return boolean */ public function delete($repository, $keys) { $context = $this->getCommandContext(); $context->repository = $repository; $context->keys = $keys; $context->query = AnDomainQuery::getInstance($repository, $keys)->delete(); if ($this->getCommandChain()->run('before.delete', $context) !== false) { $context->result = $this->execute($context->query); $this->getCommandChain()->run('after.delete', $context); } return $context->result; }
/** * Adds a relationship to query. * * @param AnDomainQuery $query Query Object * @param string $relationship Relationship name */ public static function addRelationship($query, $relationship) { $property = $query->getRepository()->getDescription()->getProperty($relationship); switch (true) { case $property->isManyToOne(): return self::_parseManyToOne($query, $property); case $property->isManyToMany(): return self::_parseManyToMany($query, $property); case $property->isOneToMany(): return self::_parseOneToMany($query, $property); } }
/** * Builds a query into a final query statement. * * @param AnDomainQuery $query Query object * @param string $string A String object * * @return string */ public function parseMethods($query, $string) { //replaces any @col(\w+) pattern with the correct column name if (strpos($string, '@col(')) { $matches = array(); if (preg_match_all('/@col\\((.*?)\\)/', $string, $matches)) { $description = $query->getRepository()->getDescription(); $replaces = array(); foreach ($matches[1] as $match) { $result = AnDomainQueryHelper::parseColumn($query, $match); if (empty($result['columns'])) { $replaces[] = $match; } else { $replaces[] = (string) $result['columns']; } } $string = str_replace($matches[0], $replaces, $string); } } if (strpos($string, '@quote(')) { $matches = array(); $replaces = array(); if (preg_match_all('/@quote\\((.*?)\\)/', $string, $matches)) { foreach ($matches[1] as $match) { $replaces[] = $this->_store->quoteValue($match); } $string = str_replace($matches[0], $replaces, $string); } } if (strpos($string, '@instanceof(')) { $matches = array(); $replaces = array(); if (preg_match_all('/\\!?@instanceof\\((.*?)\\)/', $string, $matches)) { foreach ($matches[1] as $i => $match) { $operand = ''; if ($matches[0][$i][0] == '!') { $operand = 'NOT '; } $type_col = $query->getRepository()->getDescription()->getInheritanceColumn(); $classes = explode(',', $match); $statements = array(); foreach ($classes as $class) { $class = $this->_store->quoteValue($class); $statements[] = $operand . "FIND_IN_SET({$class},{$type_col})"; } if ($operand == 'NOT ') { $operand = ' AND '; } else { $operand = ' OR '; } if (count($statements) == 1) { $statements = implode($operand, $statements); } else { $statements = '(' . implode($operand, $statements) . ')'; } $replaces[] = $statements; } $string = str_replace($matches[0], $replaces, $string); } } if (strpos($string, '@remove_from_set(')) { $matches = array(); $replaces = array(); if (preg_match_all('/@remove_from_set\\((.*?)\\)/', $string, $matches)) { foreach ($matches[1] as $i => $match) { list($set, $item) = explode(',', $match); $set = trim($set); $item = trim($item); $replaces[] = "TRIM(BOTH ',' FROM REPLACE(concat(',',{$set},','),CONCAT(',',{$item},','),','))"; } $string = str_replace($matches[0], $replaces, $string); } } if (strpos($string, '@set_length(')) { $matches = array(); $replaces = array(); if (preg_match_all('/@set_length\\((.*?)\\)/', $string, $matches)) { foreach ($matches[1] as $i => $match) { $replaces[] = "LENGTH({$match}) - LENGTH(REPLACE({$match}, ',', '')) + 1"; } $string = str_replace($matches[0], $replaces, $string); } } return $string; }
/** * Count Data. * * @param booelan $load If the flag is set to on. If the qurey is set, it will * perform a count query instead of loading all the objects * * @return int */ public function count($load = true) { //if query is set, and the data is not loaded //lets use the query to get the count if (isset($this->_query) && !$this->isLoaded() && !$load) { $query = AnDomainQuery::getInstance($this->getRepository(), $this->_query); return $query->fetchValue('count(*)'); } else { $this->_loadData(); $result = parent::count(); } return $result; }
/** * Fetch an entity. The condition can be a query object, an associative array or an id * of an entity. * * @param mixed $condition The condition for fetching data * @param int $mode The mode of fetching data. Can be single entity, entity set, value, etc * * @return mixed */ public function fetch($condition = null, $mode = AnDomain::FETCH_ENTITY) { $query = AnDomainQuery::getInstance($this, $condition); $context = $this->getCommandContext(); $context->operation = AnDomain::OPERATION_FETCH; $context->query = $query; $context->mode = $mode; $query->fetch_mode = $mode; if ($mode & AnDomain::FETCH_ITEM) { $context->query->limit(1); } $disable_chain = $query->disable_chain; if ($disable_chain) { $this->getCommandChain()->disable(); } if ($this->getCommandChain()->run('before.fetch', $context) !== false) { $result = $context->result ? $context['result'] : $this->_fetchResult($context->query, $mode); $context->result = $result; switch ($mode) { case AnDomain::FETCH_ENTITY: $context->data = $result ? $this->_createEntity($result) : $result; break; case AnDomain::FETCH_ENTITY_SET: case AnDomain::FETCH_ENTITY_LIST: $list = array(); foreach ($result as $data) { $list[] = $this->_createEntity($data); } if ($mode == AnDomain::FETCH_ENTITY_SET) { $list = $this->getService($this->_entityset, array('repository' => $this, 'query' => $context->query, 'data' => $list)); } $context->data = $list; break; default: $context->data = $result; } $this->getCommandChain()->run('after.fetch', $context); } if ($disable_chain) { $this->getCommandChain()->enable(); } return KConfig::unbox($context->data); }
/** * Validates and apply delete rules for an entity * * @param $entity */ protected function _validateDelete($entity) { $relationships = $entity->getEntityDescription()->getRelationships(); foreach ($relationships as $name => $relationship) { if ($relationship->isManyToOne() || $relationship->isManyToMany()) { continue; } if ($relationship->getDeleteRule() == AnDomain::DELETE_CASCADE || $relationship->getDeleteRule() == AnDomain::DELETE_DESTROY) { $property = $relationship->getName(); $entities = $entity->getData($property); if (!$entities) { continue; } //someone else is responsible for deleteing the relations //good for mass deletion. i.e. node and edges if ($relationship->getDeleteRule() == AnDomain::DELETE_IGNORE) { continue; } else { if ($relationship->getDeleteRule() == AnDomain::DELETE_DESTROY) { if ($relationship->isOneToOne()) { $query = AnDomainQuery::getInstance($relationship->getChildRepository(), $entities->getIdentityId()); } else { $query = $entities->getQuery(); } $relationship->getChildRepository()->destroy($query); continue; } else { if ($relationship->isOneToOne()) { $entities = array($entities); } foreach ($entities as $entity) { //if the cascading fails for the related entities then //nullify the property in the failed entity if (!$entity->delete() && $entity->getObject()) { $entity->set($relationship->getChildKey(), null); } } } } } else { if ($relationship->getDeleteRule() == AnDomain::DELETE_DENY) { //don't state change if there at least one entity left $count = $entity->getData($relationship->getName())->limit(0, 0)->getTotal(); if ($count > 0) { $entity->reset(); return false; } } else { if ($relationship->getDeleteRule() == AnDomain::DELETE_NULLIFY) { //@TODO you should set the values to null directly rather //then instantiating them $entities = $entity->getData($relationship->getName())->fetchSet(); $property = $relationship->getChildKey(); foreach ($entities as $entity) { $entity->set($property, null); } } } } } return true; }