예제 #1
0
 protected function saveOneToMany($alias, Collection $collection, EntityMetadata $childMetadata, $ourValue, $theirField)
 {
     $childPk = $childMetadata->getPrimaryKey();
     if (!empty($this->relationshipCascade[$alias])) {
         // cascading relationships must deal with each entity individually
         /** @var RepositoryInterface $childRepo */
         $childRepo = $this->relationshipCascade[$alias];
         // save all entities currently in the collection
         foreach ($collection as $child) {
             $childRepo->save($child);
         }
         $removed = $collection->getRemovedEntities();
         if (!empty($removed)) {
             // delete any that have been removed
             $delete = $this->queryBuilder->delete($childMetadata);
             $this->createWhereFromFilters($delete, [$childPk => $this->condition("in", $removed)]);
             $this->doQuery($delete, ["output" => "raw"]);
         }
     }
     // For non cascading operations, both adding and removing are updates; one sets the parent value on the child,
     // the other removes any existing values.
     // The two are so similar we can abstract the differences to the following array:
     $updates = [["entities" => $collection->toArray(false), "value" => $ourValue], ["entities" => $collection->getRemovedEntities(), "value" => null]];
     foreach ($updates as $update) {
         // obviously, we don't have to do anything if there are no entities to process
         if (empty($update["entities"])) {
             continue;
         }
         $query = $this->queryBuilder->update($childMetadata)->ref($theirField)->op("=")->val($update["value"]);
         $this->createWhereFromFilters($query, [$childPk => $this->condition("in", $update["entities"])]);
         $this->doQuery($query, ["output" => "raw"]);
     }
 }
예제 #2
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;
 }