diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e07c17d..97a1dcd5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# [4.0.6](https://github.com/phalcon/cphalcon/releases/tag/v4.0.6) (2021-03-22) +## Fixed +- Fixed model findFirst return type error [#1478](https://github.com/phalcon/phalcon-devtools/issues/1478) +- Added trailing semicolon to scaffolding crud views getters [#1477](https://github.com/phalcon/phalcon-devtools/issues/1477) +- Fixed optional options (namespace, abstract) checks on model create [#1491](https://github.com/phalcon/phalcon-devtools/issues/1491) +- Fixed wrong request filtering [#1468](https://github.com/phalcon/phalcon-devtools/issues/1468) +- Fixed empty namespace generation [#1467](https://github.com/phalcon/phalcon-devtools/issues/1467) +- Removed `model->getSource()` method generation due to its becoming final in `Phalcon\Mvc\Model` [#1297](https://github.com/phalcon/phalcon-devtools/issues/1297) +- Fixed model `--force` creation bugs [#1317](https://github.com/phalcon/phalcon-devtools/issues/1317) +- Fixed mapping of PascalCase table fields [#1463](https://github.com/phalcon/phalcon-devtools/issues/1463) + + # [4.0.5](https://github.com/phalcon/cphalcon/releases/tag/v4.0.5) (2021-03-14) ## Fixed - Fixed model creation failure in webtools due to wrong variable mutation [#1415](https://github.com/phalcon/phalcon-devtools/issues/1415) diff --git a/src/Builder/Component/AllModels.php b/src/Builder/Component/AllModels.php index e8915263a..2588b30ad 100644 --- a/src/Builder/Component/AllModels.php +++ b/src/Builder/Component/AllModels.php @@ -85,14 +85,9 @@ public function build(): void $genSettersGetters = $this->options->get('genSettersGetters', false); $mapColumn = $this->options->get('mapColumn', false); - $adapter = $config->database->adapter; + $adapter = $config->database->adapter ?? 'Mysql'; $this->isSupportedAdapter($adapter); - $adapter = 'Mysql'; - if (isset($config->database->adapter)) { - $adapter = $config->database->adapter; - } - if (is_object($config->database)) { $configArray = $config->database->toArray(); } else { diff --git a/src/Builder/Component/Controller.php b/src/Builder/Component/Controller.php index 6d8baf752..7d2e668e6 100644 --- a/src/Builder/Component/Controller.php +++ b/src/Builder/Component/Controller.php @@ -103,12 +103,14 @@ public function build() */ protected function constructNamespace(): string { - $namespace = $this->options->get('namespace'); + $namespace = $this->options->has('namespace') + ? (string) $this->options->get('namespace') : null; + if ($namespace === null) { return ''; } - if ($this->checkNamespace((string)$namespace)) { + if ($this->checkNamespace($namespace) && !empty(trim($namespace))) { return 'namespace ' . $this->options->get('namespace') . ';' . PHP_EOL . PHP_EOL; } diff --git a/src/Builder/Component/Model.php b/src/Builder/Component/Model.php index e43177aa2..e8c6b2f79 100644 --- a/src/Builder/Component/Model.php +++ b/src/Builder/Component/Model.php @@ -27,6 +27,8 @@ use Phalcon\Validation; use Phalcon\Validation\Validator\Email as EmailValidator; use ReflectionClass; +use ReflectionClassConstant; +use ReflectionProperty; /** * Builder to generate models @@ -111,23 +113,19 @@ public function build(): void require_once $config->devtools->loader; } - $namespace = ''; - if ($this->modelOptions->hasOption('namespace') && - $this->checkNamespace((string)$this->modelOptions->getOption('namespace'))) { + $namespace = $this->modelOptions->hasOption('namespace') + ? (string) $this->modelOptions->getOption('namespace') : ''; + + if ($this->checkNamespace($namespace) && !empty(trim($namespace))) { $namespace = 'namespace ' . $this->modelOptions->getOption('namespace') . ';' . PHP_EOL . PHP_EOL; } $genDocMethods = $this->modelOptions->getValidOptionOrDefault('genDocMethods', false); $useSettersGetters = $this->modelOptions->getValidOptionOrDefault('genSettersGetters', false); - $adapter = $config->database->adapter; + $adapter = $config->database->adapter ?? 'Mysql'; $this->isSupportedAdapter($adapter); - $adapter = 'Mysql'; - if (isset($config->database->adapter)) { - $adapter = $config->database->adapter; - } - if (is_object($config->database)) { $configArray = $config->database->toArray(); } else { @@ -167,40 +165,36 @@ public function build(): void foreach ($referenceList as $tableName => $references) { foreach ($references as $reference) { - if ($reference->getReferencedTable() != $this->modelOptions->getOption('name')) { + if ($reference->getReferencedTable() !== $this->modelOptions->getOption('name')) { continue; } - $entityNamespace = ''; - if ($this->modelOptions->getOption('namespace')) { - $entityNamespace = $this->modelOptions->getOption('namespace')."\\"; - } + $entityNamespace = $this->modelOptions->hasOption('namespace') + ? $this->modelOptions->getOption('namespace')."\\" : ''; $refColumns = $reference->getReferencedColumns(); $columns = $reference->getColumns(); $initialize[] = $snippet->getRelation( 'hasMany', - $this->modelOptions->getOption('camelize') ? Utils::lowerCamelize($refColumns[0]) : $refColumns[0], + $this->getFieldName($refColumns[0]), $entityNamespace . Text::camelize($tableName, '_-'), - $this->modelOptions->getOption('camelize') ? Utils::lowerCamelize($columns[0]) : $columns[0], + $this->getFieldName($columns[0]), "['alias' => '" . Text::camelize($tableName, '_-') . "']" ); } } foreach ($db->describeReferences($this->modelOptions->getOption('name'), $schema) as $reference) { - $entityNamespace = ''; - if ($this->modelOptions->getOption('namespace')) { - $entityNamespace = $this->modelOptions->getOption('namespace'); - } + $entityNamespace = $this->modelOptions->hasOption('namespace') + ? $this->modelOptions->getOption('namespace') : ''; $refColumns = $reference->getReferencedColumns(); $columns = $reference->getColumns(); $initialize[] = $snippet->getRelation( 'belongsTo', - $this->modelOptions->getOption('camelize') ? Utils::lowerCamelize($columns[0]) : $columns[0], + $this->getFieldName($columns[0]), $this->getEntityClassName($reference, $entityNamespace), - $this->modelOptions->getOption('camelize') ? Utils::lowerCamelize($refColumns[0]) : $refColumns[0], + $this->getFieldName($refColumns[0]), "['alias' => '" . Text::camelize($reference->getReferencedTable(), '_-') . "']" ); } @@ -225,8 +219,6 @@ public function build(): void } } - $possibleMethods['getSource'] = true; - /** @noinspection PhpIncludeInspection */ require_once $modelPath; @@ -237,7 +229,7 @@ public function build(): void } $reflection = new ReflectionClass($fullClassName); foreach ($reflection->getMethods() as $method) { - if ($method->getDeclaringClass()->getName() != $fullClassName) { + if ($method->getDeclaringClass()->getName() !== $fullClassName) { continue; } @@ -285,117 +277,60 @@ public function build(): void } } - $possibleFields = $possibleFieldsTransformed = []; + $possibleFieldsTransformed = []; foreach ($fields as $field) { - $possibleFields[$field->getName()] = true; - if ($this->modelOptions->getOption('camelize')) { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '_-')); - } else { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '-')); - } + $fieldName = $this->getFieldName($field->getName()); $possibleFieldsTransformed[$fieldName] = true; } if (method_exists($reflection, 'getReflectionConstants')) { foreach ($reflection->getReflectionConstants() as $constant) { - if ($constant->getDeclaringClass()->getName() != $fullClassName) { + if ($constant->getDeclaringClass()->getName() !== $fullClassName) { continue; } - $constantsPreg = '/^(\s*)const(\s+)'.$constant->getName().'([\s=;]+)/'; - $endLine = $startLine = 0; - foreach ($linesCode as $line => $code) { - if (preg_match($constantsPreg, $code)) { - $startLine = $line; - break; - } - } - if (!empty($startLine)) { - $countLines = count($linesCode); - for ($i = $startLine; $i < $countLines; $i++) { - if (preg_match('/;(\s*)$/', $linesCode[$i])) { - $endLine = $i; - break; - } - } - } - if (!empty($startLine) && !empty($endLine)) { - $constantDeclaration = join( - '', - array_slice( - $linesCode, - $startLine, - $endLine - $startLine + 1 - ) - ); - $attributes[] = PHP_EOL . " " . $constant->getDocComment() . - PHP_EOL . $constantDeclaration; + $constantsPreg = '/const(\s+)' . $constant->getName() . '([\s=;]+)/'; + $attribute = $this->getAttribute($linesCode, $constantsPreg, $constant); + if (!empty($attribute)) { + $attributes[] = $attribute; } } } foreach ($reflection->getProperties() as $property) { $propertyName = $property->getName(); - /** @var null|string $possibleFieldsValue */ - $possibleFieldsValue = $possibleFieldsTransformed[$propertyName]; - - if ($property->getDeclaringClass()->getName() != $fullClassName || - !empty($possibleFieldsValue)) { + if (!empty($possibleFieldsTransformed[$propertyName]) + || $property->getDeclaringClass()->getName() !== $fullClassName + ) { continue; } $modifiersPreg = ''; switch ($property->getModifiers()) { - case \ReflectionProperty::IS_PUBLIC: + case ReflectionProperty::IS_PUBLIC: $modifiersPreg = '^(\s*)public(\s+)'; break; - case \ReflectionProperty::IS_PRIVATE: + case ReflectionProperty::IS_PRIVATE: $modifiersPreg = '^(\s*)private(\s+)'; break; - case \ReflectionProperty::IS_PROTECTED: + case ReflectionProperty::IS_PROTECTED: $modifiersPreg = '^(\s*)protected(\s+)'; break; - case \ReflectionProperty::IS_STATIC + \ReflectionProperty::IS_PUBLIC: + case ReflectionProperty::IS_STATIC + ReflectionProperty::IS_PUBLIC: $modifiersPreg = '^(\s*)(public?)(\s+)static(\s+)'; break; - case \ReflectionProperty::IS_STATIC + \ReflectionProperty::IS_PROTECTED: + case ReflectionProperty::IS_STATIC + ReflectionProperty::IS_PROTECTED: $modifiersPreg = '^(\s*)protected(\s+)static(\s+)'; break; - case \ReflectionProperty::IS_STATIC + \ReflectionProperty::IS_PRIVATE: + case ReflectionProperty::IS_STATIC + ReflectionProperty::IS_PRIVATE: $modifiersPreg = '^(\s*)private(\s+)static(\s+)'; break; } $modifiersPreg = '/' . $modifiersPreg . '\$' . $propertyName . '([\s=;]+)/'; - $endLine = $startLine = 0; - foreach ($linesCode as $line => $code) { - if (preg_match($modifiersPreg, $code)) { - $startLine = $line; - break; - } - } - - if (!empty($startLine)) { - $countLines = count($linesCode); - for ($i = $startLine; $i < $countLines; $i++) { - if (preg_match('/;(\s*)$/', $linesCode[$i])) { - $endLine = $i; - break; - } - } - } - - if (!empty($startLine) && !empty($endLine)) { - $propertyDeclaration = join( - '', - array_slice( - $linesCode, - $startLine, - $endLine - $startLine + 1 - ) - ); - $attributes[] = PHP_EOL . " " . $property->getDocComment() . PHP_EOL . - $propertyDeclaration; + $attribute = $this->getAttribute($linesCode, $modifiersPreg, $property); + if (!empty($attribute)) { + $attributes[] = $attribute; } } } catch (\Exception $e) { @@ -411,12 +346,9 @@ public function build(): void $validations = []; foreach ($fields as $field) { + $fieldName = $this->getFieldName($field->getName()); + if ($field->getType() === Column::TYPE_CHAR) { - if ($this->modelOptions->getOption('camelize')) { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '_-')); - } else { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '-')); - } $domain = []; if (preg_match('/\((.*)\)/', (string)$field->getType(), $matches)) { foreach (explode(',', $matches[1]) as $item) { @@ -429,12 +361,7 @@ public function build(): void } } - if ($field->getName() == 'email') { - if ($this->modelOptions->getOption('camelize')) { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '_-')); - } else { - $fieldName = Utils::lowerCamelize(Utils::camelize($field->getName(), '-')); - } + if ($field->getName() === 'email') { $validations[] = $snippet->getValidateEmail($fieldName); $uses[] = $snippet->getUseAs(EmailValidator::class, 'EmailValidator'); } @@ -466,8 +393,7 @@ public function build(): void } $type = $this->getPHPType($field->getType()); - $fieldName = Utils::lowerCamelizeWithDelimiter($field->getName(), '-', true); - $fieldName = $this->modelOptions->getOption('camelize') ? Utils::lowerCamelize($fieldName) : $fieldName; + $fieldName = $this->getFieldName($field->getName()); $attributes[] = $snippet->getAttributes( $type, $useSettersGetters ? 'protected' : 'public', @@ -572,6 +498,65 @@ public function build(): void } } + /** + * @param array $linesCode + * @param string $pattern + * @param ReflectionProperty|ReflectionClassConstant $attribute + * + * @return null|string + */ + protected function getAttribute(array $linesCode, string $pattern, $attribute): ?string + { + $endLine = $startLine = 0; + foreach ($linesCode as $line => $code) { + if (preg_match($pattern, $code)) { + $startLine = $line; + break; + } + } + if (!empty($startLine)) { + $countLines = count($linesCode); + for ($i = $startLine; $i < $countLines; $i++) { + if (preg_match('/;(\s*)$/', $linesCode[$i])) { + $endLine = $i; + break; + } + } + } + + if (!empty($startLine) && !empty($endLine)) { + $attributeDeclaration = join( + '', + array_slice( + $linesCode, + $startLine, + $endLine - $startLine + 1 + ) + ); + $attributeFormatted = $attributeDeclaration; + if (!empty($attribute->getDocComment())) { + $attributeFormatted = " " . $attribute->getDocComment() . PHP_EOL . $attribute; + } + return $attributeFormatted; + } + + return null; + } + + /** + * @param string $fieldName + * + * @return string + */ + protected function getFieldName(string $fieldName): string + { + if ($this->modelOptions->getOption('camelize')) { + return Utils::lowerCamelize(Utils::camelize($fieldName, '_-')); + } + + return Utils::lowerCamelizeWithDelimiter($fieldName, '-', true); + } + /** * Set path to model * diff --git a/src/Builder/Component/Scaffold.php b/src/Builder/Component/Scaffold.php index efeb1fcd0..dbc2f21bb 100644 --- a/src/Builder/Component/Scaffold.php +++ b/src/Builder/Component/Scaffold.php @@ -183,7 +183,7 @@ public function build(): bool $attributes = $metaData->getAttributes($entity); $dataTypes = $metaData->getDataTypes($entity); $identityField = $metaData->getIdentityField($entity); - $identityField = $identityField ? $identityField : null; + $identityField = $identityField ?: null; $primaryKeys = $metaData->getPrimaryKeyAttributes($entity); $setParams = []; @@ -210,7 +210,7 @@ public function build(): bool // Build Controller $this->makeController(); - if ($this->options->get('templateEngine') == 'volt') { + if ($this->options->get('templateEngine') === 'volt') { $this->makeLayoutsVolt(); $this->makeViewVolt('index'); $this->makeViewSearchVolt(); @@ -233,7 +233,7 @@ public function build(): bool * @param string $var * @param mixed $fields * @param bool $useGetSetters - * @param string $identityField + * @param null|string $identityField * * @return string */ @@ -241,18 +241,16 @@ private function captureFilterInput(string $var, $fields, bool $useGetSetters, s { $code = ''; foreach ($fields as $field => $dataType) { - if ($identityField !== null && $field == $identityField) { + if ($identityField !== null && $field === $identityField) { continue; } - if (is_int($dataType) !== false) { + if (\in_array($dataType, [Column::TYPE_DECIMAL, Column::TYPE_INTEGER])) { $fieldCode = '$this->request->getPost("'.$field.'", "int")'; + } elseif ($field === 'email') { + $fieldCode = '$this->request->getPost("'.$field.'", "email")'; } else { - if ($field == 'email') { - $fieldCode = '$this->request->getPost("'.$field.'", "email")'; - } else { - $fieldCode = '$this->request->getPost("'.$field.'")'; - } + $fieldCode = '$this->request->getPost("'.$field.'")'; } $code .= '$' . Utils::lowerCamelizeWithDelimiter($var, '-', true) . '->'; @@ -309,33 +307,33 @@ private function makeField(string $attribute, int $dataType, $relationField, arr $code .= "\t\t" . 'tag->select(["' . $attribute . '", $' . $selectDefinition[$attribute]['varName'] . ', "using" => "' . $selectDefinition[$attribute]['primaryKey'] . ',' . $selectDefinition[$attribute]['detail'] . - '", "useDummy" => true), "class" => "form-control", "id" => "' . $id . '"] ?>'; + '", "useDummy" => true), "class" => "form-control", "id" => "' . $id . '"]; ?>'; } else { switch ($dataType) { case Column::TYPE_ENUM: // enum $code .= "\t\t" . 'tag->selectStatic(["' . $attribute . - '", [], "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", [], "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; case Column::TYPE_CHAR: $code .= "\t\t" . 'tag->textField(["' . $attribute . - '", "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; case Column::TYPE_DECIMAL: case Column::TYPE_INTEGER: $code .= "\t\t" . 'tag->textField(["' . $attribute . - '", "type" => "number", "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", "type" => "number", "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; case Column::TYPE_DATE: $code .= "\t\t" . 'tag->textField(["' . $attribute . - '", "type" => "date", "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", "type" => "date", "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; case Column::TYPE_TEXT: $code .= "\t\t" . 'tag->textArea(["' . $attribute . - '", "cols" => 30, "rows" => 4, "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", "cols" => 30, "rows" => 4, "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; default: $code .= "\t\t" . 'tag->textField(["' . $attribute . - '", "size" => 30, "class" => "form-control", "id" => "' . $id . '"]) ?>'; + '", "size" => 30, "class" => "form-control", "id" => "' . $id . '"]); ?>'; break; } } @@ -461,14 +459,13 @@ private function makeController(): void $code = file_get_contents($this->options->get('templatePath') . '/scaffold/no-forms/Controller.php'); $usesNamespaces = false; - $controllerNamespace = (string)$this->options->get('controllersNamespace'); - if ($this->options->has('controllersNamespace') && - $controllerNamespace && - $this->checkNamespace($controllerNamespace) - ) { + $controllerNamespace = $this->options->has('controllersNamespace') + ? (string) $this->options->get('controllersNamespace') : ''; + + if (!empty(trim($controllerNamespace)) && $this->checkNamespace($controllerNamespace)) { $code = str_replace( '$namespace$', - 'namespace ' . $this->options->get('controllersNamespace').';' . PHP_EOL, + 'namespace ' . $controllerNamespace.';' . PHP_EOL, $code ); $usesNamespaces = true; @@ -565,8 +562,8 @@ private function makeLayouts() // View model layout $code = ''; if ($this->options->has('theme')) { - $code .= 'tag->stylesheetLink("themes/lightness/style") ?>'.PHP_EOL; - $code .= 'tag->stylesheetLink("themes/base") ?>'.PHP_EOL; + $code .= 'tag->stylesheetLink("themes/lightness/style"); ?>'.PHP_EOL; + $code .= 'tag->stylesheetLink("themes/base"); ?>'.PHP_EOL; $code .= '