diff --git a/src/app/Library/CrudPanel/Traits/AutoSet.php b/src/app/Library/CrudPanel/Traits/AutoSet.php index 3460ac6311..93bd77b2f0 100644 --- a/src/app/Library/CrudPanel/Traits/AutoSet.php +++ b/src/app/Library/CrudPanel/Traits/AutoSet.php @@ -53,30 +53,18 @@ public function getDbColumnTypes() if (! $this->driverIsSql()) { return $dbColumnTypes; } - + // dd($this->getDbTableColumns()); foreach ($this->getDbTableColumns() as $key => $column) { - $column_type = $column->getType()->getName(); - $dbColumnTypes[$column->getName()]['type'] = trim(preg_replace('/\(\d+\)(.*)/i', '', $column_type)); - $dbColumnTypes[$column->getName()]['default'] = $column->getDefault(); + $column_type = $column['type_name']; + $dbColumnTypes[$column['name']]['type'] = trim(preg_replace('/\(\d+\)(.*)/i', '', $column_type)); + $dbColumnTypes[$column['name']]['default'] = $column['default']; } - + dump($dbColumnTypes); $this->autoset['db_column_types'] = $dbColumnTypes; return $dbColumnTypes; } - /** - * Set extra types mapping on model. - * - * DEPRECATION NOTICE: This method is no longer used and will be removed in future versions of Backpack - * - * @deprecated - */ - public function setDoctrineTypesMapping() - { - $this->getModel()->getConnectionWithExtraTypeMappings(); - } - /** * Get all columns in the database table. * diff --git a/src/app/Library/Database/DatabaseSchema.php b/src/app/Library/Database/DatabaseSchema.php index a59a014d02..dd2a83c086 100644 --- a/src/app/Library/Database/DatabaseSchema.php +++ b/src/app/Library/Database/DatabaseSchema.php @@ -7,7 +7,7 @@ final class DatabaseSchema { - private static $schema; + private array $schema; /** * Return the schema for the table. @@ -16,11 +16,11 @@ final class DatabaseSchema * @param string $table * @return array */ - public static function getForTable(string $connection, string $table) + public function getForTable(string $connection, string $table) { - self::generateDatabaseSchema($connection, $table); + $this->generateDatabaseSchema($connection, $table); - return self::$schema[$connection][$table] ?? []; + return $this->schema[$connection][$table] ?? []; } /** @@ -30,15 +30,14 @@ public static function getForTable(string $connection, string $table) * @param string $table * @return void */ - private static function generateDatabaseSchema(string $connection, string $table) + private function generateDatabaseSchema(string $connection, string $table) { - if (! isset(self::$schema[$connection])) { - $rawTables = DB::connection($connection)->getDoctrineSchemaManager()->createSchema(); - self::$schema[$connection] = self::mapTables($rawTables); + if (! isset($this->schema[$connection])) { + $this->schema[$connection] = self::mapTables($connection); } else { // check for a specific table in case it was created after schema had been generated. - if (! isset(self::$schema[$connection][$table])) { - self::$schema[$connection][$table] = DB::connection($connection)->getDoctrineSchemaManager()->listTableDetails($table); + if (! isset($this->schema[$connection][$table])) { + $this->schema[$connection][$table] = self::mapTable($connection, $table); } } } @@ -46,13 +45,64 @@ private static function generateDatabaseSchema(string $connection, string $table /** * Map the tables from raw db values into an usable array. * - * @param Doctrine\DBAL\Schema\Schema $rawTables + * * @return array */ - private static function mapTables($rawTables) + private static function mapTables(string $connection) + { + return LazyCollection::make(self::getSchemaManager($connection)->getTables())->mapWithKeys(function ($table, $key) use ($connection) { + return [$table['name'] => self::mapTable($connection, $table['name'])]; + })->toArray(); + } + + private static function mapTable($connection, $table) { - return LazyCollection::make($rawTables->getTables())->mapWithKeys(function ($table, $key) { - return [$table->getName() => $table]; + $indexedColumns = self::getIndexColumnNames($connection, $table); + + return LazyCollection::make(self::getSchemaManager($connection)->getColumns($table))->mapWithKeys(function ($column, $key) use ($indexedColumns) { + $column['index'] = array_key_exists($column['name'], $indexedColumns) ? true : false; + + return [$column['name'] => $column]; })->toArray(); } + + private static function getIndexColumnNames($connection, $table) + { + $indexedColumns = \Illuminate\Support\Arr::flatten( + array_column( + self::getSchemaManager($connection)->getIndexes($table), 'columns') + ); + + return array_unique($indexedColumns); + } + + public function getColumns() + { + return $this->schema; + } + + public function getColumnType(string $connection, string $table, string $columnName) + { + return $this->schema[$connection][$table][$columnName]['type'] ?? 'text'; + } + + public function columnHasDefault(string $connection, string $table, string $columnName) + { + return isset($this->schema[$connection][$table][$columnName]['default']); + } + + public function columnIsNullable(string $connection, string $table, string $columnName) + { + return $this->schema[$connection][$table][$columnName]['nullable'] ?? true; + } + + public function getColumnDefault(string $connection, string $table, string $columnName) + { + return $this->schema[$connection][$table][$columnName]['default'] ?? false; + } + + private static function getSchemaManager(string $connection) + { + return DB::connection($connection)->getSchemaBuilder(); + } } diff --git a/src/app/Library/Database/TableSchema.php b/src/app/Library/Database/TableSchema.php index d9e15c7e2a..2ddd2b4322 100644 --- a/src/app/Library/Database/TableSchema.php +++ b/src/app/Library/Database/TableSchema.php @@ -4,12 +4,11 @@ class TableSchema { - /** @var Doctrine\DBAL\Schema\Table */ - public $schema; + public array $schema; public function __construct(string $connection, string $table) { - $this->schema = DatabaseSchema::getForTable($connection, $table); + $this->schema = app('DatabaseSchema')->getForTable($connection, $table); } /** @@ -19,11 +18,12 @@ public function __construct(string $connection, string $table) */ public function getColumnsNames() { - return array_values( - array_map(function ($item) { - return $item->getName(); - }, $this->getColumns()) - ); + return array_keys($this->schema); + } + + public function getColumns() + { + return $this->schema; } /** @@ -38,9 +38,7 @@ public function getColumnType(string $columnName) return 'varchar'; } - $column = $this->schema->getColumn($columnName); - - return $column->getType()->getName(); + return $this->schema[$columnName]['type']; } /** @@ -55,7 +53,7 @@ public function hasColumn($columnName) return false; } - return $this->schema->hasColumn($columnName); + return array_key_exists($columnName, $this->schema); } /** @@ -70,9 +68,7 @@ public function columnIsNullable($columnName) return true; } - $column = $this->schema->getColumn($columnName); - - return $column->getNotnull() ? false : true; + return $this->schema[$columnName]['nullable'] ?? true; } /** @@ -87,9 +83,7 @@ public function columnHasDefault($columnName) return false; } - $column = $this->schema->getColumn($columnName); - - return $column->getDefault() !== null ? true : false; + return $this->schema[$columnName]['default'] !== null; } /** @@ -104,23 +98,7 @@ public function getColumnDefault($columnName) return false; } - $column = $this->schema->getColumn($columnName); - - return $column->getDefault(); - } - - /** - * Get the table schema columns. - * - * @return array - */ - public function getColumns() - { - if (! $this->schemaExists()) { - return []; - } - - return $this->schema->getColumns(); + return $this->schema[$columnName]['default']; } /** @@ -135,7 +113,7 @@ private function columnExists($columnName) return false; } - return $this->schema->hasColumn($columnName); + return array_key_exists($columnName, $this->schema); } /** diff --git a/src/app/Models/Traits/HasIdentifiableAttribute.php b/src/app/Models/Traits/HasIdentifiableAttribute.php index 98ebe15706..849d730371 100644 --- a/src/app/Models/Traits/HasIdentifiableAttribute.php +++ b/src/app/Models/Traits/HasIdentifiableAttribute.php @@ -22,7 +22,7 @@ public function identifiableAttribute() return $this->identifiableAttribute; } - return static::guessIdentifiableColumnName(); + return $this->guessIdentifiableColumnName(); } /** @@ -30,13 +30,11 @@ public function identifiableAttribute() * * @return string The name of the column in the database that is most likely to be a good indentifying attribute. */ - private static function guessIdentifiableColumnName() + private function guessIdentifiableColumnName() { - $instance = new static(); - $conn = $instance->getConnectionWithExtraTypeMappings(); - $table = $instance->getTableWithPrefix(); - $columns = $conn->getDoctrineSchemaManager()->listTableColumns($table); - $indexes = $conn->getDoctrineSchemaManager()->listTableIndexes($table); + $schema = app('DatabaseSchema')->getForTable($this->getConnection()->getName(), $this->getTableWithPrefix()); + + $columns = $schema; $columnsNames = array_keys($columns); // these column names are sensible defaults for lots of use cases @@ -50,20 +48,11 @@ private static function guessIdentifiableColumnName() } } - // get indexed columns in database table - $indexedColumns = []; - foreach ($indexes as $index) { - $indexColumns = $index->getColumns(); - foreach ($indexColumns as $ic) { - array_push($indexedColumns, $ic); - } - } - // if none of the sensible defaults exists // we get the first column from database // that is NOT indexed (usually primary, foreign keys) foreach ($columns as $columnName => $columnProperties) { - if (! in_array($columnName, $indexedColumns)) { + if ($columnProperties['index'] === false) { //check for convention "field<_id>" in case developer didn't add foreign key constraints. if (strpos($columnName, '_id') !== false) { continue; diff --git a/src/app/Models/Traits/HasRelationshipFields.php b/src/app/Models/Traits/HasRelationshipFields.php index a536fbb379..a37601dddb 100644 --- a/src/app/Models/Traits/HasRelationshipFields.php +++ b/src/app/Models/Traits/HasRelationshipFields.php @@ -13,33 +13,6 @@ */ trait HasRelationshipFields { - /** - * Register aditional types in doctrine schema manager for the current connection. - * - * @return DB - */ - public function getConnectionWithExtraTypeMappings() - { - $connection = DB::connection($this->getConnectionName()); - - $types = [ - 'enum' => 'string', - 'jsonb' => 'json', - ]; - - // only register the extra types in sql databases - if (self::isSqlConnection()) { - $platform = $connection->getDoctrineSchemaManager()->getDatabasePlatform(); - foreach ($types as $type_key => $type_value) { - if (! $platform->hasDoctrineTypeMappingFor($type_key)) { - $platform->registerDoctrineTypeMapping($type_key, $type_value); - } - } - } - - return $connection; - } - /** * Get the model's table name, with the prefix added from the configuration file. * @@ -119,7 +92,7 @@ public static function getDbColumnDefault($columnName) private static function getConnectionAndTable() { $instance = new static(); - $conn = $instance->getConnectionWithExtraTypeMappings(); + $conn = $instance->getConnection(); $table = $instance->getTableWithPrefix(); return [$conn, $table]; diff --git a/tests/Unit/CrudPanel/CrudPanelAutoSetTest.php b/tests/Unit/CrudPanel/CrudPanelAutoSetTest.php index e6f93a72c4..14cc9688cd 100644 --- a/tests/Unit/CrudPanel/CrudPanelAutoSetTest.php +++ b/tests/Unit/CrudPanel/CrudPanelAutoSetTest.php @@ -3,7 +3,6 @@ namespace Backpack\CRUD\Tests\Unit\CrudPanel; use Backpack\CRUD\Tests\config\Models\ColumnType; -use Exception; class MyColumnTypeWithOtherConnection extends ColumnType { @@ -844,29 +843,4 @@ public function testGetDbColumnsNames() $this->assertEquals(array_keys($this->expectedColumnTypes), $columnNames); } - - public function testSetDoctrineTypesMapping() - { - $original_db_config = $this->app['config']->get('database.connections.testing'); - $new_model_db_config = array_merge($original_db_config, ['prefix' => 'testing2']); - - $this->app['config']->set('database.connections.testing_2', $new_model_db_config); - - $original_db_platform = $this->crudPanel->getModel()->getConnection()->getDoctrineConnection()->getDatabasePlatform(); - $this->crudPanel->setDoctrineTypesMapping(); - $type = $original_db_platform->getDoctrineTypeMapping('enum'); - - $this->crudPanel->setModel(MyColumnTypeWithOtherConnection::class); - $new_model_db_platform = $this->crudPanel->getModel()->getConnection()->getDoctrineConnection()->getDatabasePlatform(); - - try { - $new_model_db_platform->getDoctrineTypeMapping('enum'); - } catch (Exception $e) { - $this->assertInstanceOf(Exception::class, $e); - } - $this->crudPanel->setDoctrineTypesMapping(); - - $type = $new_model_db_platform->getDoctrineTypeMapping('enum'); - $this->assertEquals('string', $type); - } }