예제 #1
2
 public function testBelongsTo()
 {
     $rawly = Bug::findFirstById(1);
     $rawly->robot;
     $eagerly = Loader::fromModel(Bug::findFirstById(1), 'Robot');
     $this->assertTrue(property_exists($eagerly, 'robot'));
     $this->assertInstanceOf('Phalcon\\Test\\Mvc\\Model\\EagerLoading\\Stubs\\Robot', $eagerly->robot);
     $this->assertEquals($rawly->robot->readAttribute('id'), $eagerly->robot->readAttribute('id'));
     // Reverse
     $rawly = Robot::findFirstById(2);
     $rawly->bugs = $this->resultSetToEagerLoadingEquivalent($rawly->bugs);
     $eagerly = Loader::fromModel(Robot::findFirstById(2), 'Bugs');
     $this->assertTrue(property_exists($eagerly, 'bugs'));
     $this->assertContainsOnlyInstancesOf('Phalcon\\Test\\Mvc\\Model\\EagerLoading\\Stubs\\Bug', $eagerly->bugs);
     $getIds = function ($obj) {
         return $obj->readAttribute('id');
     };
     $this->assertEquals(array_map($getIds, $rawly->bugs), array_map($getIds, $eagerly->bugs));
     $this->assertEmpty(Loader::fromModel(Robot::findFirstById(1), 'Bugs')->bugs);
     // Test from multiple
     $rawly = $this->resultSetToEagerLoadingEquivalent(Bug::find(['limit' => 10]));
     foreach ($rawly as $bug) {
         $bug->robot;
     }
     $eagerly = Loader::fromResultset(Bug::find(array('limit' => 10)), 'Robot');
     $this->assertTrue(is_array($eagerly));
     $this->assertTrue(array_reduce($eagerly, function ($res, $bug) {
         return $res && property_exists($bug, 'robot');
     }, true));
     $getIds = function ($obj) {
         return property_exists($obj, 'robot') && isset($obj->robot) ? $obj->robot->readAttribute('id') : null;
     };
     $this->assertEquals(array_map($getIds, $rawly), array_map($getIds, $eagerly));
 }
