diff --git a/src/Field.php b/src/Field.php new file mode 100644 index 0000000..1392c44 --- /dev/null +++ b/src/Field.php @@ -0,0 +1,201 @@ + + */ +abstract class Field +{ + public const OPT_CREATE = 'create'; + + public const OPT_DROP = 'drop'; + + public const OPT_MODIFY = 'modify'; + + public const OPT_RENAME = 'rename'; + + public const TYPE = ''; + + protected const INVALID_ARGUMENT_MESSAGE = 'The value of the %s field must be of type %s: %s given.'; + + /** + * @var bool|null|numeric|string + */ + protected $valueDefault; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $opt = self::OPT_CREATE; + + /** + * @var null|string + */ + protected $comment = null; + + /** + * @var bool + */ + protected $isNullable = false; + + public function __construct(string $name) + { + $this->name = $name; + } + + /** + * Enregistre un commentaire. + * + * @param string $comment + * + * @return $this + */ + public function comment(string $comment): self + { + $this->comment = $comment; + + return $this; + } + + /** + * Enregistre le champ comme acceptant la valeur NULL. + * + * @return $this + */ + public function nullable(): self + { + $this->isNullable = true; + + return $this; + } + + /** + * Enregistre une valeur par défaut au champ précédent. + * Lève une exception si la valeur par défaut ne correspond pas au type de valeur passée en paramètre. + * + * @param bool|null|numeric|string $value Valeur à tester. + * + * @throws ColumnsValueException + * + * @return bool|null|numeric|string + */ + abstract public function filterValue($value); + + /** + * Enregistre une valeur par défaut au champ précédent. + * Lève une exception si la valeur par défaut ne correspond pas au type de valeur passée en paramètre. + * + * @param bool|null|numeric|string $value Valeur à tester. + * + * @throws TableBuilderException + * + * @return $this + */ + public function valueDefault($value) + { + $this->valueDefault = $this->filterValue($value); + + return $this; + } + + /** + * Retourne la valeur par defaut. + * + * @throws ColumnsValueException + * + * @return bool|null|numeric|string Valeur par defaut. + */ + public function getValueDefault() + { + if (isset($this->valueDefault)) { + return $this->valueDefault; + } + if ($this->isNullable) { + return null; + } + + throw new ColumnsValueException( + sprintf('%s not nullable or not default.', $this->name) + ); + } + + /** + * Enregistre la modification du champ précédent. + * + * @return void + */ + public function modify(): void + { + $this->opt = self::OPT_MODIFY; + } + + /** + * Retourne le nom de l'opération du champ. + * + * @return string + */ + public function getOpt(): string + { + return $this->opt; + } + + /** + * Retourne le nom du champ. + * + * @return string + */ + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } + + /** + * Retourne les données du champ. + * + * @return array + */ + public function toArray(): array + { + $data = []; + if (static::TYPE !== '') { + $data[ 'type' ] = static::TYPE; + } + if ($this->isNullable) { + $data[ 'nullable' ] = $this->isNullable; + } + if ($this->comment !== null) { + $data[ '_comment' ] = $this->comment; + } + if (isset($this->valueDefault)) { + $data[ 'default' ] = $this->valueDefault; + } + + return $data; + } +} diff --git a/src/Field/BoolType.php b/src/Field/BoolType.php new file mode 100644 index 0000000..9aed5ed --- /dev/null +++ b/src/Field/BoolType.php @@ -0,0 +1,37 @@ + + */ +class BoolType extends Field +{ + public const TYPE = 'boolean'; + + /** + * {@inheritdoc} + * + * return bool + */ + public function filterValue($value) + { + if (!\is_bool($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, self::TYPE, gettype($value)) + ); + } + + return $value; + } +} diff --git a/src/Field/CharType.php b/src/Field/CharType.php new file mode 100644 index 0000000..90d728a --- /dev/null +++ b/src/Field/CharType.php @@ -0,0 +1,24 @@ + + */ +class CharType extends StringType +{ + public const TYPE = 'char'; + + /** + * @var int + */ + protected $length = 1; +} diff --git a/src/Field/DateTimeType.php b/src/Field/DateTimeType.php new file mode 100644 index 0000000..2c38fef --- /dev/null +++ b/src/Field/DateTimeType.php @@ -0,0 +1,72 @@ + + */ +class DateTimeType extends Field +{ + public const CURRENT_DEFAULT = 'current_datetime'; + + public const TYPE = 'datetime'; + + protected const FORMAT = 'Y-m-d H:i:s'; + + /** + * {@inheritdoc} + * + * return string + */ + public function filterValue($value) + { + if (!\is_string($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, 'string', gettype($value)) + ); + } + if (strtolower($value) === static::CURRENT_DEFAULT) { + return static::CURRENT_DEFAULT; + } + if (($timestamp = strtotime($value))) { + return date(static::FORMAT, $timestamp); + } + + throw new ColumnsValueException( + sprintf('The value of the %s field must be a valid date: %s given', $this->name, $value) + ); + } + + /** + * {@inheritdoc} + */ + public function getValueDefault() + { + if (isset($this->valueDefault)) { + if ($this->valueDefault === static::CURRENT_DEFAULT) { + return date(static::FORMAT, time()); + } + + /* Si les variables magiques ne sont pas utilisé alors la vrais valeur par defaut est retourné. */ + return $this->valueDefault; + } + if ($this->isNullable) { + return null; + } + + throw new ColumnsValueException( + sprintf('%s not nullable or not default.', $this->name) + ); + } +} diff --git a/src/Field/DateType.php b/src/Field/DateType.php new file mode 100644 index 0000000..2f8e256 --- /dev/null +++ b/src/Field/DateType.php @@ -0,0 +1,23 @@ + + */ +class DateType extends DateTimeType +{ + public const CURRENT_DEFAULT = 'current_date'; + + public const TYPE = 'date'; + + protected const FORMAT = 'Y-m-d'; +} diff --git a/src/Field/DropType.php b/src/Field/DropType.php new file mode 100644 index 0000000..d5afa24 --- /dev/null +++ b/src/Field/DropType.php @@ -0,0 +1,37 @@ + + */ +class DropType extends Field +{ + protected $opt = self::OPT_DROP; + + public function filterValue($value) + { + return null; + } + + /** + * {@inheritdoc} + */ + public function toArray(): array + { + $data = parent::toArray(); + $data[ 'opt' ] = $this->opt; + + return $data; + } +} diff --git a/src/Field/FloatType.php b/src/Field/FloatType.php new file mode 100644 index 0000000..8455b40 --- /dev/null +++ b/src/Field/FloatType.php @@ -0,0 +1,37 @@ + + */ +class FloatType extends Field +{ + public const TYPE = 'float'; + + /** + * {@inheritdoc} + * + * return float + */ + public function filterValue($value) + { + if (!\is_float($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, self::TYPE, gettype($value)) + ); + } + + return (float) $value; + } +} diff --git a/src/Field/IncrementType.php b/src/Field/IncrementType.php new file mode 100644 index 0000000..229ae8d --- /dev/null +++ b/src/Field/IncrementType.php @@ -0,0 +1,54 @@ + + */ +class IncrementType extends Field +{ + public const TYPE = 'increments'; + + /** + * {@inheritdoc} + * + * return int + */ + public function filterValue($value) + { + if (!\is_int($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, 'integer', gettype($value)) + ); + } + + return (int) $value; + } + + /** + * @throws ColumnsValueException + */ + public function getValueDefault() + { + throw new ColumnsValueException('An incremental type column can not have a default value.'); + } + + /** + * @throws ColumnsValueException + */ + public function valueDefault($value) + { + throw new ColumnsValueException('An incremental type column can not have a default value.'); + } +} diff --git a/src/Field/IntType.php b/src/Field/IntType.php new file mode 100644 index 0000000..99b8628 --- /dev/null +++ b/src/Field/IntType.php @@ -0,0 +1,68 @@ + + */ +class IntType extends Field +{ + public const TYPE = 'integer'; + + /** + * @var bool|null + */ + private $isUnsigned = false; + + /** + * {@inheritdoc} + * + * return int + */ + public function filterValue($value) + { + if (!\is_int($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, self::TYPE, gettype($value)) + ); + } + + return (int) $value; + } + + /** + * {@inheritdoc} + */ + public function toArray(): array + { + $data = parent::toArray(); + + if ($this->isUnsigned) { + $data[ 'unsigned' ] = $this->isUnsigned; + } + + return $data; + } + + /** + * Enregistre le champ (uniquement de type integer) comme étant non signié. + * + * @return $this + */ + public function unsigned(): self + { + $this->isUnsigned = true; + + return $this; + } +} diff --git a/src/Field/RenameType.php b/src/Field/RenameType.php new file mode 100644 index 0000000..2b18d75 --- /dev/null +++ b/src/Field/RenameType.php @@ -0,0 +1,60 @@ + + */ +class RenameType extends Field +{ + protected $opt = self::OPT_RENAME; + + /** + * @var string + */ + protected $to; + + public function __construct(string $name, string $to) + { + parent::__construct($name); + $this->to = $to; + } + + /** + * {@inheritdoc} + */ + public function filterValue($value) + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getTo(): string + { + return $this->to; + } + + /** + * {@inheritdoc} + */ + public function toArray(): array + { + $data = parent::toArray(); + $data[ 'opt' ] = $this->opt; + $data[ 'to' ] = $this->to; + + return $data; + } +} diff --git a/src/Field/StringType.php b/src/Field/StringType.php new file mode 100644 index 0000000..fb1f738 --- /dev/null +++ b/src/Field/StringType.php @@ -0,0 +1,70 @@ + + */ +class StringType extends TextType +{ + public const TYPE = 'string'; + + /** + * @var int + */ + protected $length = 255; + + public function __construct(string $name, int $length) + { + if ($length < 0) { + throw new \InvalidArgumentException('The length passed in parameter is not of numeric type.'); + } + parent::__construct($name); + $this->length = $length; + } + + /** + * {@inheritdoc} + * + * return string + */ + public function filterValue($value) + { + /** @var string $str */ + $str = parent::filterValue($value); + + if (strlen($str) > $this->length) { + throw new \LengthException( + sprintf( + 'The value of the %s field must be less than or equal to %s characters: %s given', + $this->name, + $this->length, + strlen($str) + ) + ); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function toArray(): array + { + $data = parent::toArray(); + $data[ 'length' ] = $this->length; + + return $data; + } +} diff --git a/src/Field/TextType.php b/src/Field/TextType.php new file mode 100644 index 0000000..18f2d11 --- /dev/null +++ b/src/Field/TextType.php @@ -0,0 +1,37 @@ + + */ +class TextType extends Field +{ + public const TYPE = 'text'; + + /** + * {@inheritdoc} + * + * return string + */ + public function filterValue($value) + { + if (!\is_string($value)) { + throw new \InvalidArgumentException( + sprintf(self::INVALID_ARGUMENT_MESSAGE, $this->name, 'string', gettype($value)) + ); + } + + return $value; + } +} diff --git a/src/Request.php b/src/Request.php index 7b80b23..52cb592 100644 --- a/src/Request.php +++ b/src/Request.php @@ -15,6 +15,7 @@ use Queryflatfile\Exception\Query\OperatorNotFound; use Queryflatfile\Exception\Query\QueryException; use Queryflatfile\Exception\Query\TableNotFoundException; +use Queryflatfile\Field\IncrementType; /** * Réalise des requêtes à partir d'un schéma de données passé en paramètre. @@ -27,7 +28,7 @@ class Request extends RequestHandler /** * Toutes les configurations du schéma des champs utilisés. * - * @var array + * @var array */ private $allColumnsSchema; @@ -41,9 +42,9 @@ class Request extends RequestHandler /** * Le schéma des tables utilisées par la requête. * - * @var array + * @var Table */ - private $tableSchema = []; + private $table; /** * Le schéma de base de données. @@ -147,8 +148,8 @@ public function getTableData(string $name): array public function from(string $table): self { parent::from($table); - $this->tableSchema = $this->schema->getSchemaTable($table); - $this->tableData = $this->getTableData($table); + $this->table = $this->schema->getTableSchema($table); + $this->tableData = $this->getTableData($table); return $this; } @@ -431,10 +432,10 @@ protected function executeOrderBy(array &$data, array $orderBy): void protected function executeInsert(): void { /* Si l'une des colonnes est de type incrémental. */ - $increment = $this->getIncrement(); + $increment = $this->table->getIncrement(); /* Je charge les colonnes de mon schéma. */ - $schemaColumns = $this->tableSchema[ 'fields' ]; - $count = count($this->columns); + $fields = $this->table->getFields(); + $count = count($this->columns); foreach ($this->values as $values) { /* Pour chaque ligne je vérifie si le nombre de colonne correspond au nombre valeur insérée. */ @@ -461,27 +462,27 @@ protected function executeInsert(): void } $data = []; - foreach ($schemaColumns as $field => $arg) { + foreach ($fields as $fieldName => $field) { /* Si mon champs existe dans le schema. */ - if (isset($row[ $field ])) { - $data[ $field ] = TableBuilder::filterValue($field, $arg[ 'type' ], $row[ $field ], $arg); + if (isset($row[ $fieldName ])) { + $data[ $fieldName ] = $field->filterValue($row[ $fieldName ]); /* Si le champ est de type incrémental et que sa valeur est supérieure à celui enregistrer dans le schéma. */ - if ($arg[ 'type' ] === TableBuilder::TYPE_INCREMENT && ($data[ $field ] > $increment)) { - $increment = $data[ $field ]; + if ($field instanceof IncrementType && ($data[ $fieldName ] > $increment)) { + $increment = $data[ $fieldName ]; } continue; } /* Si mon champ n'existe pas et qu'il de type incrémental. */ - if ($arg[ 'type' ] === TableBuilder::TYPE_INCREMENT) { + if ($field instanceof IncrementType) { ++$increment; - $data[ $field ] = $increment; + $data[ $fieldName ] = $increment; continue; } /* Sinon on vérifie si une valeur par défaut lui est attribué. */ - $data[ $field ] = $this->schema->getValueDefault($field, $arg); + $data[ $fieldName ] = $field->getValueDefault(); } $this->tableData[] = $data; @@ -525,27 +526,17 @@ protected function executeDelete(): void $this->tableData = array_values($this->tableData); } - /** - * Retourne les champs incrémental de la courrante. - * - * @return int|null Increment de la table courante - */ - protected function getIncrement(): ?int - { - return $this->tableSchema[ 'increments' ]; - } - /** * Charge les colonnes de la table courante et des tables de jointure. */ private function loadAllColumnsSchema(): void { - $this->allColumnsSchema = $this->tableSchema[ 'fields' ]; + $this->allColumnsSchema = $this->table->getFields(); foreach ($this->joins as $value) { $this->allColumnsSchema = array_merge( $this->allColumnsSchema, - $this->schema->getSchemaTable($value[ 'table' ])[ 'fields' ] + $this->schema->getTableSchema($value[ 'table' ])->getFields() ); } } @@ -688,15 +679,13 @@ private function diffColumns(array $columns): void * * @param string $table Nom de la table. */ - private function getRowTableNull($table): array + private function getRowTableNull(string $table): array { - /* Le schéma de la table à joindre. */ - $sch = $this->schema->getSchemaTable($table); /* Prend les noms des champs de la table à joindre. */ - $rowTableKey = array_keys($sch[ 'fields' ]); + $rowTableKey = $this->schema->getTableSchema($table)->getFieldsName(); /* Prend les noms des champs dans la requête précédente. */ - if (isset($this->tableSchema[ 'fields' ])) { - $rowTableAllKey = array_keys($this->tableSchema[ 'fields' ]); + if ($this->table->getFields() !== []) { + $rowTableAllKey = $this->table->getFieldsName(); $rowTableKey = array_merge($rowTableKey, $rowTableAllKey); } /* Utilise les noms pour créer un tableau avec des valeurs null. */ diff --git a/src/Schema.php b/src/Schema.php index 125462b..ecf3aec 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -14,10 +14,12 @@ use Queryflatfile\DriverInterface; use Queryflatfile\Exception\Exception; -use Queryflatfile\Exception\Query\ColumnsValueException; use Queryflatfile\Exception\Query\TableNotFoundException; use Queryflatfile\Exception\TableBuilder\ColumnsNotFoundException; -use Queryflatfile\TableBuilder; +use Queryflatfile\Exception\TableBuilder\ColumnsValueException; +use Queryflatfile\Field\DropType; +use Queryflatfile\Field\IncrementType; +use Queryflatfile\Field\RenameType; /** * Pattern fluent pour la gestion d'un schéma de données. @@ -64,7 +66,7 @@ class Schema /** * Schéma des tables. * - * @var array + * @var array */ protected $schema = []; @@ -134,7 +136,7 @@ public function setPathRoot(string $root = ''): self * Modifie la valeur incrémentale d'une table. * * @param string $table Nom de la table. - * @param int $increment Tableau associatif des valeurs incrémentales. + * @param int $increment Nouvelle valeur incrémentale. * * @throws TableNotFoundException * @throws Exception @@ -147,15 +149,15 @@ public function setIncrement(string $table, int $increment): bool throw new TableNotFoundException($table); } - if (!isset($this->schema[ $table ][ 'increments' ])) { + if (!$this->schema[ $table ]->hasIncrement()) { throw new Exception( sprintf('Table %s does not have an incremental value.', $table) ); } - $this->schema[ $table ][ 'increments' ] = $increment; + $this->schema[ $table ]->setIncrement($increment); - return $this->save($this->name, $this->schema); + return $this->save($this->name, $this->toArray()); } /** @@ -174,19 +176,19 @@ public function getIncrement(string $table): int throw new TableNotFoundException($table); } - if ($this->schema[ $table ][ 'increments' ] === null) { + if ($this->schema[ $table ]->getIncrement() === null) { throw new Exception( sprintf('Table %s does not have an incremental value.', $table) ); } - return $this->schema[ $table ][ 'increments' ]; + return $this->schema[ $table ]->getIncrement(); } /** - * Génère le schéma s'il n'existe pas en fonction du fichier de configuration. + * Retourne le schema des tables. * - * @return array Schéma de la base de données. + * @return array Schéma de la base de données. */ public function getSchema(): array { @@ -194,7 +196,12 @@ public function getSchema(): array return $this->schema; } $this->create($this->name); - $this->schema = $this->read($this->name); + $schema = $this->read($this->name); + + /** @var string $tableName */ + foreach ($schema as $tableName => $table) { + $this->schema[ $tableName ] = TableBuilder::createTableFromArray($tableName, $table); + } return $this->schema; } @@ -206,9 +213,9 @@ public function getSchema(): array * * @throws TableNotFoundException * - * @return array Schéma de la table. + * @return Table Schéma de la table. */ - public function getSchemaTable(string $table): array + public function getTableSchema(string $table): Table { if (!$this->hasTable($table)) { throw new TableNotFoundException($table); @@ -263,11 +270,9 @@ public function createTable(string $table, ?callable $callback = null): self throw new Exception(sprintf('Table %s exist.', $table)); } - $builder = self::tableBuilder($callback); + $this->schema[ $table ] = self::tableBuilder($table, $callback)->getTable(); - $this->schema[ $table ] = $builder->getTableSchema(); - - $this->save($this->name, $this->schema); + $this->save($this->name, $this->toArray()); $this->create($table); return $this; @@ -298,72 +303,39 @@ public function createTableIfNotExists(string $table, ?callable $callback = null * Modifie les champs du schéma de données. * * @param string $table Nom de la table. - * @param callable $callback fonction(TableBuilder $table) pour créer les champs. + * @param callable $callback fonction(TableAleter $tableAlter) pour manipuler les champs. * * @return $this */ public function alterTable(string $table, callable $callback): self { - $schema = $this->getSchemaTable($table); - $fields = $schema[ 'fields' ]; - $tableBuilder = self::tableAlterBuilder($callback)->build(); - $dataTable = $this->read($table); - - foreach ($tableBuilder as $name => $params) { - if (!isset($params[ 'opt' ])) { - self::filterFieldAdd($table, $fields, $name, $params[ 'type' ]); - self::add($schema, $dataTable, $name, $params); - } elseif ($params[ 'opt' ] === TableAlter::OPT_RENAME) { - self::filterFieldRename($table, $fields, $name, $params[ 'to' ]); - self::rename($schema, $dataTable, $name, $params[ 'to' ]); - } elseif ($params[ 'opt' ] === TableAlter::OPT_MODIFY) { - self::filterFieldModify($table, $fields, $name, $params[ 'type' ]); - self::modify($schema, $dataTable, $name, $params); - } elseif ($params[ 'opt' ] === TableAlter::OPT_DROP) { - self::filterFieldDrop($table, $fields, $name); - self::drop($schema, $dataTable, $name); + $tableSchema = $this->getTableSchema($table); + $tableBuilder = self::tableAlterBuilder($table, $callback)->getTable(); + $tableData = $this->read($table); + + foreach ($tableBuilder->getFields() as $field) { + if ($field->getOpt() === Field::OPT_CREATE) { + self::filterFieldAdd($tableSchema, $field); + self::add($tableSchema, $field, $tableData); + } elseif ($field->getOpt() === Field::OPT_RENAME) { + self::filterFieldRename($tableSchema, $field); + self::rename($tableSchema, $field, $tableData); + } elseif ($field->getOpt() === Field::OPT_MODIFY) { + self::filterFieldModify($tableSchema, $field); + self::modify($tableSchema, $field, $tableData); + } elseif ($field->getOpt() === Field::OPT_DROP) { + self::filterFieldDrop($tableSchema, $field); + self::drop($tableSchema, $field, $tableData); } } - $this->schema[ $table ] = $schema; - $this->save($this->name, $this->schema); - $this->save($table, $dataTable); + $this->schema[ $table ] = $tableSchema; + $this->save($this->name, $this->toArray()); + $this->save($table, $tableData); return $this; } - /** - * Retourne la valeur par defaut du champ passé en paramêtre. - * - * @param string $name Nom du champ. - * @param array $params Différente configurations. - * - * @throws ColumnsValueException - * - * @return bool|null|numeric|string Valeur par defaut. - */ - public static function getValueDefault(string $name, array &$params) - { - if (isset($params[ 'default' ])) { - if ($params[ 'type' ] === TableBuilder::TYPE_DATE && $params[ 'default' ] === TableBuilder::CURRENT_DATE_DEFAULT) { - return date('Y-m-d', time()); - } - if ($params[ 'type' ] === TableBuilder::TYPE_DATETIME && $params[ 'default' ] === TableBuilder::CURRENT_DATETIME_DEFAULT) { - return date('Y-m-d H:i:s', time()); - } - - /* Si les variables magiques ne sont pas utilisé alors la vrais valeur par defaut est retourné. */ - return $params[ 'default' ]; - } - if (isset($params[ 'nullable' ])) { - return null; - } - - throw new ColumnsValueException( - sprintf('%s not nullable or not default.', $name) - ); - } - /** * Détermine une table existe. * @@ -386,7 +358,9 @@ public function hasTable(string $table): bool */ public function hasColumn(string $table, string $column): bool { - return isset($this->getSchema()[ $table ][ 'fields' ][ $column ]) && $this->driver->has($this->root . $this->path, $table); + return isset($this->getSchema()[ $table ]) && + $this->getSchema()[ $table ]->hasField($column) && + $this->driver->has($this->root . $this->path, $table); } /** @@ -405,10 +379,10 @@ public function truncateTable(string $table): bool } $deleteSchema = true; - if ($this->schema[ $table ][ 'increments' ] !== null) { - $this->schema[ $table ][ 'increments' ] = 0; + if ($this->schema[ $table ]->hasIncrement()) { + $this->schema[ $table ]->setIncrement(0); - $deleteSchema = $this->save($this->name, $this->schema); + $deleteSchema = $this->save($this->name, $this->toArray()); } $deleteData = $this->save($table, []); @@ -432,7 +406,7 @@ public function dropTable(string $table): bool unset($this->schema[ $table ]); $deleteData = $this->delete($table); - $deleteSchema = $this->save($this->name, $this->schema); + $deleteSchema = $this->save($this->name, $this->toArray()); return $deleteSchema && $deleteData; } @@ -512,154 +486,130 @@ protected function delete(string $file): bool /** * Ajoute un champ dans les paramètre de la table et ses données. * - * @param array $schema Schéma de la table. - * @param array $dataTable Les données de la table. - * @param string $name Nom du champ. - * @param array $params Nouveaux paramètres. + * @param Table $table Schéma de la table. + * @param Field $field Nouveau champ. + * @param array $tableData Les données de la table. * * @return void */ protected static function add( - array &$schema, - array &$dataTable, - string $name, - array $params + Table &$table, + Field $field, + array &$tableData ): void { - $schema[ 'fields' ][ $name ] = $params; + $table->addField($field); - $increment = $params[ 'type' ] === TableBuilder::TYPE_INCREMENT + $increment = $field instanceof IncrementType ? 0 : null; try { - $valueDefault = self::getValueDefault($name, $params); - } catch (ColumnsValueException $e) { + $valueDefault = $field->getValueDefault(); + } catch (ColumnsValueException|\InvalidArgumentException $e) { $valueDefault = ''; } - foreach ($dataTable as &$data) { - $data[ $name ] = $increment === null + foreach ($tableData as &$data) { + $data[ $field->getName() ] = $increment === null ? $valueDefault : ++$increment; } - if ($params[ 'type' ] === TableBuilder::TYPE_INCREMENT) { - $schema[ 'increments' ] = $increment; + if ($increment !== null) { + $table->setIncrement($increment); } } /** * Modifie un champ dans les paramètre de la table et ses données. * - * @param array $schema Schéma de la table. - * @param array $dataTable Les données de la table. - * @param string $name Nom du champ. - * @param array $params Nouveaux paramètres. + * @param Table $table Schéma de la table. + * @param Field $field Champ modifié. + * @param array $tableData Les données de la table. * * @return void */ protected static function modify( - array &$schema, - array &$dataTable, - string $name, - array $params + Table &$table, + Field $field, + array &$tableData ): void { - unset($params[ 'opt' ]); - $schema[ 'fields' ][ $name ] = $params; + $table->addField($field); - $increment = $params[ 'type' ] === TableBuilder::TYPE_INCREMENT + $increment = $field instanceof IncrementType ? 0 : null; try { - $valueDefault = self::getValueDefault($name, $params); - foreach ($dataTable as &$data) { - $data[ $name ] = $valueDefault; + $valueDefault = $field->getValueDefault(); + foreach ($tableData as &$data) { + $data[ $field->getName() ] = $valueDefault; } - } catch (ColumnsValueException $e) { + } catch (ColumnsValueException | \InvalidArgumentException $e) { } - if ($params[ 'type' ] === TableBuilder::TYPE_INCREMENT) { - $schema[ 'increments' ] = $increment; + if ($increment !== null) { + $table->setIncrement($increment); } } /** * Renomme un champ dans les paramètre de la table et ses données. * - * @param array $schema Les champs de la table. - * @param array $dataTable Les données de la table. - * @param string $name Nom du champ. - * @param string $to Nouveau nom du champ. + * @param Table $table Schéma de la table. + * @param RenameType $fieldRename champ à renommer + * @param array $tableData Les données de la table. * * @return void */ protected static function rename( - array &$schema, - array &$dataTable, - string $name, - string $to + Table &$table, + RenameType $fieldRename, + array &$tableData ): void { - $schema[ 'fields' ][ $to ] = $schema[ 'fields' ][ $name ]; - unset($schema[ 'fields' ][ $name ]); - foreach ($dataTable as &$data) { - $data[ $to ] = $data[ $name ]; - unset($data[ $name ]); + $table->renameField($fieldRename->getName(), $fieldRename->getTo()); + + foreach ($tableData as &$data) { + $data[ $fieldRename->getTo() ] = $data[ $fieldRename->getName() ]; + unset($data[ $fieldRename->getName() ]); } } /** * Supprime un champ dans les paramètre de la table et ses données. * - * @param array $schema Les champs de la table. - * @param array $dataTable Les données de la table. - * @param string $name Nom du champ. + * @param Table $table Schéma de la table. + * @param DropType $fieldDrop Champ à supprimer + * @param array $tableData Les données de la table. * * @return void */ protected static function drop( - array &$schema, - array &$dataTable, - string $name + Table &$table, + DropType $fieldDrop, + array &$tableData ): void { - foreach (array_keys($dataTable) as $key) { - unset($dataTable[ $key ][ $name ]); + foreach (array_keys($tableData) as $key) { + unset($tableData[ $key ][ $fieldDrop->getName() ]); } - if ($schema[ 'fields' ][ $name ][ 'type' ] === TableBuilder::TYPE_INCREMENT) { - $schema[ 'increments' ] = null; - } - unset($schema[ 'fields' ][ $name ]); - } - - /** - * Retour true si l'un des champs est de type incrementale. - * - * @param array $fields - * - * @return bool - */ - protected static function isFieldIncrement(array $fields): bool - { - foreach ($fields as $field) { - if ($field[ 'type' ] === TableBuilder::TYPE_INCREMENT) { - return true; - } + if ($table->getField($fieldDrop->getName()) instanceof IncrementType) { + $table->setIncrement(null); } - - return false; + $table->unsetField($fieldDrop->getName()); } /** * Passe en premier paramètre d'une fonction anonyme un objet TableBuilder et le retourne. * + * @param string $table Nom de la table. * @param callable $callback Fonction anonyme. * * @return TableBuilder */ - protected static function tableAlterBuilder(callable $callback): TableBuilder + protected static function tableAlterBuilder(string $table, callable $callback): TableBuilder { - $builder = new TableAlter(); + $builder = new TableAlter($table); call_user_func_array($callback, [ &$builder ]); return $builder; @@ -668,13 +618,14 @@ protected static function tableAlterBuilder(callable $callback): TableBuilder /** * Passe en premier paramètre d'une fonction anonyme un objet TableBuilder et le retourne. * + * @param string $table Nom de la table. * @param callable|null $callback Fonction anonyme. * * @return TableBuilder */ - protected static function tableBuilder(?callable $callback = null): TableBuilder + protected static function tableBuilder(string $table, ?callable $callback = null): TableBuilder { - $builder = new TableBuilder(); + $builder = new TableBuilder($table); if ($callback !== null) { call_user_func_array($callback, [ &$builder ]); } @@ -683,138 +634,138 @@ protected static function tableBuilder(?callable $callback = null): TableBuilder } /** - * Vérifie si les opérations du champ sont conformes. + * Vérifie si les opérations d'ajout du champ sont conformes. * - * @param string $table Nom de la table. - * @param array $fields Paramètres du champ en base. - * @param string $name Nom du champ. - * @param string $type Type de donnée. + * @param Table $tableSchema Le schéma de la table. + * @param Field $field Nouveau champ. * * @throws Exception * @throws ColumnsNotFoundException */ - private static function filterFieldAdd( - string $table, - array $fields, - string $name, - string $type - ): void { + private static function filterFieldAdd(Table $tableSchema, Field $field): void + { /* Si un champ est ajouté il ne doit pas exister dans le schéma. */ - if (isset($fields[ $name ])) { + if ($tableSchema->hasField($field->getName())) { throw new Exception( - sprintf('%s field does not exists in %s table.', $name, $table) + sprintf( + '%s field does not exists in %s table.', + $field->getName(), + $tableSchema->getName() + ) ); } - if ($type === TableBuilder::TYPE_INCREMENT && self::isFieldIncrement($fields)) { + if ($tableSchema->hasIncrement() && $field instanceof IncrementType) { throw new ColumnsValueException( sprintf( 'The %s table can not have multiple incremental values.', - $table + $tableSchema->getName() ) ); } } /** - * @param string $table Nom de la table. - * @param array $fields Paramètres du champ en base. - * @param string $name Nom du champ. - * @param string $type Type de donnée. + * Vérifie si les opérations de modification du champ sont conformes. + * + * @param Table $tableSchema Le schéma de la table. + * @param Field $field Champ à modifier. * * @throws ColumnsNotFoundException * @throws ColumnsValueException * @throws Exception */ - private static function filterFieldModify( - string $table, - array $fields, - string $name, - string $type - ): void { - if (!isset($fields[ $name ])) { - throw new ColumnsNotFoundException( + private static function filterFieldModify(Table $tableSchema, Field $field): void + { + if (!$tableSchema->hasField($field->getName())) { + throw new Exception( sprintf( '%s field does not exists in %s table.', - $name, - $table + $field->getName(), + $tableSchema->getName() ) ); } - if ($type === TableBuilder::TYPE_INCREMENT && self::isFieldIncrement($fields)) { + if ($tableSchema->hasIncrement() && $field instanceof IncrementType) { throw new ColumnsValueException( sprintf( 'The %s table can not have multiple incremental values.', - $table + $tableSchema->getName() ) ); } + $fieldOld = $tableSchema->getField($field->getName()); + /* Si le type change, les données présents doivent être d'un type équivalent. */ - $modifyNumber = in_array($type, [ 'integer', 'float', 'increments' ]) && - !in_array($fields[ $name ][ 'type' ], [ 'integer', 'float', 'increments' ]); - $modifyString = in_array($type, [ 'text', 'string', 'char' ]) && - !in_array($fields[ $name ][ 'type' ], [ 'text', 'string', 'char' ]); - $modifyDate = in_array($type, [ 'date', 'datetime' ]) && - !in_array($fields[ $name ][ 'type' ], [ 'date', 'datetime', 'string', 'text' ]); + $modifyNumber = in_array($field::TYPE, [ 'integer', 'float', 'increments' ]) && + !in_array($fieldOld::TYPE, [ 'integer', 'float', 'increments' ]); + $modifyString = in_array($field::TYPE, [ 'text', 'string', 'char' ]) && + !in_array($fieldOld::TYPE, [ 'text', 'string', 'char' ]); + $modifyDate = in_array($field::TYPE, [ 'date', 'datetime' ]) && + !in_array($fieldOld::TYPE, [ 'date', 'datetime', 'string', 'text' ]); if ($modifyString || $modifyNumber || $modifyDate) { throw new Exception( sprintf( 'The %s column type %s can not be changed with the %s type.', - $name, - $fields[ $name ][ 'type' ], - $type + $field->getName(), + $fieldOld::TYPE, + $field::TYPE ) ); } } /** - * @param string $table Nom de la table. - * @param array $fields Paramètres du champ en base. - * @param string $name Nom du champ. - * @param string $to Nouveau nom du champ. + * Vérifie si les opérations de renommage du champ sont conformes. + * + * @param Table $table Le schéma de la table. + * @param RenameType $field Champ à renommer. * * @throws ColumnsNotFoundException * @throws Exception */ - private static function filterFieldRename( - string $table, - array $fields, - string $name, - string $to - ): void { - if (!isset($fields[ $name ])) { + private static function filterFieldRename(Table $table, RenameType $field): void + { + if (!$table->hasField($field->getName())) { throw new ColumnsNotFoundException( - sprintf('%s field does not exists in %s table.', $name, $table) + sprintf('%s field does not exists in %s table.', $field->getName(), $table->getName()) ); } /* Si le champ à renommer existe dans le schema. */ - if (isset($fields[ $to ])) { + if ($table->hasField($field->getTo())) { throw new Exception( - sprintf('%s field does exists in %s table.', $name, $table) + sprintf('%s field does exists in %s table.', $field->getName(), $table->getName()) ); } } /** - * @param string $table Nom de la table. - * @param array $fields Paramètres du champ en base. - * @param string $name Nom du champ. + * Vérifie si les opérations de suppression du champ sont conformes. + * + * @param Table $table Le schéma de la table. + * @param DropType $field Champ à supprimer * * @throws ColumnsNotFoundException * * @return void */ - private static function filterFieldDrop( - string $table, - array $fields, - string $name - ): void { - if (!isset($fields[ $name ])) { + private static function filterFieldDrop(Table $table, DropType $field): void + { + if (!$table->hasField($field->getName())) { throw new ColumnsNotFoundException( - sprintf('%s field does not exists in %s table.', $name, $table) + sprintf('%s field does not exists in %s table.', $field->getName(), $table->getName()) ); } } + + private function toArray(): array + { + $tables = []; + foreach ($this->schema as $name => $table) { + $tables[ $name ] = $table->toArray(); + } + + return $tables; + } } diff --git a/src/Table.php b/src/Table.php new file mode 100644 index 0000000..df5b5a3 --- /dev/null +++ b/src/Table.php @@ -0,0 +1,125 @@ + + */ + protected $fields = []; + + /** + * La valeur des champs incrémentaux. + * + * @var int|null + */ + private $increment = null; + + public function __construct(string $name) + { + $this->name = $name; + } + + /** + * Ajoute un nouveau champ. + * + * @param Field $field Champ. + * + * @return void + */ + public function addField(Field $field): void + { + if ($field instanceof IncrementType) { + $this->increment = 0; + } + + $this->fields[ $field->getName() ] = $field; + } + + public function getField(string $name): Field + { + if (!isset($this->fields[ $name ])) { + throw new \Exception(); + } + + return $this->fields[ $name ]; + } + + public function getFields(): array + { + return $this->fields; + } + + public function getFieldsName(): array + { + return array_keys($this->fields); + } + + public function getName(): string + { + return $this->name; + } + + public function getIncrement(): ?int + { + return $this->increment; + } + + public function hasField(string $name): bool + { + return isset($this->fields[ $name ]); + } + + public function hasIncrement(): bool + { + return $this->increment !== null; + } + + public function renameField(string $from, string $to): void + { + $this->fields[ $to ] = $this->fields[ $from ]; + unset($this->fields[ $from ]); + $this->fields[ $to ]->setName($to); + } + + public function setIncrement(?int $increment): void + { + $this->increment = $increment; + } + + public function toArray(): array + { + $fields = []; + foreach ($this->fields as $name => $field) { + $fields[ $name ] = $field->toArray(); + } + + return [ + 'fields' => $fields, + 'increments' => $this->increment + ]; + } + + public function unsetField(string $name): void + { + unset($this->fields[ $name ]); + } +} diff --git a/src/TableAlter.php b/src/TableAlter.php index 6bdaa84..c658ebf 100644 --- a/src/TableAlter.php +++ b/src/TableAlter.php @@ -10,7 +10,8 @@ namespace Queryflatfile; -use Queryflatfile\Exception\TableBuilder\ColumnsNotFoundException; +use Queryflatfile\Field\DropType; +use Queryflatfile\Field\RenameType; /** * Pattern fluent pour la création et configuration des types de données. @@ -19,24 +20,16 @@ */ class TableAlter extends TableBuilder { - public const OPT_DROP = 'drop'; - - public const OPT_MODIFY = 'modify'; - - public const OPT_RENAME = 'rename'; - /** * Enregistre la suppression d'une colonne. * * @param string $name Nom de la colonne. * - * @return $this + * @return void */ - public function dropColumn(string $name): self + public function dropColumn(string $name): void { - $this->builder[ $name ][ 'opt' ] = self::OPT_DROP; - - return $this; + $this->table->addField(new DropType($name)); } /** @@ -45,50 +38,10 @@ public function dropColumn(string $name): self * @param string $from Nom de la colonne. * @param string $to Nouveau nom de la colonne. * - * @return $this - */ - public function renameColumn(string $from, string $to): self - { - $this->builder[ $from ] = [ 'opt' => self::OPT_RENAME, 'to' => $to ]; - - return $this; - } - - /** - * Enregistre la modification du champ précédent. - * - * @return $this + * @return void */ - public function modify(): self + public function renameColumn(string $from, string $to): void { - $this->checkPreviousBuild('modify'); - $key = key($this->builder); - - $this->builder[ $key ][ 'opt' ] = self::OPT_MODIFY; - - return $this; - } - - /** - * Retourne le champs courant. - * Déclenche une exception si le champ courant n'existe pas ou - * si le champ courant est une opération. - * - * @param string $opt Nom de l'opération réalisé. - * - * @throws ColumnsNotFoundException - * - * @return array Paramètres du champ. - */ - protected function checkPreviousBuild(string $opt): array - { - $current = parent::checkPreviousBuild($opt); - if (isset($current[ 'opt' ])) { - throw new ColumnsNotFoundException( - sprintf('No column selected for %s.', $opt) - ); - } - - return $current; + $this->table->addField(new RenameType($from, $to)); } } diff --git a/src/TableBuilder.php b/src/TableBuilder.php index d60b3d3..1396de9 100644 --- a/src/TableBuilder.php +++ b/src/TableBuilder.php @@ -10,9 +10,16 @@ namespace Queryflatfile; -use Queryflatfile\Exception\TableBuilder\ColumnsNotFoundException; -use Queryflatfile\Exception\TableBuilder\ColumnsValueException; use Queryflatfile\Exception\TableBuilder\TableBuilderException; +use Queryflatfile\Field\BoolType; +use Queryflatfile\Field\CharType; +use Queryflatfile\Field\DateTimeType; +use Queryflatfile\Field\DateType; +use Queryflatfile\Field\FloatType; +use Queryflatfile\Field\IncrementType; +use Queryflatfile\Field\IntType; +use Queryflatfile\Field\StringType; +use Queryflatfile\Field\TextType; /** * Pattern fluent pour la création et configuration des types de données. @@ -21,41 +28,15 @@ */ class TableBuilder { - public const CURRENT_DATE_DEFAULT = 'current_date'; - - public const CURRENT_DATETIME_DEFAULT = 'current_datetime'; - - public const TYPE_BOOL = 'boolean'; - - public const TYPE_CHAR = 'char'; - - public const TYPE_DATE = 'date'; - - public const TYPE_DATETIME = 'datetime'; - - public const TYPE_FLOAT = 'float'; - - public const TYPE_INCREMENT = 'increments'; - - public const TYPE_INT = 'integer'; - - public const TYPE_STRING = 'string'; - - public const TYPE_TEXT = 'text'; - /** - * Les champs et leurs paramètres. - * - * @var array + * @var Table */ - protected $builder = []; + protected $table; - /** - * La valeur des champs incrémentaux. - * - * @var int|null - */ - private $increment = null; + public function __construct(string $name) + { + $this->table = new Table($name); + } /** * Enregistre un champ de type `boolean`, true ou false. @@ -63,13 +44,13 @@ class TableBuilder * * @param string $name Nom du champ. * - * @return $this + * @return Field */ - public function boolean(string $name): self + public function boolean(string $name): Field { - $this->builder[ $name ][ 'type' ] = self::TYPE_BOOL; + $this->table->addField(new BoolType($name)); - return $this; + return $this->table->getField($name); } /** @@ -81,16 +62,13 @@ public function boolean(string $name): self * * @throws TableBuilderException * - * @return $this + * @return Field */ - public function char(string $name, int $length = 1): self + public function char(string $name, int $length = 1): Field { - if ($length < 0) { - throw new TableBuilderException('The length passed in parameter is not of numeric type.'); - } - $this->builder[ $name ] = [ 'type' => self::TYPE_CHAR, 'length' => $length ]; + $this->table->addField(new CharType($name, $length)); - return $this; + return $this->table->getField($name); } /** @@ -98,13 +76,13 @@ public function char(string $name, int $length = 1): self * * @param string $name Nom du champ. * - * @return $this + * @return Field */ - public function date(string $name): self + public function date(string $name): Field { - $this->builder[ $name ][ 'type' ] = self::TYPE_DATE; + $this->table->addField(new DateType($name)); - return $this; + return $this->table->getField($name); } /** @@ -112,13 +90,13 @@ public function date(string $name): self * * @param string $name Nom du champ. * - * @return $this + * @return Field */ - public function datetime(string $name): self + public function datetime(string $name): Field { - $this->builder[ $name ][ 'type' ] = self::TYPE_DATETIME; + $this->table->addField(new DateTimeType($name)); - return $this; + return $this->table->getField($name); } /** @@ -128,13 +106,13 @@ public function datetime(string $name): self * * @param string $name Nom du champ. * - * @return $this + * @return Field */ - public function float(string $name): self + public function float(string $name): Field { - $this->builder[ $name ][ 'type' ] = self::TYPE_FLOAT; + $this->table->addField(new FloatType($name)); - return $this; + return $this->table->getField($name); } /** @@ -146,18 +124,17 @@ public function float(string $name): self * * @throws TableBuilderException * - * @return $this + * @return Field */ - public function increments(string $name): self + public function increments(string $name): Field { - if ($this->increment !== null) { + if ($this->table->getIncrement() !== null) { throw new TableBuilderException('Only one incremental column is allowed per table.'); } - $this->builder[ $name ][ 'type' ] = self::TYPE_INCREMENT; - $this->increment = 0; + $this->table->addField(new IncrementType($name)); - return $this; + return $this->table->getField($name); } /** @@ -167,13 +144,13 @@ public function increments(string $name): self * * @param string $name Nom du champ. * - * @return $this + * @return IntType */ - public function integer(string $name): self + public function integer(string $name): IntType { - $this->builder[ $name ][ 'type' ] = self::TYPE_INT; - - return $this; + $this->table->addField(new IntType($name)); + /** @var IntType */ + return $this->table->getField($name); } /** @@ -185,16 +162,13 @@ public function integer(string $name): self * * @throws TableBuilderException * - * @return $this + * @return Field */ - public function string(string $name, int $length = 255): self + public function string(string $name, int $length = 255): Field { - if ($length < 0) { - throw new TableBuilderException('The length passed in parameter is not of numeric type.'); - } - $this->builder[ $name ] = [ 'type' => self::TYPE_STRING, 'length' => $length ]; + $this->table->addField(new StringType($name, $length)); - return $this; + return $this->table->getField($name); } /** @@ -203,226 +177,72 @@ public function string(string $name, int $length = 255): self * * @param string $name Nom du champ. * - * @return $this + * @return Field */ - public function text(string $name): self + public function text(string $name): Field { - $this->builder[ $name ][ 'type' ] = self::TYPE_TEXT; + $this->table->addField(new TextType($name)); - return $this; + return $this->table->getField($name); } - /** - * Enregistre un commentaire sur le dernier champ appelé. - * - * @param string $comment Commentaire du champ précédent. - * - * @return $this - */ - public function comment(string $comment): self - { - $this->checkPreviousBuild('comment'); - $this->builder[ key($this->builder) ][ '_comment' ] = $comment; - - return $this; - } - - /** - * Enregistre le champ précédent comme acceptant la valeur NULL. - * - * @return $this - */ - public function nullable(): self - { - $this->checkPreviousBuild('nullable'); - $this->builder[ key($this->builder) ][ 'nullable' ] = true; - - return $this; - } - - /** - * Enregistre le champ précédent (uniquement de type integer) comme étant non signié. - * - * @throws ColumnsValueException - * - * @return $this - */ - public function unsigned(): self + public function getTable(): Table { - $current = $this->checkPreviousBuild('unsigned'); - if ($current[ 'type' ] !== self::TYPE_INT) { - throw new ColumnsValueException( - sprintf('Impossiblie of unsigned type %s only integer.', $current[ 'type' ]) - ); - } - - $this->builder[ key($this->builder) ][ 'unsigned' ] = true; - - return $this; + return $this->table; } /** - * Enregistre une valeur par défaut au champ précédent. - * Lève une exception si la valeur par défaut ne correspond pas au type de valeur passée en paramètre. + * Créer une table à partir d'un tableau de données. * - * @param bool|null|numeric|string $value Valeur à tester. + * @param string $table Nom de la table. + * @param array $data Donnaées pour créer une table. * * @throws TableBuilderException - * - * @return $this - */ - public function valueDefault($value): self - { - $current = $this->checkPreviousBuild('value default'); - $type = $current[ 'type' ]; - - if ($type === self::TYPE_INCREMENT) { - throw new TableBuilderException('An incremental type column can not have a default value.'); - } - - $name = (string) key($this->builder); - - $this->builder[ $name ][ 'default' ] = self::filterValue($name, $type, $value, $current); - - return $this; - } - - /** - * Retourne la valeur s'il correspond au type déclaré. - * Sinon déclenche une exception. - * - * @param string $name Nom du champ. - * @param string $type Type de donnée (string|text|int|float|bool|char|date|datetime). - * @param bool|null|numeric|string $value Valeur à tester. - * @param array $args Arguments de tests optionnels (length). - * - * @throws ColumnsValueException - * - * @return bool|null|numeric|string - */ - public static function filterValue(string $name, string $type, $value, array $args = []) - { - $error = sprintf( - 'The default value (%s) for column %s does not correspond to type %s.', - $value, - $name, - $type - ); - - switch (strtolower($type)) { - case self::TYPE_STRING: - case self::TYPE_CHAR: - if (!\is_string($value)) { - throw new ColumnsValueException($error); - } - if (!isset($args[ 'length' ]) || strlen($value) > $args[ 'length' ]) { - throw new ColumnsValueException('The default value is larger than the specified size.'); - } - - break; - case self::TYPE_TEXT: - if (!\is_string($value)) { - throw new ColumnsValueException($error); - } - - break; - case self::TYPE_INT: - case self::TYPE_INCREMENT: - if (!\is_int($value)) { - throw new ColumnsValueException($error); - } - - return (int) $value; - case self::TYPE_FLOAT: - if (!\is_float($value)) { - throw new ColumnsValueException($error); - } - - return (float) $value; - case self::TYPE_BOOL: - if (!\is_bool($value)) { - throw new ColumnsValueException($error); - } - - break; - case self::TYPE_DATE: - if (!\is_string($value)) { - throw new ColumnsValueException($error); - } - $value = (string) $value; - if (strtolower($value) === self::CURRENT_DATE_DEFAULT) { - return self::CURRENT_DATE_DEFAULT; - } - if (($timestamp = strtotime($value))) { - return date('Y-m-d', $timestamp); - } - - throw new ColumnsValueException($error); - case self::TYPE_DATETIME: - if (!\is_string($value)) { - throw new ColumnsValueException($error); - } - $value = (string) $value; - if (strtolower($value) === self::CURRENT_DATETIME_DEFAULT) { - return self::CURRENT_DATETIME_DEFAULT; - } - if (($timestamp = strtotime($value))) { - return date('Y-m-d H:i:s', $timestamp); - } - - throw new ColumnsValueException($error); - default: - throw new ColumnsValueException( - sprintf('Type %s not supported', $type) - ); - } - - return $value; - } - - /** - * Retourne le tableau contenant les configurations - * - * @return array Les configurations. - */ - public function build(): array - { - return $this->builder; - } - - /** - * Retour le schéma de la table. - * - * @return array - */ - public function getTableSchema(): array - { - return [ - 'fields' => $this->builder, - 'increments' => $this->increment - ]; - } - - /** - * Retourne le champs courant. - * Déclenche une exception si le champ courant n'existe pas ou - * si le champ courant est une opération. - * - * @param string $opt Nom de l'opération réalisé. - * - * @throws ColumnsNotFoundException - * - * @return array Paramètres du champ. - */ - protected function checkPreviousBuild(string $opt): array - { - $current = end($this->builder); - if (!$current) { - throw new ColumnsNotFoundException( - sprintf('No column selected for %s.', $opt) - ); + * @return Table + */ + public static function createTableFromArray(string $table, array $data): Table + { + $tableBuilder = new self($table); + foreach ($data[ 'fields' ] as $name => $value) { + switch ($value[ 'type' ]) { + case BoolType::TYPE: + case DateType::TYPE: + case DateTimeType::TYPE: + case FloatType::TYPE: + case IncrementType::TYPE: + case TextType::TYPE: + $field = $tableBuilder->{$value[ 'type' ]}($name); + + break; + case CharType::TYPE: + case StringType::TYPE: + $field = $tableBuilder->{$value[ 'type' ]}($name, $value[ 'length' ] ?? 0); + + break; + case IntType::TYPE: + $field = $tableBuilder->{$value[ 'type' ]}($name); + + if (isset($value[ 'unsigned' ])) { + $field->unsigned(); + } + + break; + default: + throw new TableBuilderException(sprintf('Type %s not supported.', $value[ 'type' ])); + } + + if (isset($value[ 'nullable' ])) { + $field->nullable(); + } + if (isset($value[ 'default' ])) { + $field->valueDefault($value[ 'default' ]); + } + if (isset($value[ '_comment' ])) { + $field->comment($value[ '_comment' ]); + } } + $tableBuilder->table->setIncrement($data[ 'increments' ] ?? null); - return $current; + return $tableBuilder->table; } } diff --git a/tests/unit/RequestExecuteTest.php b/tests/unit/RequestExecuteTest.php index fff2cfc..bec340f 100644 --- a/tests/unit/RequestExecuteTest.php +++ b/tests/unit/RequestExecuteTest.php @@ -56,17 +56,17 @@ protected function setUp(): void public function testCreateTable(): void { $this->bdd->createTable('user', static function (TableBuilder $table): void { - $table->increments('id') - ->string('name')->nullable() - ->string('firstname')->nullable(); + $table->increments('id'); + $table->string('name')->nullable(); + $table->string('firstname')->nullable(); }); $this->bdd->createTable('user_role', static function (TableBuilder $table): void { - $table->integer('id_user') - ->integer('id_role'); + $table->integer('id_user'); + $table->integer('id_role'); }); $this->bdd->createTable('role', static function (TableBuilder $table): void { - $table->increments('id_role') - ->string('labelle'); + $table->increments('id_role'); + $table->string('labelle'); }); self::assertFileExists(self::ROOT . 'user.' . $this->bdd->getExtension()); diff --git a/tests/unit/SchemaJsonTest.php b/tests/unit/SchemaJsonTest.php index d46a4f6..1404cdb 100644 --- a/tests/unit/SchemaJsonTest.php +++ b/tests/unit/SchemaJsonTest.php @@ -31,9 +31,9 @@ protected function setUp(): void $this->request = new Request($this->bdd); $this->bdd->createTableIfNotExists('test', static function (TableBuilder $table): void { - $table->increments('id') - ->string('name') - ->string('firstname'); + $table->increments('id'); + $table->string('name'); + $table->string('firstname'); }); $this->request->insertInto('test', [ 'name', 'firstname' ]) @@ -43,8 +43,8 @@ protected function setUp(): void ->execute(); $this->bdd->createTable('test_second', static function (TableBuilder $table): void { - $table->integer('value_i') - ->string('value_s'); + $table->integer('value_i'); + $table->string('value_s'); }); $this->request->insertInto('test_second', [ 'value_i', 'value_s' ]) @@ -73,7 +73,12 @@ protected function tearDown(): void public function testGetSchema(): void { - self::assertEquals($this->bdd->getSchema(), [ + $schema = []; + foreach ($this->bdd->getSchema() as $name => $table) { + $schema[$name] = $table->toArray(); + } + + self::assertEquals($schema, [ 'test' => [ 'fields' => [ 'id' => [ 'type' => 'increments' ], @@ -94,7 +99,7 @@ public function testGetSchema(): void public function testGetSchemaTable(): void { - self::assertEquals($this->bdd->getSchemaTable('test'), [ + self::assertEquals($this->bdd->getTableSchema('test')->toArray(), [ 'fields' => [ 'id' => [ 'type' => 'increments' ], 'name' => [ 'type' => 'string', 'length' => 255 ], @@ -135,19 +140,21 @@ public function testSetIncrementsException(): void public function testAlterTableAdd(): void { $this->bdd->alterTable('test', static function (TableAlter $table): void { - $table - ->string('field_s_default')->valueDefault('foo') - ->string('field_s_null')->nullable() - ->string('field_s'); + $table->string('field_s_default')->valueDefault('foo'); + $table->string('field_s_null')->nullable(); + $table->string('field_s'); }); - self::assertEquals($this->bdd->getSchemaTable('test')[ 'fields' ], [ - 'id' => [ 'type' => 'increments' ], - 'name' => [ 'type' => 'string', 'length' => 255 ], - 'firstname' => [ 'type' => 'string', 'length' => 255 ], - 'field_s_default' => [ 'type' => 'string', 'length' => 255, 'default' => 'foo' ], - 'field_s_null' => [ 'type' => 'string', 'length' => 255, 'nullable' => true ], - 'field_s' => [ 'type' => 'string', 'length' => 255 ] + self::assertEquals($this->bdd->getTableSchema('test')->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'increments' ], + 'name' => [ 'type' => 'string', 'length' => 255 ], + 'firstname' => [ 'type' => 'string', 'length' => 255 ], + 'field_s_default' => [ 'type' => 'string', 'length' => 255, 'default' => 'foo' ], + 'field_s_null' => [ 'type' => 'string', 'length' => 255, 'nullable' => true ], + 'field_s' => [ 'type' => 'string', 'length' => 255 ] + ], + 'increments' => 3 ]); self::assertEquals($this->bdd->read('test'), [ [ @@ -181,7 +188,7 @@ public function testAlterTableAddIncrement(): void $table->increments('id'); }); - self::assertEquals($this->bdd->getSchemaTable('test_second'), [ + self::assertEquals($this->bdd->getTableSchema('test_second')->toArray(), [ 'fields' => [ 'id' => [ 'type' => 'increments' ], 'value_i' => [ 'type' => 'integer' ], @@ -213,10 +220,13 @@ public function testAlterTableRename(): void $table->renameColumn('name', '_name'); }); - self::assertEquals($this->bdd->getSchemaTable('test')[ 'fields' ], [ - 'id' => [ 'type' => 'increments' ], - '_name' => [ 'type' => 'string', 'length' => 255 ], - 'firstname' => [ 'type' => 'string', 'length' => 255 ] + self::assertEquals($this->bdd->getTableSchema('test')->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'increments' ], + '_name' => [ 'type' => 'string', 'length' => 255 ], + 'firstname' => [ 'type' => 'string', 'length' => 255 ] + ], + 'increments' => 3 ]); self::assertEquals($this->bdd->read('test'), [ [ @@ -241,9 +251,12 @@ public function testAlterTableModify(): void $table->float('value_i')->valueDefault(1.0)->modify(); }); - self::assertEquals($this->bdd->getSchemaTable('test_second')[ 'fields' ], [ - 'value_i' => [ 'type' => 'float', 'default' => 1.0 ], - 'value_s' => [ 'type' => 'string', 'length' => 255 ] + self::assertEquals($this->bdd->getTableSchema('test_second')->toArray(), [ + 'fields' => [ + 'value_i' => [ 'type' => 'float', 'default' => 1.0 ], + 'value_s' => [ 'type' => 'string', 'length' => 255 ] + ], + 'increments' => null ]); self::assertEquals($this->bdd->read('test_second'), [ [ 'value_i' => 1, 'value_s' => 'value1' ], @@ -258,7 +271,7 @@ public function testAlterTableModifyIncrement(): void $table->increments('value_i')->modify(); }); - self::assertEquals($this->bdd->getSchemaTable('test_second'), [ + self::assertEquals($this->bdd->getTableSchema('test_second')->toArray(), [ 'fields' => [ 'value_i' => [ 'type' => 'increments' ], 'value_s' => [ 'type' => 'string', 'length' => 255 ] @@ -275,11 +288,11 @@ public function testAlterTableModifyIncrement(): void public function testAlterTableDrop(): void { $this->bdd->alterTable('test', static function (TableAlter $table): void { - $table->dropColumn('id') - ->dropColumn('firstname'); + $table->dropColumn('id'); + $table->dropColumn('firstname'); }); - self::assertEquals($this->bdd->getSchemaTable('test'), [ + self::assertEquals($this->bdd->getTableSchema('test')->toArray(), [ 'fields' => [ 'name' => [ 'type' => 'string', 'length' => 255 ] ], @@ -385,7 +398,7 @@ public function testTruncateTable(): void { $output = $this->bdd->truncateTable('test'); - self::assertEquals($this->bdd->getSchemaTable('test'), [ + self::assertEquals($this->bdd->getTableSchema('test')->toArray(), [ 'fields' => [ 'id' => [ 'type' => 'increments' ], 'name' => [ 'type' => 'string', 'length' => 255 ], diff --git a/tests/unit/TableAlterTest.php b/tests/unit/TableAlterTest.php index 1035fa8..6fa8d58 100644 --- a/tests/unit/TableAlterTest.php +++ b/tests/unit/TableAlterTest.php @@ -2,6 +2,7 @@ namespace Queryflatfile\Tests\unit; +use Queryflatfile\Field; use Queryflatfile\TableAlter; class TableAlterTest extends \PHPUnit\Framework\TestCase @@ -13,15 +14,18 @@ class TableAlterTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - $this->object = new TableAlter; + $this->object = new TableAlter('test'); } public function testDrop(): void { $this->object->dropColumn('0'); - self::assertEquals($this->object->build(), [ - '0' => [ 'opt' => TableAlter::OPT_DROP ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + '0' => [ 'opt' => Field::OPT_DROP ] + ], + 'increments' => null ]); } @@ -29,8 +33,11 @@ public function testRename(): void { $this->object->renameColumn('0', '1'); - self::assertEquals($this->object->build(), [ - '0' => [ 'opt' => TableAlter::OPT_RENAME, 'to' => '1' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + '0' => [ 'opt' => Field::OPT_RENAME, 'to' => '1' ] + ], + 'increments' => null ]); } @@ -38,29 +45,11 @@ public function testModify(): void { $this->object->char('0')->modify(); - self::assertEquals($this->object->build(), [ - '0' => [ 'type' => 'char', 'length' => 1, 'opt' => TableAlter::OPT_MODIFY ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + '0' => [ 'type' => 'char', 'length' => 1 ] + ], + 'increments' => null ]); } - - public function testDropException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for value default.'); - $this->object->dropColumn('0')->valueDefault('test'); - } - - public function testRenameException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for value default.'); - $this->object->renameColumn('0', '1')->valueDefault('test'); - } - - public function testModifyException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for value default.'); - $this->object->char('0')->modify()->valueDefault('test'); - } } diff --git a/tests/unit/TableBuilderTest.php b/tests/unit/TableBuilderTest.php index b5ae367..32816ed 100644 --- a/tests/unit/TableBuilderTest.php +++ b/tests/unit/TableBuilderTest.php @@ -2,6 +2,7 @@ namespace Queryflatfile\Tests\unit; +use Queryflatfile\Exception\TableBuilder\ColumnsValueException; use Queryflatfile\TableBuilder; class TableBuilderTest extends \PHPUnit\Framework\TestCase @@ -13,15 +14,18 @@ class TableBuilderTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - $this->object = new TableBuilder; + $this->object = new TableBuilder('test'); } public function testIncrements(): void { $this->object->increments('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'increments' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'increments' ] + ], + 'increments' => 0 ]); } @@ -31,20 +35,21 @@ public function testIncrementsException(): void $this->expectExceptionMessage( 'Only one incremental column is allowed per table.' ); - $this->object - ->increments('id') - ->increments('error'); + $this->object->increments('id'); + $this->object->increments('error'); } public function testChar(): void { - $this->object - ->char('id') - ->char('id2', 2); + $this->object->char('id'); + $this->object->char('id2', 2); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'char', 'length' => 1 ], - 'id2' => [ 'type' => 'char', 'length' => 2 ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'char', 'length' => 1 ], + 'id2' => [ 'type' => 'char', 'length' => 2 ] + ], + 'increments' => null ]); } @@ -61,20 +66,25 @@ public function testText(): void { $this->object->text('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'text' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'text' ] + ], + 'increments' => null ]); } public function testString(): void { - $this->object - ->string('id') - ->string('id2', 256); + $this->object->string('id'); + $this->object->string('id2', 256); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'string', 'length' => 255 ], - 'id2' => [ 'type' => 'string', 'length' => 256 ], + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'string', 'length' => 255 ], + 'id2' => [ 'type' => 'string', 'length' => 256 ], + ], + 'increments' => null ]); } @@ -91,8 +101,11 @@ public function testInteger(): void { $this->object->integer('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'integer' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'integer' ] + ], + 'increments' => null ]); } @@ -100,8 +113,11 @@ public function testFloat(): void { $this->object->float('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'float' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'float' ] + ], + 'increments' => null ]); } @@ -109,8 +125,11 @@ public function testBoolean(): void { $this->object->boolean('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'boolean' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'boolean' ] + ], + 'increments' => null ]); } @@ -118,8 +137,11 @@ public function testDate(): void { $this->object->date('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'date' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'date' ] + ], + 'increments' => null ]); } @@ -127,216 +149,251 @@ public function testDatetime(): void { $this->object->datetime('id'); - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'datetime' ] + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'datetime' ] + ], + 'increments' => null ]); } public function testNullable(): void { - $this->object - ->increments('0')->nullable() - ->char('1')->nullable() - ->text('2')->nullable() - ->string('3')->nullable() - ->integer('4')->nullable() - ->float('5')->nullable() - ->boolean('6')->nullable() - ->date('7')->nullable() - ->datetime('8')->nullable(); - - self::assertEquals($this->object->build(), [ - '0' => [ 'type' => 'increments', 'nullable' => true ], - '1' => [ 'type' => 'char', 'length' => 1, 'nullable' => true ], - '2' => [ 'type' => 'text', 'nullable' => true ], - '3' => [ 'type' => 'string', 'length' => 255, 'nullable' => true ], - '4' => [ 'type' => 'integer', 'nullable' => true ], - '5' => [ 'type' => 'float', 'nullable' => true ], - '6' => [ 'type' => 'boolean', 'nullable' => true ], - '7' => [ 'type' => 'date', 'nullable' => true ], - '8' => [ 'type' => 'datetime', 'nullable' => true ], + $this->object->increments('0')->nullable(); + $this->object->char('1')->nullable(); + $this->object->text('2')->nullable(); + $this->object->string('3')->nullable(); + $this->object->integer('4')->nullable(); + $this->object->float('5')->nullable(); + $this->object->boolean('6')->nullable(); + $this->object->date('7')->nullable(); + $this->object->datetime('8')->nullable(); + + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + '0' => [ 'type' => 'increments', 'nullable' => true ], + '1' => [ 'type' => 'char', 'length' => 1, 'nullable' => true ], + '2' => [ 'type' => 'text', 'nullable' => true ], + '3' => [ 'type' => 'string', 'length' => 255, 'nullable' => true ], + '4' => [ 'type' => 'integer', 'nullable' => true ], + '5' => [ 'type' => 'float', 'nullable' => true ], + '6' => [ 'type' => 'boolean', 'nullable' => true ], + '7' => [ 'type' => 'date', 'nullable' => true ], + '8' => [ 'type' => 'datetime', 'nullable' => true ], + ], + 'increments' => 0 ]); + self::assertEquals(null, $this->object->getTable()->getField('7')->getValueDefault()); + self::assertEquals(null, $this->object->getTable()->getField('8')->getValueDefault()); } - public function testNullableException(): void + public function testDateNullableException(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for nullable.'); - $this->object->nullable(); - } + $this->object->date('7'); - public function testUnsigned(): void - { - $this->object->integer('id')->unsigned(); - - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'integer', 'unsigned' => true ] - ]); - } - - public function testUnsignedException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for unsigned.'); - $this->object->unsigned(); - } - - public function testUnsignedTypeException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'Impossiblie of unsigned type string only integer.' - ); - $this->object->string('id')->unsigned(); - } - - public function testComment(): void - { - $this->object->increments('id')->comment('identifiant'); - - self::assertEquals($this->object->build(), [ - 'id' => [ 'type' => 'increments', '_comment' => 'identifiant' ] - ]); - } - - public function testCommentException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for comment.'); - $this->object->comment('identifiant'); - } - - public function testValueDefault(): void - { - $this->object - ->increments('0') - ->char('1')->valueDefault('a') - ->text('2')->valueDefault('test') - ->string('3')->valueDefault('test') - ->integer('4')->valueDefault(1) - ->float('5')->valueDefault(1.1) - ->boolean('6')->valueDefault(true) - ->date('7')->valueDefault('2017-11-26') - ->date('7.1')->valueDefault('current_date') - ->datetime('8')->valueDefault('2017-11-26 22:00:00') - ->datetime('8.1')->valueDefault('current_datetime'); - - self::assertEquals($this->object->build(), [ - '0' => [ 'type' => 'increments' ], - '1' => [ 'type' => 'char', 'length' => 1, 'default' => 'a' ], - '2' => [ 'type' => 'text', 'default' => 'test' ], - '3' => [ 'type' => 'string', 'length' => 255, 'default' => 'test' ], - '4' => [ 'type' => 'integer', 'default' => 1 ], - '5' => [ 'type' => 'float', 'default' => 1.1 ], - '6' => [ 'type' => 'boolean', 'default' => true ], - '7' => [ 'type' => 'date', 'default' => '2017-11-26' ], - '7.1' => [ 'type' => 'date', 'default' => 'current_date' ], - '8' => [ 'type' => 'datetime', 'default' => '2017-11-26 22:00:00' ], - '8.1' => [ 'type' => 'datetime', 'default' => 'current_datetime' ], - ]); - } - - public function testValueDefaultException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No column selected for value default.'); - $this->object->valueDefault('1'); - } - - public function testValueDefaultIncrementException(): void - { $this->expectException(\Exception::class); $this->expectExceptionMessage( - 'An incremental type column can not have a default value.' + '7 not nullable or not default.' ); - $this->object->increments('0')->valueDefault(2); + self::assertEquals(null, $this->object->getTable()->getField('7')->getValueDefault()); } - public function testValueDefaultCharException(): void + public function testDatetimeNullableException(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type char.' - ); - $this->object->char('0')->valueDefault(1); - } + $this->object->datetime('8'); - public function testValueDefaultCharLenghtException(): void - { $this->expectException(\Exception::class); $this->expectExceptionMessage( - 'The default value is larger than the specified size.' + '8 not nullable or not default.' ); - $this->object->char('0')->valueDefault('error'); + self::assertEquals(null, $this->object->getTable()->getField('8')->getValueDefault()); } - public function testValueDefaultTextException(): void + public function testUnsigned(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type text.' - ); - $this->object->text('0')->valueDefault(1); - } + $this->object->integer('id')->unsigned(); - public function testValueDefaultStringException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type string.' - ); - $this->object->string('0')->valueDefault(1); + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'integer', 'unsigned' => true ] + ], + 'increments' => null + ]); } - public function testValueDefaultIntegerException(): void + public function testComment(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (error) for column 0 does not correspond to type integer.' - ); - $this->object->integer('0')->valueDefault('error'); - } + $this->object->increments('id')->comment('identifiant'); - public function testValueDefaultFloatException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (error) for column 0 does not correspond to type float.' - ); - $this->object->float('0')->valueDefault('error'); + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + 'id' => [ 'type' => 'increments', '_comment' => 'identifiant' ] + ], + 'increments' => null + ]); } - public function testValueDefaultBoolException(): void + public function testValueDefault(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type boolean.' - ); - $this->object->boolean('0')->valueDefault('1'); + $this->object->increments('0'); + $this->object->char('1')->valueDefault('a'); + $this->object->text('2')->valueDefault('test'); + $this->object->string('3')->valueDefault('test'); + $this->object->integer('4')->valueDefault(1); + $this->object->float('5')->valueDefault(1.1); + $this->object->boolean('6')->valueDefault(true); + $this->object->date('7')->valueDefault('2017-11-26'); + $this->object->date('7.1')->valueDefault('current_date'); + $this->object->datetime('8')->valueDefault('2017-11-26 22:00:00'); + $this->object->datetime('8.1')->valueDefault('current_datetime'); + + self::assertEquals($this->object->getTable()->toArray(), [ + 'fields' => [ + '0' => [ 'type' => 'increments' ], + '1' => [ 'type' => 'char', 'length' => 1, 'default' => 'a' ], + '2' => [ 'type' => 'text', 'default' => 'test' ], + '3' => [ 'type' => 'string', 'length' => 255, 'default' => 'test' ], + '4' => [ 'type' => 'integer', 'default' => 1 ], + '5' => [ 'type' => 'float', 'default' => 1.1 ], + '6' => [ 'type' => 'boolean', 'default' => true ], + '7' => [ 'type' => 'date', 'default' => '2017-11-26' ], + '7.1' => [ 'type' => 'date', 'default' => 'current_date' ], + '8' => [ 'type' => 'datetime', 'default' => '2017-11-26 22:00:00' ], + '8.1' => [ 'type' => 'datetime', 'default' => 'current_datetime' ], + ], + 'increments' => 0 + ]); + self::assertEquals('2017-11-26', $this->object->getTable()->getField('7')->getValueDefault()); + self::assertEquals(date('Y-m-d', time()), $this->object->getTable()->getField('7.1')->getValueDefault()); + self::assertEquals('2017-11-26 22:00:00', $this->object->getTable()->getField('8')->getValueDefault()); + self::assertEquals(date('Y-m-d H:i:s', time()), $this->object->getTable()->getField('8.1')->getValueDefault()); } - public function testValueDefaultDateException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type date.' + /** + * @param class-string<\Throwable> $exceptionClass + * @param mixed $valueDefault + * + * @dataProvider getValueDefaultException + */ + public function testValueDefaulException( + string $method, + $valueDefault, + string $exceptionClass, + string $exceptionMessage + ): void { + $tableBuilder = new TableBuilder('test'); + + $this->expectException($exceptionClass); + $this->expectExceptionMessage($exceptionMessage); + $tableBuilder->$method('0')->valueDefault($valueDefault); + } + + public function getValueDefaultException(): \Generator + { + yield [ + 'boolean', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type boolean: integer given.' + ]; + yield [ + 'char', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type string: integer given.' + ]; + yield [ + 'char', 'error', + \LengthException::class, 'The value of the 0 field must be less than or equal to 1 characters: 5 given' + ]; + yield [ + 'date', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type string: integer given.' + ]; + yield [ + 'date', '1', + ColumnsValueException::class, 'The value of the 0 field must be a valid date: 1 given' + ]; + yield [ + 'datetime', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type string: integer given.' + ]; + yield [ + 'datetime', '1', + ColumnsValueException::class, 'The value of the 0 field must be a valid date: 1 given' + ]; + yield [ + 'float', '1', + \InvalidArgumentException::class, 'The value of the 0 field must be of type float: string given.' + ]; + yield [ + 'increments', 2, + \Exception::class, 'An incremental type column can not have a default value.' + ]; + yield [ + 'integer', '1', + \InvalidArgumentException::class, 'The value of the 0 field must be of type integer: string given.' + ]; + yield [ + 'string', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type string: integer given.' + ]; + yield [ + 'string', str_repeat('0', 256), + \LengthException::class, 'The value of the 0 field must be less than or equal to 255 characters: 256 given' + ]; + yield [ + 'text', 1, + \InvalidArgumentException::class, 'The value of the 0 field must be of type string: integer given.' + ]; + } + + public function testCreateTableFromArray(): void + { + $this->object->increments('field_0'); + $this->object->char('field_1')->valueDefault('a'); + $this->object->text('field_2')->valueDefault('test'); + $this->object->string('field_3')->valueDefault('test'); + $this->object->integer('field_4')->valueDefault(1)->unsigned(); + $this->object->float('field_5')->valueDefault(1.1); + $this->object->boolean('field_6')->valueDefault(true); + $this->object->date('field_7')->valueDefault('2017-11-26'); + $this->object->date('field_7.1')->valueDefault('current_date'); + $this->object->datetime('field_8')->valueDefault('2017-11-26 22:00:00'); + $this->object->datetime('field_8.1')->valueDefault('current_datetime'); + + $expected = [ + 'test' => [ + 'fields' => [ + 'field_0' => [ 'type' => 'increments' ], + 'field_1' => [ 'type' => 'char', 'length' => 1, 'default' => 'a' ], + 'field_2' => [ 'type' => 'text', 'default' => 'test' ], + 'field_3' => [ 'type' => 'string', 'length' => 255, 'default' => 'test' ], + 'field_4' => [ 'type' => 'integer', 'default' => 1, 'unsigned' => true ], + 'field_5' => [ 'type' => 'float', 'default' => 1.1 ], + 'field_6' => [ 'type' => 'boolean', 'default' => true ], + 'field_7' => [ 'type' => 'date', 'default' => '2017-11-26' ], + 'field_7.1' => [ 'type' => 'date', 'default' => 'current_date' ], + 'field_8' => [ 'type' => 'datetime', 'default' => '2017-11-26 22:00:00' ], + 'field_8.1' => [ 'type' => 'datetime', 'default' => 'current_datetime' ], + ], + 'increments' => 0 + ] + ]; + + self::assertEquals( + $this->object->getTable(), + TableBuilder::createTableFromArray('test', $expected[ 'test' ]) ); - $this->object->date('0')->valueDefault('1'); } - public function testValueDefaultDatetimesException(): void + public function testCreateTableFromArrayException(): void { + $data = [ + 'fields' => [ + 'field_0' => [ 'type' => 'error' ] + ] + ]; $this->expectException(\Exception::class); $this->expectExceptionMessage( - 'The default value (1) for column 0 does not correspond to type datetime.' + 'Type error not supported.' ); - $this->object->datetime('0')->valueDefault('1'); - } - - public function testCheckValueException(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Type error not supported'); - TableBuilder::filterValue('testName', 'error', 'testValue'); + TableBuilder::createTableFromArray('test', $data); } }