Example #1
0
 public function build()
 {
     if (!$this->options->contains('name')) {
         throw new BuilderException('You must specify the table name');
     }
     if ($this->options->contains('directory')) {
         $this->path->setRootPath($this->options->get('directory'));
     }
     $config = $this->getConfig();
     if (!($modelsDir = $this->options->get('modelsDir'))) {
         if (!isset($config->application->modelsDir)) {
             throw new BuilderException("Builder doesn't know where is the models directory.");
         }
         $modelsDir = $config->application->modelsDir;
     }
     $modelsDir = rtrim($modelsDir, '/\\') . DIRECTORY_SEPARATOR;
     $modelPath = $modelsDir;
     if (false == $this->isAbsolutePath($modelsDir)) {
         $modelPath = $this->path->getRootPath($modelsDir);
     }
     $methodRawCode = array();
     $className = $this->options->get('className');
     $modelPath .= $className . '.php';
     if (file_exists($modelPath) && !$this->options->contains('force')) {
         throw new BuilderException(sprintf('The model file "%s.php" already exists in models dir', $className));
     }
     if (!isset($config->database)) {
         throw new BuilderException('Database configuration cannot be loaded from your config file.');
     }
     if (!isset($config->database->adapter)) {
         throw new BuilderException("Adapter was not found in the config. " . "Please specify a config variable [database][adapter]");
     }
     $namespace = '';
     if ($this->options->contains('namespace') && $this->checkNamespace($this->options->get('namespace'))) {
         $namespace = 'namespace ' . $this->options->get('namespace') . ';' . PHP_EOL . PHP_EOL;
     }
     $genDocMethods = $this->options->get('genDocMethods', false);
     $useSettersGetters = $this->options->get('genSettersGetters', false);
     $adapter = $config->database->adapter;
     $this->isSupportedAdapter($adapter);
     $adapter = 'Mysql';
     if (isset($config->database->adapter)) {
         $adapter = $config->database->adapter;
     }
     if (is_object($config->database)) {
         $configArray = $config->database->toArray();
     } else {
         $configArray = $config->database;
     }
     // An array for use statements
     $uses = array();
     $adapterName = 'Phalcon\\Db\\Adapter\\Pdo\\' . $adapter;
     unset($configArray['adapter']);
     /** @var \Phalcon\Db\Adapter\Pdo $db */
     $db = new $adapterName($configArray);
     $initialize = array();
     if ($this->options->contains('schema')) {
         $schema = $this->options->get('schema');
         if ($schema != $config->database->dbname) {
             $initialize[] = $this->snippet->getThisMethod('setSchema', $schema);
         }
     } elseif ($adapter == 'Postgresql') {
         $schema = 'public';
         $initialize[] = $initialize[] = $this->snippet->getThisMethod('setSchema', $schema);
     } else {
         $schema = $config->database->dbname;
     }
     $table = $this->options->get('name');
     if ($this->options->get('fileName') != $this->options->get('name')) {
         $initialize[] = $this->snippet->getThisMethod('setSource', '\'' . $table . '\'');
     }
     if (!$db->tableExists($table, $schema)) {
         throw new BuilderException(sprintf('Table "%s" does not exist.', $table));
     }
     $fields = $db->describeColumns($table, $schema);
     foreach ($db->listTables() as $tableName) {
         foreach ($db->describeReferences($tableName, $schema) as $reference) {
             if ($reference->getReferencedTable() != $this->options->get('name')) {
                 continue;
             }
             $entityNamespace = '';
             if ($this->options->contains('namespace')) {
                 $entityNamespace = $this->options->get('namespace') . "\\";
             }
             $refColumns = $reference->getReferencedColumns();
             $columns = $reference->getColumns();
             $initialize[] = $this->snippet->getRelation('hasMany', $refColumns[0], $entityNamespace . Utils::camelize($tableName), $columns[0], "array('alias' => '" . Utils::camelize($tableName) . "')");
         }
     }
     foreach ($db->describeReferences($this->options->get('name'), $schema) as $reference) {
         $entityNamespace = '';
         if ($this->options->contains('namespace')) {
             $entityNamespace = $this->options->get('namespace') . "\\";
         }
         $refColumns = $reference->getReferencedColumns();
         $columns = $reference->getColumns();
         $initialize[] = $this->snippet->getRelation('belongsTo', $columns[0], $entityNamespace . Utils::camelize($reference->getReferencedTable()), $refColumns[0], "array('alias' => '" . Utils::camelize($reference->getReferencedTable()) . "')");
     }
     if ($this->options->has('hasMany')) {
         if (count($this->options->get('hasMany'))) {
             foreach ($this->options->get('hasMany') as $relation) {
                 if (!is_string($relation['fields'])) {
                     continue;
                 }
                 $entityName = $relation['camelizedName'];
                 $entityNamespace = '';
                 if ($this->options->contains('namespace')) {
                     $entityNamespace = $this->options->get('namespace') . "\\";
                     $relation['options']['alias'] = $entityName;
                 }
                 $initialize[] = $this->snippet->getRelation('hasMany', $relation['fields'], $entityNamespace . $entityName, $relation['relationFields'], $this->snippet->getRelationOptions(isset($relation['options']) ? $relation["options"]->toArray() : null));
             }
         }
     }
     if ($this->options->has('belongsTo')) {
         if (count($this->options->get('belongsTo'))) {
             foreach ($this->options->get('belongsTo') as $relation) {
                 if (!is_string($relation['fields'])) {
                     continue;
                 }
                 $entityName = Utils::camelize($relation['referencedModel']);
                 $entityNamespace = '';
                 if ($this->options->contains('namespace')) {
                     $entityNamespace = $this->options->get('namespace') . "\\";
                     $relation['options']['alias'] = $entityName;
                 }
                 $initialize[] = $this->snippet->getRelation('belongsTo', $relation['fields'], $entityNamespace . $entityName, $relation['relationFields'], $this->snippet->getRelationOptions(isset($relation['options']) ? $relation["options"]->toArray() : null));
             }
         }
     }
     $alreadyInitialized = false;
     $alreadyValidations = false;
     $alreadyFind = false;
     $alreadyFindFirst = false;
     $alreadyColumnMapped = false;
     $alreadyGetSourced = false;
     if (file_exists($modelPath)) {
         try {
             $possibleMethods = array();
             if ($useSettersGetters) {
                 foreach ($fields as $field) {
                     /** @var \Phalcon\Db\Column $field */
                     $methodName = Utils::camelize($field->getName());
                     $possibleMethods['set' . $methodName] = true;
                     $possibleMethods['get' . $methodName] = true;
                 }
             }
             $possibleMethods['getSource'] = true;
             require $modelPath;
             $linesCode = file($modelPath);
             $fullClassName = $this->options->get('className');
             if ($this->options->contains('namespace')) {
                 $fullClassName = $this->options->get('namespace') . '\\' . $fullClassName;
             }
             $reflection = new ReflectionClass($fullClassName);
             foreach ($reflection->getMethods() as $method) {
                 if ($method->getDeclaringClass()->getName() != $fullClassName) {
                     continue;
                 }
                 $methodName = $method->getName();
                 if (isset($possibleMethods[$methodName])) {
                     continue;
                 }
                 $indent = PHP_EOL;
                 if ($method->getDocComment()) {
                     $firstLine = $linesCode[$method->getStartLine() - 1];
                     preg_match('#^\\s+#', $firstLine, $matches);
                     if (isset($matches[0])) {
                         $indent .= $matches[0];
                     }
                 }
                 $methodDeclaration = join('', array_slice($linesCode, $method->getStartLine() - 1, $method->getEndLine() - $method->getStartLine() + 1));
                 $methodRawCode[$methodName] = $indent . $method->getDocComment() . PHP_EOL . $methodDeclaration;
                 switch ($methodName) {
                     case 'initialize':
                         $alreadyInitialized = true;
                         break;
                     case 'validation':
                         $alreadyValidations = true;
                         break;
                     case 'find':
                         $alreadyFind = true;
                         break;
                     case 'findFirst':
                         $alreadyFindFirst = true;
                         break;
                     case 'columnMap':
                         $alreadyColumnMapped = true;
                         break;
                     case 'getSource':
                         $alreadyGetSourced = true;
                         break;
                 }
             }
         } catch (ReflectionException $e) {
         }
     }
     $validations = array();
     foreach ($fields as $field) {
         if ($field->getType() === Column::TYPE_CHAR) {
             $domain = array();
             if (preg_match('/\\((.*)\\)/', $field->getType(), $matches)) {
                 foreach (explode(',', $matches[1]) as $item) {
                     $domain[] = $item;
                 }
             }
             if (count($domain)) {
                 $varItems = join(', ', $domain);
                 $validations[] = $this->snippet->getValidateInclusion($field->getName(), $varItems);
             }
         }
         if ($field->getName() == 'email') {
             $validations[] = $this->snippet->getValidateEmail($field->getName());
             $uses[] = $this->snippet->getUseAs('Phalcon\\Mvc\\Model\\Validator\\Email', 'Email');
         }
     }
     if (count($validations)) {
         $validations[] = $this->snippet->getValidationFailed();
     }
     // Check if there has been an extender class
     $extends = $this->options->get('extends', '\\Phalcon\\Mvc\\Model');
     // Check if there have been any excluded fields
     $exclude = array();
     if ($this->options->contains('excludeFields')) {
         $keys = explode(',', $this->options->get('excludeFields'));
         if (count($keys) > 0) {
             foreach ($keys as $key) {
                 $exclude[trim($key)] = '';
             }
         }
     }
     $attributes = array();
     $setters = array();
     $getters = array();
     foreach ($fields as $field) {
         $type = $this->getPHPType($field->getType());
         if ($useSettersGetters) {
             if (!array_key_exists(strtolower($field->getName()), $exclude)) {
                 $attributes[] = $this->snippet->getAttributes($type, 'protected', $field->getName());
                 $setterName = Utils::camelize($field->getName());
                 $setters[] = $this->snippet->getSetter($field->getName(), $type, $setterName);
                 if (isset($this->_typeMap[$type])) {
                     $getters[] = $this->snippet->getGetterMap($field->getName(), $type, $setterName, $this->_typeMap[$type]);
                 } else {
                     $getters[] = $this->snippet->getGetter($field->getName(), $type, $setterName);
                 }
             }
         } else {
             $attributes[] = $this->snippet->getAttributes($type, 'public', $field->getName());
         }
     }
     $validationsCode = '';
     if ($alreadyValidations == false && count($validations) > 0) {
         $validationsCode = $this->snippet->getValidationsMethod($validations);
     }
     $initCode = '';
     if ($alreadyInitialized == false && count($initialize) > 0) {
         $initCode = $this->snippet->getInitialize($initialize);
     }
     $license = '';
     if (file_exists('license.txt')) {
         $license = trim(file_get_contents('license.txt')) . PHP_EOL . PHP_EOL;
     }
     if (false == $alreadyGetSourced) {
         $methodRawCode[] = $this->snippet->getModelSource($this->options->get('name'));
     }
     if (false == $alreadyFind) {
         $methodRawCode[] = $this->snippet->getModelFind($className);
     }
     if (false == $alreadyFindFirst) {
         $methodRawCode[] = $this->snippet->getModelFindFirst($className);
     }
     $content = join('', $attributes);
     if ($useSettersGetters) {
         $content .= join('', $setters) . join('', $getters);
     }
     $content .= $validationsCode . $initCode;
     foreach ($methodRawCode as $methodCode) {
         $content .= $methodCode;
     }
     $classDoc = '';
     if ($genDocMethods) {
         $classDoc = $this->snippet->getClassDoc($className, $namespace);
     }
     if ($this->options->contains('mapColumn') && false == $alreadyColumnMapped) {
         $content .= $this->snippet->getColumnMap($fields);
     }
     $useDefinition = '';
     if (!empty($uses)) {
         $useDefinition = join('', $uses) . PHP_EOL . PHP_EOL;
     }
     $abstract = $this->options->contains('abstract') ? 'abstract ' : '';
     $code = $this->snippet->getClass($namespace, $useDefinition, $classDoc, $abstract, $className, $extends, $content, $license);
     if (file_exists($modelPath) && !is_writable($modelPath)) {
         throw new BuilderException(sprintf('Unable to write to %s. Check write-access of a file.', $modelPath));
     }
     if (!file_put_contents($modelPath, $code)) {
         throw new BuilderException(sprintf('Unable to write to %s', $modelPath));
     }
     if ($this->isConsole()) {
         $msgSuccess = ($this->options->contains('abstract') ? 'Abstract ' : '') . 'Model "%s" was successfully created.';
         $this->_notifySuccess(sprintf($msgSuccess, Utils::camelize($this->options->get('name'))));
     }
 }
