Prechádzať zdrojové kódy

feat(platform): add auto-create index handling for columns

phpdevcommunity 3 týždňov pred
rodič
commit
2ca6b1ba41

+ 2 - 2
README.md

@@ -21,7 +21,7 @@ PaperORM is available via **Composer** and installs in seconds.
 
 ### 📦 Via Composer (recommended)
 ```bash
-composer require phpdevcommunity/paper-orm:1.0.18-alpha
+composer require phpdevcommunity/paper-orm:1.0.19-alpha
 ```  
 
 ### 🔧 Minimal Configuration
@@ -257,7 +257,7 @@ PaperORM est disponible via **Composer** et s'installe en quelques secondes.
 
 ### 📦 Via Composer (recommandé)
 ```bash
-composer require phpdevcommunity/paper-orm:1.0.18-alpha
+composer require phpdevcommunity/paper-orm:1.0.19-alpha
 ```  
 
 ### 🔧 Configuration minimale

+ 0 - 13
src/Generator/SchemaDiffGenerator.php

@@ -58,19 +58,6 @@ final class SchemaDiffGenerator
              */
             $columns = $tableData['columns'];
             $indexes = $tableData['indexes'];
-
-            if ($schema->supportsIndexes()) {
-                foreach ($columns as $column) {
-                    if (!$column->getIndex()) {
-                        continue;
-                    }
-                    $indexes[] = $column->getIndex();
-                }
-            } else {
-                $indexes = [];
-            }
-
-
             $diff = $this->platform->diff($tableName, $columns, $indexes);
             $columnsToAdd = $diff->getColumnsToAdd();
             $columnsToUpdate = $diff->getColumnsToUpdate();

+ 0 - 8
src/Mapping/Column/Column.php

@@ -18,7 +18,6 @@ abstract class Column
     private $defaultValue;
     private ?string $firstArgument;
     private ?string $secondArgument;
-    private ?Index $index = null;
 
      public function __construct(
           string $property,
@@ -120,13 +119,6 @@ abstract class Column
         return $this->convertToDatabase($this->getDefaultValue());
     }
 
