Пример #1
0
 /**
  * @param string $class
  * @param ORM    $orm
  * @throws SourceException
  */
 public function __construct($class = null, ORM $orm = null)
 {
     if (empty($class)) {
         if (empty(static::RECORD)) {
             throw new SourceException("Unable to create source without associate class.");
         }
         $class = static::RECORD;
     }
     $this->class = $class;
     $this->orm = $this->saturate($orm, ORM::class);
     $this->setSelector($this->orm->selector($this->class));
 }
Пример #2
0
 /**
  * @param Debugger           $debugger
  * @param ORM                $orm
  * @param ContainerInterface $container
  * @param ClassLocator       $locator
  */
 public function perform(Debugger $debugger, ORM $orm, ContainerInterface $container, ClassLocator $locator)
 {
     //We don't really need location errors here
     $locator->setLogger(new NullLogger());
     $benchmark = $debugger->benchmark($this, 'update');
     $builder = $orm->schemaBuilder($locator);
     //To make builder available for other commands (in sequence)
     $container->bind(get_class($builder), $builder);
     if (!$this->option('sync')) {
         $this->writeln("<comment>Silent mode on, no databases to be altered.</comment>");
     }
     $orm->updateSchema($builder, $this->option('sync'));
     $elapsed = number_format($debugger->benchmark($this, $benchmark), 3);
     $countModels = count($builder->getRecords());
     $this->write("<info>ORM Schema has been updated: <comment>{$elapsed} s</comment>");
     $this->writeln(", found records: <comment>{$countModels}</comment></info>");
 }
Пример #3
0
 /**
  * {@inheritdoc}
  *
  * @return RecordInterface
  * @see ORM::record()
  * @see Record::setContext()
  * @throws ORMException
  */
 public function current()
 {
     if (isset($this->instances[$this->position])) {
         //Due record was pre-constructed we must update it's context to force values for relations
         //and pivot fields
         return $this->instances[$this->position];
     }
     //Let's ask ORM to create needed record
     return $this->instances[$this->position] = $this->orm->record($this->class, $this->data[$this->position], $this->cache);
 }
Пример #4
0
 /**
  * Fetch one record from database. Attention, LIMIT statement will be used, meaning you can not
  * use loaders for HAS_MANY or MANY_TO_MANY relations with data inload (joins), use default
  * loading method.
  *
  * @see findByPK()
  * @param array $where    Selection WHERE statement.
  * @param bool  $setLimit Use limit 1.
  * @return RecordEntity|null
  */
 public function findOne(array $where = [], $setLimit = true)
 {
     if (!empty($where)) {
         $this->where($where);
     }
     $data = $this->limit($setLimit ? 1 : null)->fetchData();
     if (empty($data)) {
         return null;
     }
     return $this->orm->record($this->class, $data[0]);
 }
Пример #5
0
 /**
  * Create instance of inspector associated with ORM and ODM entities.
  *
  * @param InspectionsConfig $config
  * @param ODM               $odm
  * @param ORM               $orm
  * @return Inspector
  */
 protected function createInspector(InspectionsConfig $config, ODM $odm, ORM $orm)
 {
     if ($this->container->has(\Spiral\ODM\Entities\SchemaBuilder::class)) {
         $odmBuilder = $this->container->get(\Spiral\ODM\Entities\SchemaBuilder::class);
     } else {
         $odmBuilder = $odm->schemaBuilder();
     }
     if ($this->container->has(\Spiral\ORM\Entities\SchemaBuilder::class)) {
         $ormBuilder = $this->container->get(\Spiral\ORM\Entities\SchemaBuilder::class);
     } else {
         $ormBuilder = $orm->schemaBuilder();
     }
     return new Inspector($config, array_merge($odmBuilder->getDocuments(), $ormBuilder->getRecords()));
 }
Пример #6
0
 /**
  * Create appropriate instance of RelationSchema based on it's definition provided by ORM Record
  * or manually. Due internal format first definition key will be stated as definition type and
  * key value as record/entity definition relates too.
  *
  * @param RecordSchema $record
  * @param string       $name
  * @param array        $definition
  * @return RelationInterface
  * @throws SchemaException
  */
 public function relationSchema(RecordSchema $record, $name, array $definition)
 {
     if (empty($definition)) {
         throw new SchemaException("Relation definition can not be empty.");
     }
     reset($definition);
     //Relation type must be provided as first in definition
     $type = key($definition);
     //We are letting ORM to resolve relation schema using container
     $relation = $this->orm->relationSchema($type, $this, $record, $name, $definition);
     if ($relation->hasEquivalent()) {
         //Some relations may declare equivalent relation to be used instead, used for Morphed
         //relations
         return $relation->createEquivalent();
     }
     return $relation;
 }
Пример #7
0
 /**
  * Save simple related entity.
  *
  * @param EntityInterface $entity
  * @param bool            $validate
  * @return bool|void
  */
 private function saveEntity(EntityInterface $entity, $validate)
 {
     if ($entity instanceof RecordInterface && $entity->isDeleted()) {
         return true;
     }
     if (!$entity instanceof ActiveEntityInterface) {
         throw new RelationException("Unable to save non active entity.");
     }
     $this->mountRelation($entity);
     if (!$entity->save($validate)) {
         return false;
     }
     if ($entity instanceof IdentifiedInterface) {
         $this->orm->cache()->remember($entity);
     }
     return true;
 }