Example #2
0
 /**
  * Generate specified table migration
  *
  * @param      $version
  * @param      $table
  * @param null $exportData
  *
  * @return string
  * @throws \Phalcon\Db\Exception
  */
 public static function generate($version, $table, $exportData = null)
 {
     $oldColumn = null;
     $allFields = [];
     $numericFields = [];
     $tableDefinition = [];
     $snippet = new Snippet();
     $defaultSchema = Utils::resolveDbSchema(self::$_databaseConfig);
     $description = self::$_connection->describeColumns($table, $defaultSchema);
     foreach ($description as $field) {
         /** @var \Phalcon\Db\ColumnInterface $field */
         $fieldDefinition = [];
         switch ($field->getType()) {
             case Column::TYPE_INTEGER:
                 $fieldDefinition[] = "'type' => Column::TYPE_INTEGER";
                 $numericFields[$field->getName()] = true;
                 break;
             case Column::TYPE_VARCHAR:
                 $fieldDefinition[] = "'type' => Column::TYPE_VARCHAR";
                 break;
             case Column::TYPE_CHAR:
                 $fieldDefinition[] = "'type' => Column::TYPE_CHAR";
                 break;
             case Column::TYPE_DATE:
                 $fieldDefinition[] = "'type' => Column::TYPE_DATE";
                 break;
             case Column::TYPE_DATETIME:
                 $fieldDefinition[] = "'type' => Column::TYPE_DATETIME";
                 break;
             case Column::TYPE_TIMESTAMP:
                 $fieldDefinition[] = "'type' => Column::TYPE_TIMESTAMP";
                 break;
             case Column::TYPE_DECIMAL:
                 $fieldDefinition[] = "'type' => Column::TYPE_DECIMAL";
                 $numericFields[$field->getName()] = true;
                 break;
             case Column::TYPE_TEXT:
                 $fieldDefinition[] = "'type' => Column::TYPE_TEXT";
                 break;
             case Column::TYPE_BOOLEAN:
                 $fieldDefinition[] = "'type' => Column::TYPE_BOOLEAN";
                 break;
             case Column::TYPE_FLOAT:
                 $fieldDefinition[] = "'type' => Column::TYPE_FLOAT";
                 break;
             case Column::TYPE_DOUBLE:
                 $fieldDefinition[] = "'type' => Column::TYPE_DOUBLE";
                 break;
             case Column::TYPE_TINYBLOB:
                 $fieldDefinition[] = "'type' => Column::TYPE_TINYBLOB";
                 break;
             case Column::TYPE_BLOB:
                 $fieldDefinition[] = "'type' => Column::TYPE_BLOB";
                 break;
             case Column::TYPE_MEDIUMBLOB:
                 $fieldDefinition[] = "'type' => Column::TYPE_MEDIUMBLOB";
                 break;
             case Column::TYPE_LONGBLOB:
                 $fieldDefinition[] = "'type' => Column::TYPE_LONGBLOB";
                 break;
             case Column::TYPE_JSON:
                 $fieldDefinition[] = "'type' => Column::TYPE_JSON";
                 break;
             case Column::TYPE_JSONB:
                 $fieldDefinition[] = "'type' => Column::TYPE_JSONB";
                 break;
             case Column::TYPE_BIGINTEGER:
                 $fieldDefinition[] = "'type' => Column::TYPE_BIGINTEGER";
                 break;
             default:
                 throw new DbException('Unrecognized data type ' . $field->getType() . ' at column ' . $field->getName());
         }
         if (null !== ($default = $field->getDefault())) {
             $fieldDefinition[] = "'default' => \"{$default}\"";
         }
         //if ($field->isPrimary()) {
         //	$fieldDefinition[] = "'primary' => true";
         //}
         if ($field->isUnsigned()) {
             $fieldDefinition[] = "'unsigned' => true";
         }
         if ($field->isNotNull()) {
             $fieldDefinition[] = "'notNull' => true";
         }
         if ($field->isAutoIncrement()) {
             $fieldDefinition[] = "'autoIncrement' => true";
         }
         if (self::$_databaseConfig->adapter == 'Postgresql' && in_array($field->getType(), [Column::TYPE_BOOLEAN, Column::TYPE_INTEGER, Column::TYPE_BIGINTEGER])) {
             // nothing
         } else {
             if ($field->getSize()) {
                 $fieldDefinition[] = "'size' => " . $field->getSize();
             } else {
                 $fieldDefinition[] = "'size' => 1";
             }
         }
         if ($field->getScale()) {
             $fieldDefinition[] = "'scale' => " . $field->getScale();
         }
         if ($oldColumn != null) {
             $fieldDefinition[] = "'after' => '" . $oldColumn . "'";
         } else {
             $fieldDefinition[] = "'first' => true";
         }
         $oldColumn = $field->getName();
         $tableDefinition[] = $snippet->getColumnDefinition($field->getName(), $fieldDefinition);
         $allFields[] = "'" . $field->getName() . "'";
     }
     $indexesDefinition = [];
     $indexes = self::$_connection->describeIndexes($table, $defaultSchema);
     foreach ($indexes as $indexName => $dbIndex) {
         /** @var \Phalcon\Db\Index $dbIndex */
         $indexDefinition = [];
         foreach ($dbIndex->getColumns() as $indexColumn) {
             $indexDefinition[] = "'" . $indexColumn . "'";
         }
         $indexesDefinition[] = $snippet->getIndexDefinition($indexName, $indexDefinition, $dbIndex->getType());
     }
     $referencesDefinition = [];
     $references = self::$_connection->describeReferences($table, $defaultSchema);
     foreach ($references as $constraintName => $dbReference) {
         $columns = [];
         foreach ($dbReference->getColumns() as $column) {
             $columns[] = "'" . $column . "'";
         }
         $referencedColumns = [];
         foreach ($dbReference->getReferencedColumns() as $referencedColumn) {
             $referencedColumns[] = "'" . $referencedColumn . "'";
         }
         $referenceDefinition = [];
         $referenceDefinition[] = "'referencedSchema' => '" . $dbReference->getReferencedSchema() . "'";
         $referenceDefinition[] = "'referencedTable' => '" . $dbReference->getReferencedTable() . "'";
         $referenceDefinition[] = "'columns' => [" . join(",", $columns) . "]";
         $referenceDefinition[] = "'referencedColumns' => [" . join(",", $referencedColumns) . "]";
         $referenceDefinition[] = "'onUpdate' => '" . $dbReference->getOnUpdate() . "'";
         $referenceDefinition[] = "'onDelete' => '" . $dbReference->getOnDelete() . "'";
         $referencesDefinition[] = $snippet->getReferenceDefinition($constraintName, $referenceDefinition);
     }
     $optionsDefinition = [];
     $tableOptions = self::$_connection->tableOptions($table, $defaultSchema);
     foreach ($tableOptions as $optionName => $optionValue) {
         if (self::$_skipAI && strtoupper($optionName) == "AUTO_INCREMENT") {
             $optionValue = '';
         }
         $optionsDefinition[] = "'" . strtoupper($optionName) . "' => '" . $optionValue . "'";
     }
     $classVersion = preg_replace('/[^0-9A-Za-z]/', '', $version);
     $className = Text::camelize($table) . 'Migration_' . $classVersion;
     // morph()
     $classData = $snippet->getMigrationMorph($className, $table, $tableDefinition);
     if (count($indexesDefinition)) {
         $classData .= $snippet->getMigrationDefinition('indexes', $indexesDefinition);
     }
     if (count($referencesDefinition)) {
         $classData .= $snippet->getMigrationDefinition('references', $referencesDefinition);
     }
     if (count($optionsDefinition)) {
         $classData .= $snippet->getMigrationDefinition('options', $optionsDefinition);
     }
     $classData .= "            ]\n        );\n    }\n";
     // up()
     $classData .= $snippet->getMigrationUp();
     if ($exportData == 'always') {
         $classData .= $snippet->getMigrationBatchInsert($table, $allFields);
     }
     $classData .= "\n    }\n";
     // down()
     $classData .= $snippet->getMigrationDown();
     if ($exportData == 'always') {
         $classData .= $snippet->getMigrationBatchDelete($table);
     }
     $classData .= "\n    }\n";
     // afterCreateTable()
     if ($exportData == 'oncreate') {
         $classData .= $snippet->getMigrationAfterCreateTable($table, $allFields);
     }
     // end of class
     $classData .= "\n}\n";
     // dump data
     if ($exportData == 'always' || $exportData == 'oncreate') {
         $fileHandler = fopen(self::$_migrationPath . $version . '/' . $table . '.dat', 'w');
         $cursor = self::$_connection->query('SELECT * FROM ' . $table);
         $cursor->setFetchMode(Db::FETCH_ASSOC);
         while ($row = $cursor->fetchArray()) {
             $data = [];
             foreach ($row as $key => $value) {
                 if (isset($numericFields[$key])) {
                     if ($value === '' || is_null($value)) {
                         $data[] = 'NULL';
                     } else {
                         $data[] = addslashes($value);
                     }
                 } else {
                     $data[] = "'" . addslashes($value) . "'";
                 }
                 unset($value);
             }
             fputs($fileHandler, join('|', $data) . PHP_EOL);
             unset($row);
             unset($data);
         }
         fclose($fileHandler);
     }
     return $classData;
 }