Compare commits
40
Commits
2de3139c80
...
v1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
@@ -51,7 +51,9 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
?string $server = null,
|
?string $server = null,
|
||||||
?string $database = null,
|
?string $database = null,
|
||||||
|
#[\SensitiveParameter]
|
||||||
?string $username = null,
|
?string $username = null,
|
||||||
|
#[\SensitiveParameter]
|
||||||
?string $password = null,
|
?string $password = null,
|
||||||
?int $port = null
|
?int $port = null
|
||||||
) {
|
) {
|
||||||
@@ -204,9 +206,10 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function escapeIdentifier(string $segment, int $type) : string
|
public static function escapeIdentifier(string $segment, int $type) : string
|
||||||
{
|
{
|
||||||
switch($type) {
|
switch($type) {
|
||||||
|
default:
|
||||||
case static::IDENTIFIER_SCHEMA:
|
case static::IDENTIFIER_SCHEMA:
|
||||||
case static::IDENTIFIER_DATABASE:
|
case static::IDENTIFIER_DATABASE:
|
||||||
case static::IDENTIFIER_TABLE:
|
case static::IDENTIFIER_TABLE:
|
||||||
|
|||||||
+22
-1
@@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
namespace Ulmus\Adapter;
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\ConnectionAdapter;
|
||||||
|
use Ulmus\Entity\Mysql\Table;
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\Migration\MigrateInterface;
|
use Ulmus\Migration\MigrateInterface;
|
||||||
use Ulmus\QueryBuilder\Sql;
|
use Ulmus\QueryBuilder\Sql;
|
||||||
use Ulmus\Common\PdoObject;
|
use Ulmus\Common\PdoObject;
|
||||||
|
|
||||||
use Ulmus\Exception\AdapterConfigurationException;
|
use Ulmus\Exception\AdapterConfigurationException;
|
||||||
|
use Ulmus\Repository;
|
||||||
|
|
||||||
class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
||||||
use SqlAdapterTrait;
|
use SqlAdapterTrait;
|
||||||
@@ -34,7 +38,9 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
?string $hostname = null,
|
?string $hostname = null,
|
||||||
?string $database = null,
|
?string $database = null,
|
||||||
|
#[\SensitiveParameter]
|
||||||
?string $username = null,
|
?string $username = null,
|
||||||
|
#[\SensitiveParameter]
|
||||||
?string $password = null,
|
?string $password = null,
|
||||||
?int $port = null,
|
?int $port = null,
|
||||||
?string $charset = null
|
?string $charset = null
|
||||||
@@ -136,9 +142,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) {
|
switch($type) {
|
||||||
|
default:
|
||||||
case static::IDENTIFIER_DATABASE:
|
case static::IDENTIFIER_DATABASE:
|
||||||
case static::IDENTIFIER_TABLE:
|
case static::IDENTIFIER_TABLE:
|
||||||
case static::IDENTIFIER_FIELD:
|
case static::IDENTIFIER_FIELD:
|
||||||
@@ -159,4 +173,11 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface {
|
|||||||
return Sql\MysqlQueryBuilder::class;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
|
|
||||||
|
class MySQLFieldMapper extends SqlFieldMapper
|
||||||
|
{
|
||||||
|
public readonly string $type;
|
||||||
|
|
||||||
|
public readonly string $length;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
-8
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace Ulmus\Adapter;
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Collator;
|
||||||
use Ulmus\Common\PdoObject;
|
use Ulmus\Common\PdoObject;
|
||||||
use Ulmus\ConnectionAdapter;
|
use Ulmus\ConnectionAdapter;
|
||||||
|
|
||||||
use Ulmus\Entity;
|
use Ulmus\Entity;
|
||||||
use Ulmus\Migration\FieldDefinition;
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder};
|
use Ulmus\{Migration\MigrateInterface, Repository, QueryBuilder};
|
||||||
@@ -13,7 +13,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
use SqlAdapterTrait;
|
use SqlAdapterTrait;
|
||||||
|
|
||||||
const ALLOWED_ATTRIBUTES = [
|
const ALLOWED_ATTRIBUTES = [
|
||||||
'default', 'primary_key', 'auto_increment'
|
'default', 'primary_key', 'auto_increment', 'collate nocase', 'collate binary', 'collate rtrim',
|
||||||
];
|
];
|
||||||
|
|
||||||
const DSN_PREFIX = "sqlite";
|
const DSN_PREFIX = "sqlite";
|
||||||
@@ -27,7 +27,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
public function connect() : PdoObject
|
public function connect() : PdoObject
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$pdo = new PdoObject($this->buildDataSourceName(), null, null);
|
$pdo = new PdoObject\SqlitePdoObject($this->buildDataSourceName(), null, null);
|
||||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||||
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
|
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
|
||||||
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
|
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
|
||||||
@@ -37,6 +37,7 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
};
|
};
|
||||||
|
|
||||||
$this->exportFunctions($pdo);
|
$this->exportFunctions($pdo);
|
||||||
|
$this->exportCollations($pdo);
|
||||||
$this->registerPragma($pdo, $this->pragmaBegin);
|
$this->registerPragma($pdo, $this->pragmaBegin);
|
||||||
}
|
}
|
||||||
catch(\PDOException $ex){
|
catch(\PDOException $ex){
|
||||||
@@ -61,9 +62,10 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
# https://sqlite.org/lang_keywords.html
|
# 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) {
|
switch($type) {
|
||||||
|
default:
|
||||||
case static::IDENTIFIER_DATABASE:
|
case static::IDENTIFIER_DATABASE:
|
||||||
case static::IDENTIFIER_TABLE:
|
case static::IDENTIFIER_TABLE:
|
||||||
case static::IDENTIFIER_FIELD:
|
case static::IDENTIFIER_FIELD:
|
||||||
@@ -96,7 +98,6 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||||
{
|
{
|
||||||
$type = $field->type;
|
$type = $field->type;
|
||||||
|
|
||||||
$length = $field->length;
|
$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) ) {
|
if ( is_a($type, Entity\Field\Date::class, true) || is_a($type, Entity\Field\Time::class, true) || is_a($type, \DateTime::class, true) ) {
|
||||||
@@ -114,6 +115,10 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "array":
|
case "array":
|
||||||
|
$type = "JSON";
|
||||||
|
$length = null;
|
||||||
|
break;
|
||||||
|
|
||||||
case "string":
|
case "string":
|
||||||
$type = "TEXT";
|
$type = "TEXT";
|
||||||
$length = null;
|
$length = null;
|
||||||
@@ -129,7 +134,11 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $typeOnly ? $type : $type . ( $length ? "($length" . ( isset($precision) ? ",$precision" : "" ) . ")" : "" );
|
if (in_array($type, [ 'JSON', 'TEXT', 'BLOB', 'GEOMETRY' ])) {
|
||||||
|
unset($field->default);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $typeOnly ? $type : $type . ( $length ? "($length" . ")" : "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tableSyntax() : array
|
public function tableSyntax() : array
|
||||||
@@ -183,11 +192,42 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||||||
|
|
||||||
return (int) in_array($string, explode(',', $string_list));
|
return (int) in_array($string, explode(',', $string_list));
|
||||||
}, 2);
|
}, 2);
|
||||||
$pdo->sqliteCreateFunction('day', fn($date) => ( new \DateTime($date) )->format('d'), 1);
|
$pdo->sqliteCreateFunction('day', fn($date) => ( new \DateTime($date) )->format('j'), 1);
|
||||||
$pdo->sqliteCreateFunction('month', fn($date) => ( new \DateTime($date) )->format('m'), 1);
|
$pdo->sqliteCreateFunction('month', fn($date) => ( new \DateTime($date) )->format('n'), 1);
|
||||||
$pdo->sqliteCreateFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
$pdo->sqliteCreateFunction('year', fn($date) => ( new \DateTime($date) )->format('Y'), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function exportCollations(PdoObject $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->sqliteCreateCollation('locale_cmp', fn($e1, $e2) => $collator->compare($e1, $e2));
|
||||||
|
$pdo->sqliteCreateCollation('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->sqliteCreateCollation('locale_cmp_ci', fn($e1, $e2) => $collatorCi->compare($e1, $e2));
|
||||||
|
$pdo->sqliteCreateCollation('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->sqliteCreateCollation('locale_cmp', fn($e1, $e2) => $comp);
|
||||||
|
$pdo->sqliteCreateCollation('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->sqliteCreateCollation('locale_cmp_ci', fn($e1, $e2) => $compCi);
|
||||||
|
$pdo->sqliteCreateCollation('locale_cmp_ci_desc', fn($e2, $e1) => $compCi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function registerPragma(PdoObject $pdo, array $pragmaList) : void
|
public static function registerPragma(PdoObject $pdo, array $pragmaList) : void
|
||||||
{
|
{
|
||||||
$builder = new QueryBuilder\Sql\SqliteQueryBuilder();
|
$builder = new QueryBuilder\Sql\SqliteQueryBuilder();
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ namespace Ulmus\Adapter;
|
|||||||
|
|
||||||
interface SqlAdapterInterface
|
interface SqlAdapterInterface
|
||||||
{
|
{
|
||||||
public function escapeIdentifier(string $segment, int $type) : string;
|
public static function escapeIdentifier(string $segment, int $type) : string;
|
||||||
public function defaultEngine() : ? string;
|
public function defaultEngine() : ? string;
|
||||||
}
|
}
|
||||||
@@ -46,60 +46,9 @@ trait SqlAdapterTrait
|
|||||||
|
|
||||||
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
|
||||||
{
|
{
|
||||||
$type = $field->type;
|
$mapper = new SqlFieldMapper($field);
|
||||||
|
|
||||||
$length = $field->length;
|
return $typeOnly ? $mapper->type : $mapper->render();
|
||||||
|
|
||||||
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
|
public function whitelistAttributes(array &$parameters) : void
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Adapter;
|
||||||
|
|
||||||
|
use Ulmus\Migration\FieldDefinition;
|
||||||
|
use Ulmus\Entity;
|
||||||
|
|
||||||
|
class SqlFieldMapper
|
||||||
|
{
|
||||||
|
public readonly string $type;
|
||||||
|
|
||||||
|
public readonly 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":
|
||||||
|
$this->type = "JSON";
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,5 +4,7 @@ namespace Ulmus\Attribute\Obj;
|
|||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
class Collation {
|
class Collation {
|
||||||
|
public function __construct(
|
||||||
|
public string $name = ""
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
@@ -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 mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public null|int $decimal = null,
|
public null|int $decimal = null,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Bigint extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
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 bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Blob extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
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 bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,5 @@ class Date extends \Ulmus\Attribute\Property\Field {
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,5 @@ class Datetime extends \Ulmus\Attribute\Property\Field {
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Decimal extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
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 bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,6 @@ class ForeignKey extends PrimaryKey {
|
|||||||
public null|string $relation = null,
|
public null|string $relation = null,
|
||||||
public ConstrainActionEnum $onDelete = ConstrainActionEnum::NoAction,
|
public ConstrainActionEnum $onDelete = ConstrainActionEnum::NoAction,
|
||||||
public ConstrainActionEnum $onUpdate = ConstrainActionEnum::NoAction,
|
public ConstrainActionEnum $onUpdate = ConstrainActionEnum::NoAction,
|
||||||
public string $description = "",
|
|
||||||
) {
|
) {
|
||||||
#$this->references = Attribute::handleArrayField($this->references, false);
|
#$this->references = Attribute::handleArrayField($this->references, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ class Id extends \Ulmus\Attribute\Property\Field {
|
|||||||
],
|
],
|
||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = true,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -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 bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Longtext extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Mediumblob extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Mediumint extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Mediumtext extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Numeric extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,5 @@ class PrimaryKey extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Smallint extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Text extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,5 @@ class Time extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,5 @@ class Timestamp extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Blob extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Tinyint extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,5 @@ class Tinytext extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = false,
|
public bool $nullable = false,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string $description = "",
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,5 @@ class UpdatedAt extends \Ulmus\Attribute\Property\Field
|
|||||||
public bool $nullable = true,
|
public bool $nullable = true,
|
||||||
public mixed $default = null,
|
public mixed $default = null,
|
||||||
public bool $readonly = false,
|
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 = "",
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property;
|
|||||||
use Ulmus\Attribute\Attribute;
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
#[\Attribute]
|
#[\Attribute]
|
||||||
class Join {
|
class Join implements ResettablePropertyInterface {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $type,
|
public string $type,
|
||||||
public null|string|\Stringable|array $key = null,
|
public null|string|\Stringable|array $key = null,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class OrWhere extends Where {
|
|||||||
public string $operator = Query\Where::OPERATOR_EQUAL,
|
public string $operator = Query\Where::OPERATOR_EQUAL,
|
||||||
public string $condition = Query\Where::CONDITION_OR,
|
public string $condition = Query\Where::CONDITION_OR,
|
||||||
public string|\Stringable|array|null $fieldValue = null,
|
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);
|
parent::__construct($field, $value, $operator, $condition, $fieldValue, $generateValue);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property;
|
|||||||
use Ulmus\Attribute\Attribute;
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
class Relation {
|
class Relation implements ResettablePropertyInterface {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public Relation\RelationTypeEnum|string $type,
|
public Relation\RelationTypeEnum|string $type,
|
||||||
public \Stringable|string|array $key = "",
|
public \Stringable|string|array $key = "",
|
||||||
@@ -35,7 +35,7 @@ class Relation {
|
|||||||
try {
|
try {
|
||||||
$e = $this->entity;
|
$e = $this->entity;
|
||||||
} catch (\Throwable $ex) {
|
} 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();
|
return new $e();
|
||||||
|
|||||||
@@ -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,7 +3,7 @@
|
|||||||
namespace Ulmus\Attribute\Property;
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
class Virtual extends Field {
|
class Virtual extends Field implements ResettablePropertyInterface {
|
||||||
|
|
||||||
public bool $readonly = true;
|
public bool $readonly = true;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Where {
|
|||||||
public string $operator = Query\Where::OPERATOR_EQUAL,
|
public string $operator = Query\Where::OPERATOR_EQUAL,
|
||||||
public string $condition = Query\Where::CONDITION_AND,
|
public string $condition = Query\Where::CONDITION_AND,
|
||||||
public string|\Stringable|array|null $fieldValue = null,
|
public string|\Stringable|array|null $fieldValue = null,
|
||||||
public null|array $generateValue = null,
|
public null|array|\Closure $generateValue = null,
|
||||||
) {
|
) {
|
||||||
$this->field = Attribute::handleArrayField($field);
|
$this->field = Attribute::handleArrayField($field);
|
||||||
$this->fieldValue = Attribute::handleArrayField($fieldValue);
|
$this->fieldValue = Attribute::handleArrayField($fieldValue);
|
||||||
@@ -29,6 +29,9 @@ class Where {
|
|||||||
throw new \Exception(sprintf("Could not generate value from non-instanciated entity for field %s.", (string) $this->field));
|
throw new \Exception(sprintf("Could not generate value from non-instanciated entity for field %s.", (string) $this->field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif ($this->fieldValue && $entity) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
return $this->fieldValue ?? $this->value;
|
return $this->fieldValue ?? $this->value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
use Ulmus\Entity\EntityInterface;
|
||||||
|
use Ulmus\QueryBuilder\QueryBuilderInterface;
|
||||||
|
use Ulmus\Repository\RepositoryInterface;
|
||||||
|
|
||||||
|
trait CacheTrait
|
||||||
|
{
|
||||||
|
protected CacheInterface $cache;
|
||||||
|
|
||||||
|
public function attachCachingObject(CacheInterface $cache) : self
|
||||||
|
{
|
||||||
|
$cacheKey = "";
|
||||||
|
$this->cache = $cache;
|
||||||
|
|
||||||
|
# Reading from cache
|
||||||
|
$this->eventRegister(new class($cacheKey) implements Event\Repository\CollectionFromQueryDatasetInterface {
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected string & $cacheKey
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, array &$data): void
|
||||||
|
{
|
||||||
|
$this->cacheKey = $repository->queryBuilder->hashSerializedQuery();
|
||||||
|
$data = $repository->getFromCache( $this->cacheKey) ?: [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
# Setting to cache
|
||||||
|
$this->eventRegister(new class($cacheKey) implements Event\Repository\CollectionFromQueryInterface {
|
||||||
|
public function __construct(
|
||||||
|
protected string & $cacheKey
|
||||||
|
) {}
|
||||||
|
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, EntityCollection $collection): EntityCollection
|
||||||
|
{
|
||||||
|
$repository->setToCache( $this->cacheKey, $collection->map(fn(EntityInterface $e) => $e->entityGetDataset(false, true)));
|
||||||
|
$this->cacheKey = "";
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Insert {
|
||||||
|
use Cache\CacheEventTrait;
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, object|array $entity, ?array $dataset = null, bool $replace = false): void
|
||||||
|
{
|
||||||
|
$this->purgeCache();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
# Cache invalidation
|
||||||
|
$this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Update {
|
||||||
|
use Cache\CacheEventTrait;
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, object|array $entity, ?array $dataset = null, bool $replace = false): void
|
||||||
|
{
|
||||||
|
$this->purgeCache();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Delete {
|
||||||
|
use Cache\CacheEventTrait;
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, EntityInterface $entity): void
|
||||||
|
{
|
||||||
|
$this->purgeCache();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Truncate {
|
||||||
|
use Cache\CacheEventTrait;
|
||||||
|
|
||||||
|
public function execute(RepositoryInterface $repository, ?string $table = null, ?string $alias = null, ?string $schema = null): void
|
||||||
|
{
|
||||||
|
$this->purgeCache();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function entityCacheKey() : string
|
||||||
|
{
|
||||||
|
return sprintf("%s.%s", $this->entityResolver->databaseName(), $this->entityResolver->tableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromCache(string $key) : mixed
|
||||||
|
{
|
||||||
|
$keys = $this->cache->get($this->entityCacheKey(), []);
|
||||||
|
|
||||||
|
if (in_array($key, $keys)) {
|
||||||
|
return $this->cache->get(sprintf("%s:%s:", $this->entityCacheKey(), $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToCache(string $key, mixed $value) : void
|
||||||
|
{
|
||||||
|
$keys = $this->cache->get($this->entityCacheKey(), []);
|
||||||
|
|
||||||
|
if (! in_array($key, $keys)) {
|
||||||
|
$keys[] = $key;
|
||||||
|
|
||||||
|
$this->cache->set($this->entityCacheKey(), $keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache->set(sprintf("%s:%s:", $this->entityCacheKey(), $key), $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
namespace Ulmus\Common;
|
namespace Ulmus\Common;
|
||||||
|
|
||||||
use Ulmus\Annotation\Annotation;
|
use Ulmus\Attribute\Property\{ Field };
|
||||||
use Ulmus\Attribute;
|
|
||||||
use Ulmus\Migration\FieldDefinition;
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\Ulmus,
|
use Ulmus\Ulmus,
|
||||||
Ulmus\Adapter\AdapterInterface,
|
Ulmus\Adapter\AdapterInterface,
|
||||||
Ulmus\Annotation\Property\Field,
|
|
||||||
Ulmus\Query\WhereRawParameter;
|
Ulmus\Query\WhereRawParameter;
|
||||||
|
|
||||||
class EntityField implements WhereRawParameter
|
class EntityField implements WhereRawParameter
|
||||||
@@ -30,7 +28,7 @@ class EntityField implements WhereRawParameter
|
|||||||
|
|
||||||
public function name($useAlias = true) : string
|
public function name($useAlias = true) : string
|
||||||
{
|
{
|
||||||
$name = $this->entityResolver->searchFieldAnnotation($this->name, [ Attribute\Property\Field::class, Field::class ] )->name ?? $this->name;
|
$name = $this->entityResolver->searchFieldAnnotation($this->name, [ Field::class ] )->name ?? $this->name;
|
||||||
|
|
||||||
$name = $this->entityResolver->databaseAdapter()->adapter()->escapeIdentifier($name, AdapterInterface::IDENTIFIER_FIELD);
|
$name = $this->entityResolver->databaseAdapter()->adapter()->escapeIdentifier($name, AdapterInterface::IDENTIFIER_FIELD);
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use Notes\Common\ReflectedClass;
|
|||||||
use Notes\Common\ReflectedProperty;
|
use Notes\Common\ReflectedProperty;
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Ulmus\Ulmus,
|
use Ulmus\Ulmus,
|
||||||
Ulmus\Annotation\Classes\Table,
|
Ulmus\Attribute\Obj\Table,
|
||||||
Ulmus\Annotation\Property\Field,
|
Ulmus\Attribute\Obj\AdapterAttributeInterface,
|
||||||
Ulmus\Annotation\Property\Virtual,
|
Ulmus\Attribute\Property\Field,
|
||||||
Ulmus\Annotation\Property\Relation,
|
Ulmus\Attribute\Property\Relation,
|
||||||
Ulmus\Attribute;
|
Ulmus\Attribute\Property\Virtual;
|
||||||
|
|
||||||
use Notes\Annotation;
|
use Notes\Common\ReflectedAttribute;
|
||||||
|
|
||||||
use Notes\ObjectReflection;
|
use Notes\ObjectReflection;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class EntityResolver {
|
|||||||
$this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
|
$this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : ? ReflectedProperty
|
public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : null|ReflectedProperty
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
return $this->fieldList($fieldKey)[$name] ?? null;
|
return $this->fieldList($fieldKey)[$name] ?? null;
|
||||||
@@ -51,7 +51,7 @@ class EntityResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchField($name) : null|array
|
public function searchField($name) : null|ReflectedProperty
|
||||||
{
|
{
|
||||||
return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false);
|
return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false);
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ class EntityResolver {
|
|||||||
|
|
||||||
foreach($this->reflectedClass->getProperties(true) as $item) {
|
foreach($this->reflectedClass->getProperties(true) as $item) {
|
||||||
foreach($item->getAttributes() as $tag) {
|
foreach($item->getAttributes() as $tag) {
|
||||||
if ( $tag->object instanceof Attribute\Property\Field ) {
|
if ( $tag->object instanceof Field ) {
|
||||||
if ( $skipVirtual && $tag->object instanceof Attribute\Property\Virtual ) {
|
if ( $skipVirtual && $tag->object instanceof Virtual ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,6 @@ class EntityResolver {
|
|||||||
$key = strtolower($item->name);
|
$key = strtolower($item->name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case static::KEY_ENTITY_NAME:
|
case static::KEY_ENTITY_NAME:
|
||||||
$key = $item->name;
|
$key = $item->name;
|
||||||
break;
|
break;
|
||||||
@@ -102,7 +101,7 @@ class EntityResolver {
|
|||||||
try{
|
try{
|
||||||
if ( $property ) {
|
if ( $property ) {
|
||||||
foreach($property->getAttributes() as $tag) {
|
foreach($property->getAttributes() as $tag) {
|
||||||
if ( $tag->object instanceof Relation or $tag->object instanceof Attribute\Property\Relation ) {
|
if ( $tag->object instanceof Relation ) {
|
||||||
return $property;
|
return $property;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +119,7 @@ class EntityResolver {
|
|||||||
return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null;
|
return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchFieldAnnotationList(string $field, array|object|string $annotationType, bool $caseSensitive = true) : array
|
public function searchFieldAnnotationList(string $field, array|object|string $attributeType, bool $caseSensitive = true) : false|array
|
||||||
{
|
{
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
@@ -128,19 +127,11 @@ class EntityResolver {
|
|||||||
|
|
||||||
$search = $caseSensitive ? $properties : array_change_key_case($properties, \CASE_LOWER);
|
$search = $caseSensitive ? $properties : array_change_key_case($properties, \CASE_LOWER);
|
||||||
|
|
||||||
$annotations = is_array($annotationType) ? $annotationType : [ $annotationType ];
|
|
||||||
|
|
||||||
if ( null !== ( $search[$field] ?? null ) ) {
|
if ( null !== ( $search[$field] ?? null ) ) {
|
||||||
foreach($search[$field]->getAttributes() as $tag) {
|
return array_map(fn(ReflectedAttribute $e) => $e->object, $search[$field]->getAttributes((array) $attributeType));
|
||||||
foreach($annotations as $annotation) {
|
|
||||||
if ( $tag->object instanceof $annotation ) {
|
|
||||||
$list[] = $tag->object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tableName($required = false) : string
|
public function tableName($required = false) : string
|
||||||
@@ -156,7 +147,7 @@ class EntityResolver {
|
|||||||
return $table->name ?? "";
|
return $table->name ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tableAnnotation($required = false) : null|Table|Attribute\Obj\Table
|
public function tableAnnotation($required = false) : null|Table
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getTableAttribute() ) {
|
if ( null === $table = $this->getTableAttribute() ) {
|
||||||
if ($required) {
|
if ($required) {
|
||||||
@@ -167,7 +158,7 @@ class EntityResolver {
|
|||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function databaseName() : ? string
|
public function databaseName() : null|string
|
||||||
{
|
{
|
||||||
return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null;
|
return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null;
|
||||||
}
|
}
|
||||||
@@ -196,7 +187,7 @@ class EntityResolver {
|
|||||||
return $this->sqlAdapter();
|
return $this->sqlAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function schemaName(bool $required = false) : ? string
|
public function schemaName(bool $required = false) : null|string
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getTableAttribute() ) {
|
if ( null === $table = $this->getTableAttribute() ) {
|
||||||
throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation");
|
throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation");
|
||||||
@@ -209,10 +200,10 @@ class EntityResolver {
|
|||||||
return $table->schema ?? null;
|
return $table->schema ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPrimaryKeyField() : ? array
|
public function getPrimaryKeyField() : null|array
|
||||||
{
|
{
|
||||||
foreach($this->fieldList() as $key => $value) {
|
foreach($this->fieldList() as $key => $value) {
|
||||||
$field = $this->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
|
$field = $this->searchFieldAnnotation($key, [ Field::class ]);
|
||||||
if ( null !== $field ) {
|
if ( null !== $field ) {
|
||||||
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
||||||
return [ $key => $field ];
|
return [ $key => $field ];
|
||||||
@@ -235,57 +226,17 @@ class EntityResolver {
|
|||||||
|
|
||||||
protected function getAdapterInterfaceAttribute() : null|object
|
protected function getAdapterInterfaceAttribute() : null|object
|
||||||
{
|
{
|
||||||
return $this->getAttributeImplementing(Attribute\Obj\AdapterAttributeInterface::class);
|
return $this->getAttributeImplementing(AdapterAttributeInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getTableAttribute()
|
protected function getTableAttribute()
|
||||||
{
|
{
|
||||||
return $this->getAttributeImplementing(Attribute\Obj\Table::class) ?: $this->getAnnotationFromClassname( Table::class, false );
|
return $this->getAttributeImplementing(Table::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getAttributeImplementing(string $interface) : null|object
|
||||||
* Transform an annotation into it's object's counterpart
|
|
||||||
*/
|
|
||||||
public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
|
|
||||||
{
|
{
|
||||||
exit(__FILE__);
|
foreach ($this->reflectedClass->getAttributes(true) as $item) {
|
||||||
if ( $name = $this->uses[$className] ?? false ) {
|
|
||||||
foreach(array_reverse($this->class['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->properties as $item) {
|
|
||||||
foreach(array_reverse($item['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->methods as $item) {
|
|
||||||
foreach(array_reverse($item['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($throwError) {
|
|
||||||
throw new \TypeError("Annotation `$className` could not be found within your object `{$this->entityClass}`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ($throwError) {
|
|
||||||
throw new \InvalidArgumentException("Class `$className` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAttributeImplementing(string $interface) : ? object
|
|
||||||
{
|
|
||||||
foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) {
|
|
||||||
if ($item->object instanceof $interface) {
|
if ($item->object instanceof $interface) {
|
||||||
return $item->object;
|
return $item->object;
|
||||||
}
|
}
|
||||||
@@ -293,14 +244,4 @@ class EntityResolver {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($tagDefinition instanceof \ReflectionAttribute) {
|
|
||||||
$obj = $tagDefinition->newInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,11 @@ class PdoObject extends PDO {
|
|||||||
return $this->execute($statement, $parameters, true);
|
return $this->execute($statement, $parameters, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch(\PDOException $pdo) {
|
||||||
|
if ( substr($pdo->getMessage(), 0, 30) !== 'There is no active transaction' ) {
|
||||||
|
throw $pdo;
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (\Throwable $e) {
|
catch (\Throwable $e) {
|
||||||
throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters));
|
throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Common\PdoObject;
|
||||||
|
|
||||||
|
class SqlPdoObject extends \Ulmus\Common\PdoObject
|
||||||
|
{
|
||||||
|
protected int $openedTransaction = 0;
|
||||||
|
|
||||||
|
public function beginTransaction(): bool
|
||||||
|
{
|
||||||
|
if ( 0 === $this->openedTransaction++ ) {
|
||||||
|
return $this->openTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->exec('SAVEPOINT transaction_'.$this->openedTransaction) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit() : bool
|
||||||
|
{
|
||||||
|
if ( 0 === --$this->openedTransaction) {
|
||||||
|
return parent::commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rollback() : bool
|
||||||
|
{
|
||||||
|
if (0 !== $this->openedTransaction) {
|
||||||
|
return $this->exec('ROLLBACK TO transaction_' . $this->openedTransaction--) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function openTransaction() : bool
|
||||||
|
{
|
||||||
|
return parent::beginTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Common\PdoObject;
|
||||||
|
|
||||||
|
class SqlitePdoObject extends SqlPdoObject
|
||||||
|
{
|
||||||
|
public bool $inTransaction = false;
|
||||||
|
|
||||||
|
public function inTransaction(): bool
|
||||||
|
{
|
||||||
|
return $this->openedTransaction > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit(): bool
|
||||||
|
{
|
||||||
|
if ( 0 === --$this->openedTransaction) {
|
||||||
|
return $this->exec("COMMIT") !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function openTransaction(): bool
|
||||||
|
{
|
||||||
|
return $this->exec("BEGIN IMMEDIATE TRANSACTION") !== false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-1
@@ -84,8 +84,12 @@ abstract class Sql {
|
|||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function parameter($value) : string
|
public static function collate(string $name) : string
|
||||||
{
|
{
|
||||||
|
if ( ! preg_match('/^[a-z0-9$_]+$/i',$name) ) {
|
||||||
|
throw new \InvalidArgumentException(sprintf("Given identifier '%s' should contains supported characters in function name (a-Z, 0-9, $ and _)", $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::raw(sprintf("COLLATE %s", $name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,26 +2,23 @@
|
|||||||
|
|
||||||
namespace Ulmus;
|
namespace Ulmus;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Ulmus\Adapter\AdapterInterface;
|
use Ulmus\Adapter\AdapterInterface;
|
||||||
|
|
||||||
use Ulmus\Common\PdoObject;
|
use Ulmus\Common\PdoObject;
|
||||||
|
|
||||||
class ConnectionAdapter
|
class ConnectionAdapter
|
||||||
{
|
{
|
||||||
public string $name;
|
|
||||||
|
|
||||||
public array $configuration;
|
|
||||||
|
|
||||||
protected AdapterInterface $adapter;
|
protected AdapterInterface $adapter;
|
||||||
|
|
||||||
protected PdoObject $pdo;
|
protected PdoObject $pdo;
|
||||||
|
|
||||||
public function __construct(string $name = "default", array $configuration = [], bool $default = false)
|
public function __construct(
|
||||||
{
|
public string $name = "default",
|
||||||
$this->name = $name;
|
protected array $configuration = [],
|
||||||
|
public bool $default = false,
|
||||||
$this->configuration = $configuration;
|
public ? CacheInterface $cacheObject = null
|
||||||
|
) {
|
||||||
Ulmus::registerAdapter($this, $default);
|
Ulmus::registerAdapter($this, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Entity;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
use Ulmus\Attribute\Property\Field;
|
||||||
|
use Ulmus\Attribute\Property\Relation;
|
||||||
|
use Ulmus\Common\EntityField;
|
||||||
|
use Ulmus\Common\EntityResolver;
|
||||||
|
use Ulmus\Ulmus;
|
||||||
|
|
||||||
|
class DatasetHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected EntityResolver $entityResolver,
|
||||||
|
protected bool $entityStrictFieldsDeclaration = false,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function pull(object $entity) : Generator
|
||||||
|
{
|
||||||
|
foreach($this->entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
|
||||||
|
$attribute = $this->entityResolver->searchFieldAnnotation($key,[ Field::class ]);
|
||||||
|
|
||||||
|
if ( $entity->__isset($key) ) {
|
||||||
|
yield $attribute->name ?? $key => $entity->$key;
|
||||||
|
}
|
||||||
|
elseif ( $field->allowsNull() ) {
|
||||||
|
yield $attribute->name ?? $key => null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function push(iterable $dataset) : Generator|array
|
||||||
|
{
|
||||||
|
$unmatched = [];
|
||||||
|
|
||||||
|
foreach($dataset as $key => $value) {
|
||||||
|
$field = $this->entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $this->entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
|
||||||
|
|
||||||
|
if ( $field === null ) {
|
||||||
|
if ($this->entityStrictFieldsDeclaration ) {
|
||||||
|
throw new \Exception("Field `$key` can not be found within your entity ".static::class);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$unmatched[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $field->getTypes()[0];
|
||||||
|
|
||||||
|
if ( is_null($value) ) {
|
||||||
|
yield $field->name => null;
|
||||||
|
}
|
||||||
|
elseif ( $field->expectType('array') ) {
|
||||||
|
if ( is_string($value)) {
|
||||||
|
if (substr($value, 0, 1) === "a") {
|
||||||
|
|
||||||
|
yield $field->name => unserialize($value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$data = json_decode($value, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== \JSON_ERROR_NONE) {
|
||||||
|
throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $field->name => $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( is_array($value) ) {
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( EntityField::isScalarType($type->type) ) {
|
||||||
|
|
||||||
|
if ( $type->type === 'string' ) {
|
||||||
|
$attribute = $this->entityResolver->searchFieldAnnotation($field->name, [ Field::class ] );
|
||||||
|
|
||||||
|
if ( $attribute->length ?? null ) {
|
||||||
|
$value = mb_substr($value, 0, $attribute->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( $type->type === 'bool' ) {
|
||||||
|
$value = (bool) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
elseif ( $value instanceof \UnitEnum ) {
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
elseif (enum_exists($type->type)) {
|
||||||
|
yield $field->name => $type->type::from($value);
|
||||||
|
}
|
||||||
|
elseif ( ! $type->builtIn ) {
|
||||||
|
try {
|
||||||
|
yield $field->name => Ulmus::instanciateObject($type->type, [ $value ]);
|
||||||
|
}
|
||||||
|
catch(\Error $e) {
|
||||||
|
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $unmatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pullRelation(object $entity) : Generator
|
||||||
|
{
|
||||||
|
foreach($this->entityResolver->reflectedClass->getProperties(true) as $name => $field){
|
||||||
|
$relation = $this->entityResolver->searchFieldAnnotation($name, [ Relation::class ] );
|
||||||
|
|
||||||
|
if ($relation) {
|
||||||
|
$ignore = $this->entityResolver->searchFieldAnnotation($name, [ Relation\Ignore::class ] );
|
||||||
|
|
||||||
|
if ($ignore && $ignore->ignoreExport) {
|
||||||
|
if ( $relation->isOneToOne() ) {
|
||||||
|
# @TODO TO INCLUDED INTO getTypes() RETURNED CLASS WHEN DONE !
|
||||||
|
yield $name => ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# empty collection
|
||||||
|
yield $name => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
# @TODO Must fix recursive bug.. this last check is way too basic to work
|
||||||
|
if ( $entity->__isset($name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
||||||
|
if ( null !== $value = $entity->__isset($name) ?? null ) {
|
||||||
|
if ( is_iterable($value) ) {
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach($value as $entityObj) {
|
||||||
|
$list[] = $entityObj->entityGetDataset(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $name => $list;
|
||||||
|
}
|
||||||
|
elseif ( is_object($value) ) {
|
||||||
|
yield $name => $value->entityGetDataset(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,9 +3,13 @@
|
|||||||
namespace Ulmus\Entity;
|
namespace Ulmus\Entity;
|
||||||
|
|
||||||
use Ulmus\Common\{ EntityField, EntityResolver };
|
use Ulmus\Common\{ EntityField, EntityResolver };
|
||||||
use Ulmus\{ ConnectionAdapter, EntityCollection, QueryBuilder\QueryBuilderInterface, Repository };
|
use Ulmus\{ConnectionAdapter,
|
||||||
|
EntityCollection,
|
||||||
|
QueryBuilder\QueryBuilderInterface,
|
||||||
|
Repository,
|
||||||
|
SearchRequest\SearchableInterface};
|
||||||
|
|
||||||
interface EntityInterface /* extends \JsonSerializable */
|
interface EntityInterface extends SearchableInterface /* extends \JsonSerializable */
|
||||||
{
|
{
|
||||||
public function fromArray(iterable $dataset) : static;
|
public function fromArray(iterable $dataset) : static;
|
||||||
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array;
|
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array;
|
||||||
|
|||||||
@@ -12,12 +12,20 @@ class Datetime extends \DateTime implements EntityObjectInterface {
|
|||||||
{
|
{
|
||||||
$value = $arguments[0];
|
$value = $arguments[0];
|
||||||
|
|
||||||
|
try {
|
||||||
# From Timestamp
|
# From Timestamp
|
||||||
if ( is_numeric($value) ) {
|
if ( is_numeric($value) ) {
|
||||||
return new static("@$value");
|
$obj = new static("@$value");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$obj = new static($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(\Throwable $ex) {
|
||||||
|
throw new \Exception(sprintf("An error occured trying to instanciate from '%s'. %s", $value, $ex->getMessage()), $ex->getCode(), $ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new static($value);
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save()
|
public function save()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Ulmus\Entity\InformationSchema;
|
namespace Ulmus\Entity\InformationSchema;
|
||||||
|
|
||||||
|
use Notes\Common\ReflectedProperty;
|
||||||
use Ulmus\Entity\Field\Datetime;
|
use Ulmus\Entity\Field\Datetime;
|
||||||
|
|
||||||
use Ulmus\{Attribute\Obj\Table};
|
use Ulmus\{Attribute\Obj\Table};
|
||||||
@@ -12,6 +13,9 @@ class Column
|
|||||||
{
|
{
|
||||||
use \Ulmus\EntityTrait;
|
use \Ulmus\EntityTrait;
|
||||||
|
|
||||||
|
#[Field\Id]
|
||||||
|
public ? id $srs_id;
|
||||||
|
|
||||||
#[Field(name: "TABLE_CATALOG", length: 512)]
|
#[Field(name: "TABLE_CATALOG", length: 512)]
|
||||||
public string $tableCatalog;
|
public string $tableCatalog;
|
||||||
|
|
||||||
@@ -78,4 +82,44 @@ class Column
|
|||||||
#[Field(name: "GENERATION_EXPRESSION", type: "longtext")]
|
#[Field(name: "GENERATION_EXPRESSION", type: "longtext")]
|
||||||
public ? string $generationExpression;
|
public ? string $generationExpression;
|
||||||
|
|
||||||
|
public function matchFieldDefinition(ReflectedProperty $definition) : bool
|
||||||
|
{
|
||||||
|
$nullable = $this->nullable === 'YES';
|
||||||
|
|
||||||
|
if ($nullable !== $definition->allowsNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset($definition->value) && $this->canHaveDefaultValue() ) {
|
||||||
|
if ( $definition->value !== $this->defaultValue()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (! isset($definition->value)) {
|
||||||
|
if ( ! $this->defaultValueIsNull() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defaultValueIsNull() : bool
|
||||||
|
{
|
||||||
|
return $this->defaultValue() === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defaultValue() : mixed
|
||||||
|
{
|
||||||
|
if (is_numeric($this->default)) {
|
||||||
|
return (int) $this->default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->default;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canHaveDefaultValue() : bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace Ulmus\Entity\InformationSchema;
|
|||||||
use Ulmus\EntityCollection,
|
use Ulmus\EntityCollection,
|
||||||
Ulmus\Entity\Field\Datetime;
|
Ulmus\Entity\Field\Datetime;
|
||||||
|
|
||||||
use Ulmus\{Attribute\Obj\Table as TableObj};
|
use Ulmus\{Attribute\Obj\Table as TableObj, Entity\EntityInterface};
|
||||||
use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual, Where};
|
use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual, Where};
|
||||||
|
|
||||||
#[TableObj(name: "tables", database: "information_schema")]
|
#[TableObj(name: "tables", database: "information_schema")]
|
||||||
@@ -83,6 +83,12 @@ class Table
|
|||||||
public ? string $temporary;
|
public ? string $temporary;
|
||||||
|
|
||||||
#[Relation(type: "oneToMany", key: "name", foreignKey: [ Column::class, 'tableName' ], entity: Column::class)]
|
#[Relation(type: "oneToMany", key: "name", foreignKey: [ Column::class, 'tableName' ], entity: Column::class)]
|
||||||
#[Where('TABLE_SCHEMA', fieldValue: [ Column::class, 'tableSchema' ])]
|
#[Where(field: 'TABLE_SCHEMA', generateValue: [ Table::class, 'getSchema' ])]
|
||||||
public EntityCollection $columns;
|
public EntityCollection $columns;
|
||||||
|
|
||||||
|
# Awaiting PHP 8.5 https://wiki.php.net/rfc/closures_in_const_expr
|
||||||
|
public static function getSchema(Table $entity) : string
|
||||||
|
{
|
||||||
|
return $entity->schema;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Entity\Mysql;
|
||||||
|
|
||||||
|
class Column extends \Ulmus\Entity\InformationSchema\Column
|
||||||
|
{
|
||||||
|
# TODO ! Handle FUNCTIONAL default value
|
||||||
|
protected function canHaveDefaultValue(): bool
|
||||||
|
{
|
||||||
|
return ! in_array(strtoupper($this->dataType), [
|
||||||
|
'BLOB', 'TINYBLOB', 'MEDIUMBLOB', 'LONGBLOB', 'JSON', 'TEXT', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'GEOMETRY'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user