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; }
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); }
public static function getMigrationsNamespace() { $namespace = ClassHelper::getFormatNamespace(self::getInstance()->appNamespace, true); return ClassHelper::getFormatNamespace(sprintf('%s%s', $namespace, 'Migrations'), true, false); }
/** * {@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]; }
/** * @param $name * * @return BaseCommand * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ public function fetchCommand($name) { $name = ucfirst($name); $file = null; $packageName = null; foreach ($this->path as $package => $path) { $file_handler = new FileHandler($path); $file = $file_handler->getFile($name); if ($file !== false) { $packageName = $package; break; } } if (false === $file) { $this->error(sprintf('Unknown command: ` %1$s`. Does the file exists `%2$s/%1$s.php` ?' . PHP_EOL, $name, $this->path)); $message = $this->ansiFormat(sprintf('php %s.php help', $this->managerName), Console::FG_YELLOW); $this->normal(sprintf('Type %s for usage.' . PHP_EOL, $message)); return false; } // commands are in the commands namespace /** @var $className BaseCommand */ $className = ClassHelper::getFormatNamespace($packageName) . 'Console\\Command\\' . $name; return new $className(); }
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')); }
/** * @return array * * @throws ClassNotFoundException * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ public function getMigrationsClasses() { $migrationFiles = $this->getMigrationsFiles(); $classes = []; $namespace = BaseOrm::getMigrationsNamespace(); foreach ($migrationFiles as $migrationFile) { $className = ClassHelper::getClassNameFromFile($migrationFile, BaseOrm::getMigrationsPath()); $foundClass = ClassHelper::classExists($className, $namespace); if (!$className) { throw new ClassNotFoundException(sprintf('The class [ %2$s\\%1$s or \\%1$s ] could not be located', $className, $namespace)); } $classes[] = $foundClass; } return $classes; }
/** * Defines a new model class. * * we create a new namespace and define new classes because, we might be dealing with a model that has been dropped * Meaning if we try to load the model using the normal way, we will get and error of model does not exist. * * @param string $className * @param string $extends * * @return Model * * @since 1.1.0 * * @author Eddilbert Macharia (http://eddmash.com) <*****@*****.**> */ private static function createInstance($className, $extends = '') { if (!ClassHelper::classExists($className, BaseOrm::getModelsNamespace())) { MigrationModel::defineClass($className, $extends); } return new $className(); }