public static function defineClass($className, $extends = '') { // $namespace = 'Eddmash\PowerOrm\Migration\Model'; $namespace = ''; $use = ''; $extendedClass = ''; if (empty($extends) || Model::isModelBase($extends)) { $extends = Model::getFullClassName(); } else { $extendedClass = sprintf('%s%s', ClassHelper::getFormatNamespace($namespace, true), $extends); $use = sprintf('use %s;', $extendedClass); $extends = trim(substr($extends, strripos($extends, '\\')), '\\'); } if (!StringHelper::isEmpty($extendedClass) && !ClassHelper::classExists($extendedClass, $namespace)) { self::$deferedClasses[$extends][] = ['class' => $className, 'extends' => $extends]; return false; } $extends = ClassHelper::getNameFromNs($extends, $namespace); $class = sprintf(self::getTemplate(), $namespace, $use, $className, $extends); $className = sprintf('%s%s', ClassHelper::getFormatNamespace($namespace, true), $className); if (ArrayHelper::hasKey(self::$deferedClasses, $className)) { foreach (self::$deferedClasses[$className] as $deferedClass) { self::defineClass($deferedClass['class'], $deferedClass['extends']); } } if (!ClassHelper::classExists($className, $namespace)) { eval($class); } return $className; }
public function getConstructorArgs() { $constructorArgs = parent::getConstructorArgs(); if (isset($constructorArgs['meta']) && empty($constructorArgs['meta'])) { unset($constructorArgs['meta']); } if (isset($constructorArgs['extends'])) { if (StringHelper::isEmpty($constructorArgs['extends']) || Model::isModelBase($constructorArgs['extends'])) { unset($constructorArgs['extends']); } else { $constructorArgs['extends'] = ClassHelper::getNameFromNs($constructorArgs['extends'], BaseOrm::getModelsNamespace()); } } return $constructorArgs; }
/** * Returns the migration(s) which match the given prefix. * * @param $prefix * * @return mixed * * @throws AmbiguityError * @throws KeyError * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ public function getMigrationByPrefix($prefix) { $migrations = []; foreach ($this->getMigrations() as $name => $migration) { $shortName = ClassHelper::getNameFromNs($name, BaseOrm::getMigrationsNamespace()); if (StringHelper::startsWith($name, $prefix) || StringHelper::startsWith($shortName, $prefix)) { $migrations[] = $name; } } if (count($migrations) > 1) { throw new AmbiguityError(sprintf("There is more than one migration with the prefix '%s'", $prefix)); } elseif (count($migrations) == 0) { throw new KeyError(sprintf("There no migrations with the prefix '%s'", $prefix)); } return $migrations[0]; }
public function registerModel(Model $model) { $name = ClassHelper::getNameFromNs($model->meta->modelName, BaseOrm::getModelsNamespace()); if (!ArrayHelper::hasKey($this->allModels, $name)) { $this->allModels[$name] = $model; } $this->resolvePendingOps($model); }
/** * {@inheritdoc} */ public function getConstructorArgs() { $kwargs = parent::getConstructorArgs(); if (ArrayHelper::hasKey($kwargs, 'onDelete')) { $kwargs['onDelete'] = $this->relation->onDelete; } if (is_string($this->relation->toModel)) { $kwargs['to'] = $this->relation->toModel; } else { $name = $this->relation->toModel->getFullClassName(); $kwargs['to'] = ClassHelper::getNameFromNs($name, BaseOrm::getModelsNamespace()); } if ($this->relation->parentLink) { $kwargs['parentLink'] = $this->relation->parentLink; } return $kwargs; }
/** * Gets information about a model and all its parent. * * Some fact to check for : * - proxy model should have at least one concrete model. * - proxy model should not extend an abstract class that contains fields. * * returns the concrete model in the hierarchy and the fields in each of the models in the hierarchy. * * @param string $method the method to invoke * @param null $args the arguments to pass to the method * @param bool|true $fromOldest do we traverse from BaseObject to the child model * * @return array * * @throws TypeError * @throws FieldError * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ private function getHierarchyMeta($method = 'unboundFields', $args = null, $fromOldest = true) { $modelNamespace = BaseOrm::getModelsNamespace(); $isProxy = $this->meta->proxy; // start from oldest parent e.g BaseObject to the last child model $parents = $this->getParents([\PModel::getFullClassName(), self::getFullClassName()]); $parents = array_merge([$this->getFullClassName() => new \ReflectionObject($this)], $parents); if ($fromOldest) { $parents = array_reverse($parents); } $modelFields = []; $concreteParent = null; $immediateParent = null; $previousAbstractParent = null; /** @var $reflectionParent \ReflectionClass */ /* @var $concreteParent \ReflectionClass */ foreach ($parents as $index => $reflectionParent) { $parentName = $reflectionParent->getName(); $isOnCurrentModel = $this->getFullClassName() === $parentName; if (!$reflectionParent->hasMethod($method) || $reflectionParent->getMethod($method)->isAbstract()) { continue; } // concrete is a class that can be instantiated. // check for at least one concrete parent nearest to the last child model. // since we are going downwards we keep updating the concrete variable. if (!($isOnCurrentModel && $isProxy) && $reflectionParent->isInstantiable()) { $concreteParent = $reflectionParent; } // ************ get the fields ******************* // we need to call the parent version of the method for each class to get its fields // this is how we bypass the overriding functionality of php, otherwise if we don't do this the $method will // always provide the fields defined in the last child class. $parentMethodCall = sprintf('%1$s::%2$s', $parentName, $method); if ($args != null) { if (is_array($args)) { $fields = call_user_func_array([$this, $parentMethodCall], $args); } else { $fields = call_user_func([$this, $parentMethodCall], $args); } } else { $fields = call_user_func([$this, $parentMethodCall]); } // =========================== Some Validations ======================== /* * confirm fields with same name don't exist on the parents and current model. * i choose to through an exception of overriding for consistence sake. that is on the $method no overriding * takes place. * */ if ($immediateParent != null && $immediateParent != $previousAbstractParent) { $fieldKeys = array_keys($fields); $parentKeys = isset($modelFields[$immediateParent]) ? array_keys($modelFields[$immediateParent]) : []; $commonFields = array_intersect($parentKeys, $fieldKeys); if (!empty($commonFields)) { throw new FieldError(sprintf('Local field [ %s ] in class "%s" clashes with field of similar name from base class "%s" ', implode(', ', $commonFields), $parentName, $immediateParent)); } } // if the parent is an abstract model and the current model is a proxy model // the parent should not have any fields. abstract models cant have fields // incases where the child is a proxy model if ($isOnCurrentModel && $isProxy && $immediateParent === $previousAbstractParent) { $parentFields = $modelFields[$previousAbstractParent]; if (!empty($parentFields)) { throw new TypeError(sprintf('Abstract base class containing model fields not ' . "permitted for proxy model '%s'.", $parentName)); } } // ****************** Import fields from Abstract *************** // get fields of immediate parent fields if it was an abstract model add them to child model. if (!$isProxy && $previousAbstractParent != null) { $parentFields = isset($modelFields[$previousAbstractParent]) ? $modelFields[$previousAbstractParent] : []; $fields = array_merge($parentFields, $fields); } if ($reflectionParent->isAbstract()) { $previousAbstractParent = $parentName; } else { $previousAbstractParent = null; } if (!$isOnCurrentModel) { $immediateParent = $parentName == $previousAbstractParent ? '' : $parentName; } $modelFields[ClassHelper::getNameFromNs($parentName, $modelNamespace)] = $fields; } if ($isProxy && $concreteParent == null) { throw new TypeError(sprintf("Proxy model '%s' has no non-abstract" . ' model base class.', $this->getShortClassName())); } return [$concreteParent == null ?: ClassHelper::getNameFromNs($concreteParent->getName(), $modelNamespace), $immediateParent, $modelFields]; }
public function getName($name) { return ClassHelper::getNameFromNs($name, BaseOrm::getModelsNamespace()); }
/** * @dataProvider nameFromNamespaceProvider * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ public function testGettingNameFromNamespace($originalValue, $expectedValue) { $this->assertEquals($expectedValue, ClassHelper::getNameFromNs($originalValue, '\\app\\model')); }
/** * Takes a model returns a ModelState representing it. * * @param Model $model * @param bool|false $excludeRels * * @return static * * @throws TypeError * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ public static function fromModel($model, $excludeRels = false) { $fields = []; /** @var $field Field */ foreach ($model->meta->localFields as $name => $field) { try { $fields[$name] = $field->deepClone(); } catch (\Exception $e) { throw new TypeError(sprintf("Couldn't reconstruct field %s on %s: %s", $name, $model->meta->modelName)); } } if ($excludeRels == false) { foreach ($model->meta->localManyToMany as $name => $field) { try { $fields[$name] = $field->deepClone(); } catch (\Exception $e) { throw new TypeError(sprintf("Couldn't reconstruct field %s on %s: %s", $name, $model->meta->modelName)); } } } $overrides = $model->meta->getOverrides(); $meta = []; $ignore = ['registry']; foreach ($overrides as $name => $value) { if (in_array($name, $ignore)) { continue; } $meta[$name] = $value; } $extends = ''; $parent = $model->getParent(); if (!$parent->isAbstract() && !Model::isModelBase($parent->getName())) { $extends = ClassHelper::getNameFromNs($parent->getName(), BaseOrm::getModelsNamespace()); } $kwargs = ['meta' => $meta, 'extends' => $extends]; return new static($model->meta->modelName, $fields, $kwargs); }