예제 #1
0
 public function interpretQuery(TokenSequencerInterface $query)
 {
     $this->reset();
     $this->query = $query;
     $sql = "DELETE FROM " . $this->renderArbitraryReference($query->getEntityMetadata()->getCollection());
     while ($token = $query->getNextToken()) {
         $sql .= " " . $this->renderToken($token);
     }
     return $sql;
 }
 protected function renderInCondition()
 {
     $sql = "IN ";
     $sql .= $this->renderToken($this->query->getNextToken());
     // open
     $list = [];
     while (($token = $this->query->getNextToken()) && $token->getType() != "close") {
         $list[] = $this->renderToken($token);
     }
     $sql .= implode(", ", $list);
     if (!empty($token)) {
         $sql .= $this->renderToken($token);
         // close
     }
     return $sql;
 }
예제 #3
0
 protected function addIncludes(TokenSequencerInterface $query, $includeRelationships = null)
 {
     $includeRelationships = is_null($includeRelationships) ? $this->includeRelationshipsByDefault : $includeRelationships;
     if (!empty($includeRelationships)) {
         if (!is_array($includeRelationships) || isset($includeRelationships[0])) {
             $includeRelationships = ["this" => $includeRelationships];
         }
         $allRelationships = ["this" => $this->entityMetadata->getRelationships()];
         $relationships = [];
         $parents = [];
         // add all the relationship metadata we need into the allRelationships array
         foreach (array_keys($includeRelationships) as $alias) {
             if ($alias == "this") {
                 // already added the subject entity's relationships
                 continue;
             }
             foreach ($allRelationships as $subset) {
                 if (!empty($subset[$alias])) {
                     $relationshipEntity = $subset[$alias][EntityMetadata::METADATA_ENTITY];
                     $relationshipMetadata = $this->metadataProvider->getEntityMetadata($relationshipEntity);
                     $allRelationships[$alias] = $relationshipMetadata->getRelationships();
                     break;
                 }
             }
         }
         foreach ($includeRelationships as $alias => $includes) {
             if (empty($allRelationships[$alias])) {
                 continue;
             }
             $thisRelationships = $allRelationships[$alias];
             // if we have an array of includes, filter thisRelationships
             if (is_array($includes)) {
                 $thisRelationships = array_intersect_key($allRelationships[$alias], array_flip($includes));
             }
             // record the parent of each of the child aliases, so we can reference them when we include the entity
             foreach (array_keys($thisRelationships) as $childAlias) {
                 $parents[$childAlias] = $alias;
             }
             // add thisRelationships to the final list
             $relationships = array_replace($relationships, $thisRelationships);
         }
         // get the metadata for each entity and include it on the query
         foreach ($relationships as $alias => $relationship) {
             $metadata = $this->metadataProvider->getEntityMetadata($relationship[EntityMetadata::METADATA_ENTITY]);
             if ($alias == $metadata->getEntity()) {
                 $alias = "";
             }
             $parent = "";
             if (!empty($parents[$alias]) && $parents[$alias] != "this") {
                 $parent = $parents[$alias];
             }
             $query->includeEntity($metadata, $alias, $parent);
         }
     }
 }
예제 #4
0
 public function interpretQuery(TokenSequencerInterface $query)
 {
     $this->reset();
     $this->query = $query;
     $includes = $query->getIncludes();
     $mainMetadata = $query->getEntityMetadata();
     $mainCollection = $mainMetadata->getCollection();
     $token = $query->getNextToken();
     $this->fields = [];
     while (!empty($token) && in_array($token->getType(), ["function", "field"])) {
         if ($token->getType() == "function") {
             /** @var Value $token */
             // render the aggregate function SQL e.g. COUNT(*), SUM(field), etc...
             $fieldSql = $this->renderFunction($token);
             // create an alias for this aggregate and append the SQL
             $collectionAlias = $this->findFreeAlias($token->getValue(), $this->fields);
             $fieldSql .= $this->renderAlias($collectionAlias);
         } else {
             /** @var Reference $token */
             $fieldName = $mainCollection . "." . $token->getValue();
             $collectionAlias = $this->getSelectFieldAlias($fieldName);
             $fieldSql = $this->renderArbitraryReference($fieldName, $collectionAlias);
         }
         // add the sql to the fields array and load the next token
         $this->fields[$collectionAlias] = $fieldSql;
         $token = $query->getNextToken();
     }
     // if we had no aggregate functions in the sequence, then this is a standard select query
     // so, we need to get the fields to return from the entity metadata for each
     if (empty($this->fields)) {
         $metadata = $mainMetadata;
         $collectionAlias = $mainCollection;
         do {
             if (empty($metadata)) {
                 continue;
             }
             // for each entity field, create an aliased SQL reference
             $entityFields = $metadata->getFieldNames();
             sort($entityFields);
             foreach ($entityFields as $field) {
                 $field = $collectionAlias . "." . $field;
                 $thisFieldAlias = $this->getSelectFieldAlias($field);
                 $this->fields[$thisFieldAlias] = $this->renderArbitraryReference($field, $thisFieldAlias);
             }
         } while (list($collectionAlias, $metadata) = each($includes));
     }
     if (empty($this->fields)) {
         throw new InterpretationException("Cannot interpret find query, there are no fields to return");
     }
     // if this query has an include, it's more complex and requires separate processing
     if (count($includes) > 0) {
         return $this->renderIncludeQuery($token);
     }
     // simple, no include query. Render all remaining tokens
     $sql = "SELECT " . implode(", ", $this->fields) . " FROM " . $this->renderArbitraryReference($mainCollection);
     // render all other tokens
     do {
         if (empty($token)) {
             break;
         }
         $sql .= " " . $this->renderToken($token);
     } while ($token = $this->query->getNextToken());
     return $sql;
 }