Пример #8
0
 /**
  * Execute query and every related query to compile records data in tree form - every relation
  * data will be included as sub key.
  *
  * Attention, Selector will cache compiled data tree and not query itself to keep data integrity
  * and to skip data compilation on second query.
  *
  * @return array
  */
 public function fetchData()
 {
     //Pagination!
     $this->applyPagination();
     //Generating statement
     $statement = $this->sqlStatement();
     if (!empty($this->cacheLifetime)) {
         $cacheKey = $this->cacheKey ?: md5(serialize([$statement, $this->getParameters()]));
         if (empty($this->cacheStore)) {
             $this->cacheStore = $this->orm->container()->get(CacheInterface::class)->store();
         }
         if ($this->cacheStore->has($cacheKey)) {
             $this->logger()->debug("Selector result were fetched from cache.");
             //We are going to store parsed result, not queries
             return $this->cacheStore->get($cacheKey);
         }
     }
     //We are bypassing run() method here to prevent query caching, we will prefer to cache
     //parsed data rather that database response
     $result = $this->database->query($statement, $this->getParameters());
     //In many cases (too many inloads, too complex queries) parsing can take significant amount
     //of time, so we better profile it
     $benchmark = $this->benchmark('parseResult', $statement);
     //Here we are feeding selected data to our primary loaded to parse it and and create
     //data tree for our records
     $this->loader->parseResult($result, $rowsCount);
     $this->benchmark($benchmark);
     //Memory freeing
     $result->close();
     //This must force loader to execute all post loaders (including ODM and etc)
     $this->loader->loadData();
     //Now we can request our primary loader for compiled data
     $data = $this->loader->getResult();
     //Memory free! Attention, it will not reset columns aliases but only make possible to run
     //query again
     $this->loader->clean();
     if (!empty($this->cacheLifetime) && !empty($cacheKey)) {
         //We are caching full records tree, not queries
         $this->cacheStore->set($cacheKey, $data, $this->cacheLifetime);
     }
     return $data;
 }
Пример #9
0
 /**
  * Create selector dedicated to load data for current loader.
  *
  * @return RecordSelector|null
  */
 public function createSelector()
 {
     if (!$this->isLoadable()) {
         return null;
     }
     $selector = $this->orm->selector($this->definition[static::RELATION_TYPE], $this);
     //Setting columns to be loaded
     $this->configureColumns($selector);
     foreach ($this->loaders as $loader) {
         if ($loader instanceof self) {
             //Allowing sub loaders to configure required columns and conditions as well
             $loader->configureSelector($selector);
         }
     }
     foreach ($this->joiners as $joiner) {
         //Joiners must configure selector as well
         $joiner->configureSelector($selector);
     }
     return $selector;
 }
Пример #10
0
 /**
  * {@inheritdoc}
  */
 protected function container()
 {
     if (empty($this->orm)) {
         return parent::container();
     }
     return $this->orm->container();
 }
Пример #11
0
 /**
  * Instance of DBAL\Table associated with relation pivot table.
  *
  * @return Table
  */
 protected function pivotTable()
 {
     return $this->orm->database($this->definition[ORM::R_DATABASE])->table($this->definition[RecordEntity::PIVOT_TABLE]);
 }
Пример #12
0
 /**
  * Filter data on inner relation or relation chain. Method automatically called by Selector,
  * see with() method. Logic is identical to loader() method.
  *
  * @see Selector::load()
  * @param string $relation Relation name, or chain of relations separated by.
  * @param array  $options  Loader options (will be applied to last chain element only).
  * @return Loader
  * @throws LoaderException
  */
 public function joiner($relation, array $options = [])
 {
     //We have to force joining method for full chain
     $options['method'] = self::JOIN;
     if (($position = strpos($relation, '.')) !== false) {
         //Chain of relations provided
         $nested = $this->joiner(substr($relation, 0, $position), []);
         if (empty($nested) || !$nested instanceof self) {
             throw new LoaderException("Only ORM loaders can be used to generate/configure chain of relation joiners.");
         }
         //Recursively (will work only with ORM loaders).
         return $nested->joiner(substr($relation, $position + 1), $options);
     }
     if (!isset($this->schema[ORM::M_RELATIONS][$relation])) {
         $container = $this->container ?: $this->schema[ORM::M_ROLE_NAME];
         throw new LoaderException("Undefined relation '{$relation}' under '{$container}'.");
     }
     if (isset($this->joiners[$relation])) {
         //Updating existed joiner options
         return $this->joiners[$relation]->setOptions($options);
     }
     $relationOptions = $this->schema[ORM::M_RELATIONS][$relation];
     $joiner = $this->orm->loader($relationOptions[ORM::R_TYPE], $relation, $relationOptions[ORM::R_DEFINITION], $this);
     if (!$joiner instanceof self) {
         throw new LoaderException("Only ORM loaders can be used to generate/configure chain of relation joiners.");
     }
     return $this->joiners[$relation] = $joiner->setOptions($options);
 }