-    public function getIndex(): ?Index
-    {
-        if ($this->index === null && ($this instanceof JoinColumn || $this->isUnique())) {
-            $this->index = new Index([$this->getName()], $this->isUnique());
-        }
-        return $this->index;
-    }
 
     /**
      * Converts a value to its corresponding database representation.

+ 1 - 29
src/Metadata/ColumnMetadata.php

@@ -110,25 +110,11 @@ class ColumnMetadata
     public static function fromColumn(
         Column $column,
         string $sqlType,
+        ?ForeignKeyMetadata $foreignKeyMetadata = null,
         ?string $defaultFirstArgument = null,
         ?string $defaultSecondArgument = null
     ): self
     {
-        $foreignKeyMetadata = null;
-        if ($column instanceof JoinColumn) {
-            $targetEntity = $column->getTargetEntity();
-            if (is_subclass_of($targetEntity, EntityInterface::class)) {
-                $tableName = EntityMapper::getTable($targetEntity);
-                $foreignKeyMetadata = ForeignKeyMetadata::fromArray([
-                    'name' => null,
-                    'columns' => [$column->getName()],
-                    'referenceTable' => $tableName,
-                    'referenceColumns' => [$column->getReferencedColumnName()],
-                    'onDelete' => $column->getOnDelete(),
-                    'onUpdate' => $column->getOnUpdate(),
-                ]);
-            }
-        }
         $arguments = [];
         if ($column->getFirstArgument()) {
             $arguments[] = $column->getFirstArgument();
@@ -171,20 +157,6 @@ class ColumnMetadata
         );
     }
 
-    public function replaceForeignKey(ForeignKeyMetadata $foreignKey): self
-    {
-        return new self(
-            $this->getName(),
-            $this->getType(),
-            $this->isPrimary(),
-            $this->isNullable(),
-            $this->getDefaultValue(),
-            $foreignKey,
-            $this->getComment(),
-            $this->getAttributes()
-        );
-    }
-
     public function toArray(): array
     {
         return [

+ 45 - 15
src/Platform/AbstractPlatform.php

@@ -4,7 +4,11 @@ namespace PhpDevCommunity\PaperORM\Platform;
 
 use LogicException;
 use PhpDevCommunity\PaperORM\Collection\ObjectStorage;
+use PhpDevCommunity\PaperORM\Entity\EntityInterface;
+use PhpDevCommunity\PaperORM\Mapper\EntityMapper;
 use PhpDevCommunity\PaperORM\Mapping\Column\Column;
+use PhpDevCommunity\PaperORM\Mapping\Column\JoinColumn;
+use PhpDevCommunity\PaperORM\Mapping\Column\PrimaryKeyColumn;
 use PhpDevCommunity\PaperORM\Mapping\Index;
 use PhpDevCommunity\PaperORM\Metadata\ColumnMetadata;
 use PhpDevCommunity\PaperORM\Metadata\DatabaseSchemaDiffMetadata;
@@ -37,27 +41,43 @@ abstract class AbstractPlatform implements PlatformInterface
         $mapping = $mappings[$className];
         $sqlType = $mapping['type'];
         $args = $mapping['args'];
-        $columnMetadata = ColumnMetadata::fromColumn($column, $sqlType,$args[0] ?? null, $args[1] ??  null);
-        if ($columnMetadata->getForeignKeyMetadata() && $columnMetadata->getForeignKeyMetadata()->getName() === null) {
-            $columnForeignKey = $columnMetadata->getForeignKeyMetadata();
-            return $columnMetadata->replaceForeignKey(
-                ForeignKeyMetadata::fromForeignKeyMetadataOverrideName(
-                    $columnForeignKey,
-                     $this->generateForeignKeyName($tableName, $columnForeignKey->getColumns())
-                )
-            );
+        $foreignKeyMetadata = null;
+        if ($this->getSchema()->supportsForeignKeyConstraints() && $column instanceof JoinColumn) {
+            $targetEntity = $column->getTargetEntity();
+            if (is_subclass_of($targetEntity, EntityInterface::class)) {
+                $referenceTable = EntityMapper::getTable($targetEntity);
+                $foreignKeyMetadata = ForeignKeyMetadata::fromArray([
+                    'name' => $this->generateForeignKeyName($tableName, [$column->getName()]),
+                    'columns' => [$column->getName()],
+                    'referenceTable' => $referenceTable,
+                    'referenceColumns' => [$column->getReferencedColumnName()],
+                    'onDelete' => $column->getOnDelete(),
+                    'onUpdate' => $column->getOnUpdate(),
+                ]);
+            }
         }
-        return $columnMetadata;
+        return ColumnMetadata::fromColumn($column, $sqlType, $foreignKeyMetadata, $args[0] ?? null, $args[1] ?? null);
     }
 
     /**
      * @param string $tableName
      * @param array<Column> $columns
      * @param array<Index> $indexes
-     * @return void
+     * @return DatabaseSchemaDiffMetadata
      */
     final public function diff(string $tableName, array $columns, array $indexes): DatabaseSchemaDiffMetadata
     {
+
+        foreach ($columns as $column) {
+            if ($column->isUnique() && $this->autoCreateIndexUniqueColumns()) {
+                $indexes[] = new Index([$column->getName()], true);
+            } elseif ($column instanceof JoinColumn && $this->autoCreateIndexJoinColumns()) {
+                $indexes[] = new Index([$column->getName()], $column->isUnique());
+            } elseif ($column instanceof PrimaryKeyColumn && $this->autoCreateIndexPrimaryKeys()) {
+                $indexes[] = new Index([$column->getName()], true);
+            }
+        }
+
         list(
             $columnsToAdd,
             $columnsToUpdate,
@@ -132,7 +152,7 @@ abstract class AbstractPlatform implements PlatformInterface
                         $foreignKeyToDrop[] = $foreignKeysExisting[$foreignKeyName];
                         $foreignKeyToAdd[] = $columnForeignKey;
                     }
-                }else {
+                } else {
                     $foreignKeyToAdd[] = $columnForeignKey;
                 }
 