예제 #5
0
 public function includeEntity(EntityMetadata $childMetadata, $collectionAlias = "", $parent = "", TokenSequencerInterface $additionalFilters = null)
 {
     // check we're dealing with a query
     if (!$this->isQuery()) {
         throw new TokenParseException("Cannot include an entity on an expression sequence.");
     }
     // get data on the child entity
     $childEntity = $childMetadata->getEntity();
     $childCollection = $childMetadata->getCollection();
     $childAlias = empty($collectionAlias) ? $childCollection : $collectionAlias;
     // determine which entity to join on (the parent)
     $parentMetadata = $this->getEntityMetadata();
     if (!empty($parent)) {
         if (empty($this->includes[$parent])) {
             throw new TokenParseException("Cannot include the entity '{$childEntity}'. The parent entity '{$parent}' has not yet been included");
         }
         /** @var EntityMetadata $parentMetadata */
         $parentMetadata = $this->includes[$parent];
         if ($parent == $parentMetadata->getEntity()) {
             $parent = $parentMetadata->getCollection();
         }
     }
     // make sure we have a parent that we can use as a table name or alias
     if (empty($parent) || $parent == $parentMetadata->getEntity()) {
         $parent = $parentMetadata->getCollection();
     }
     // get the relationship between the child and parent
     $relationshipAlias = empty($collectionAlias) ? $childEntity : $collectionAlias;
     $relationship = $parentMetadata->getRelationship($relationshipAlias);
     if (empty($relationship)) {
         throw new TokenParseException("The parent entity '{$parentMetadata->getEntity()}' has no relationship defined for '{$relationshipAlias}'");
     }
     // find the fields we will need to use in the join condition
     // we need the primary key and/or the parent field defined in the relationship
     $parentKey = $parentMetadata->getPrimaryKey();
     $parentField = $parent . "." . (empty($relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD]) ? $parentKey : $relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD]);
     // we need the primary key and/or the child field defined in the relationship
     $childKey = $childMetadata->getPrimaryKey();
     $childField = $childAlias . "." . (empty($relationship[EntityMetadata::METADATA_RELATIONSHIP_THEIR_FIELD]) ? $childKey : $relationship[EntityMetadata::METADATA_RELATIONSHIP_THEIR_FIELD]);
     // many to many relationships require an extra join, so treat them differently
     if ($relationship[EntityMetadata::METADATA_RELATIONSHIP_TYPE] != EntityMetadata::RELATIONSHIP_TYPE_MANY_TO_MANY) {
         // create the join condition
         $onClause = new TokenSequencer($this->tokenFactory);
         $onClause->ref($parentField)->op("=")->ref($childField);
         // if we have additional join filters, add them now
         if (!empty($additionalFilters)) {
             $onClause->andL()->mergeSequence($additionalFilters->getSequence());
         }
         // create the join
         $this->join($childCollection, $onClause, $collectionAlias);
     } else {
         // many to many. Requires intermediary join table
         $joinTable = $relationship[EntityMetadata::METADATA_RELATIONSHIP_JOIN_TABLE];
         // create the join condition from the parent to the intermediate
         $parentToMany = new TokenSequencer($this->tokenFactory);
         $parentToMany->ref($parentField)->op("=")->ref("{$joinTable}.{$parent}_id");
         // create the join condition from the intermediate to the child, including any additional join filters
         $manyToChild = new TokenSequencer($this->tokenFactory);
         $manyToChild->ref("{$joinTable}.{$childAlias}_id")->op("=")->ref($childField);
         if (!empty($additionalFilters)) {
             $manyToChild->andL()->mergeSequence($additionalFilters->getSequence());
         }
         // create the joins
         $this->join($joinTable, $parentToMany)->join($childCollection, $manyToChild, $collectionAlias);
     }
     // add the include
     $this->includes[$childAlias] = $childMetadata;
     return $this;
 }
