Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][BC] Remove dbal #5471

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions src/app/Library/CrudPanel/Traits/AutoSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
78 changes: 64 additions & 14 deletions src/app/Library/Database/DatabaseSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

final class DatabaseSchema
{
private static $schema;
private array $schema;

/**
* Return the schema for the table.
Expand All @@ -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] ?? [];
}

/**
Expand All @@ -30,29 +30,79 @@ 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);
}
}
}

/**
* 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();
}
}
50 changes: 14 additions & 36 deletions src/app/Library/Database/TableSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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'];
}

/**
Expand All @@ -55,7 +53,7 @@ public function hasColumn($columnName)
return false;
}

return $this->schema->hasColumn($columnName);
return array_key_exists($columnName, $this->schema);
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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'];
}

/**
Expand All @@ -135,7 +113,7 @@ private function columnExists($columnName)
return false;
}

return $this->schema->hasColumn($columnName);
return array_key_exists($columnName, $this->schema);
}

/**
Expand Down
23 changes: 6 additions & 17 deletions src/app/Models/Traits/HasIdentifiableAttribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,19 @@ public function identifiableAttribute()
return $this->identifiableAttribute;
}

return static::guessIdentifiableColumnName();
return $this->guessIdentifiableColumnName();
}

/**
* Get the most likely column in the db table that could be used as an identifiable attribute.
*
* @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
Expand All @@ -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;
Expand Down
29 changes: 1 addition & 28 deletions src/app/Models/Traits/HasRelationshipFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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];
Expand Down
26 changes: 0 additions & 26 deletions tests/Unit/CrudPanel/CrudPanelAutoSetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Backpack\CRUD\Tests\Unit\CrudPanel;

use Backpack\CRUD\Tests\config\Models\ColumnType;
use Exception;

class MyColumnTypeWithOtherConnection extends ColumnType
{
Expand Down Expand Up @@ -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);
}
}