@@ -176,6 +196,10 @@ abstract class AbstractPlatform implements PlatformInterface
      */
     private function diffIndexes(string $tableName, array $indexes): array
     {
+        if ($this->getSchema()->supportsIndexes() === false) {
+            return [[], [], [], []];
+        }
+
         $indexesFromTable = new ObjectStorage($this->listTableIndexes($tableName));
         $indexesToAdd = [];
         $indexesToUpdate = [];
@@ -183,7 +207,12 @@ abstract class AbstractPlatform implements PlatformInterface
 
         $indexesExisting = [];
         foreach ($indexes as $index) {
-            $indexMetadata = new IndexMetadata($tableName, $index->getName() ?: $this->generateIndexName($tableName, $index->getColumns()), $index->getColumns(), $index->isUnique());
+            $indexMetadata = new IndexMetadata(
+                $tableName,
+                $index->getName() ?: $this->generateIndexName($tableName, $index->getColumns(), $index->isUnique()),
+                $index->getColumns(),
+                $index->isUnique()
+            );
             $indexFound = $indexesFromTable->findOneByMethod('getName', $indexMetadata->getName());
             if ($indexFound) {
                 if ($indexMetadata->toArray() != $indexFound->toArray()) {
@@ -205,13 +234,14 @@ abstract class AbstractPlatform implements PlatformInterface
     }
 
 
-    final protected function generateIndexName(string $tableName, array $columnNames): string
+    final protected function generateIndexName(string $tableName, array $columnNames, bool $unique): string
     {
         $hash = implode('', array_map(static function ($column) {
             return dechex(crc32($column));
         }, array_merge([$tableName], $columnNames)));
 
-        return strtoupper(substr($this->getPrefixIndexName() . $hash, 0, $this->getMaxLength()));
+        $prefix = $unique ? $this->getPrefixUniqIndexName() : $this->getPrefixIndexName();
+        return strtoupper(substr($prefix . $hash, 0, $this->getMaxLength()));
     }
 
     final protected function generateForeignKeyName(string $tableName, array $columnNames): string

+ 20 - 1
src/Platform/MariaDBPlatform.php

@@ -2,7 +2,6 @@
 
 namespace PhpDevCommunity\PaperORM\Platform;
 
-use InvalidArgumentException;
 use LogicException;
 use PhpDevCommunity\PaperORM\Mapping\Column\AnyColumn;
 use PhpDevCommunity\PaperORM\Mapping\Column\AutoIncrementColumn;
@@ -222,6 +221,11 @@ class MariaDBPlatform extends AbstractPlatform
         return 'ix_';
     }
 
+    public function getPrefixUniqIndexName(): string
+    {
+        return 'uniq_';
+    }
+
     public function getPrefixForeignKeyName(): string
     {
         return 'fk_';
@@ -347,4 +351,19 @@ class MariaDBPlatform extends AbstractPlatform
         }
         return $result;
     }
+
+    public function autoCreateIndexJoinColumns(): bool
+    {
+        return true;
+    }
+
+    public function autoCreateIndexPrimaryKeys(): bool
+    {
+        return false;
+    }
+
+    public function autoCreateIndexUniqueColumns(): bool
+    {
+        return true;
+    }
 }

+ 18 - 1
src/Platform/PlatformInterface.php

@@ -74,7 +74,6 @@ interface PlatformInterface
     /**
      * @param string $tableName
      * @param array<Column> $columns
-     * @param array $options
      * @return int
      */
     public function createTable(string $tableName, array $columns): int;
@@ -91,11 +90,29 @@ interface PlatformInterface
     public function convertForeignKeyRuleStringToCode(?string $rule): int;
     public function getMaxLength(): int;
     public function getPrefixIndexName(): string;
+    public function getPrefixUniqIndexName(): string;
     public function getPrefixForeignKeyName(): string;
     public function diff(string $tableName, array $columns, array $indexes): DatabaseSchemaDiffMetadata;
     public function getSchema(): SchemaInterface;
     public function supportsTransactionalDDL(): bool;
 
     public function getConnection(): PaperConnection;
+    /**
+     * Indicates whether this Platform automatically creates indexes
+     * for JoinColumns when generating tables.
+     */
+    public function autoCreateIndexJoinColumns(): bool;
+
+    /**
+     * Indicates whether this Platform automatically creates indexes
+     * for PrimaryKey columns when generating tables.
+     */
+    public function autoCreateIndexPrimaryKeys(): bool;
+
+    /**
+     * Indicates whether this Platform automatically creates indexes
+     * for columns with a unique constraint (that are neither PK nor JoinColumn).
+     */
+    public function autoCreateIndexUniqueColumns(): bool;
 }
 

+ 20 - 0
src/Platform/SqlitePlatform.php

@@ -229,6 +229,11 @@ class SqlitePlatform extends AbstractPlatform
         return 'ix_';
     }
 
+    public function getPrefixUniqIndexName(): string
+    {
+        return 'uniq_';
+    }
+
     public function getPrefixForeignKeyName(): string
     {
         return 'fk_';
@@ -344,4 +349,19 @@ class SqlitePlatform extends AbstractPlatform
     {
         return $this->connection;
     }
+
+    public function autoCreateIndexJoinColumns(): bool
+    {
+        return true;
+    }
+
+    public function autoCreateIndexPrimaryKeys(): bool
+    {
+        return false;
+    }
+
+    public function autoCreateIndexUniqueColumns(): bool
+    {
+        return true;
+    }
 }

+ 0 - 1
tests/DatabaseSyncCommandTest.php

@@ -67,7 +67,6 @@ class DatabaseSyncCommandTest extends TestCase
 
         $this->assertEquals(0, $code);
         $this->assertStringContains( implode(' ', $out), "✔ Executed:");
