Merge pull request #636 from acelaya-forks/feature/postgres-schema-support

Feature/postgres schema support
This commit is contained in:
Alejandro Celaya authored and GitHub committed 2020-01-29 11:02:23 +01:00
commit e18187f04e
10 files changed
+185 -163

No files matched your search

+1 -1
View File
@@ -47,7 +47,7 @@
"phly/phly-event-dispatcher": "^1.0", "phly/phly-event-dispatcher": "^1.0",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"pugx/shortid-php": "^0.5", "pugx/shortid-php": "^0.5",
"shlinkio/shlink-common": "^2.6.0", "shlinkio/shlink-common": "^2.7.0",
"shlinkio/shlink-event-dispatcher": "^1.3", "shlinkio/shlink-event-dispatcher": "^1.3",
"shlinkio/shlink-installer": "^4.0.1", "shlinkio/shlink-installer": "^4.0.1",
"shlinkio/shlink-ip-geolocation": "^1.3.1", "shlinkio/shlink-ip-geolocation": "^1.3.1",
@@ -9,6 +9,7 @@ return [
'entity_manager' => [ 'entity_manager' => [
'orm' => [ 'orm' => [
'proxies_dir' => 'data/proxies', 'proxies_dir' => 'data/proxies',
'load_mappings_using_functional_style' => true,
], ],
'connection' => [ 'connection' => [
'user' => '', 'user' => '',
@@ -6,20 +6,21 @@ namespace Shlinkio\Shlink\Core;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata); $builder = new ClassMetadataBuilder($metadata);
$builder->setTable('domains'); $builder->setTable(determineTableName('domains', $emConfig));
$builder->createField('id', Types::BIGINT) $builder->createField('id', Types::BIGINT)
->columnName('id') ->columnName('id')
->makePrimaryKey() ->makePrimaryKey()
->generatedValue('IDENTITY') ->generatedValue('IDENTITY')
->option('unsigned', true) ->option('unsigned', true)
->build(); ->build();
$builder->createField('authority', Types::STRING) $builder->createField('authority', Types::STRING)
->unique() ->unique()
->build(); ->build();
};
@@ -6,65 +6,66 @@ namespace Shlinkio\Shlink\Core;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType; use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata); $builder = new ClassMetadataBuilder($metadata);
$builder->setTable('short_urls') $builder->setTable(determineTableName('short_urls', $emConfig))
->setCustomRepositoryClass(Repository\ShortUrlRepository::class); ->setCustomRepositoryClass(Repository\ShortUrlRepository::class);
$builder->createField('id', Types::BIGINT) $builder->createField('id', Types::BIGINT)
->columnName('id') ->columnName('id')
->makePrimaryKey() ->makePrimaryKey()
->generatedValue('IDENTITY') ->generatedValue('IDENTITY')
->option('unsigned', true) ->option('unsigned', true)
->build(); ->build();
$builder->createField('longUrl', Types::STRING) $builder->createField('longUrl', Types::STRING)
->columnName('original_url') ->columnName('original_url')
->length(2048) ->length(2048)
->build(); ->build();
$builder->createField('shortCode', Types::STRING) $builder->createField('shortCode', Types::STRING)
->columnName('short_code') ->columnName('short_code')
->length(255) ->length(255)
->build(); ->build();
$builder->createField('dateCreated', ChronosDateTimeType::CHRONOS_DATETIME) $builder->createField('dateCreated', ChronosDateTimeType::CHRONOS_DATETIME)
->columnName('date_created') ->columnName('date_created')
->build(); ->build();
$builder->createField('validSince', ChronosDateTimeType::CHRONOS_DATETIME) $builder->createField('validSince', ChronosDateTimeType::CHRONOS_DATETIME)
->columnName('valid_since') ->columnName('valid_since')
->nullable() ->nullable()
->build(); ->build();
$builder->createField('validUntil', ChronosDateTimeType::CHRONOS_DATETIME) $builder->createField('validUntil', ChronosDateTimeType::CHRONOS_DATETIME)
->columnName('valid_until') ->columnName('valid_until')
->nullable() ->nullable()
->build(); ->build();
$builder->createField('maxVisits', Types::INTEGER) $builder->createField('maxVisits', Types::INTEGER)
->columnName('max_visits') ->columnName('max_visits')
->nullable() ->nullable()
->build(); ->build();
$builder->createOneToMany('visits', Entity\Visit::class) $builder->createOneToMany('visits', Entity\Visit::class)
->mappedBy('shortUrl') ->mappedBy('shortUrl')
->fetchExtraLazy() ->fetchExtraLazy()
->build(); ->build();
$builder->createManyToMany('tags', Entity\Tag::class) $builder->createManyToMany('tags', Entity\Tag::class)
->setJoinTable('short_urls_in_tags') ->setJoinTable(determineTableName('short_urls_in_tags', $emConfig))
->addInverseJoinColumn('tag_id', 'id', true, false, 'CASCADE') ->addInverseJoinColumn('tag_id', 'id', true, false, 'CASCADE')
->addJoinColumn('short_url_id', 'id', true, false, 'CASCADE') ->addJoinColumn('short_url_id', 'id', true, false, 'CASCADE')
->build(); ->build();
$builder->createManyToOne('domain', Entity\Domain::class) $builder->createManyToOne('domain', Entity\Domain::class)
->addJoinColumn('domain_id', 'id', true, false, 'RESTRICT') ->addJoinColumn('domain_id', 'id', true, false, 'RESTRICT')
->cascadePersist() ->cascadePersist()
->build(); ->build();
$builder->addUniqueConstraint(['short_code', 'domain_id'], 'unique_short_code_plus_domain'); $builder->addUniqueConstraint(['short_code', 'domain_id'], 'unique_short_code_plus_domain');
};
@@ -6,21 +6,22 @@ namespace Shlinkio\Shlink\Core;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata); $builder = new ClassMetadataBuilder($metadata);
$builder->setTable('tags') $builder->setTable(determineTableName('tags', $emConfig))
->setCustomRepositoryClass(Repository\TagRepository::class); ->setCustomRepositoryClass(Repository\TagRepository::class);
$builder->createField('id', Types::BIGINT) $builder->createField('id', Types::BIGINT)
->columnName('id') ->columnName('id')
->makePrimaryKey() ->makePrimaryKey()
->generatedValue('IDENTITY') ->generatedValue('IDENTITY')
->option('unsigned', true) ->option('unsigned', true)
->build(); ->build();
$builder->createField('name', Types::STRING) $builder->createField('name', Types::STRING)
->unique() ->unique()
->build(); ->build();
};
@@ -6,49 +6,50 @@ namespace Shlinkio\Shlink\Core;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType; use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
use Shlinkio\Shlink\Core\Model\Visitor; use Shlinkio\Shlink\Core\Model\Visitor;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata); $builder = new ClassMetadataBuilder($metadata);
$builder->setTable('visits') $builder->setTable(determineTableName('visits', $emConfig))
->setCustomRepositoryClass(Repository\VisitRepository::class); ->setCustomRepositoryClass(Repository\VisitRepository::class);
$builder->createField('id', Types::BIGINT) $builder->createField('id', Types::BIGINT)
->columnName('id') ->columnName('id')
->makePrimaryKey() ->makePrimaryKey()
->generatedValue('IDENTITY') ->generatedValue('IDENTITY')
->option('unsigned', true) ->option('unsigned', true)
->build(); ->build();
$builder->createField('referer', Types::STRING) $builder->createField('referer', Types::STRING)
->nullable() ->nullable()
->length(Visitor::REFERER_MAX_LENGTH) ->length(Visitor::REFERER_MAX_LENGTH)
->build(); ->build();
$builder->createField('date', ChronosDateTimeType::CHRONOS_DATETIME) $builder->createField('date', ChronosDateTimeType::CHRONOS_DATETIME)
->columnName('`date`') ->columnName('`date`')
->build(); ->build();
$builder->createField('remoteAddr', Types::STRING) $builder->createField('remoteAddr', Types::STRING)
->columnName('remote_addr') ->columnName('remote_addr')
->length(Visitor::REMOTE_ADDRESS_MAX_LENGTH) ->length(Visitor::REMOTE_ADDRESS_MAX_LENGTH)
->nullable() ->nullable()
->build(); ->build();
$builder->createField('userAgent', Types::STRING) $builder->createField('userAgent', Types::STRING)
->columnName('user_agent') ->columnName('user_agent')
->length(Visitor::USER_AGENT_MAX_LENGTH) ->length(Visitor::USER_AGENT_MAX_LENGTH)
->nullable() ->nullable()
->build(); ->build();
$builder->createManyToOne('shortUrl', Entity\ShortUrl::class) $builder->createManyToOne('shortUrl', Entity\ShortUrl::class)
->addJoinColumn('short_url_id', 'id', false, false, 'CASCADE') ->addJoinColumn('short_url_id', 'id', false, false, 'CASCADE')
->build(); ->build();
$builder->createManyToOne('visitLocation', Entity\VisitLocation::class) $builder->createManyToOne('visitLocation', Entity\VisitLocation::class)
->addJoinColumn('visit_location_id', 'id', true, false, 'Set NULL') ->addJoinColumn('visit_location_id', 'id', true, false, 'Set NULL')
->cascadePersist() ->cascadePersist()
->build(); ->build();
};
@@ -6,41 +6,42 @@ namespace Shlinkio\Shlink\Core;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata); $builder = new ClassMetadataBuilder($metadata);
$builder->setTable('visit_locations'); $builder->setTable(determineTableName('visit_locations', $emConfig));
$builder->createField('id', Types::BIGINT) $builder->createField('id', Types::BIGINT)
->columnName('id') ->columnName('id')
->makePrimaryKey() ->makePrimaryKey()
->generatedValue('IDENTITY') ->generatedValue('IDENTITY')
->option('unsigned', true) ->option('unsigned', true)
->build();
$columns = [
'country_code' => 'countryCode',
'country_name' => 'countryName',
'region_name' => 'regionName',
'city_name' => 'cityName',
'timezone' => 'timezone',
];
foreach ($columns as $columnName => $fieldName) {
$builder->createField($fieldName, Types::STRING)
->columnName($columnName)
->nullable()
->build(); ->build();
}
$builder->createField('latitude', Types::FLOAT) $columns = [
->columnName('lat') 'country_code' => 'countryCode',
->nullable(false) 'country_name' => 'countryName',
->build(); 'region_name' => 'regionName',
'city_name' => 'cityName',
'timezone' => 'timezone',
];
$builder->createField('longitude', Types::FLOAT) foreach ($columns as $columnName => $fieldName) {
->columnName('lon') $builder->createField($fieldName, Types::STRING)
->nullable(false) ->columnName($columnName)
->build(); ->nullable()
->build();
}
$builder->createField('latitude', Types::FLOAT)
->columnName('lat')
->nullable(false)
->build();
$builder->createField('longitude', Types::FLOAT)
->columnName('lon')
->nullable(false)
->build();
};
+14
View File
@@ -8,6 +8,8 @@ use Cake\Chronos\Chronos;
use DateTimeInterface; use DateTimeInterface;
use PUGX\Shortid\Factory as ShortIdFactory; use PUGX\Shortid\Factory as ShortIdFactory;
use function sprintf;
function generateRandomShortCode(int $length = 5): string function generateRandomShortCode(int $length = 5): string
{ {
static $shortIdFactory; static $shortIdFactory;
@@ -39,3 +41,15 @@ function parseDateField($date): ?Chronos
return Chronos::parse($date); return Chronos::parse($date);
} }
function determineTableName(string $tableName, array $emConfig = []): string
{
$schema = $emConfig['connection']['schema'] ?? null;
// $tablePrefix = $emConfig['connection']['table_prefix'] ?? null; // TODO
if ($schema === null) {
return $tableName;
}
return sprintf('%s.%s', $schema, $tableName);
}
@@ -6,29 +6,32 @@ namespace Shlinkio\Shlink\Rest;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata; // @codingStandardsIgnoreLine use Doctrine\ORM\Mapping\ClassMetadata;
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType; use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
/** @var $metadata ClassMetadata */ // @codingStandardsIgnoreLine use function Shlinkio\Shlink\Core\determineTableName;
$builder = new ClassMetadataBuilder($metadata);
$builder->setTable('api_keys'); return static function (ClassMetadata $metadata, array $emConfig): void {
$builder = new ClassMetadataBuilder($metadata);
$builder->createField('id', Types::BIGINT) $builder->setTable(determineTableName('api_keys', $emConfig));
->makePrimaryKey()
->generatedValue('IDENTITY')
->option('unsigned', true)
->build();
$builder->createField('key', Types::STRING) $builder->createField('id', Types::BIGINT)
->columnName('`key`') ->makePrimaryKey()
->unique() ->generatedValue('IDENTITY')
->build(); ->option('unsigned', true)
->build();
$builder->createField('expirationDate', ChronosDateTimeType::CHRONOS_DATETIME) $builder->createField('key', Types::STRING)
->columnName('expiration_date') ->columnName('`key`')
->nullable() ->unique()
->build(); ->build();
$builder->createField('enabled', Types::BOOLEAN) $builder->createField('expirationDate', ChronosDateTimeType::CHRONOS_DATETIME)
->build(); ->columnName('expiration_date')
->nullable()
->build();
$builder->createField('enabled', Types::BOOLEAN)
->build();
};
-1
View File
@@ -2,6 +2,5 @@ parameters:
checkMissingIterableValueType: false checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false checkGenericClassInNonGenericObjectType: false
ignoreErrors: ignoreErrors:
- '#Undefined variable: \$metadata#'
- '#AbstractQuery::setParameters()#' - '#AbstractQuery::setParameters()#'
- '#mustRun()#' - '#mustRun()#'