예제 #6
0
 public function interpretQuery(TokenSequencerInterface $query)
 {
     $this->reset();
     $this->query = $query;
     $metadata = $this->query->getEntityMetadata();
     // is this an update or insert query
     /** @var Entity $token */
     $token = $this->query->getNextToken();
     $entity = $token->getEntity();
     $this->primaryKey = $metadata->getPrimaryKey();
     if (is_object($entity)) {
         $pkGetter = "get" . $this->toStudlyCaps($this->primaryKey);
         if (!method_exists($entity, $pkGetter)) {
             throw new InterpretationException("Could not get the primary key '{$this->primaryKey}'. The method '{$pkGetter}' does not exist on the entity (" . get_class($entity) . ")");
         }
         $id = $entity->{$pkGetter}();
     } else {
         $id = isset($entity[$this->primaryKey]) ? $entity[$this->primaryKey] : null;
     }
     $this->fieldSql = [];
     $pkField = $this->toSplitCase($this->primaryKey);
     foreach ($metadata->getFieldNames() as $field) {
         $this->fieldSql[$field] = $this->renderArbitraryReference($field);
     }
     // if any of this entities relationships are one to one, check if we need to set "our" field
     foreach ($metadata->getRelationships() as $alias => $relationship) {
         if ($relationship[EntityMetadata::METADATA_RELATIONSHIP_TYPE] == EntityMetadata::RELATIONSHIP_TYPE_ONE_TO_ONE && !empty($relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD])) {
             $field = $relationship[EntityMetadata::METADATA_RELATIONSHIP_OUR_FIELD];
             $this->fieldSql[$field] = $this->renderArbitraryReference($field);
             $theirField = $relationship[EntityMetadata::METADATA_RELATIONSHIP_THEIR_FIELD];
             if (empty($theirField)) {
                 $theirField = "id";
             }
             $this->relatedProperties[$field] = ["property" => $relationship[EntityMetadata::METADATA_RELATIONSHIP_PROPERTY], "theirField" => $theirField];
         }
     }
     $collection = $this->renderArbitraryReference($metadata->getCollection());
     $options = $query->getOptions();
     $pkMetadata = $metadata->getPrimaryKeyMetadata();
     // this is an insert if, we don't have a value for the ID (auto incrementing PK) or the PK isn't auto incrementing
     // and the query does not specifically request us to update
     $autoIncrementing = $pkMetadata[EntityMetadata::METADATA_FIELD_AUTO_INCREMENTING];
     $isInsert = empty($id) || !$autoIncrementing && (empty($options["saveType"]) || $options["saveType"] != "update");
     // remove the primary key from the field list if we're updating or this PK is auto incrementing
     if (!$isInsert || $autoIncrementing) {
         unset($this->fieldSql[$pkField]);
     }
     if ($isInsert) {
         // insert;
         $this->sqlCommand = "insert";
         $sql = "INSERT INTO {$collection}";
         $sql .= " (" . implode(", ", $this->fieldSql) . ") VALUES ";
         $entities = [];
         do {
             $entities[] = $this->renderToken($token);
         } while ($token = $this->query->getNextToken());
         $sql .= implode(", ", $entities);
         if ($autoIncrementing) {
             $this->primaryKeySequence = $collection . "_" . $metadata->getPrimaryKey() . "_seq";
         }
     } else {
         // update
         $this->sqlCommand = "update";
         $sql = "UPDATE {$collection} SET ";
         $sql .= $this->renderToken($token);
         $sql .= " WHERE " . $this->renderArbitraryReference($this->primaryKey) . " = :searchId";
         $this->values["searchId"] = $id;
     }
     return $sql;
 }
예제 #7
0
 public function parseTokenSequence(TokenSequencerInterface $tokens)
 {
     $sequence = $tokens->getSequence();
     $type = $tokens->getType();
     $position = $this->parseTokens($type, $sequence);
     if (!empty($sequence[$position])) {
         throw new TokenParseException("Unexpected tokens at the end of the sequence. Reached position {$position} of " . count($sequence));
     }
 }