Example #1
0
 /**
  * Get related objects from the database
  * 
  * Supports the following signatures:
  * 
  * - getRelated( object|array $source , string $relationName )
  * - getRelated( object|array $source , string $relationName , $query )
  * - getRelated( object|array $source , string $relationName , Meta $meta )
  * - getRelated( object|array $source , string $relationName , $query, Meta $meta )
  *
  * @return object[]
  */
 public function getRelated($source, $relationName, $query = null, $meta = null)
 {
     if (!$source) {
         return;
     }
     $sourceIsArray = false;
     $test = $source;
     if (is_array($test) || $test instanceof \Traversable) {
         $sourceIsArray = true;
         $test = $test[0];
     }
     if (!$meta) {
         if ($query instanceof Meta) {
             list($meta, $query) = [$query, null];
         } else {
             $meta = $this->mapper->getMeta(get_class($test));
         }
     } else {
         $meta = $meta instanceof Meta ? $meta : $this->mapper->getMeta($meta);
     }
     if (!isset($meta->relations[$relationName])) {
         throw new Exception("Unknown relation {$relationName} on {$meta->class}");
     }
     $relation = $meta->relations[$relationName];
     $relator = $this->getRelator($relation);
     if ($query) {
         // need to support both Query\Criteria and Query\Select
         // this is a cheeky hack - the API doesn't declare support for
         // Select in Relators because it carries promises of things like
         // 'fields' and whatnot that we'll never be able to satisfy.
         // That whole hierarchy needs to be cleaned
         // up into a bunch of traits so we can have RelatorCriteria or something.
         $query = $query instanceof Query\Criteria ? $query : Query\Select::fromParamArgs([$query]);
         $stack = $query->stack;
     } else {
         $stack = [];
     }
     $stack[$meta->class] = true;
     if ($sourceIsArray) {
         return $relator->getRelatedForList($meta, $source, $relation, $query ?: null, $stack);
     } else {
         return $relator->getRelated($meta, $source, $relation, $query ?: null, $stack);
     }
 }
Example #2
0
 protected function buildQuery($index, $relatedMeta, $viaMeta, $sourceToViaOn, $viaToDestOn, $criteria)
 {
     $viaFields = $viaMeta->fields;
     $relatedFields = $relatedMeta->fields;
     $query = new Query\Select();
     list($query->where, $query->params) = $this->buildRelatedClause($index, 't2');
     if ($criteria instanceof Query\Select) {
         $query->page = $criteria->page;
         $query->limit = $criteria->limit;
         $query->args = $criteria->args;
         $query->offset = $criteria->offset;
         $query->order = $criteria->order;
         $query->forUpdate = $criteria->forUpdate;
     }
     $queryFields = $query->buildFields($relatedMeta, 't1');
     $sourcePkFields = array();
     foreach ($sourceToViaOn as $l => $r) {
         $field = $viaFields[$r];
         $sourcePkFields[] = $field['name'];
     }
     $joinOn = array();
     foreach ($viaToDestOn as $l => $r) {
         $joinOn[] = 't2.`' . $viaFields[$l]['name'] . '` = t1.`' . $relatedFields[$r]['name'] . '`';
     }
     $joinOn = implode(' AND ', $joinOn);
     list($where, $params, $props) = $query->buildClause(null);
     if ($criteria) {
         list($cWhere, $cParams, $cProps) = $criteria->buildClause($relatedMeta);
         if ($cWhere) {
             $params = array_merge($cParams, $params);
             $props = array_merge($props, $cProps);
             $where .= ' AND (' . $cWhere . ')';
         }
     }
     $order = $query->buildOrder($relatedMeta, 't1');
     list($limit, $offset) = $query->getLimitOffset();
     $vt = ($viaMeta->schema ? "`{$viaMeta->schema}`." : null) . "`{$viaMeta->table}`";
     $rt = ($relatedMeta->schema ? "`{$relatedMeta->schema}`." : null) . "`{$relatedMeta->table}`";
     $sql = "\n            SELECT \n                {$queryFields}, t2." . '`' . implode('`, t2.`', $sourcePkFields) . '`' . "\n            FROM\n                {$vt} t2\n            INNER JOIN\n                {$rt} t1\n                ON  ({$joinOn})\n            WHERE {$where} " . ($order ? "ORDER BY {$order} " : '') . ' ' . ($limit ? "LIMIT  " . (int) $limit . " " : '') . ' ' . ($offset ? "OFFSET " . (int) $offset . " " : '') . ' ' . ($query->forUpdate ? 'FOR UPDATE' : '');
     return array($sql, $params, $sourcePkFields, $props);
 }
Example #3
0
 /**
  * @covers Amiss\Sql\Query\Select::buildOrder
  */
 public function testBuildOrderFromArrayWithIncompleteMeta()
 {
     $criteria = new Query\Select();
     $criteria->order = array('foo', 'bar');
     $meta = new \Amiss\Meta('stdClass', array('table' => 'std_class', 'fields' => array('foo' => array('name' => 'foo_field'))));
     $fields = $criteria->buildOrder($meta);
     $this->assertEquals('`foo_field`, `bar`', $fields);
 }