예제 #2
1
 /**
  * Executes each db query needed
  *
  * Note: The {$alias} property is set two times because Phalcon Model ignores
  * empty arrays when overloading property set.
  *
  * Also {@see https://github.com/stibiumz/phalcon.eager-loading/issues/1}
  *
  * @return $this
  */
 public function load()
 {
     $relation = $this->relation;
     $alias = $relation->getOptions();
     $alias = strtolower($alias['alias']);
     $relField = $relation->getFields();
     $relReferencedModel = $relation->getReferencedModel();
     $relReferencedField = $relation->getReferencedFields();
     $relIrModel = $relation->getIntermediateModel();
     $relIrField = $relation->getIntermediateFields();
     $relIrReferencedField = $relation->getIntermediateReferencedFields();
     // PHQL has problems with this slash
     if ($relReferencedModel[0] === '\\') {
         $relReferencedModel = ltrim($relReferencedModel, '\\');
     }
     $bindValues = array();
     foreach ($this->parent->getSubject() as $record) {
         $bindValues[$record->readAttribute($relField)] = true;
     }
     $bindValues = array_keys($bindValues);
     $subjectSize = count($this->parent->getSubject());
     $isManyToManyForMany = false;
     $builder = new QueryBuilder();
     $builder->from($relReferencedModel);
     if ($isThrough = $relation->isThrough()) {
         if ($subjectSize === 1) {
             // The query is for a single model
             $builder->innerJoin($relIrModel, sprintf('[%s].[%s] = [%s].[%s]', $relIrModel, $relIrReferencedField, $relReferencedModel, $relReferencedField))->inWhere("[{$relIrModel}].[{$relIrField}]", $bindValues);
         } else {
             // The query is for many models, so it's needed to execute an
             // extra query
             $isManyToManyForMany = true;
             $relIrValues = new QueryBuilder();
             $relIrValues = $relIrValues->from($relIrModel)->inWhere("[{$relIrModel}].[{$relIrField}]", $bindValues)->getQuery()->execute()->setHydrateMode(Resultset::HYDRATE_ARRAYS);
             $bindValues = $modelReferencedModelValues = array();
             foreach ($relIrValues as $row) {
                 $bindValues[$row[$relIrReferencedField]] = true;
                 $modelReferencedModelValues[$row[$relIrField]][$row[$relIrReferencedField]] = true;
             }
             unset($relIrValues, $row);
             $builder->inWhere("[{$relReferencedField}]", array_keys($bindValues));
         }
     } else {
         $builder->inWhere("[{$relReferencedField}]", $bindValues);
     }
     if ($this->constraints) {
         call_user_func($this->constraints, $builder);
     }
     $records = array();
     if ($isManyToManyForMany) {
         foreach ($builder->getQuery()->execute() as $record) {
             $records[$record->readAttribute($relReferencedField)] = $record;
         }
         foreach ($this->parent->getSubject() as $record) {
             $referencedFieldValue = $record->readAttribute($relField);
             if (isset($modelReferencedModelValues[$referencedFieldValue])) {
                 $referencedModels = array();
                 foreach ($modelReferencedModelValues[$referencedFieldValue] as $idx => $_) {
                     $referencedModels[] = $records[$idx];
                 }
                 $record->{$alias} = $referencedModels;
                 if (static::$isPhalcon2) {
                     $record->{$alias} = null;
                     $record->{$alias} = $referencedModels;
                 }
             } else {
                 $record->{$alias} = null;
                 $record->{$alias} = array();
             }
         }
         $records = array_values($records);
     } else {
         // We expect a single object or a set of it
         $isSingle = !$isThrough && ($relation->getType() === Relation::HAS_ONE || $relation->getType() === Relation::BELONGS_TO);
         if ($subjectSize === 1) {
             // Keep all records in memory
             foreach ($builder->getQuery()->execute() as $record) {
                 $records[] = $record;
             }
             $record = $this->parent->getSubject();
             $record = $record[0];
             if ($isSingle) {
                 $record->{$alias} = empty($records) ? null : $records[0];
             } else {
                 if (empty($records)) {
                     $record->{$alias} = null;
                     $record->{$alias} = array();
                 } else {
                     $record->{$alias} = $records;
                     if (static::$isPhalcon2) {
                         $record->{$alias} = null;
                         $record->{$alias} = $records;
                     }
                 }
             }
         } else {
             $indexedRecords = array();
             // Keep all records in memory
             foreach ($builder->getQuery()->execute() as $record) {
                 $records[] = $record;
                 if ($isSingle) {
                     $indexedRecords[$record->readAttribute($relReferencedField)] = $record;
                 } else {
                     $indexedRecords[$record->readAttribute($relReferencedField)][] = $record;
                 }
             }
             foreach ($this->parent->getSubject() as $record) {
                 $referencedFieldValue = $record->readAttribute($relField);
                 if (isset($indexedRecords[$referencedFieldValue])) {
                     $record->{$alias} = $indexedRecords[$referencedFieldValue];
                     if (static::$isPhalcon2 && is_array($indexedRecords[$referencedFieldValue])) {
                         $record->{$alias} = null;
                         $record->{$alias} = $indexedRecords[$referencedFieldValue];
                     }
                 } else {
                     $record->{$alias} = null;
                     if (!$isSingle) {
                         $record->{$alias} = array();
                     }
                 }
             }
         }
     }
     $this->subject = $records;
     return $this;
 }
예제 #3
1
 public function testHasManyToMany()
 {
     $rawly = Robot::findFirstById(1);
     $rawly->parts;
     $eagerly = Loader::fromModel(Robot::findFirstById(1), 'Parts');
     $this->assertTrue(property_exists($eagerly, 'parts'));
     $this->assertTrue(is_array($eagerly->parts));
     $this->assertSame(count($eagerly->parts), $rawly->parts->count());
     $getIds = function ($arr) {
         $ret = array();
         foreach ($arr as $r) {
             if (is_object($r)) {
                 $ret[] = $r->readAttribute('id');
             }
         }
         return $ret;
     };
     $this->assertEquals($getIds($this->resultSetToEagerLoadingEquivalent($rawly->parts)), $getIds($eagerly->parts));
 }
예제 #4
0
 /**
  * At original repo
  */
 public function testIssue4()
 {
     // Has many -> Belongs to
     // Should be the same for Has many -> Has one
     $loader = new Loader(Robot::findFirstById(1), 'Bugs.Robot');
     $this->assertEquals($loader->execute()->get()->bugs, array());
 }