Compare commits
85
Commits
2de3139c80
..
v2.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75f4b1d5f8 | ||
|
|
caf5bd9664 | ||
|
|
69dcfe9324 | ||
|
|
a18b7dba6c | ||
|
|
9062a73ee6 | ||
|
|
447430b7bb | ||
|
|
00093b0398 | ||
|
|
e5a842a812 | ||
|
|
1dcf32e0da | ||
|
|
13b7cf06f1 | ||
|
|
709ed63323 | ||
|
|
5d32d9f635 | ||
|
|
1e4a528d39 | ||
|
|
2d86adc3e1 | ||
|
|
2a03789e7c | ||
|
|
1af0063203 | ||
|
|
7b35de3258 | ||
|
|
f938e18572 | ||
|
|
b394b9348f | ||
|
|
009e30eb7e | ||
|
|
fd5d31fa17 | ||
|
|
b0b3aca6d9 | ||
|
|
36162c6486 | ||
|
|
11e436236c | ||
|
|
a9b9c2cce9 | ||
|
|
cb125545c7 | ||
|
|
2271b0b034 | ||
|
|
2e45eba520 | ||
|
|
033a183269 | ||
|
|
0192975f10 | ||
|
|
b33c67b594 | ||
|
|
2f482324b2 | ||
|
|
a5d65025f8 | ||
|
|
b53327a6ed | ||
|
|
fb644b0b0a | ||
|
|
c719e4a6d1 | ||
|
|
fb4985160a | ||
|
|
c54de30069 | ||
|
|
8fff21ecb0 | ||
|
|
cc6048d4ee | ||
|
|
761e0401b0 | ||
|
|
1ec582d1ac | ||
|
|
9556dea849 | ||
|
|
bfddf84564 | ||
|
|
e0ec140661 | ||
|
|
0fd6889c6f | ||
|
|
bd0d928f35 | ||
|
|
5a5d326d70 | ||
|
|
b5e96eb7e0 | ||
|
|
7c589ab7b4 | ||
|
|
589524ca3a | ||
|
|
1fac12c928 | ||
|
|
9eed2fe1a8 | ||
|
|
b601939459 | ||
|
|
e3314f40ac | ||
|
|
4ad44f73d7 | ||
|
|
68a6636c06 | ||
|
|
70c6cde603 | ||
|
|
079a3fd110 | ||
|
|
ec4d02b9d9 | ||
|
|
35ceb97241 | ||
|
|
83f673b37f | ||
|
|
411992c7a8 | ||
|
|
5f4f23a8e4 | ||
|
|
2fda7e82d7 | ||
|
|
573d4cc06b | ||
|
|
18313fd7f5 | ||
|
|
9503b24467 | ||
|
|
3c2ae86653 | ||
|
|
9977a25cf5 | ||
|
|
3ba8a2a5d0 | ||
|
|
4106c8db91 | ||
|
|
d5cca085bc | ||
|
|
c56b584140 | ||
|
|
8b1c11676d | ||
|
|
aa07c728fe | ||
|
|
d4181065cf | ||
|
|
62998faf40 | ||
|
|
feee26cd26 | ||
|
|
e37944c63a | ||
|
|
1d38ae8245 | ||
|
|
0c8591f238 | ||
|
|
bbfd7c02b4 | ||
|
|
bd9078230d | ||
|
|
f3be11a590 |
No files matched your search
+3
-3
@@ -10,12 +10,12 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"mcnd/notes": "dev-master"
|
||||
"mcnd/notes": "^2.1.1"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/mcNdave/notes.git"
|
||||
"type": "composer",
|
||||
"url": "https://git.mcnd.ca/api/packages/mcndave/composer"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Common\PdoObject;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
|
||||
interface AdapterInterface {
|
||||
@@ -12,7 +11,7 @@ interface AdapterInterface {
|
||||
public const IDENTIFIER_SCHEMA = 4;
|
||||
public const IDENTIFIER_VALUE = 5;
|
||||
|
||||
public function connect() : object /* | PdoObject|mixed */;
|
||||
public function connect() : object;
|
||||
public function buildDataSourceName() : string;
|
||||
public function setup(array $configuration) : void;
|
||||
public function writableValue(/* mixed */ $value); /*: mixed*/
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\{ConnectionAdapter, Entity\InformationSchema\Table, Migration\FieldDefinition, Repository, QueryBuilder\Sql\MysqlQueryBuilder, Entity};
|
||||
|
||||
trait DefaultAdapterTrait
|
||||
{
|
||||
public function repositoryClass() : string
|
||||
{
|
||||
return Repository::class;
|
||||
}
|
||||
|
||||
public function queryBuilderClass() : string
|
||||
{
|
||||
return MysqlQueryBuilder::class;
|
||||
}
|
||||
|
||||
public function tableSyntax() : array
|
||||
{
|
||||
return [
|
||||
'ai' => "AUTO_INCREMENT",
|
||||
'pk' => "PRIMARY KEY",
|
||||
'unsigned' => "UNSIGNED",
|
||||
];
|
||||
}
|
||||
|
||||
public function databaseName() : string
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function schemaTable(ConnectionAdapter $adapter, $databaseName, string $tableName) : null|object
|
||||
{
|
||||
return Table::repository(Repository::DEFAULT_ALIAS, $adapter)
|
||||
->select(\Ulmus\Common\Sql::raw('this.*'))
|
||||
->where($this->escapeIdentifier('table_schema', AdapterInterface::IDENTIFIER_FIELD), $databaseName)
|
||||
->loadOneFromField($this->escapeIdentifier('table_name', AdapterInterface::IDENTIFIER_FIELD), $tableName);
|
||||
}
|
||||
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$type = $field->type;
|
||||
|
||||
$length = $field->length;
|
||||
|
||||
if ( is_a($type, Entity\Field\Date::class, true) ) {
|
||||
$type = "DATE";
|
||||
}
|
||||
elseif ( is_a($type, Entity\Field\Time::class, true) ) {
|
||||
$type = "TIME";
|
||||
}
|
||||
elseif ( is_a($type, \DateTime::class, true) ) {
|
||||
$type = "DATETIME";
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
case "bool":
|
||||
$type = "TINYINT";
|
||||
$length = 1;
|
||||
break;
|
||||
|
||||
case "array":
|
||||
case "string":
|
||||
if ($length && $length <= 255) {
|
||||
$type = "VARCHAR";
|
||||
break;
|
||||
}
|
||||
elseif (! $length || ( $length <= 65535 ) ) {
|
||||
$type = "TEXT";
|
||||
}
|
||||
elseif ( $length <= 16777215 ) {
|
||||
$type = "MEDIUMTEXT";
|
||||
}
|
||||
elseif ($length <= 4294967295) {
|
||||
$type = "LONGTEXT";
|
||||
}
|
||||
else {
|
||||
throw new \Exception("A column with size bigger than 4GB cannot be created.");
|
||||
}
|
||||
|
||||
# Length is unnecessary on TEXT fields
|
||||
unset($length);
|
||||
|
||||
break;
|
||||
|
||||
case "float":
|
||||
$type = "DOUBLE";
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = strtoupper($type);
|
||||
break;
|
||||
}
|
||||
|
||||
return $typeOnly ? $type : $type . ( isset($length) ? "($length" . ( ! empty($precision) ? ",$precision" : "" ) . ")" : "" );
|
||||
}
|
||||
|
||||
public function whitelistAttributes(array &$parameters) : void
|
||||
{
|
||||
$parameters = array_intersect_key($parameters, array_flip(static::ALLOWED_ATTRIBUTES));
|
||||
}
|
||||
|
||||
public function generateAlterColumn(FieldDefinition $definition, array $field) : string|\Stringable
|
||||
{
|
||||
if ($field['previous']) {
|
||||
$position = sprintf('AFTER %s', $this->escapeIdentifier($field['previous']['field'], AdapterInterface::IDENTIFIER_FIELD));
|
||||
}
|
||||
else {
|
||||
$position = "FIRST";
|
||||
}
|
||||
|
||||
return implode(" ", [
|
||||
strtoupper($field['action']),
|
||||
$this->escapeIdentifier($definition->getSqlName(), AdapterInterface::IDENTIFIER_FIELD),
|
||||
$definition->getSqlType(),
|
||||
$definition->getSqlParams(),
|
||||
$position,
|
||||
]);
|
||||
}
|
||||
}
|
||||
+30
-6
@@ -2,17 +2,22 @@
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Common\PdoObject;
|
||||
use Ulmus\Pdo;
|
||||
|
||||
use Ulmus\Exception\AdapterConfigurationException;
|
||||
|
||||
use Ulmus\Ulmus;
|
||||
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\{Entity\InformationSchema\Table, Migration\MigrateInterface, Repository, QueryBuilder};
|
||||
use Ulmus\{ConnectionAdapter,
|
||||
Entity\InformationSchema\Table,
|
||||
Migration\MigrateInterface,
|
||||
Migration\SqlMigrationTrait,
|
||||
Repository,
|
||||
QueryBuilder};
|
||||
|
||||
class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
use SqlAdapterTrait;
|
||||
use SqlAdapterTrait, SqlMigrationTrait;
|
||||
|
||||
const ALLOWED_ATTRIBUTES = [
|
||||
'default', 'primary_key', 'auto_increment',
|
||||
@@ -51,7 +56,9 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
public function __construct(
|
||||
?string $server = null,
|
||||
?string $database = null,
|
||||
#[\SensitiveParameter]
|
||||
?string $username = null,
|
||||
#[\SensitiveParameter]
|
||||
?string $password = null,
|
||||
?int $port = null
|
||||
) {
|
||||
@@ -76,10 +83,10 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public function connect() : PdoObject
|
||||
public function connect() : \PDO
|
||||
{
|
||||
try {
|
||||
$pdo = new PdoObject($this->buildDataSourceName(), $this->username, $this->password);
|
||||
$pdo = new Pdo\Mssql($this->buildDataSourceName(), $this->username, $this->password);
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
|
||||
$pdo->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_UTF8);
|
||||
@@ -204,9 +211,17 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public function escapeIdentifier(string $segment, int $type) : string
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$mapper = new MsSQLFieldMapper($field);
|
||||
|
||||
return $typeOnly ? $mapper->type : $mapper->render();
|
||||
}
|
||||
|
||||
public static function escapeIdentifier(string $segment, int $type) : string
|
||||
{
|
||||
switch($type) {
|
||||
default:
|
||||
case static::IDENTIFIER_SCHEMA:
|
||||
case static::IDENTIFIER_DATABASE:
|
||||
case static::IDENTIFIER_TABLE:
|
||||
@@ -232,4 +247,13 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
{
|
||||
return QueryBuilder\Sql\MssqlQueryBuilder::class;
|
||||
}
|
||||
|
||||
public function schemaTable(ConnectionAdapter $adapter, $databaseName, string $tableName) : null|object
|
||||
{
|
||||
return \Ulmus\Entity\Mssql\Table::repository(Repository::DEFAULT_ALIAS, $adapter)
|
||||
->select(\Ulmus\Common\Sql::raw('this.*'))
|
||||
->where($this->escapeIdentifier('table_schema', AdapterInterface::IDENTIFIER_FIELD), $databaseName)
|
||||
->or($this->escapeIdentifier('table_catalog', AdapterInterface::IDENTIFIER_FIELD), $databaseName)
|
||||
->loadOneFromField($this->escapeIdentifier('table_name', AdapterInterface::IDENTIFIER_FIELD), $tableName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
|
||||
class MsSQLFieldMapper extends SqlFieldMapper
|
||||
{
|
||||
public function map() : void
|
||||
{
|
||||
parent::map();
|
||||
|
||||
if (in_array($this->type, [ 'CHAR', 'VARCHAR', 'TEXT', ])) {
|
||||
$this->type = "N" . $this->type;
|
||||
};
|
||||
}
|
||||
|
||||
/* @TODO !
|
||||
public function postProcess() : void
|
||||
{
|
||||
if (
|
||||
in_array($this->type, [ 'BLOB', 'TINYBLOB', 'MEDIUMBLOB', 'LONGBLOB', 'JSON', 'TEXT', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'GEOMETRY' ]) &&
|
||||
! is_object($this->field->default ?? false) # Could be a functional default, which would now be valid
|
||||
) {
|
||||
unset($this->field->default);
|
||||
}
|
||||
}
|
||||
* */
|
||||
}
|
||||
+49
-5
@@ -2,14 +2,19 @@
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\ConnectionAdapter;
|
||||
use Ulmus\Entity\Mysql\Table;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\Migration\MigrateInterface;
|
||||
use Ulmus\Migration\SqlMigrationTrait;
|
||||
use Ulmus\QueryBuilder\Sql;
|
||||
use Ulmus\Common\PdoObject;
|
||||
use Ulmus\Pdo;
|
||||
|
||||
use Ulmus\Exception\AdapterConfigurationException;
|
||||
use Ulmus\Repository;
|
||||
|
||||
class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
use SqlAdapterTrait;
|
||||
use SqlAdapterTrait, SqlMigrationTrait;
|
||||
|
||||
const ALLOWED_ATTRIBUTES = [
|
||||
'default', 'primary_key', 'auto_increment', 'update',
|
||||
@@ -34,7 +39,9 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
public function __construct(
|
||||
?string $hostname = null,
|
||||
?string $database = null,
|
||||
#[\SensitiveParameter]
|
||||
?string $username = null,
|
||||
#[\SensitiveParameter]
|
||||
?string $password = null,
|
||||
?int $port = null,
|
||||
?string $charset = null
|
||||
@@ -64,10 +71,10 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public function connect() : PdoObject
|
||||
public function connect() : \PDO
|
||||
{
|
||||
try {
|
||||
$pdo = new PdoObject($this->buildDataSourceName(), $this->username, $this->password);
|
||||
$pdo = new Pdo\Mysql($this->buildDataSourceName(), $this->username, $this->password);
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
|
||||
$pdo->setAttribute(\PDO::ATTR_AUTOCOMMIT, false);
|
||||
@@ -136,9 +143,17 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public function escapeIdentifier(string $segment, int $type) : string
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$mapper = new MySQLFieldMapper($field);
|
||||
|
||||
return $typeOnly ? $mapper->type : $mapper->render();
|
||||
}
|
||||
|
||||
public static function escapeIdentifier(string $segment, int $type) : string
|
||||
{
|
||||
switch($type) {
|
||||
default:
|
||||
case static::IDENTIFIER_DATABASE:
|
||||
case static::IDENTIFIER_TABLE:
|
||||
case static::IDENTIFIER_FIELD:
|
||||
@@ -159,4 +174,33 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
return Sql\MysqlQueryBuilder::class;
|
||||
}
|
||||
|
||||
public function schemaTable(ConnectionAdapter $adapter, $databaseName, string $tableName) : null|object
|
||||
{
|
||||
return Table::repository(Repository::DEFAULT_ALIAS, $adapter)
|
||||
->select(\Ulmus\Common\Sql::raw('this.*'))
|
||||
->where($this->escapeIdentifier('table_schema', AdapterInterface::IDENTIFIER_FIELD), $databaseName)
|
||||
->loadOneFromField($this->escapeIdentifier('table_name', AdapterInterface::IDENTIFIER_FIELD), $tableName);
|
||||
}
|
||||
|
||||
|
||||
public function generateAlterColumn(FieldDefinition $definition, array $field) : string|\Stringable
|
||||
{
|
||||
if ($field['action'] === 'add') {
|
||||
if (! empty($field['previous'])) {
|
||||
$position = sprintf('AFTER %s', $this->escapeIdentifier($field['previous']->field, AdapterInterface::IDENTIFIER_FIELD));
|
||||
}
|
||||
else {
|
||||
$position = "FIRST";
|
||||
}
|
||||
}
|
||||
|
||||
return implode(" ", array_filter([
|
||||
strtoupper($field['action']),
|
||||
$this->escapeIdentifier($definition->getSqlName(), AdapterInterface::IDENTIFIER_FIELD),
|
||||
$definition->getSqlType(),
|
||||
$definition->getSqlParams(),
|
||||
$position ?? null,
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
|
||||
class MySQLFieldMapper extends SqlFieldMapper
|
||||
{
|
||||
public function map() : void
|
||||
{
|
||||
$type = $this->field->type;
|
||||
$length = $this->field->length;
|
||||
|
||||
if ( enum_exists($type) ) {
|
||||
# Haven't found a better way yet to check for BackendEnum without an instance of the object
|
||||
if ( ! method_exists($type, 'tryFrom') ) {
|
||||
throw new \Ulmus\Exception\BackedEnumRequired(sprintf("You must define your enum as a BackedEnum instead of an UnitEnum for field '%s'.", $this->field->getColumnName()));
|
||||
}
|
||||
|
||||
$this->length = implode(',', array_map(fn($e) => MySQL::escapeIdentifier($e->value, MySQL::IDENTIFIER_VALUE) , $type::cases()));
|
||||
$this->type = "ENUM";
|
||||
}
|
||||
else {
|
||||
parent::map();
|
||||
}
|
||||
}
|
||||
|
||||
public function postProcess() : void
|
||||
{
|
||||
if (
|
||||
in_array($this->type, [ 'BLOB', 'TINYBLOB', 'MEDIUMBLOB', 'LONGBLOB', 'JSON', 'TEXT', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'GEOMETRY' ]) &&
|
||||
! is_object($this->field->default ?? false) # Could be a functional default, which would now be valid
|
||||
) {
|
||||
unset($this->field->default);
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
-37
@@ -2,18 +2,18 @@
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Common\PdoObject;
|
||||
use Collator;
|
||||
use Ulmus\Pdo;
|
||||
use Ulmus\ConnectionAdapter;
|
||||
|
||||
use Ulmus\Entity;
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder};
|
||||
use Ulmus\{Migration\MigrateInterface, Migration\SqlMigrationTrait, Repository, QueryBuilder};
|
||||
|
||||
class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||
use SqlAdapterTrait;
|
||||
use SqlAdapterTrait, SqlMigrationTrait;
|
||||
|
||||
const ALLOWED_ATTRIBUTES = [
|
||||
'default', 'primary_key', 'auto_increment'
|
||||
'default', 'primary_key', 'auto_increment', 'collate nocase', 'collate binary', 'collate rtrim',
|
||||
];
|
||||
|
||||
const DSN_PREFIX = "sqlite";
|
||||
@@ -24,19 +24,20 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
public null|array $pragmaClose = null,
|
||||
) { }
|
||||
|
||||
public function connect() : PdoObject
|
||||
public function connect() : \Pdo
|
||||
{
|
||||
try {
|
||||
$pdo = new PdoObject($this->buildDataSourceName(), null, null);
|
||||
$pdo = new Pdo\Sqlite($this->buildDataSourceName(), null, null);
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
|
||||
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
|
||||
|
||||
$pdo->onClose = function(PdoObject $obj) {
|
||||
$pdo->onClose = function(\PDO $obj) {
|
||||
static::registerPragma($obj, $this->pragmaClose);
|
||||
};
|
||||
|
||||
$this->exportFunctions($pdo);
|
||||
$this->exportCollations($pdo);
|
||||
$this->registerPragma($pdo, $this->pragmaBegin);
|
||||
}
|
||||
catch(\PDOException $ex){
|
||||
@@ -61,9 +62,10 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
}
|
||||
|
||||
# https://sqlite.org/lang_keywords.html
|
||||
public function escapeIdentifier(string $segment, int $type) : string
|
||||
public static function escapeIdentifier(string $segment, int $type) : string
|
||||
{
|
||||
switch($type) {
|
||||
default:
|
||||
case static::IDENTIFIER_DATABASE:
|
||||
case static::IDENTIFIER_TABLE:
|
||||
case static::IDENTIFIER_FIELD:
|
||||
@@ -96,12 +98,12 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$type = $field->type;
|
||||
|
||||
$length = $field->length;
|
||||
|
||||
if ( is_a($type, Entity\Field\Date::class, true) || is_a($type, Entity\Field\Time::class, true) || is_a($type, \DateTime::class, true) ) {
|
||||
$type = "TEXT";
|
||||
$length = strlen((string) $type);
|
||||
|
||||
#$length = strlen((string) $type);
|
||||
}
|
||||
else {
|
||||
switch($type) {
|
||||
@@ -114,6 +116,10 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
break;
|
||||
|
||||
case "array":
|
||||
$type = "JSON";
|
||||
$length = null;
|
||||
break;
|
||||
|
||||
case "string":
|
||||
$type = "TEXT";
|
||||
$length = null;
|
||||
@@ -129,7 +135,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
}
|
||||
}
|
||||
|
||||
return $typeOnly ? $type : $type . ( $length ? "($length" . ( isset($precision) ? ",$precision" : "" ) . ")" : "" );
|
||||
return $typeOnly ? $type : $type . ( $length ? "($length" . ")" : "" );
|
||||
}
|
||||
|
||||
public function tableSyntax() : array
|
||||
@@ -151,28 +157,28 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
return QueryBuilder\Sql\SqliteQueryBuilder::class;
|
||||
}
|
||||
|
||||
public function exportFunctions(PdoObject $pdo) : void
|
||||
public function exportFunctions(\PDO $pdo) : void
|
||||
{
|
||||
$pdo->sqliteCreateFunction('if', fn($comparison, $yes, $no) => $comparison ? $yes : $no, 3);
|
||||
$pdo->sqliteCreateFunction('length', fn($string) => strlen($string), 1);
|
||||
$pdo->sqliteCreateFunction('lcase', fn($string) => strtolower($string), 1);
|
||||
$pdo->sqliteCreateFunction('ucase', fn($string) => strtoupper($string), 1);
|
||||
$pdo->sqliteCreateFunction('md5', fn($string) => md5($string), 1);
|
||||
$pdo->sqliteCreateFunction('sha1', fn($string) => sha1($string), 1);
|
||||
$pdo->sqliteCreateFunction('sha256', fn($string) => hash('sha256', $string), 1);
|
||||
$pdo->sqliteCreateFunction('sha512', fn($string) => hash('sha512', $string), 1);
|
||||
$pdo->sqliteCreateFunction('whirlpool', fn($string) => hash('whirlpool', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3a', fn($string) => hash('murmur3a', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3c', fn($string) => hash('murmur3c', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3f', fn($string) => hash('murmur3f', $string), 1);
|
||||
$pdo->sqliteCreateFunction('left', fn($string, $length) => substr($string, 0, $length), 2);
|
||||
$pdo->sqliteCreateFunction('right', fn($string, $length) => substr($string, -$length), 2);
|
||||
$pdo->sqliteCreateFunction('strcmp', fn($s1, $s2) => strcmp($s1, $s2), 2);
|
||||
$pdo->sqliteCreateFunction('lpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_LEFT), 3);
|
||||
$pdo->sqliteCreateFunction('rpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_RIGHT), 3);
|
||||
$pdo->sqliteCreateFunction('concat', fn(...$args) => implode('', $args), -1);
|
||||
$pdo->sqliteCreateFunction('concat_ws', fn($separator, ...$args) => implode($separator, $args), -1);
|
||||
$pdo->sqliteCreateFunction('find_in_set', function($string, $string_list) {
|
||||
$pdo->createFunction('if', fn($comparison, $yes, $no) => $comparison ? $yes : $no, 3);
|
||||
$pdo->createFunction('length', fn($string) => strlen($string), 1);
|
||||
$pdo->createFunction('lcase', fn($string) => strtolower($string), 1);
|
||||
$pdo->createFunction('ucase', fn($string) => strtoupper($string), 1);
|
||||
$pdo->createFunction('md5', fn($string) => md5($string), 1);
|
||||
$pdo->createFunction('sha1', fn($string) => sha1($string), 1);
|
||||
$pdo->createFunction('sha256', fn($string) => hash('sha256', $string), 1);
|
||||
$pdo->createFunction('sha512', fn($string) => hash('sha512', $string), 1);
|
||||
$pdo->createFunction('whirlpool', fn($string) => hash('whirlpool', $string), 1);
|
||||
$pdo->createFunction('murmur3a', fn($string) => hash('murmur3a', $string), 1);
|
||||
$pdo->createFunction('murmur3c', fn($string) => hash('murmur3c', $string), 1);
|
||||
$pdo->createFunction('murmur3f', fn($string) => hash('murmur3f', $string), 1);
|
||||
$pdo->createFunction('left', fn($string, $length) => substr($string, 0, $length), 2);
|
||||
$pdo->createFunction('right', fn($string, $length) => substr($string, -$length), 2);
|
||||
$pdo->createFunction('strcmp', fn($s1, $s2) => strcmp($s1, $s2), 2);
|
||||
$pdo->createFunction('lpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_LEFT), 3);
|
||||
$pdo->createFunction('rpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_RIGHT), 3);
|
||||
$pdo->createFunction('concat', fn(...$args) => implode('', $args), -1);
|
||||
$pdo->createFunction('concat_ws', fn($separator, ...$args) => implode($separator, $args), -1);
|
||||
$pdo->createFunction('find_in_set', function($string, $string_list) {
|
||||
if ( $string === null || $string_list === null ) {
|
||||
return null;
|
||||
}
|
||||
@@ -183,12 +189,43 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
|
||||
return (int) in_array($string, explode(',', $string_list));
|
||||
}, 2);
|
||||
$pdo->sqliteCreateFunction('day', fn($date) => ( new \DateTime($date) )->format('d'), 1);
|
||||
$pdo->sqliteCreateFunction('month', fn($date) => ( new \DateTime($date) )->format('m'), 1);
|
||||
$pdo->sqliteCreateFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
||||
$pdo->createFunction('day', fn($date) => ( new \DateTime($date) )->format('j'), 1);
|
||||
$pdo->createFunction('month', fn($date) => ( new \DateTime($date) )->format('n'), 1);
|
||||
$pdo->createFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
||||
$pdo->createFunction('str_to_date', fn($value, $format) => ($f = \DateTime::createFromFormat($format, $value)) ? $f->format('Y-m-d H:i:s') : false);
|
||||
}
|
||||
|
||||
public static function registerPragma(PdoObject $pdo, array $pragmaList) : void
|
||||
public function exportCollations(\PDO $pdo) : void
|
||||
{
|
||||
|
||||
if ( class_exists('Locale') ) {
|
||||
# @TODO debug this, case-sensitivity not working properly !!
|
||||
$collator = new Collator(\Locale::getDefault());
|
||||
$collator->setStrength(Collator::TERTIARY);
|
||||
$collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
|
||||
|
||||
$pdo->createCollation('locale_cmp', fn($e1, $e2) => $collator->compare($e1, $e2));
|
||||
$pdo->createCollation('locale_cmp_desc', fn($e1, $e2) => $collator->compare($e2, $e1));
|
||||
|
||||
$collatorCi = new Collator(\Locale::getDefault());
|
||||
$collatorCi->setStrength(Collator::SECONDARY);
|
||||
$collatorCi->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
|
||||
|
||||
$pdo->createCollation('locale_cmp_ci', fn($e1, $e2) => $collatorCi->compare($e1, $e2));
|
||||
$pdo->createCollation('locale_cmp_ci_desc', fn($e1, $e2) => $collatorCi->compare($e2, $e1));
|
||||
}
|
||||
else {
|
||||
$comp = fn(string $e1, string $e2) => \iconv('UTF-8', 'ASCII//TRANSLIT', $e1) <=> \iconv('UTF-8', 'ASCII//TRANSLIT', $e2);
|
||||
$pdo->createCollation('locale_cmp', fn($e1, $e2) => $comp);
|
||||
$pdo->createCollation('locale_cmp_desc', fn($e2, $e1) => $comp);
|
||||
|
||||
$compCi = fn(string $e1, string $e2) => strtoupper(\iconv('UTF-8', 'ASCII//TRANSLIT', $e1)) <=> strtoupper(\iconv('UTF-8', 'ASCII//TRANSLIT', $e2));
|
||||
$pdo->createCollation('locale_cmp_ci', fn($e1, $e2) => $compCi);
|
||||
$pdo->createCollation('locale_cmp_ci_desc', fn($e2, $e1) => $compCi);
|
||||
}
|
||||
}
|
||||
|
||||
public static function registerPragma(\PDO $pdo, array $pragmaList) : void
|
||||
{
|
||||
$builder = new QueryBuilder\Sql\SqliteQueryBuilder();
|
||||
|
||||
@@ -216,6 +253,11 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
||||
]);
|
||||
}
|
||||
|
||||
public function supportAlterColumnAction(string $action)
|
||||
{
|
||||
return in_array(strtolower($action), [ 'add' ]);
|
||||
}
|
||||
|
||||
public function splitAlterQuery() : bool
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -4,6 +4,6 @@ namespace Ulmus\Adapter;
|
||||
|
||||
interface SqlAdapterInterface
|
||||
{
|
||||
public function escapeIdentifier(string $segment, int $type) : string;
|
||||
public static function escapeIdentifier(string $segment, int $type) : string;
|
||||
public function defaultEngine() : ? string;
|
||||
}
|
||||
@@ -36,95 +36,11 @@ trait SqlAdapterTrait
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function schemaTable(ConnectionAdapter $adapter, $databaseName, string $tableName) : null|object
|
||||
{
|
||||
return Table::repository(Repository::DEFAULT_ALIAS, $adapter)
|
||||
->select(\Ulmus\Common\Sql::raw('this.*'))
|
||||
->where($this->escapeIdentifier('table_schema', AdapterInterface::IDENTIFIER_FIELD), $databaseName)
|
||||
->loadOneFromField($this->escapeIdentifier('table_name', AdapterInterface::IDENTIFIER_FIELD), $tableName);
|
||||
}
|
||||
|
||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||
{
|
||||
$type = $field->type;
|
||||
|
||||
$length = $field->length;
|
||||
|
||||
if ( is_a($type, Entity\Field\Date::class, true) ) {
|
||||
$type = "DATE";
|
||||
}
|
||||
elseif ( is_a($type, Entity\Field\Time::class, true) ) {
|
||||
$type = "TIME";
|
||||
}
|
||||
elseif ( is_a($type, \DateTime::class, true) ) {
|
||||
$type = "DATETIME";
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
case "bool":
|
||||
$type = "TINYINT";
|
||||
$length = 1;
|
||||
break;
|
||||
|
||||
case "array":
|
||||
case "string":
|
||||
if ($length && $length <= 255) {
|
||||
$type = "VARCHAR";
|
||||
break;
|
||||
}
|
||||
elseif (! $length || ( $length <= 65535 ) ) {
|
||||
$type = "TEXT";
|
||||
}
|
||||
elseif ( $length <= 16777215 ) {
|
||||
$type = "MEDIUMTEXT";
|
||||
}
|
||||
elseif ($length <= 4294967295) {
|
||||
$type = "LONGTEXT";
|
||||
}
|
||||
else {
|
||||
throw new \Exception("A column with size bigger than 4GB cannot be created.");
|
||||
}
|
||||
|
||||
# Length is unnecessary on TEXT fields
|
||||
unset($length);
|
||||
|
||||
break;
|
||||
|
||||
case "float":
|
||||
$type = "DOUBLE";
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = strtoupper($type);
|
||||
break;
|
||||
}
|
||||
|
||||
return $typeOnly ? $type : $type . ( isset($length) ? "($length" . ( ! empty($precision) ? ",$precision" : "" ) . ")" : "" );
|
||||
}
|
||||
|
||||
public function whitelistAttributes(array &$parameters) : void
|
||||
{
|
||||
$parameters = array_intersect_key($parameters, array_flip(static::ALLOWED_ATTRIBUTES));
|
||||
}
|
||||
|
||||
public function generateAlterColumn(FieldDefinition $definition, array $field) : string|\Stringable
|
||||
{
|
||||
if (! empty($field['previous']) ) {
|
||||
$position = sprintf('AFTER %s', $this->escapeIdentifier($field['previous']->field, AdapterInterface::IDENTIFIER_FIELD));
|
||||
}
|
||||
else {
|
||||
$position = "FIRST";
|
||||
}
|
||||
|
||||
return implode(" ", [
|
||||
strtoupper($field['action']),
|
||||
$this->escapeIdentifier($definition->getSqlName(), AdapterInterface::IDENTIFIER_FIELD),
|
||||
$definition->getSqlType(),
|
||||
$definition->getSqlParams(),
|
||||
$position,
|
||||
]);
|
||||
}
|
||||
|
||||
public function writableValue(mixed $value) : mixed
|
||||
{
|
||||
switch (true) {
|
||||
@@ -143,9 +59,4 @@ trait SqlAdapterTrait
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function splitAlterQuery() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Adapter;
|
||||
|
||||
use Ulmus\Migration\FieldDefinition;
|
||||
use Ulmus\Entity;
|
||||
|
||||
class SqlFieldMapper
|
||||
{
|
||||
public string $type;
|
||||
|
||||
public string $length;
|
||||
|
||||
public function __construct(
|
||||
public FieldDefinition $field,
|
||||
) {
|
||||
$this->map();
|
||||
}
|
||||
|
||||
public function map() : void
|
||||
{
|
||||
$type = $this->field->type;
|
||||
$length = $this->field->length;
|
||||
|
||||
if ( is_a($type, Entity\Field\Date::class, true) ) {
|
||||
$type = "DATE";
|
||||
}
|
||||
elseif ( is_a($type, Entity\Field\Time::class, true) ) {
|
||||
$type = "TIME";
|
||||
}
|
||||
elseif ( is_a($type, \DateTime::class, true) ) {
|
||||
$type = "DATETIME";
|
||||
}
|
||||
elseif ( enum_exists($type) ) {
|
||||
# Haven't found a better way yet to check for BackendEnum without an instance of the object
|
||||
if ( ! method_exists($type, 'tryFrom') ) {
|
||||
throw new \Ulmus\Exception\BackedEnumRequired(sprintf("You must define your enum as a BackedEnum instead of an UnitEnum for field '%s'.", $this->field->getColumnName()));
|
||||
}
|
||||
|
||||
$type = "string";
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
case "bool":
|
||||
$this->type = "TINYINT";
|
||||
$this->length = 1;
|
||||
break;
|
||||
|
||||
case "array":
|
||||
# Was set at JSON, but for now LONGTEXT is an alias of it (with additional constraints)
|
||||
$this->type = "LONGTEXT";
|
||||
break;
|
||||
|
||||
case "string":
|
||||
if ($length && $length <= 255) {
|
||||
$this->type = "VARCHAR";
|
||||
$this->length = $length;
|
||||
break;
|
||||
}
|
||||
elseif (! $length || ( $length <= 65535 ) ) {
|
||||
$this->type = "TEXT";
|
||||
}
|
||||
elseif ( $length <= 16777215 ) {
|
||||
$this->type = "MEDIUMTEXT";
|
||||
}
|
||||
elseif ($length <= 4294967295) {
|
||||
$this->type = "LONGTEXT";
|
||||
}
|
||||
else {
|
||||
throw new \Exception("A column with a length bigger than 4GB cannot be created.");
|
||||
}
|
||||
|
||||
# Length is unnecessary on TEXT fields
|
||||
unset($length);
|
||||
|
||||
break;
|
||||
|
||||
case "float":
|
||||
$this->type = "DOUBLE";
|
||||
|
||||
default:
|
||||
if ($length) {
|
||||
$this->length = $length;
|
||||
}
|
||||
|
||||
$this->type ??= strtoupper($type);
|
||||
}
|
||||
|
||||
$this->postProcess();
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->type . ( isset($this->length) ? "($this->length)" : "" );
|
||||
}
|
||||
|
||||
public function postProcess() : void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Classes;
|
||||
|
||||
class Collation implements \Notes\Annotation {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Classes;
|
||||
|
||||
class Method implements \Notes\Annotation {
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Classes;
|
||||
|
||||
class Table implements \Notes\Annotation {
|
||||
|
||||
public string $name;
|
||||
|
||||
public string $database;
|
||||
|
||||
public string $schema;
|
||||
|
||||
public string $adapter;
|
||||
|
||||
public string $engine;
|
||||
|
||||
public function __construct($name = null, $engine = null)
|
||||
{
|
||||
if ( $name !== null ) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
if ( $engine !== null ) {
|
||||
$this->engine = $engine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Field implements \Notes\Annotation {
|
||||
|
||||
public string $type;
|
||||
|
||||
public string $name;
|
||||
|
||||
public int|string $length;
|
||||
|
||||
public int $precision;
|
||||
|
||||
public array $attributes = [];
|
||||
|
||||
public bool $nullable;
|
||||
|
||||
public /* mixed */ $default;
|
||||
|
||||
public bool $readonly = false;
|
||||
|
||||
public function __construct(? string $type = null, ? int $length = null)
|
||||
{
|
||||
if ( $type !== null ) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
if ( $length !== null ) {
|
||||
$this->length = $length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Bigint extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "bigint", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Blob extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "blob", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class CreatedAt extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->nullable = false;
|
||||
$this->type = "timestamp";
|
||||
$this->attributes['default'] = "CURRENT_TIMESTAMP";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Date extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct(? string $type = "date", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Datetime extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct(? string $type = "datetime", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
/**
|
||||
* Since we need consistancy between the declaration of our ID and FK fields, it
|
||||
* was decided to extend the Id class instead of Field for this case.
|
||||
*/
|
||||
class ForeignKey extends PrimaryKey {
|
||||
|
||||
public function __construct(? string $type = null, ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
|
||||
unset($this->nullable);
|
||||
$this->attributes['primary_key'] = false;
|
||||
$this->attributes['auto_increment'] = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Id extends \Ulmus\Annotation\Property\Field\PrimaryKey {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->attributes['unsigned'] = true;
|
||||
$this->attributes['auto_increment'] = true;
|
||||
|
||||
parent::__construct('bigint');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Longblob extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "longblob", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Longtext extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "longtext", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Mediumblob extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "mediumblob", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Mediumtext extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "mediumtext", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class PrimaryKey extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct(? string $type = null, ? int $length = null)
|
||||
{
|
||||
$this->nullable = false;
|
||||
$this->attributes['primary_key'] = true;
|
||||
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Text extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "text", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Time extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct(? string $type = "time", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Blob extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "tinyblob", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class Tinyint extends \Ulmus\Annotation\Property\Field
|
||||
{
|
||||
public function __construct(? string $type = "tinyint", ? int $length = null)
|
||||
{
|
||||
parent::__construct($type, $length);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Field;
|
||||
|
||||
class UpdatedAt extends \Ulmus\Annotation\Property\Field {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->nullable = true;
|
||||
$this->type = "timestamp";
|
||||
$this->attributes['update'] = "CURRENT_TIMESTAMP";
|
||||
$this->attributes['default'] = null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Filter implements \Notes\Annotation {
|
||||
|
||||
public string $method;
|
||||
|
||||
public function __construct(string $method = null)
|
||||
{
|
||||
if ( $method !== null ) {
|
||||
$this->method = $method;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class FilterJoin implements \Notes\Annotation {
|
||||
|
||||
public string $method;
|
||||
|
||||
public function __construct(string $method = null)
|
||||
{
|
||||
if ( $method !== null ) {
|
||||
$this->method = $method;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class GroupBy implements \Notes\Annotation {
|
||||
|
||||
public array $fields = [];
|
||||
|
||||
public function __construct(...$field)
|
||||
{
|
||||
if ( $field ) {
|
||||
$this->fields = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Having extends Where {}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Join implements \Notes\Annotation {
|
||||
|
||||
public string $type;
|
||||
|
||||
public string|Stringable $key;
|
||||
|
||||
public string|Stringable $foreignKey;
|
||||
|
||||
public string $entity;
|
||||
|
||||
public string $alias;
|
||||
|
||||
public function __construct(? string $type = null, /*? string|Stringable*/ $key = null, /*? string|Stringable*/ $foreignKey = null)
|
||||
{
|
||||
if ($type !== null) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
if ($key !== null) {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
if ($foreignKey !== null) {
|
||||
$this->foreignKey = $foreignKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class On extends Where {}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
use Ulmus\Query;
|
||||
|
||||
class OrWhere extends Where {
|
||||
|
||||
public function __construct(/* ? Stringable */ $field = null, $value = null, ? string $operator = null, ? string $condition = null)
|
||||
{
|
||||
parent::__construct($field, $value, $operator, Query\Where::CONDITION_OR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class OrderBy implements \Notes\Annotation {
|
||||
|
||||
public string $field;
|
||||
|
||||
public string $order = "ASC";
|
||||
|
||||
public function __construct(string $field = null, string $order = null)
|
||||
{
|
||||
if ( $field !== null ) {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
if ( $order !== null ) {
|
||||
$this->order = $order;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Relation implements \Notes\Annotation {
|
||||
|
||||
public string $type;
|
||||
|
||||
public /*stringable*/ $key;
|
||||
|
||||
public /* callable */ $generateKey;
|
||||
|
||||
public /*stringable*/ $foreignKey;
|
||||
|
||||
public array $foreignKeys;
|
||||
|
||||
public string $bridge;
|
||||
|
||||
public /*stringable*/ $bridgeKey;
|
||||
|
||||
public /*stringable*/ $bridgeForeignKey;
|
||||
|
||||
public string $entity;
|
||||
|
||||
public string $join;
|
||||
|
||||
public string $function = "loadAll";
|
||||
|
||||
public function __construct(string $type = null)
|
||||
{
|
||||
if ( $type !== null ) {
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
||||
|
||||
public function entity() {
|
||||
try {
|
||||
$e = $this->entity;
|
||||
} catch (\Throwable $ex) {
|
||||
throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry.");
|
||||
}
|
||||
|
||||
return new $e();
|
||||
}
|
||||
|
||||
public function bridge() {
|
||||
$e = $this->bridge;
|
||||
|
||||
return new $e();
|
||||
}
|
||||
|
||||
public function normalizeType() : string
|
||||
{
|
||||
return strtolower(str_replace(['-', '_', ' '], '', $this->type));
|
||||
}
|
||||
|
||||
public function isOneToOne() : bool
|
||||
{
|
||||
return $this->normalizeType() === 'onetoone';
|
||||
}
|
||||
|
||||
public function isOneToMany() : bool
|
||||
{
|
||||
return $this->normalizeType() === 'onetomany';
|
||||
}
|
||||
|
||||
public function isManyToMany() : bool
|
||||
{
|
||||
return $this->normalizeType() === 'manytomany';
|
||||
}
|
||||
|
||||
public function function() : string
|
||||
{
|
||||
if ($this->function) {
|
||||
return $this->function;
|
||||
}
|
||||
elseif ($this->isOneToOne()) {
|
||||
return 'load';
|
||||
}
|
||||
|
||||
return 'loadAll';
|
||||
}
|
||||
|
||||
public function hasBridge() : bool
|
||||
{
|
||||
return isset($this->bridge);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property\Relation;
|
||||
|
||||
class Ignore implements \Notes\Annotation {}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class Virtual extends Field {
|
||||
|
||||
public bool $readonly = true;
|
||||
|
||||
public \Closure $closure;
|
||||
|
||||
public string $method;
|
||||
|
||||
public function __construct(? \Closure $closure = null)
|
||||
{
|
||||
if ( $closure !== null ) {
|
||||
$this->closure = $closure;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
use Ulmus\Query;
|
||||
|
||||
class Where implements \Notes\Annotation {
|
||||
|
||||
public /* stringable */ $field;
|
||||
|
||||
public $value;
|
||||
|
||||
public string $operator;
|
||||
|
||||
public string $condition;
|
||||
|
||||
public function __construct(/* ? Stringable */ $field = null, $value = null, ? string $operator = null, ? string $condition = null)
|
||||
{
|
||||
if ( $field !== null ) {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
if ( $value !== null ) {
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
$this->operator = $operator !== null ? $operator : Query\Where::OPERATOR_EQUAL;
|
||||
$this->condition = $condition !== null ? $condition : Query\Where::CONDITION_AND;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Annotation\Property;
|
||||
|
||||
class WithJoin implements \Notes\Annotation {
|
||||
|
||||
protected array $joins;
|
||||
|
||||
public function __construct(/*Stringable|array|null*/ $joins = null)
|
||||
{
|
||||
if ( $joins ) {
|
||||
$this->joins = (array)$joins;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,12 @@ class Attribute
|
||||
public static function handleArrayField(null|\Stringable|string|array $field, null|string|bool $alias = Repository::DEFAULT_ALIAS, string $separator = ', ') : mixed
|
||||
{
|
||||
if ( is_array($field) ) {
|
||||
if (count($field) < 2) {
|
||||
throw new \RuntimeException(
|
||||
sprintf("Array field must be formed of at least two things, a class name, and a property. (received %s)", json_encode($field))
|
||||
);
|
||||
}
|
||||
|
||||
$class = array_shift($field);
|
||||
$field[1] ??= $alias;
|
||||
|
||||
|
||||
@@ -4,5 +4,7 @@ namespace Ulmus\Attribute\Obj;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Collation {
|
||||
|
||||
public function __construct(
|
||||
public string $name = ""
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Obj;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class JsonSerialize {
|
||||
public function __construct(
|
||||
public bool $includeRelations = true,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
use Notes\Common\ReflectedProperty;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
use Ulmus\Entity\JsonUnserializable;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class ArrayOf implements \Ulmus\Entity\EntityValueModifier
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $type,
|
||||
) {}
|
||||
|
||||
public function push(mixed $value, ReflectedProperty $property): mixed
|
||||
{
|
||||
$return = [];
|
||||
|
||||
foreach($value as $index => $item) {
|
||||
if (! is_object($item)) {
|
||||
if (enum_exists($this->type)) {
|
||||
if ($this->type::tryFrom($item) === null) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Given item '%s' is not a valid enum for type %s ; try one of theses instead : %s", $item, $this->type, implode("', '", array_map(fn($e) => $e->value, $this->type::cases())))
|
||||
);
|
||||
} else {
|
||||
$obj = $this->type::from($item);
|
||||
}
|
||||
}
|
||||
elseif (class_exists($this->type)) {
|
||||
if (is_subclass_of($this->type, JsonUnserializable::class)) {
|
||||
$obj = (new \ReflectionClass($this->type))->newInstanceWithoutConstructor();
|
||||
$obj->jsonUnserialize($item);
|
||||
}
|
||||
else {
|
||||
$obj = new $this->type($item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException("Given type for ArrayOf is incompatible with it's use. An object should be provided");
|
||||
}
|
||||
|
||||
$return[$index] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $property->type->builtIn) {
|
||||
$cls = $property->type->type;
|
||||
|
||||
return new $cls($return);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function pull(mixed $value, ReflectedProperty $property) : mixed
|
||||
{
|
||||
$return = [];
|
||||
|
||||
foreach($value as $index => $item) {
|
||||
if (is_object($item)) {
|
||||
if (enum_exists($this->type)) {
|
||||
$value = $item->value;
|
||||
} elseif (class_exists($this->type)) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
$return[$index] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Collation {
|
||||
public function __construct(
|
||||
public string $name = ""
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Field {
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public null|int $decimal = null,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Bigint extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Binary extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "binary",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Bit extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Blob extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Char extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "char",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -13,6 +13,5 @@ class CreatedAt extends \Ulmus\Attribute\Property\Field {
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -11,6 +11,5 @@ class Date extends \Ulmus\Attribute\Property\Field {
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -11,6 +11,5 @@ class Datetime extends \Ulmus\Attribute\Property\Field {
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Decimal extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Double extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "float",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Float extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ class ForeignKey extends PrimaryKey {
|
||||
public null|string $relation = null,
|
||||
public ConstrainActionEnum $onDelete = ConstrainActionEnum::NoAction,
|
||||
public ConstrainActionEnum $onUpdate = ConstrainActionEnum::NoAction,
|
||||
public string $description = "",
|
||||
) {
|
||||
#$this->references = Attribute::handleArrayField($this->references, false);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ class Id extends \Ulmus\Attribute\Property\Field {
|
||||
],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
public bool $readonly = true,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Json extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "json",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Longblob extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Longtext extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Mediumblob extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Mediumint extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Mediumtext extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Numeric extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -16,6 +16,5 @@ class PrimaryKey extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Select {
|
||||
public function __construct(
|
||||
public string $sql,
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Smallint extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Text extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -12,6 +12,5 @@ class Time extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -12,6 +12,5 @@ class Timestamp extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Blob extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Tinyint extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class Tinytext extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -15,6 +15,5 @@ class UpdatedAt extends \Ulmus\Attribute\Property\Field
|
||||
public bool $nullable = true,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Varbinary extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "varbinary",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Varchar extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "varchar",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Field;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Year extends \Ulmus\Attribute\Property\Field
|
||||
{
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = "year",
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [],
|
||||
public bool $nullable = false,
|
||||
public mixed $default = null,
|
||||
public bool $readonly = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
}
|
||||
@@ -6,6 +6,5 @@ namespace Ulmus\Attribute\Property;
|
||||
class Filter {
|
||||
public function __construct(
|
||||
public string $method = ""
|
||||
)
|
||||
{}
|
||||
) {}
|
||||
}
|
||||
@@ -3,9 +3,10 @@
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
use Ulmus\Attribute\Attribute;
|
||||
use Ulmus\Repository;
|
||||
|
||||
#[\Attribute]
|
||||
class Join {
|
||||
class Join implements ResettablePropertyInterface {
|
||||
public function __construct(
|
||||
public string $type,
|
||||
public null|string|\Stringable|array $key = null,
|
||||
@@ -16,4 +17,35 @@ class Join {
|
||||
$this->key = Attribute::handleArrayField($this->key);
|
||||
$this->foreignKey = Attribute::handleArrayField($this->foreignKey);
|
||||
}
|
||||
|
||||
## AWAITING THE Closures in constant expression from PHP 8.5 !
|
||||
public function foreignKey(? Repository $repository = null) : mixed
|
||||
{
|
||||
if (is_string($this->foreignKey)) {
|
||||
if (str_starts_with($this->foreignKey, 'fn(') && str_contains($this->foreignKey, '=>')) {
|
||||
$closure = eval("return {$this->foreignKey};");
|
||||
|
||||
return $repository ? $closure($repository) : $closure;
|
||||
}
|
||||
|
||||
return $this->entity::field($this->foreignKey, $this->alias);
|
||||
}
|
||||
|
||||
return $this->foreignKey;
|
||||
}
|
||||
|
||||
public function isOneToOne() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isOneToMany() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isManyToMany() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class JsonSerialize {
|
||||
public function __construct(
|
||||
public bool $ignoreField = false,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Limit {
|
||||
public function __construct(
|
||||
public int $value,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Offset {
|
||||
public function __construct(
|
||||
public int $value,
|
||||
) {}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ class OrWhere extends Where {
|
||||
public string $operator = Query\Where::OPERATOR_EQUAL,
|
||||
public string $condition = Query\Where::CONDITION_OR,
|
||||
public string|\Stringable|array|null $fieldValue = null,
|
||||
public null|array $generateValue = null,
|
||||
public null|array|\Closure $generateValue = null,
|
||||
) {
|
||||
parent::__construct($field, $value, $operator, $condition, $fieldValue, $generateValue);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
use Ulmus\Attribute\Attribute;
|
||||
use Ulmus\Repository;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Relation {
|
||||
class Relation implements ResettablePropertyInterface {
|
||||
public function __construct(
|
||||
public Relation\RelationTypeEnum|string $type,
|
||||
public \Stringable|string|array $key = "",
|
||||
@@ -21,6 +22,7 @@ class Relation {
|
||||
public null|string $entity = null,
|
||||
public null|string $join = null,
|
||||
public null|string $function = null,
|
||||
public null|string $alias = null,
|
||||
) {
|
||||
$this->key = Attribute::handleArrayField($this->key);
|
||||
$this->foreignKey = Attribute::handleArrayField($this->foreignKey);
|
||||
@@ -35,7 +37,7 @@ class Relation {
|
||||
try {
|
||||
$e = $this->entity;
|
||||
} catch (\Throwable $ex) {
|
||||
throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry.");
|
||||
throw new \Exception("Your @Relation attribute seems to be missing an `entity` entry.");
|
||||
}
|
||||
|
||||
return new $e();
|
||||
@@ -83,4 +85,20 @@ class Relation {
|
||||
{
|
||||
return (bool) $this->bridge;
|
||||
}
|
||||
|
||||
## AWAITING THE Closures in constant expression from PHP 8.5 !
|
||||
public function foreignKey(? Repository $repository = null) : mixed
|
||||
{
|
||||
if (is_string($this->foreignKey)) {
|
||||
if (str_starts_with($this->foreignKey, 'fn(') && str_contains($this->foreignKey, '=>')) {
|
||||
$closure = eval("return {$this->foreignKey};");
|
||||
|
||||
return $repository ? $closure($repository) : $closure;
|
||||
}
|
||||
|
||||
return $this->entity::field($this->foreignKey, $this->alias);
|
||||
}
|
||||
|
||||
return $this->foreignKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Relation;
|
||||
|
||||
use Ulmus\Attribute\Property\Relation;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class ManyToMany extends Relation
|
||||
{
|
||||
public function __construct(
|
||||
public \Stringable|string|array $key = "",
|
||||
public null|\Closure|array $generateKey = null,
|
||||
public null|\Stringable|string|array $foreignKey = null,
|
||||
public null|\Stringable|string|array $foreignField = null,
|
||||
public array $foreignKeys = [],
|
||||
public null|string $bridge = null,
|
||||
public null|\Stringable|string|array $bridgeKey = null,
|
||||
public null|\Stringable|string|array $bridgeField = null,
|
||||
public null|\Stringable|string|array $bridgeForeignKey = null,
|
||||
public null|\Stringable|string|array $field = null,
|
||||
public null|string $entity = null,
|
||||
public null|string $join = null,
|
||||
public null|string $function = null,
|
||||
) {
|
||||
parent::__construct(
|
||||
RelationTypeEnum::manyToMany,
|
||||
$this->key,
|
||||
$this->generateKey,
|
||||
$this->foreignKey,
|
||||
$this->foreignField,
|
||||
$this->foreignKeys,
|
||||
$this->bridge,
|
||||
$this->bridgeKey,
|
||||
$this->bridgeField,
|
||||
$this->bridgeForeignKey,
|
||||
$this->field,
|
||||
$this->entity,
|
||||
$this->join,
|
||||
$this->function,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Relation;
|
||||
|
||||
use Ulmus\Attribute\Property\Relation;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class OneToMany extends Relation
|
||||
{
|
||||
public function __construct(
|
||||
public \Stringable|string|array $key = "",
|
||||
public null|\Closure|array $generateKey = null,
|
||||
public null|\Stringable|string|array $foreignKey = null,
|
||||
public null|\Stringable|string|array $foreignField = null,
|
||||
public array $foreignKeys = [],
|
||||
public null|string $bridge = null,
|
||||
public null|\Stringable|string|array $bridgeKey = null,
|
||||
public null|\Stringable|string|array $bridgeField = null,
|
||||
public null|\Stringable|string|array $bridgeForeignKey = null,
|
||||
public null|\Stringable|string|array $field = null,
|
||||
public null|string $entity = null,
|
||||
public null|string $join = null,
|
||||
public null|string $function = null,
|
||||
) {
|
||||
parent::__construct(
|
||||
RelationTypeEnum::oneToMany,
|
||||
$this->key,
|
||||
$this->generateKey,
|
||||
$this->foreignKey,
|
||||
$this->foreignField,
|
||||
$this->foreignKeys,
|
||||
$this->bridge,
|
||||
$this->bridgeKey,
|
||||
$this->bridgeField,
|
||||
$this->bridgeForeignKey,
|
||||
$this->field,
|
||||
$this->entity,
|
||||
$this->join,
|
||||
$this->function,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property\Relation;
|
||||
|
||||
use Ulmus\Attribute\Property\Relation;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class OneToOne extends Relation
|
||||
{
|
||||
public function __construct(
|
||||
public \Stringable|string|array $key = "",
|
||||
public null|\Closure|array $generateKey = null,
|
||||
public null|\Stringable|string|array $foreignKey = null,
|
||||
public null|\Stringable|string|array $foreignField = null,
|
||||
public array $foreignKeys = [],
|
||||
public null|string $bridge = null,
|
||||
public null|\Stringable|string|array $bridgeKey = null,
|
||||
public null|\Stringable|string|array $bridgeField = null,
|
||||
public null|\Stringable|string|array $bridgeForeignKey = null,
|
||||
public null|\Stringable|string|array $field = null,
|
||||
public null|string $entity = null,
|
||||
public null|string $join = null,
|
||||
public null|string $function = null,
|
||||
) {
|
||||
parent::__construct(
|
||||
RelationTypeEnum::oneToOne,
|
||||
$this->key,
|
||||
$this->generateKey,
|
||||
$this->foreignKey,
|
||||
$this->foreignField,
|
||||
$this->foreignKeys,
|
||||
$this->bridge,
|
||||
$this->bridgeKey,
|
||||
$this->bridgeField,
|
||||
$this->bridgeForeignKey,
|
||||
$this->field,
|
||||
$this->entity,
|
||||
$this->join,
|
||||
$this->function,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
interface ResettablePropertyInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -3,13 +3,14 @@
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class Virtual extends Field {
|
||||
class Virtual extends Field implements ResettablePropertyInterface {
|
||||
|
||||
public bool $readonly = true;
|
||||
|
||||
public function __construct(
|
||||
public null|string|array $method = null,
|
||||
public ? \Closure $closure = null,
|
||||
public null|string $name = null,
|
||||
) {
|
||||
$this->method ??= [ static::class, 'noop' ];
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ use Ulmus\Query;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||
class Where {
|
||||
|
||||
public function __construct(
|
||||
public string|\Stringable|array $field,
|
||||
public mixed $value = null,
|
||||
public string $operator = Query\Where::OPERATOR_EQUAL,
|
||||
public string $condition = Query\Where::CONDITION_AND,
|
||||
public string|\Stringable|array|null $fieldValue = null,
|
||||
public null|array $generateValue = null,
|
||||
public null|array|\Closure $generateValue = null,
|
||||
) {
|
||||
$this->field = Attribute::handleArrayField($field);
|
||||
$this->fieldValue = Attribute::handleArrayField($fieldValue);
|
||||
@@ -21,15 +22,23 @@ class Where {
|
||||
|
||||
public function getValue(/* null|EntityInterface */ $entity = null) : mixed
|
||||
{
|
||||
if ($this->generateValue) {
|
||||
if ($entity) {
|
||||
if ($this->generateValue) {
|
||||
return call_user_func_array($this->generateValue, [ $entity ]);
|
||||
}
|
||||
elseif ($this->fieldValue) {
|
||||
throw new \Exception(sprintf("Field value, from %s, could not be included in query since the entity is already loaded; it is meant to be used with a OneToOne relation loaded within a join.", (string) $this->fieldValue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($this->fieldValue) {
|
||||
return $this->fieldValue;
|
||||
}
|
||||
elseif ($this->generateValue) {
|
||||
throw new \Exception(sprintf("Could not generate value from non-instanciated entity for field %s.", (string) $this->field));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->fieldValue ?? $this->value;
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@ namespace Ulmus\Attribute\Property;
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||
class WithJoin {
|
||||
public function __construct(
|
||||
array $joins = []
|
||||
public string|array $joins = []
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute;
|
||||
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
interface RegisterEntityEventInterface
|
||||
{
|
||||
public function attach(EntityInterface $entity, string $field);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Cache;
|
||||
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
|
||||
trait CacheEventTrait
|
||||
{
|
||||
public function __construct(
|
||||
protected CacheInterface $cache,
|
||||
protected string $cacheKey,
|
||||
) {}
|
||||
|
||||
public function purgeCache() : void
|
||||
{
|
||||
$keys = $this->cache->get($this->cacheKey);
|
||||
|
||||
if ( $keys && is_iterable($keys) ) {
|
||||
$this->cache->deleteMultiple(array_map(fn($e) => sprintf("%s:%s:", $this->cacheKey, $e), $keys));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 197 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user