-//
         $out = [];
         $code = $runner->run(new CommandParser(['', 'paper:database:sync']), new Output(function ($message) use(&$out) {
             $out[] = $message;

+ 17 - 17
tests/MigrationTest.php

@@ -68,16 +68,16 @@ class MigrationTest extends TestCase
                 $this->assertEquals($lines, array (
                     0 => '-- UP MIGRATION --',
                     1 => 'CREATE TABLE `user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,`firstname` VARCHAR(255) NOT NULL,`lastname` VARCHAR(255) NOT NULL,`email` VARCHAR(255) NOT NULL,`password` VARCHAR(255) NOT NULL,`token` VARCHAR(32) NOT NULL,`is_active` BOOLEAN NOT NULL,`created_at` DATETIME,`last_post_id` INTEGER,FOREIGN KEY (`last_post_id`) REFERENCES `post` (id) ON DELETE SET NULL ON UPDATE NO ACTION);',
-                    2 => 'CREATE UNIQUE INDEX IX_8D93D6495F37A13B ON `user` (`token`);',
-                    3 => 'CREATE UNIQUE INDEX IX_8D93D6492D053F64 ON `user` (`last_post_id`);',
+                    2 => 'CREATE UNIQUE INDEX UNIQ_8D93D6495F37A13B ON `user` (`token`);',
+                    3 => 'CREATE UNIQUE INDEX UNIQ_8D93D6492D053F64 ON `user` (`last_post_id`);',
                     4 => 'CREATE TABLE `post` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,`title` VARCHAR(255) NOT NULL,`content` VARCHAR(255) NOT NULL,`slug` VARCHAR(128) NOT NULL,`created_at` DATETIME NOT NULL,`user_id` INTEGER,FOREIGN KEY (`user_id`) REFERENCES `user` (id) ON DELETE SET NULL ON UPDATE NO ACTION);',
-                    5 => 'CREATE UNIQUE INDEX IX_5A8A6C8D989D9B62 ON `post` (`slug`);',
+                    5 => 'CREATE UNIQUE INDEX UNIQ_5A8A6C8D989D9B62 ON `post` (`slug`);',
                     6 => 'CREATE INDEX IX_5A8A6C8DA76ED395 ON `post` (`user_id`);',
                     7 => '-- DOWN MIGRATION --',
-                    8 => 'DROP INDEX IX_8D93D6495F37A13B;',
-                    9 => 'DROP INDEX IX_8D93D6492D053F64;',
+                    8 => 'DROP INDEX UNIQ_8D93D6495F37A13B;',
+                    9 => 'DROP INDEX UNIQ_8D93D6492D053F64;',
                     10 => 'DROP TABLE `user`;',
-                    11 => 'DROP INDEX IX_5A8A6C8D989D9B62;',
+                    11 => 'DROP INDEX UNIQ_5A8A6C8D989D9B62;',
                     12 => 'DROP INDEX IX_5A8A6C8DA76ED395;',
                     13 => 'DROP TABLE `post`;',
                 ));
@@ -87,20 +87,20 @@ class MigrationTest extends TestCase
                 $this->assertEquals($lines, array (
                     0 => '-- UP MIGRATION --',
                     1 => 'CREATE TABLE `user` (`id` INT(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,`firstname` VARCHAR(255) NOT NULL,`lastname` VARCHAR(255) NOT NULL,`email` VARCHAR(255) NOT NULL,`password` VARCHAR(255) NOT NULL,`token` VARCHAR(32) NOT NULL,`is_active` TINYINT(1) NOT NULL,`created_at` DATETIME DEFAULT NULL,`last_post_id` INT(11) DEFAULT NULL);',
-                    2 => 'CREATE UNIQUE INDEX IX_8D93D6495F37A13B ON `user` (`token`);',
-                    3 => 'CREATE UNIQUE INDEX IX_8D93D6492D053F64 ON `user` (`last_post_id`);',
+                    2 => 'CREATE UNIQUE INDEX UNIQ_8D93D6495F37A13B ON `user` (`token`);',
+                    3 => 'CREATE UNIQUE INDEX UNIQ_8D93D6492D053F64 ON `user` (`last_post_id`);',
                     4 => 'CREATE TABLE `post` (`id` INT(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,`title` VARCHAR(255) NOT NULL,`content` VARCHAR(255) NOT NULL,`slug` VARCHAR(128) NOT NULL,`created_at` DATETIME NOT NULL,`user_id` INT(11) DEFAULT NULL);',
-                    5 => 'CREATE UNIQUE INDEX IX_5A8A6C8D989D9B62 ON `post` (`slug`);',
+                    5 => 'CREATE UNIQUE INDEX UNIQ_5A8A6C8D989D9B62 ON `post` (`slug`);',
                     6 => 'CREATE INDEX IX_5A8A6C8DA76ED395 ON `post` (`user_id`);',
                     7 => 'ALTER TABLE `user` ADD CONSTRAINT FK_8D93D6492D053F64 FOREIGN KEY (`last_post_id`) REFERENCES `post`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;',
                     8 => 'ALTER TABLE `post` ADD CONSTRAINT FK_5A8A6C8DA76ED395 FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;',
                     9 => '-- DOWN MIGRATION --',
                     10 => 'ALTER TABLE `user` DROP FOREIGN KEY FK_8D93D6492D053F64;',
                     11 => 'ALTER TABLE `post` DROP FOREIGN KEY FK_5A8A6C8DA76ED395;',
-                    12 => 'DROP INDEX IX_8D93D6495F37A13B ON `user`;',
-                    13 => 'DROP INDEX IX_8D93D6492D053F64 ON `user`;',
+                    12 => 'DROP INDEX UNIQ_8D93D6495F37A13B ON `user`;',
+                    13 => 'DROP INDEX UNIQ_8D93D6492D053F64 ON `user`;',
                     14 => 'DROP TABLE `user`;',
-                    15 => 'DROP INDEX IX_5A8A6C8D989D9B62 ON `post`;',
+                    15 => 'DROP INDEX UNIQ_5A8A6C8D989D9B62 ON `post`;',
                     16 => 'DROP INDEX IX_5A8A6C8DA76ED395 ON `post`;',
                     17 => 'DROP TABLE `post`;',
                 ));
@@ -146,14 +146,14 @@ class MigrationTest extends TestCase
                 if ($schema->supportsDropColumn()) {
                     $this->assertEquals($lines, array());
                 } else {
-                    $this->assertEquals($lines, array(
+                    $this->assertEquals($lines, array (
                         0 => '-- UP MIGRATION --',
                         1 => 'ALTER TABLE `user` ADD `childs` INTEGER NOT NULL DEFAULT 0;',
-                        2 => 'CREATE UNIQUE INDEX IX_8D93D649E7927C74 ON `user` (`email`);',
+                        2 => 'CREATE UNIQUE INDEX UNIQ_8D93D649E7927C74 ON `user` (`email`);',
                         3 => '-- Modify column email is not supported with PhpDevCommunity\\PaperORM\\Schema\\SqliteSchema. Consider creating a new column and migrating the data.;',
                         4 => '-- DOWN MIGRATION --',
                         5 => '-- Drop column childs is not supported with PhpDevCommunity\\PaperORM\\Schema\\SqliteSchema. You might need to manually drop the column.;',
-                        6 => 'DROP INDEX IX_8D93D649E7927C74;',
+                        6 => 'DROP INDEX UNIQ_8D93D649E7927C74;',
                     ));
                 }
                 break;
@@ -162,11 +162,11 @@ class MigrationTest extends TestCase
                 $this->assertEquals($lines, array (
                     0 => '-- UP MIGRATION --',
                     1 => 'ALTER TABLE `user` ADD COLUMN `childs` INT(11) NOT NULL DEFAULT 0;',
-                    2 => 'CREATE UNIQUE INDEX IX_8D93D649E7927C74 ON `user` (`email`);',
+                    2 => 'CREATE UNIQUE INDEX UNIQ_8D93D649E7927C74 ON `user` (`email`);',
                     3 => 'ALTER TABLE `user` MODIFY COLUMN `email` VARCHAR(255) DEFAULT NULL;',
                     4 => '-- DOWN MIGRATION --',
                     5 => 'ALTER TABLE `user` DROP COLUMN `childs`;',
-                    6 => 'DROP INDEX IX_8D93D649E7927C74 ON `user`;',
+                    6 => 'DROP INDEX UNIQ_8D93D649E7927C74 ON `user`;',
                     7 => 'ALTER TABLE `user` MODIFY COLUMN `email` VARCHAR(255) NOT NULL;',
                 ));
                 break;

+ 0 - 3
tests/PlatformDiffTest.php

@@ -47,9 +47,6 @@ class PlatformDiffTest extends TestCase
             (new BoolColumn('is_active'))->bindProperty('active'),
         ];
         $rows = $platform->createTable('user', $columns);
-//        var_dump($rows);
-//        exit();
-
         $diff = $platform->diff('user', $columns, [] );
         $this->assertEmpty($diff->getColumnsToAdd());
         $this->assertEmpty($diff->getColumnsToUpdate());