Compare commits
4 Commits
5295a335b3
...
26ffecbb6e
Author | SHA1 | Date | |
---|---|---|---|
26ffecbb6e | |||
|
88e9f048db | ||
|
70021d829d | ||
e6d0279c1a |
@ -6,9 +6,9 @@ class Join implements \Notes\Annotation {
|
|||||||
|
|
||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
public /*string|Stringable*/ $key;
|
public string|Stringable $key;
|
||||||
|
|
||||||
public /*string|Stringable*/ $foreignKey;
|
public string|Stringable $foreignKey;
|
||||||
|
|
||||||
public string $entity;
|
public string $entity;
|
||||||
|
|
||||||
|
19
src/Attribute/Attribute.php
Normal file
19
src/Attribute/Attribute.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute;
|
||||||
|
|
||||||
|
use Ulmus\Common\EntityField;
|
||||||
|
|
||||||
|
class Attribute
|
||||||
|
{
|
||||||
|
public static function handleArrayField(null|\Stringable|string|array $field) : mixed
|
||||||
|
{
|
||||||
|
if ( is_array($field) ) {
|
||||||
|
$class = array_shift($field);
|
||||||
|
|
||||||
|
return $class::field(...$field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
}
|
8
src/Attribute/Obj/Collation.php
Normal file
8
src/Attribute/Obj/Collation.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Obj;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
|
class Collation {
|
||||||
|
|
||||||
|
}
|
8
src/Attribute/Obj/Method.php
Normal file
8
src/Attribute/Obj/Method.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Obj;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
|
class Method {
|
||||||
|
|
||||||
|
}
|
14
src/Attribute/Obj/Table.php
Normal file
14
src/Attribute/Obj/Table.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Obj;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
|
class Table {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $database = null,
|
||||||
|
public ? string $schema = null,
|
||||||
|
public ? string $adapter = null,
|
||||||
|
public ? string $engine = null,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field.php
Normal file
18
src/Attribute/Property/Field.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Field {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = null,
|
||||||
|
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 null|int $decimal = null,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Bigint.php
Normal file
18
src/Attribute/Property/Field/Bigint.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Bigint extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "bigint",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Bit.php
Normal file
18
src/Attribute/Property/Field/Bit.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Bit extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "bit",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Blob.php
Normal file
18
src/Attribute/Property/Field/Blob.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Blob extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "blob",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
17
src/Attribute/Property/Field/CreatedAt.php
Normal file
17
src/Attribute/Property/Field/CreatedAt.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class CreatedAt extends \Ulmus\Attribute\Property\Field {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "timestamp",
|
||||||
|
public array $attributes = [
|
||||||
|
'default' => "CURRENT_TIMESTAMP",
|
||||||
|
],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
15
src/Attribute/Property/Field/Date.php
Normal file
15
src/Attribute/Property/Field/Date.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Date extends \Ulmus\Attribute\Property\Field {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "date",
|
||||||
|
public array $attributes = [],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
15
src/Attribute/Property/Field/Datetime.php
Normal file
15
src/Attribute/Property/Field/Datetime.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Datetime extends \Ulmus\Attribute\Property\Field {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "datetime",
|
||||||
|
public array $attributes = [],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Decimal.php
Normal file
18
src/Attribute/Property/Field/Decimal.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Decimal extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "decimal",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Float.php
Normal file
18
src/Attribute/Property/Field/Float.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Float 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,
|
||||||
|
) {}
|
||||||
|
}
|
24
src/Attribute/Property/Field/ForeignKey.php
Normal file
24
src/Attribute/Property/Field/ForeignKey.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since we need consistancy between the declaration of our ID and FK fields, it
|
||||||
|
* was decided to extend the PK class instead of Field for this case.
|
||||||
|
*/
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class ForeignKey extends PrimaryKey {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = 'bigint',
|
||||||
|
public null|int|string $length = null,
|
||||||
|
public ? int $precision = null,
|
||||||
|
public array $attributes = [
|
||||||
|
'primary_key' => false,
|
||||||
|
'auto_increment' => false
|
||||||
|
],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
21
src/Attribute/Property/Field/Id.php
Normal file
21
src/Attribute/Property/Field/Id.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Id extends \Ulmus\Attribute\Property\Field {
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = 'bigint',
|
||||||
|
public null|int|string $length = null,
|
||||||
|
public ? int $precision = null,
|
||||||
|
public array $attributes = [
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'primary_key' => true,
|
||||||
|
],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Longblob.php
Normal file
18
src/Attribute/Property/Field/Longblob.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Longblob extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "longblob",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Longtext.php
Normal file
18
src/Attribute/Property/Field/Longtext.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Longtext extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "longtext",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Mediumblob.php
Normal file
18
src/Attribute/Property/Field/Mediumblob.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Mediumblob extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "mediumblob",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Mediumint.php
Normal file
18
src/Attribute/Property/Field/Mediumint.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Mediumint extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "mediumint",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Mediumtext.php
Normal file
18
src/Attribute/Property/Field/Mediumtext.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Mediumtext extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "mediumtext",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Numeric.php
Normal file
18
src/Attribute/Property/Field/Numeric.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Numeric extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "numeric",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
20
src/Attribute/Property/Field/PrimaryKey.php
Normal file
20
src/Attribute/Property/Field/PrimaryKey.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class PrimaryKey extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = 'bigint',
|
||||||
|
public null|int|string $length = null,
|
||||||
|
public ? int $precision = null,
|
||||||
|
public array $attributes = [
|
||||||
|
'primary_key' => true,
|
||||||
|
],
|
||||||
|
public bool $nullable = false,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Smallint.php
Normal file
18
src/Attribute/Property/Field/Smallint.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Smallint extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "smallint",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Text.php
Normal file
18
src/Attribute/Property/Field/Text.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Text extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "text",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
12
src/Attribute/Property/Field/Time.php
Normal file
12
src/Attribute/Property/Field/Time.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Time extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(? string $type = "time", ? int $length = null)
|
||||||
|
{
|
||||||
|
parent::__construct($type, $length);
|
||||||
|
}
|
||||||
|
}
|
12
src/Attribute/Property/Field/Timestamp.php
Normal file
12
src/Attribute/Property/Field/Timestamp.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Timestamp extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(? string $type = "timestamp", ? int $length = null)
|
||||||
|
{
|
||||||
|
parent::__construct($type, $length);
|
||||||
|
}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Tinyblob.php
Normal file
18
src/Attribute/Property/Field/Tinyblob.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Blob extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "tinyblob",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Tinyint.php
Normal file
18
src/Attribute/Property/Field/Tinyint.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Tinyint extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "tinyint",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Field/Tinytext.php
Normal file
18
src/Attribute/Property/Field/Tinytext.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Tinytext extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "tinytext",
|
||||||
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
19
src/Attribute/Property/Field/UpdatedAt.php
Normal file
19
src/Attribute/Property/Field/UpdatedAt.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Field;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class UpdatedAt extends \Ulmus\Attribute\Property\Field
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ? string $name = null,
|
||||||
|
public ? string $type = "timestamp",
|
||||||
|
public array $attributes = [
|
||||||
|
'update' => "CURRENT_TIMESTAMP",
|
||||||
|
'default' => null,
|
||||||
|
],
|
||||||
|
public bool $nullable = true,
|
||||||
|
public mixed $default = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
) {}
|
||||||
|
}
|
11
src/Attribute/Property/Filter.php
Normal file
11
src/Attribute/Property/Filter.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class Filter {
|
||||||
|
public function __construct(
|
||||||
|
public string $method = ""
|
||||||
|
)
|
||||||
|
{}
|
||||||
|
}
|
10
src/Attribute/Property/FilterJoin.php
Normal file
10
src/Attribute/Property/FilterJoin.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class FilterJoin {
|
||||||
|
public function __construct(
|
||||||
|
public string $method = ""
|
||||||
|
) {}
|
||||||
|
}
|
16
src/Attribute/Property/GroupBy.php
Normal file
16
src/Attribute/Property/GroupBy.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class GroupBy {
|
||||||
|
|
||||||
|
public array $fields = [];
|
||||||
|
|
||||||
|
public function __construct(...$field)
|
||||||
|
{
|
||||||
|
if ( $field ) {
|
||||||
|
$this->fields = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
src/Attribute/Property/Having.php
Normal file
6
src/Attribute/Property/Having.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class Having extends Where {}
|
19
src/Attribute/Property/Join.php
Normal file
19
src/Attribute/Property/Join.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
|
#[\Attribute]
|
||||||
|
class Join {
|
||||||
|
public function __construct(
|
||||||
|
public string $type,
|
||||||
|
public null|string|\Stringable|array $key = null,
|
||||||
|
public null|string|\Stringable $foreignKey = null,
|
||||||
|
public null|string $entity = null,
|
||||||
|
public null|string $alias = null,
|
||||||
|
) {
|
||||||
|
$this->key = Attribute::handleArrayField($this->key);
|
||||||
|
$this->foreignKey = Attribute::handleArrayField($this->foreignKey);
|
||||||
|
}
|
||||||
|
}
|
6
src/Attribute/Property/On.php
Normal file
6
src/Attribute/Property/On.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class On extends Where {}
|
19
src/Attribute/Property/OrWhere.php
Normal file
19
src/Attribute/Property/OrWhere.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
use Ulmus\Attribute\Attribute;
|
||||||
|
use Ulmus\Query;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class OrWhere extends Where {
|
||||||
|
public function __construct(
|
||||||
|
public string|\Stringable|array $field,
|
||||||
|
public mixed $value = null,
|
||||||
|
public null|string $operator = null,
|
||||||
|
public null|string $condition = Query\Where::CONDITION_OR,
|
||||||
|
) {
|
||||||
|
|
||||||
|
$this->key = Attribute::handleArrayField($this->key);
|
||||||
|
}
|
||||||
|
}
|
16
src/Attribute/Property/OrderBy.php
Normal file
16
src/Attribute/Property/OrderBy.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class OrderBy {
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string|\Stringable|array $field,
|
||||||
|
public string $order = "ASC",
|
||||||
|
) {
|
||||||
|
$this->field = Attribute::handleArrayField($this->field);
|
||||||
|
}
|
||||||
|
}
|
87
src/Attribute/Property/Relation.php
Normal file
87
src/Attribute/Property/Relation.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Relation {
|
||||||
|
public function __construct(
|
||||||
|
public string $type,
|
||||||
|
public \Stringable|string|array $key = "",
|
||||||
|
public null|\Closure $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 string $function = "loadAll",
|
||||||
|
) {
|
||||||
|
$this->key = Attribute::handleArrayField($this->key);
|
||||||
|
$this->foreignKey = Attribute::handleArrayField($this->foreignKey);
|
||||||
|
$this->foreignField = Attribute::handleArrayField($this->foreignField);
|
||||||
|
$this->bridgeKey = Attribute::handleArrayField($this->bridgeKey);
|
||||||
|
$this->bridgeField = Attribute::handleArrayField($this->bridgeField);
|
||||||
|
$this->bridgeForeignKey = Attribute::handleArrayField($this->bridgeForeignKey);
|
||||||
|
$this->field = Attribute::handleArrayField($this->field);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (bool) $this->bridge;
|
||||||
|
}
|
||||||
|
}
|
6
src/Attribute/Property/Relation/Ignore.php
Normal file
6
src/Attribute/Property/Relation/Ignore.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property\Relation;
|
||||||
|
|
||||||
|
#[\Attribute]
|
||||||
|
class Ignore {}
|
13
src/Attribute/Property/Virtual.php
Normal file
13
src/Attribute/Property/Virtual.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class Virtual extends Field {
|
||||||
|
|
||||||
|
public bool $readonly = true;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public ? string $method = null,
|
||||||
|
) {}
|
||||||
|
}
|
18
src/Attribute/Property/Where.php
Normal file
18
src/Attribute/Property/Where.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
use Ulmus\Attribute\Attribute;
|
||||||
|
use Ulmus\Query;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class Where {
|
||||||
|
public function __construct(
|
||||||
|
public string|\Stringable|array $field,
|
||||||
|
public mixed $value = null,
|
||||||
|
public string $operator = Query\Where::OPERATOR_EQUAL,
|
||||||
|
public string $condition = Query\Where::CONDITION_AND,
|
||||||
|
) {
|
||||||
|
$this->field = Attribute::handleArrayField($field);
|
||||||
|
}
|
||||||
|
}
|
10
src/Attribute/Property/WithJoin.php
Normal file
10
src/Attribute/Property/WithJoin.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||||
|
class WithJoin {
|
||||||
|
public function __construct(
|
||||||
|
array $joins = []
|
||||||
|
) {}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
namespace Ulmus\Common;
|
namespace Ulmus\Common;
|
||||||
|
|
||||||
use Ulmus\Annotation\Annotation;
|
use Ulmus\Annotation\Annotation;
|
||||||
|
use Ulmus\Attribute;
|
||||||
use Ulmus\Migration\FieldDefinition;
|
use Ulmus\Migration\FieldDefinition;
|
||||||
use Ulmus\Ulmus,
|
use Ulmus\Ulmus,
|
||||||
Ulmus\Adapter\AdapterInterface,
|
Ulmus\Adapter\AdapterInterface,
|
||||||
@ -29,7 +30,7 @@ class EntityField implements WhereRawParameter
|
|||||||
|
|
||||||
public function name($useAlias = true) : string
|
public function name($useAlias = true) : string
|
||||||
{
|
{
|
||||||
$name = $this->entityResolver->searchFieldAnnotation($this->name, new Field() )->name ?? $this->name;
|
$name = $this->entityResolver->searchFieldAnnotation($this->name, [ Attribute\Property\Field::class, 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);
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
namespace Ulmus\Common;
|
namespace Ulmus\Common;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Ulmus\Ulmus,
|
use Ulmus\Ulmus,
|
||||||
Ulmus\Annotation\Classes\Table,
|
Ulmus\Annotation\Classes\Table,
|
||||||
Ulmus\Annotation\Property\Field,
|
Ulmus\Annotation\Property\Field,
|
||||||
Ulmus\Annotation\Property\Virtual,
|
Ulmus\Annotation\Property\Virtual,
|
||||||
Ulmus\Annotation\Property\Relation;
|
Ulmus\Annotation\Property\Relation,
|
||||||
|
Ulmus\Attribute;
|
||||||
|
|
||||||
use Notes\Annotation;
|
use Notes\Annotation;
|
||||||
|
|
||||||
@ -32,12 +34,12 @@ class EntityResolver {
|
|||||||
|
|
||||||
protected array $fieldList = [];
|
protected array $fieldList = [];
|
||||||
|
|
||||||
public function __construct(string $entityClass)
|
public function __construct(string $entityClass, ? CacheInterface $cache = null)
|
||||||
{
|
{
|
||||||
$this->entityClass = $entityClass;
|
$this->entityClass = $entityClass;
|
||||||
|
|
||||||
list($this->uses, $this->class, $this->methods, $this->properties) = array_values(
|
list($this->uses, $this->class, $this->methods, $this->properties) = array_values(
|
||||||
ObjectReflection::fromClass($entityClass)->read()
|
ObjectReflection::fromClass($entityClass, $cache)->read()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->resolveAnnotations();
|
$this->resolveAnnotations();
|
||||||
@ -57,14 +59,28 @@ class EntityResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function searchField($name) : null|array
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false);
|
||||||
|
}
|
||||||
|
catch(\Throwable $e) {
|
||||||
|
if ( $throwException) {
|
||||||
|
throw new \InvalidArgumentException("Can't find entity field's column named `$name` from entity {$this->entityClass}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public function fieldList($fieldKey = self::KEY_ENTITY_NAME, bool $skipVirtual = false) : array
|
public function fieldList($fieldKey = self::KEY_ENTITY_NAME, bool $skipVirtual = false) : array
|
||||||
{
|
{
|
||||||
$fieldList = [];
|
$fieldList = [];
|
||||||
|
|
||||||
foreach($this->properties as $item) {
|
foreach($this->properties as $item) {
|
||||||
foreach($item['tags'] ?? [] as $tag) {
|
foreach($item['tags'] ?? [] as $tag) {
|
||||||
if ( $tag['object'] instanceof Field ) {
|
if ( $tag['object'] instanceof Field or $tag['object'] instanceof Attribute\Property\Field ) {
|
||||||
if ( $skipVirtual && ($tag['object'] instanceof Virtual )) {
|
if ( $skipVirtual && ($tag['object'] instanceof Virtual or $tag['object'] instanceof Attribute\Property\Virtual )) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +117,7 @@ class EntityResolver {
|
|||||||
try{
|
try{
|
||||||
if ( null !== ( $this->properties[$name] ?? null ) ) {
|
if ( null !== ( $this->properties[$name] ?? null ) ) {
|
||||||
foreach($this->properties[$name]['tags'] ?? [] as $tag) {
|
foreach($this->properties[$name]['tags'] ?? [] as $tag) {
|
||||||
if ( $tag['object'] instanceof Relation ) {
|
if ( $tag['object'] instanceof Relation or $tag['object'] instanceof Attribute\Property\Relation ) {
|
||||||
return $this->properties[$name];
|
return $this->properties[$name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,25 +134,28 @@ class EntityResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchFieldAnnotation(string $field, Annotation $annotationType, bool $caseSensitive = true) : ? Annotation
|
public function searchFieldAnnotation(string $field, array|object|string $annotationType, bool $caseSensitive = true) : ? object
|
||||||
{
|
{
|
||||||
$found = $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive);
|
return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null;
|
||||||
return $found ? $found[0] : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchFieldAnnotationList(string $field, Annotation $annotationType, bool $caseSensitive = true) : array
|
public function searchFieldAnnotationList(string $field, array|object|string $annotationType, bool $caseSensitive = true) : array
|
||||||
{
|
{
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
$search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER);
|
$search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER);
|
||||||
|
|
||||||
|
$annotations = is_array($annotationType) ? $annotationType : [ $annotationType ];
|
||||||
|
|
||||||
if ( null !== ( $search[$field] ?? null ) ) {
|
if ( null !== ( $search[$field] ?? null ) ) {
|
||||||
foreach($search[$field]['tags'] ?? [] as $tag) {
|
foreach($search[$field]['tags'] ?? [] as $tag) {
|
||||||
if ( $tag['object'] instanceof $annotationType ) {
|
foreach($annotations as $annotation) {
|
||||||
|
if ( $tag['object'] instanceof $annotation ) {
|
||||||
$list[] = $tag['object'];
|
$list[] = $tag['object'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
@ -154,9 +173,9 @@ class EntityResolver {
|
|||||||
return $table->name ?? "";
|
return $table->name ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tableAnnotation($required = false) : Table
|
public function tableAnnotation($required = false) : Table|Attribute\Obj\Table
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getAnnotationFromClassname( Table::class ) ) {
|
if ( null === $table = $this->getTableAttribute() ) {
|
||||||
if ($required) {
|
if ($required) {
|
||||||
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");
|
||||||
}
|
}
|
||||||
@ -172,7 +191,7 @@ class EntityResolver {
|
|||||||
|
|
||||||
public function sqlAdapter() : \Ulmus\ConnectionAdapter
|
public function sqlAdapter() : \Ulmus\ConnectionAdapter
|
||||||
{
|
{
|
||||||
if ( null !== $table = $this->getAnnotationFromClassname( Table::class ) ) {
|
if ( null !== $table = $this->getTableAttribute() ) {
|
||||||
if ( $table->adapter ?? null ) {
|
if ( $table->adapter ?? null ) {
|
||||||
if ( null === ( $adapter = \Ulmus\Ulmus::$registeredAdapters[$table->adapter] ?? null ) ) {
|
if ( null === ( $adapter = \Ulmus\Ulmus::$registeredAdapters[$table->adapter] ?? null ) ) {
|
||||||
throw new \Exception("Requested database adapter `{$table->adapter}` is not registered.");
|
throw new \Exception("Requested database adapter `{$table->adapter}` is not registered.");
|
||||||
@ -196,7 +215,7 @@ class EntityResolver {
|
|||||||
|
|
||||||
public function schemaName(bool $required = false) : ? string
|
public function schemaName(bool $required = false) : ? string
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getAnnotationFromClassname( Table::class ) ) {
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +229,8 @@ class EntityResolver {
|
|||||||
public function getPrimaryKeyField() : ? array
|
public function getPrimaryKeyField() : ? array
|
||||||
{
|
{
|
||||||
foreach($this->fieldList() as $key => $value) {
|
foreach($this->fieldList() as $key => $value) {
|
||||||
if ( null !== ( $field = $this->searchFieldAnnotation($key, new Field() ) ) ) {
|
$field = $this->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
|
||||||
|
if ( null !== $field ) {
|
||||||
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
||||||
return [ $key => $field ];
|
return [ $key => $field ];
|
||||||
}
|
}
|
||||||
@ -230,13 +250,17 @@ class EntityResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getTableAttribute()
|
||||||
|
{
|
||||||
|
return $this->getAnnotationFromClassname(Attribute\Obj\Table::class, false) ?: $this->getAnnotationFromClassname( Table::class );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform an annotation into it's object's counterpart
|
* Transform an annotation into it's object's counterpart
|
||||||
*/
|
*/
|
||||||
public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
|
public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
|
||||||
{
|
{
|
||||||
if ( $name = $this->uses[$className] ?? false ) {
|
if ( $name = $this->uses[$className] ?? false ) {
|
||||||
|
|
||||||
foreach(array_reverse($this->class['tags']) as $item) {
|
foreach(array_reverse($this->class['tags']) as $item) {
|
||||||
if ( $item['tag'] === $name ) {
|
if ( $item['tag'] === $name ) {
|
||||||
return $this->instanciateAnnotationObject($item);
|
return $this->instanciateAnnotationObject($item);
|
||||||
@ -270,19 +294,24 @@ class EntityResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instanciateAnnotationObject(array $tagDefinition) : Annotation
|
public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object
|
||||||
{
|
{
|
||||||
|
if ($tagDefinition instanceof \ReflectionAttribute) {
|
||||||
|
$obj = $tagDefinition->newInstance();
|
||||||
|
}
|
||||||
|
else {
|
||||||
$arguments = $this->extractArguments($tagDefinition['arguments']);
|
$arguments = $this->extractArguments($tagDefinition['arguments']);
|
||||||
|
|
||||||
if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) {
|
if (false === $class = array_search($tagDefinition['tag'], $this->uses)) {
|
||||||
throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
||||||
}
|
}
|
||||||
|
|
||||||
$obj = new $class(... $arguments['constructor']);
|
$obj = new $class(... $arguments['constructor']);
|
||||||
|
|
||||||
foreach($arguments['setter'] as $key => $value) {
|
foreach ($arguments['setter'] as $key => $value) {
|
||||||
$obj->$key = $value;
|
$obj->$key = $value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
@ -309,18 +338,18 @@ class EntityResolver {
|
|||||||
protected function resolveAnnotations()
|
protected function resolveAnnotations()
|
||||||
{
|
{
|
||||||
foreach($this->class['tags'] as &$tag) {
|
foreach($this->class['tags'] as &$tag) {
|
||||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
$tag['object'] ??= $this->instanciateAnnotationObject($tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->properties as &$property) {
|
foreach($this->properties as &$property) {
|
||||||
foreach($property['tags'] as &$tag){
|
foreach($property['tags'] as &$tag){
|
||||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
$tag['object'] ??= $this->instanciateAnnotationObject($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->methods as &$method) {
|
foreach($this->methods as &$method) {
|
||||||
foreach($method['tags'] as &$tag){
|
foreach($method['tags'] as &$tag){
|
||||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
$tag['object'] ??= $this->instanciateAnnotationObject($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ class ConnectionAdapter
|
|||||||
|
|
||||||
public function pdo() : PdoObject
|
public function pdo() : PdoObject
|
||||||
{
|
{
|
||||||
return $this->pdo ?? $this->pdo = $this->connect()->pdo;
|
return $this->pdo ?? $this->connect()->pdo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connector() : object
|
public function connector() : object
|
||||||
|
@ -40,8 +40,8 @@ trait EntityTrait {
|
|||||||
$entityResolver = $this->resolveEntity();
|
$entityResolver = $this->resolveEntity();
|
||||||
|
|
||||||
foreach($dataset as $key => $value) {
|
foreach($dataset as $key => $value) {
|
||||||
$field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
|
|
||||||
|
|
||||||
|
$field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
|
||||||
$field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
|
$field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
|
||||||
|
|
||||||
if ( $field === null ) {
|
if ( $field === null ) {
|
||||||
@ -66,7 +66,7 @@ trait EntityTrait {
|
|||||||
elseif ( EntityField::isScalarType($field['type']) ) {
|
elseif ( EntityField::isScalarType($field['type']) ) {
|
||||||
|
|
||||||
if ( $field['type'] === 'string' ) {
|
if ( $field['type'] === 'string' ) {
|
||||||
$annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() );
|
$annotation = $entityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ] );
|
||||||
|
|
||||||
if ( $annotation->length ?? null ) {
|
if ( $annotation->length ?? null ) {
|
||||||
$value = mb_substr($value, 0, $annotation->length);
|
$value = mb_substr($value, 0, $annotation->length);
|
||||||
@ -90,7 +90,6 @@ trait EntityTrait {
|
|||||||
}
|
}
|
||||||
catch(\Error $e) {
|
catch(\Error $e) {
|
||||||
$f = $field['type'];
|
$f = $field['type'];
|
||||||
dump($f, $f::from($value));
|
|
||||||
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name']));
|
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,17 +125,11 @@ trait EntityTrait {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function fromArray(iterable $dataset) : self
|
public function fromArray(iterable $dataset) : self
|
||||||
{
|
{
|
||||||
return $this->entityFillFromDataset($dataset);
|
return $this->entityFillFromDataset($dataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array
|
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array
|
||||||
{
|
{
|
||||||
if ( $returnSource ) {
|
if ( $returnSource ) {
|
||||||
@ -148,7 +141,7 @@ trait EntityTrait {
|
|||||||
$entityResolver = $this->resolveEntity();
|
$entityResolver = $this->resolveEntity();
|
||||||
|
|
||||||
foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
|
foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
|
||||||
$annotation = $entityResolver->searchFieldAnnotation($key, new Field() );
|
$annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
|
||||||
|
|
||||||
if ( isset($this->$key) ) {
|
if ( isset($this->$key) ) {
|
||||||
$dataset[$annotation->name ?? $key] = static::repository()->adapter->adapter()->writableValue($this->$key);
|
$dataset[$annotation->name ?? $key] = static::repository()->adapter->adapter()->writableValue($this->$key);
|
||||||
@ -161,7 +154,7 @@ trait EntityTrait {
|
|||||||
# @TODO Must fix recursive bug !
|
# @TODO Must fix recursive bug !
|
||||||
if ($includeRelations) {
|
if ($includeRelations) {
|
||||||
foreach($entityResolver->properties as $name => $field){
|
foreach($entityResolver->properties as $name => $field){
|
||||||
$relation = $entityResolver->searchFieldAnnotation($name, new Relation() );
|
$relation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Relation::class. Relation::class ] );
|
||||||
|
|
||||||
if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
||||||
if ( null !== $value = $this->$name ?? null ) {
|
if ( null !== $value = $this->$name ?? null ) {
|
||||||
@ -185,9 +178,6 @@ trait EntityTrait {
|
|||||||
return $dataset;
|
return $dataset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function toArray($includeRelations = false, array $filterFields = null) : array
|
public function toArray($includeRelations = false, array $filterFields = null) : array
|
||||||
{
|
{
|
||||||
$dataset = $this->entityGetDataset($includeRelations);
|
$dataset = $this->entityGetDataset($includeRelations);
|
||||||
@ -195,17 +185,11 @@ trait EntityTrait {
|
|||||||
return $filterFields ? array_intersect_key($dataset, array_flip($filterFields)) : $dataset;
|
return $filterFields ? array_intersect_key($dataset, array_flip($filterFields)) : $dataset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function toCollection() : EntityCollection
|
public function toCollection() : EntityCollection
|
||||||
{
|
{
|
||||||
return static::entityCollection([ $this ]);
|
return static::entityCollection([ $this ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function isLoaded() : bool
|
public function isLoaded() : bool
|
||||||
{
|
{
|
||||||
if (empty($this->entityLoadedDataset)) {
|
if (empty($this->entityLoadedDataset)) {
|
||||||
@ -221,9 +205,6 @@ trait EntityTrait {
|
|||||||
return isset($this->$key);
|
return isset($this->$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function __get(string $name)
|
public function __get(string $name)
|
||||||
{
|
{
|
||||||
$relation = new Repository\RelationBuilder($this);
|
$relation = new Repository\RelationBuilder($this);
|
||||||
@ -235,32 +216,30 @@ trait EntityTrait {
|
|||||||
throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name));
|
throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function __isset(string $name) : bool
|
public function __isset(string $name) : bool
|
||||||
{
|
{
|
||||||
#if ( null !== $relation = static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
|
#if ( null !== $relation = static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
|
||||||
# return isset($this->{$relation->key});
|
# return isset($this->{$relation->key});
|
||||||
#}
|
#}
|
||||||
if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
|
$rel = static::resolveEntity()->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ]);
|
||||||
|
|
||||||
|
if ( $this->isLoaded() && $rel ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($this->$name);
|
return isset($this->$name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function __sleep()
|
public function __sleep()
|
||||||
{
|
{
|
||||||
return array_keys($this->resolveEntity()->fieldList());
|
return array_merge(array_keys($this->resolveEntity()->fieldList()), [ 'entityLoadedDataset' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __wakeup()
|
||||||
|
{
|
||||||
|
$this->resetVirtualProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function __clone()
|
public function __clone()
|
||||||
{
|
{
|
||||||
foreach($this as $prop) {
|
foreach($this as $prop) {
|
||||||
@ -274,33 +253,21 @@ trait EntityTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function jsonSerialize() : mixed
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public function jsonSerialize()
|
|
||||||
{
|
{
|
||||||
return $this->entityGetDataset();
|
return $this->entityGetDataset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function resolveEntity() : EntityResolver
|
public static function resolveEntity() : EntityResolver
|
||||||
{
|
{
|
||||||
return Ulmus::resolveEntity(static::class);
|
return Ulmus::resolveEntity(static::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function repository(string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository
|
public static function repository(string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository
|
||||||
{
|
{
|
||||||
return Ulmus::repository(static::class, $alias, $adapter);
|
return Ulmus::repository(static::class, $alias, $adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function entityCollection(...$arguments) : EntityCollection
|
public static function entityCollection(...$arguments) : EntityCollection
|
||||||
{
|
{
|
||||||
$collection = new EntityCollection(...$arguments);
|
$collection = new EntityCollection(...$arguments);
|
||||||
@ -309,26 +276,16 @@ trait EntityTrait {
|
|||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function queryBuilder() : QueryBuilder
|
public static function queryBuilder() : QueryBuilder
|
||||||
{
|
{
|
||||||
return Ulmus::queryBuilder(static::class);
|
return Ulmus::queryBuilder(static::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function field($name, ? string $alias = Repository::DEFAULT_ALIAS) : EntityField
|
public static function field($name, ? string $alias = Repository::DEFAULT_ALIAS) : EntityField
|
||||||
{
|
{
|
||||||
|
|
||||||
return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class));
|
return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Ignore
|
|
||||||
*/
|
|
||||||
public static function fields(array $fields, ? string $alias = Repository::DEFAULT_ALIAS) : string
|
public static function fields(array $fields, ? string $alias = Repository::DEFAULT_ALIAS) : string
|
||||||
{
|
{
|
||||||
return implode(', ', array_map(function($item) use ($alias){
|
return implode(', ', array_map(function($item) use ($alias){
|
||||||
|
@ -4,6 +4,7 @@ namespace Ulmus\Migration;
|
|||||||
|
|
||||||
use Ulmus\Adapter\AdapterInterface;
|
use Ulmus\Adapter\AdapterInterface;
|
||||||
use Ulmus\Annotation\Property\Field;
|
use Ulmus\Annotation\Property\Field;
|
||||||
|
use Ulmus\Attribute;
|
||||||
use Ulmus\Entity;
|
use Ulmus\Entity;
|
||||||
|
|
||||||
class FieldDefinition {
|
class FieldDefinition {
|
||||||
@ -40,7 +41,7 @@ class FieldDefinition {
|
|||||||
$this->type = $field->type ?? $data['type'];
|
$this->type = $field->type ?? $data['type'];
|
||||||
$this->length = $field->length ?? null;
|
$this->length = $field->length ?? null;
|
||||||
$this->precision = $field->precision ?? null;
|
$this->precision = $field->precision ?? null;
|
||||||
$this->nullable = isset($field->nullable) ? $field->nullable : $data['nullable'];
|
$this->nullable = $data['nullable'] ?: $field->nullable;
|
||||||
$this->update = $field->attributes['update'] ?? null;
|
$this->update = $field->attributes['update'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +70,9 @@ class FieldDefinition {
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldTag() : ? Field
|
public function getFieldTag() : Field|Attribute\Property\Field|null
|
||||||
{
|
{
|
||||||
$field = array_filter($this->tags, fn($item) => $item['object'] instanceof Field);
|
$field = array_filter($this->tags, fn($item) => $item['object'] instanceof Field || $item['object'] instanceof Attribute\Property\Field);
|
||||||
|
|
||||||
return array_pop($field)['object'];
|
return array_pop($field)['object'];
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function select($field, bool $distinct = false) : self
|
public function select(string|\Stringable|array $field, bool $distinct = false) : self
|
||||||
{
|
{
|
||||||
if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
|
if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
|
||||||
$select->add($field);
|
$select->add($field);
|
||||||
@ -195,7 +195,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function where(/* stringable*/ $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
public function where(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
||||||
{
|
{
|
||||||
# Empty IN case
|
# Empty IN case
|
||||||
if ( [] === $value ) {
|
if ( [] === $value ) {
|
||||||
@ -217,12 +217,12 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notWhere($field, $value, string $operator = Query\Where::CONDITION_AND) : self
|
public function notWhere(string|\Stringable $field, $value, string $operator = Query\Where::CONDITION_AND) : self
|
||||||
{
|
{
|
||||||
return $this->where($field, $value, $operator, true);
|
return $this->where($field, $value, $operator, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
public function having(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
||||||
{
|
{
|
||||||
if ( $this->having ?? false ) {
|
if ( $this->having ?? false ) {
|
||||||
$having = $this->having;
|
$having = $this->having;
|
||||||
@ -266,7 +266,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orderBy(string $field, ? string $direction = null) : self
|
public function orderBy(string|\Stringable $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
|
if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
|
||||||
$orderBy = new Query\OrderBy();
|
$orderBy = new Query\OrderBy();
|
||||||
@ -278,7 +278,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function groupBy(string $field, ? string $direction = null) : self
|
public function groupBy(string|\Stringable $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
|
if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
|
||||||
$groupBy = new Query\GroupBy();
|
$groupBy = new Query\GroupBy();
|
||||||
@ -290,14 +290,14 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function join(string $type, /*string | QueryBuilder*/ $table, $field, $value, bool $outer = false, ? string $alias = null) : self
|
public function join(string $type, /*string | QueryBuilder*/ $table, mixed $field, mixed $value, bool $outer = false, ? string $alias = null) : self
|
||||||
{
|
{
|
||||||
$this->withJoin(...func_get_args());
|
$this->withJoin(...func_get_args());
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withJoin(string $type, $table, $field, $value, bool $outer = false, ? string $alias = null) : Query\Join
|
public function withJoin(string $type, $table, mixed $field, mixed $value, bool $outer = false, ? string $alias = null) : Query\Join
|
||||||
{
|
{
|
||||||
$join = new Query\Join($this);
|
$join = new Query\Join($this);
|
||||||
|
|
||||||
|
@ -2,7 +2,16 @@
|
|||||||
|
|
||||||
namespace Ulmus;
|
namespace Ulmus;
|
||||||
|
|
||||||
use Ulmus\Annotation\Property\{Field, Where, Having, Relation, Filter, Join, FilterJoin, WithJoin, Relation\Ignore as RelationIgnore};
|
use Ulmus\Annotation\Property\{Field,
|
||||||
|
OrderBy,
|
||||||
|
Where,
|
||||||
|
Having,
|
||||||
|
Relation,
|
||||||
|
Filter,
|
||||||
|
Join,
|
||||||
|
FilterJoin,
|
||||||
|
WithJoin,
|
||||||
|
Relation\Ignore as RelationIgnore};
|
||||||
use Ulmus\Common\EntityResolver;
|
use Ulmus\Common\EntityResolver;
|
||||||
|
|
||||||
class Repository
|
class Repository
|
||||||
@ -307,7 +316,7 @@ class Repository
|
|||||||
$array = array_change_key_case($entity->toArray());
|
$array = array_change_key_case($entity->toArray());
|
||||||
|
|
||||||
$dataset = array_change_key_case($entity->entityGetDataset(false, true));
|
$dataset = array_change_key_case($entity->entityGetDataset(false, true));
|
||||||
# dump($array, $dataset);
|
|
||||||
return array_udiff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset, function($e1, $e2) {
|
return array_udiff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset, function($e1, $e2) {
|
||||||
if ( is_array($e1) ) {
|
if ( is_array($e1) ) {
|
||||||
if (is_array($e2)) {
|
if (is_array($e2)) {
|
||||||
@ -332,7 +341,7 @@ class Repository
|
|||||||
$dataset = $this->generateDatasetDiff($entity, $oldValues);
|
$dataset = $this->generateDatasetDiff($entity, $oldValues);
|
||||||
|
|
||||||
foreach($dataset as $field => $value) {
|
foreach($dataset as $field => $value) {
|
||||||
if ( false === ( $this->entityResolver->searchFieldAnnotation($field, new Field, false)->readonly ?? false ) ) {
|
if ( false === ( $this->entityResolver->searchFieldAnnotation($field, [ Attribute\Property\Field::class, Field::class ], false)->readonly ?? false ) ) {
|
||||||
$intersect[$field] = $field;
|
$intersect[$field] = $field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,7 +376,7 @@ class Repository
|
|||||||
$prependField and ($prependField .= "$");
|
$prependField and ($prependField .= "$");
|
||||||
|
|
||||||
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||||
if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore)) {
|
if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
|
||||||
$this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias)));
|
$this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,7 +389,7 @@ class Repository
|
|||||||
$fieldlist = [];
|
$fieldlist = [];
|
||||||
|
|
||||||
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||||
if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore)) {
|
if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
|
||||||
$fieldlist[] = $key;
|
$fieldlist[] = $key;
|
||||||
$fieldlist[] = $entity::field($field['name'], $this->escapeIdentifier($alias));
|
$fieldlist[] = $entity::field($field['name'], $this->escapeIdentifier($alias));
|
||||||
}
|
}
|
||||||
@ -455,7 +464,7 @@ class Repository
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function join(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self
|
public function join(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self
|
||||||
{
|
{
|
||||||
$join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null);
|
$join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null);
|
||||||
|
|
||||||
@ -466,7 +475,7 @@ class Repository
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function outerJoin(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self
|
public function outerJoin(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self
|
||||||
{
|
{
|
||||||
$join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null);
|
$join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null);
|
||||||
|
|
||||||
@ -497,7 +506,7 @@ class Repository
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function groupBy($field) : self
|
public function groupBy(string|\Stringable $field) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->groupBy($field);
|
$this->queryBuilder->groupBy($field);
|
||||||
|
|
||||||
@ -513,7 +522,7 @@ class Repository
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orderBy($field, ? string $direction = null) : self
|
public function orderBy(string|\Stringable $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->orderBy($field, $direction);
|
$this->queryBuilder->orderBy($field, $direction);
|
||||||
|
|
||||||
@ -563,7 +572,7 @@ class Repository
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function wherePrimaryKey($value) : self
|
public function wherePrimaryKey(mixed $value) : self
|
||||||
{
|
{
|
||||||
if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
|
if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
|
||||||
throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
|
throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
|
||||||
@ -574,18 +583,21 @@ class Repository
|
|||||||
return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
|
return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withJoin(/*string|array*/ $fields) : self
|
public function withJoin(string|array $fields) : self
|
||||||
{
|
{
|
||||||
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
|
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
|
||||||
$this->select("{$this->alias}.*");
|
$select = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
|
||||||
|
$this->select($this->entityClass::fields(array_map(fn($f) => $f['object']->name ?? $f['name'], $select)));
|
||||||
}
|
}
|
||||||
|
|
||||||
# @TODO Apply FILTER annotation to this too !
|
# @TODO Apply FILTER annotation to this too !
|
||||||
foreach(array_filter((array) $fields) as $item) {
|
foreach(array_filter((array) $fields) as $item) {
|
||||||
$annotation = $this->entityResolver->searchFieldAnnotation($item, new Join) ?:
|
$annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class, Join::class ]) ?:
|
||||||
$this->entityResolver->searchFieldAnnotation($item, new Relation);
|
$this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]);
|
||||||
|
|
||||||
if (( $annotation instanceof Relation ) && ( $annotation->normalizeType() === 'manytomany' )) {
|
$isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation);
|
||||||
|
|
||||||
|
if ($isRelation && ( $annotation->normalizeType() === 'manytomany' )) {
|
||||||
throw new Exception("Many-to-many relation can not be preloaded within joins.");
|
throw new Exception("Many-to-many relation can not be preloaded within joins.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,10 +607,10 @@ class Repository
|
|||||||
$entity = $annotation->entity ?? $this->entityResolver->properties[$item]['type'];
|
$entity = $annotation->entity ?? $this->entityResolver->properties[$item]['type'];
|
||||||
|
|
||||||
foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||||
if ( null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore) ) {
|
if ( null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ]) ) {
|
||||||
$escAlias = $this->escapeIdentifier($alias);
|
$escAlias = $this->escapeIdentifier($alias);
|
||||||
|
|
||||||
$name = $entity::resolveEntity()->searchFieldAnnotation($field['name'], new Field())->name ?? $field['name'];
|
$name = $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ])->name ?? $field['name'];
|
||||||
|
|
||||||
$this->select("$escAlias.$key as $alias\${$name}");
|
$this->select("$escAlias.$key as $alias\${$name}");
|
||||||
}
|
}
|
||||||
@ -606,17 +618,17 @@ class Repository
|
|||||||
|
|
||||||
$this->open();
|
$this->open();
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ] ) as $condition) {
|
||||||
if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) {
|
if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) {
|
||||||
$this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
$this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Having() ) as $condition) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class, Having::class ] ) as $condition) {
|
||||||
$this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
$this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Filter() ) as $filter) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Filter::class, Filter::class ] ) as $filter) {
|
||||||
call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item, true ]);
|
call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item, true ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,8 +639,7 @@ class Repository
|
|||||||
$foreignKey = is_string($annotation->foreignKey) ? $entity::field($annotation->foreignKey, $alias) : $annotation->foreignKey;
|
$foreignKey = is_string($annotation->foreignKey) ? $entity::field($annotation->foreignKey, $alias) : $annotation->foreignKey;
|
||||||
|
|
||||||
$this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias) {
|
$this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias) {
|
||||||
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) {
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) {
|
|
||||||
if ( ! is_object($condition->field) ) {
|
if ( ! is_object($condition->field) ) {
|
||||||
$field = $this->entityClass::field($condition->field);
|
$field = $this->entityClass::field($condition->field);
|
||||||
}
|
}
|
||||||
@ -644,7 +655,7 @@ class Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new FilterJoin() ) as $filter) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\FilterJoin::class, FilterJoin::class ]) as $filter) {
|
||||||
call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item, true ]);
|
call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item, true ]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -670,7 +681,7 @@ class Repository
|
|||||||
|
|
||||||
# Apply FILTER annotation to this too !
|
# Apply FILTER annotation to this too !
|
||||||
foreach(array_filter((array) $fields) as $item) {
|
foreach(array_filter((array) $fields) as $item) {
|
||||||
if ( $relation = $this->entityResolver->searchFieldAnnotation($item, new Relation) ) {
|
if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]) ) {
|
||||||
$alias = $relation->alias ?? $item;
|
$alias = $relation->alias ?? $item;
|
||||||
|
|
||||||
if ( $relation->isManyToMany() ) {
|
if ( $relation->isManyToMany() ) {
|
||||||
@ -691,11 +702,11 @@ class Repository
|
|||||||
|
|
||||||
# $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
|
# $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) {
|
||||||
$repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
$repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->entityResolver->searchFieldAnnotationList($item, new Having() ) as $condition) {
|
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class, Having::class ] ) as $condition) {
|
||||||
$repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
$repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,9 +733,9 @@ class Repository
|
|||||||
public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void
|
public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void
|
||||||
{
|
{
|
||||||
foreach ((array)$fields as $name) {
|
foreach ((array)$fields as $name) {
|
||||||
if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, new Annotation\Property\Relation()))) {
|
if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ))) {
|
||||||
$order = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\OrderBy());
|
$order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ]);
|
||||||
$where = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\Where());
|
$where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ]);
|
||||||
|
|
||||||
$baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type'];
|
$baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type'];
|
||||||
$baseEntityResolver = $baseEntity::resolveEntity();
|
$baseEntityResolver = $baseEntity::resolveEntity();
|
||||||
@ -735,7 +746,7 @@ class Repository
|
|||||||
$repository = $baseEntity::repository();
|
$repository = $baseEntity::repository();
|
||||||
|
|
||||||
foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||||
if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], new RelationIgnore)) {
|
if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) {
|
||||||
$repository->select($baseEntityResolver->entityClass::field($key));
|
$repository->select($baseEntityResolver->entityClass::field($key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -825,28 +836,28 @@ class Repository
|
|||||||
return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter);
|
return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runQuery() /* : mixed */
|
public function runQuery() : mixed
|
||||||
{
|
{
|
||||||
$this->finalizeQuery();
|
$this->finalizeQuery();
|
||||||
|
|
||||||
return Ulmus::runQuery($this->queryBuilder, $this->adapter);
|
return Ulmus::runQuery($this->queryBuilder, $this->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runInsertQuery() /* : mixed */
|
public function runInsertQuery() : mixed
|
||||||
{
|
{
|
||||||
$this->finalizeQuery();
|
$this->finalizeQuery();
|
||||||
|
|
||||||
return Ulmus::runInsertQuery($this->queryBuilder, $this->adapter);
|
return Ulmus::runInsertQuery($this->queryBuilder, $this->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runUpdateQuery() /* : mixed */
|
public function runUpdateQuery() : mixed
|
||||||
{
|
{
|
||||||
$this->finalizeQuery();
|
$this->finalizeQuery();
|
||||||
|
|
||||||
return Ulmus::runUpdateQuery($this->queryBuilder, $this->adapter);
|
return Ulmus::runUpdateQuery($this->queryBuilder, $this->adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runDeleteQuery() /* : mixed */
|
public function runDeleteQuery() : mixed
|
||||||
{
|
{
|
||||||
$this->finalizeQuery();
|
$this->finalizeQuery();
|
||||||
|
|
||||||
@ -888,7 +899,8 @@ class Repository
|
|||||||
protected function selectSqlQuery() : self
|
protected function selectSqlQuery() : self
|
||||||
{
|
{
|
||||||
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
|
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
|
||||||
$this->select("{$this->alias}.*");
|
$fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
|
||||||
|
$this->select($this->entityClass::fields(array_map(fn($f) => $f['object']->name ?? $f['name'], $fields)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {
|
if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {
|
||||||
|
@ -25,7 +25,7 @@ trait ConditionTrait
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
|
public function where(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator, $condition);
|
$this->queryBuilder->where($field, $value, $operator, $condition);
|
||||||
|
|
||||||
@ -41,101 +41,101 @@ trait ConditionTrait
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function and(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
{
|
{
|
||||||
return $this->where($field, $value, $operator);
|
return $this->where($field, $value, $operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function or($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function or(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
|
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function notWhere(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
public function orNot(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
|
$this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
|
public function having(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->having($field, $value, $operator, $condition);
|
$this->queryBuilder->having($field, $value, $operator, $condition);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orHaving($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function orHaving(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR);
|
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
public function notHaving(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_AND, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orNotHaving($field, $value) : self
|
public function orNotHaving(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
|
$this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function in($field, $value, string $operator = Query\Where::COMPARISON_IN) : self
|
public function in(string|\Stringable $field, $value, string $operator = Query\Where::COMPARISON_IN) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator);
|
$this->queryBuilder->where($field, $value, $operator);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orIn($field, $value, string $operator = Query\Where::COMPARISON_IN) : self
|
public function orIn(string|\Stringable $field, $value, string $operator = Query\Where::COMPARISON_IN) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
|
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notIn($field, $value) : self
|
public function notIn(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, Query\Where::COMPARISON_IN, true);
|
$this->queryBuilder->where($field, $value, Query\Where::COMPARISON_IN, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orNotIn($field, $value) : self
|
public function orNotIn(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
return $this->orNot($field, $value, Query\Where::COMPARISON_IN, Query\Where::CONDITION_OR, true);
|
return $this->orNot($field, $value, Query\Where::COMPARISON_IN, Query\Where::CONDITION_OR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function like($field, $value) : self
|
public function like(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
$this->where($field, $value, Query\Where::OPERATOR_LIKE);
|
$this->where($field, $value, Query\Where::OPERATOR_LIKE);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orLike($field, $value) : self
|
public function orLike(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
$this->or($field, $value, Query\Where::OPERATOR_LIKE);
|
$this->or($field, $value, Query\Where::OPERATOR_LIKE);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notLike($field, $value) : self
|
public function notLike(string|\Stringable $field, $value) : self
|
||||||
{
|
{
|
||||||
$this->notWhere($field, $value, Query\Where::OPERATOR_LIKE);
|
$this->notWhere($field, $value, Query\Where::OPERATOR_LIKE);
|
||||||
|
|
||||||
|
@ -2,7 +2,17 @@
|
|||||||
|
|
||||||
namespace Ulmus\Repository;
|
namespace Ulmus\Repository;
|
||||||
|
|
||||||
use Ulmus\{ Ulmus, Annotation, Query, Common, Common\EntityResolver, Repository, Event, EntityCollection, };
|
use Ulmus\{Attribute\Property\Field,
|
||||||
|
Ulmus,
|
||||||
|
Annotation,
|
||||||
|
Attribute,
|
||||||
|
Query,
|
||||||
|
Common,
|
||||||
|
Common\EntityResolver,
|
||||||
|
Repository,
|
||||||
|
Event,
|
||||||
|
EntityCollection};
|
||||||
|
|
||||||
use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, };
|
use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, };
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
@ -15,7 +25,7 @@ class RelationBuilder
|
|||||||
|
|
||||||
protected Repository $repository;
|
protected Repository $repository;
|
||||||
|
|
||||||
protected /*object|string*/ $entity;
|
protected object|string $entity;
|
||||||
|
|
||||||
protected EntityResolver $resolver;
|
protected EntityResolver $resolver;
|
||||||
|
|
||||||
@ -27,7 +37,7 @@ class RelationBuilder
|
|||||||
|
|
||||||
protected array $joins;
|
protected array $joins;
|
||||||
|
|
||||||
public function __construct(/*string|object*/ $entity, ? Repository $repository = null)
|
public function __construct(string|object $entity, ? Repository $repository = null)
|
||||||
{
|
{
|
||||||
$this->entity = $entity;
|
$this->entity = $entity;
|
||||||
$this->resolver = $entity::resolveEntity();
|
$this->resolver = $entity::resolveEntity();
|
||||||
@ -48,7 +58,7 @@ class RelationBuilder
|
|||||||
return $this->resolveRelation($name) ?: $this->resolveVirtual($name) ?: false;
|
return $this->resolveRelation($name) ?: $this->resolveVirtual($name) ?: false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) {
|
if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class , Relation::class ] ) ) {
|
||||||
return $this->instanciateEmptyObject($name, $relation);
|
return $this->instanciateEmptyObject($name, $relation);
|
||||||
}
|
}
|
||||||
elseif ($virtual = $this->resolveVirtual($name)) {
|
elseif ($virtual = $this->resolveVirtual($name)) {
|
||||||
@ -59,9 +69,9 @@ class RelationBuilder
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resolveVirtual(string $name) /* : bool|object|EntityCollection */
|
protected function resolveVirtual(string $name) : bool|object
|
||||||
{
|
{
|
||||||
if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Virtual()))) {
|
if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) {
|
||||||
if ($virtual->closure ?? false) {
|
if ($virtual->closure ?? false) {
|
||||||
return call_user_func_array($virtual->closure, [ $this->entity ]);
|
return call_user_func_array($virtual->closure, [ $this->entity ]);
|
||||||
}
|
}
|
||||||
@ -72,17 +82,18 @@ class RelationBuilder
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resolveRelation(string $name) /* : bool|object|EntityCollection */
|
protected function resolveRelation(string $name) : bool|object
|
||||||
{
|
{
|
||||||
if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) ) {
|
if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ) ) ) {
|
||||||
$this->orders = $this->resolver->searchFieldAnnotationList($name, new OrderBy() );
|
$this->orders = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ] );
|
||||||
$this->wheres = $this->resolver->searchFieldAnnotationList($name, new Where() );
|
$this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ] );
|
||||||
$this->filters = $this->resolver->searchFieldAnnotationList($name, new Filter() );
|
$this->filters = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Filter::class, Filter::class ] );
|
||||||
$this->joins = $this->resolver->searchFieldAnnotationList($name, new WithJoin() );
|
$this->joins = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\WithJoin::class, WithJoin::class ] );
|
||||||
|
|
||||||
switch( true ) {
|
switch( true ) {
|
||||||
case $relation->isOneToOne():
|
case $relation->isOneToOne():
|
||||||
if ( $relation->hasBridge() ) {
|
if ( $relation->hasBridge() ) {
|
||||||
|
#dump($name, $relation);
|
||||||
# @TODO ! dump($this->relationAnnotations($name, $relation));
|
# @TODO ! dump($this->relationAnnotations($name, $relation));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -155,7 +166,7 @@ class RelationBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function instanciateEmptyEntity(string $name, Relation $relation) : object
|
protected function instanciateEmptyEntity(string $name, Relation|Attribute\Property\Relation $relation) : object
|
||||||
{
|
{
|
||||||
$class = $relation->entity ?? $this->resolver->properties[$name]['type'];
|
$class = $relation->entity ?? $this->resolver->properties[$name]['type'];
|
||||||
|
|
||||||
@ -163,7 +174,7 @@ class RelationBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function instanciateEmptyObject(string $name, Relation $relation) : object
|
protected function instanciateEmptyObject(string $name, Relation|Attribute\Property\Relation $relation) : object
|
||||||
{
|
{
|
||||||
switch( true ) {
|
switch( true ) {
|
||||||
case $relation->isOneToOne():
|
case $relation->isOneToOne():
|
||||||
@ -181,16 +192,18 @@ class RelationBuilder
|
|||||||
return new $class();
|
return new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function fetchFromDataset($name, ? array $data = null) /* object|bool */
|
protected function fetchFromDataset($name, ? array $data = null) : object|bool
|
||||||
{
|
{
|
||||||
$annotation = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Join) ?:
|
$annotation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Join::class, Annotation\Property\Join::class ]) ?:
|
||||||
$this->resolver->searchFieldAnnotation($name, new Annotation\Property\Relation);
|
$this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Annotation\Property\Relation::class ]);
|
||||||
|
|
||||||
if ( $annotation ) {
|
if ( $annotation ) {
|
||||||
$vars = [];
|
$vars = [];
|
||||||
$len = strlen( $name ) + 1;
|
$len = strlen( $name ) + 1;
|
||||||
|
|
||||||
if ( ( $annotation instanceof Relation ) && $annotation->isManyToMany() ) {
|
$isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation);
|
||||||
|
|
||||||
|
if ( $isRelation && $annotation->isManyToMany() ) {
|
||||||
$entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
|
$entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -231,12 +244,12 @@ class RelationBuilder
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oneToOne(string $name, Relation $relation) : Repository
|
public function oneToOne(string $name, Relation|Attribute\Property\Relation $relation) : Repository
|
||||||
{
|
{
|
||||||
return $this->oneToMany($name, $relation)->limit(1);
|
return $this->oneToMany($name, $relation)->limit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oneToMany(string $name, Relation $relation) : Repository
|
public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository
|
||||||
{
|
{
|
||||||
$baseEntity = $relation->entity ?? $this->resolver->properties[$name]['type'];
|
$baseEntity = $relation->entity ?? $this->resolver->properties[$name]['type'];
|
||||||
|
|
||||||
@ -249,13 +262,17 @@ class RelationBuilder
|
|||||||
$field = $relation->key;
|
$field = $relation->key;
|
||||||
|
|
||||||
if ($relation->foreignKey) {
|
if ($relation->foreignKey) {
|
||||||
$this->repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), ! is_string($field) && is_callable($field) ? $field($this->entity) : $this->entity->$field );
|
# dump($baseEntity::resolveEntity()->searchField($field));
|
||||||
|
|
||||||
|
# dump($this->resolver->properties[$name], $field);
|
||||||
|
$value = ! is_string($field) && is_callable($field) ? $field($this->entity) : $this->entity->$field;
|
||||||
|
$this->repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), $value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->applyFilter($this->repository, $name);
|
return $this->applyFilter($this->repository, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function manyToMany(string $name, Relation $relation, ? Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository
|
public function manyToMany(string $name, Relation|Attribute\Property\Relation $relation, Relation|Attribute\Property\Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository
|
||||||
{
|
{
|
||||||
extract($this->relationAnnotations($name, $relation));
|
extract($this->relationAnnotations($name, $relation));
|
||||||
|
|
||||||
@ -272,7 +289,6 @@ class RelationBuilder
|
|||||||
|
|
||||||
})->where( $this->entity::field($bridgeRelation->foreignKey, $relationAlias), is_string($this->entity) ? $this->entity::field($bridgeRelation->foreignKey) : $this->entity->{$bridgeRelation->foreignKey} );
|
})->where( $this->entity::field($bridgeRelation->foreignKey, $relationAlias), is_string($this->entity) ? $this->entity::field($bridgeRelation->foreignKey) : $this->entity->{$bridgeRelation->foreignKey} );
|
||||||
|
|
||||||
|
|
||||||
$this->applyWhere();
|
$this->applyWhere();
|
||||||
|
|
||||||
$this->applyOrderBy();
|
$this->applyOrderBy();
|
||||||
@ -284,7 +300,7 @@ class RelationBuilder
|
|||||||
return $this->applyFilter($this->repository, $name);
|
return $this->applyFilter($this->repository, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function relationAnnotations(string $name, Relation $relation) : array
|
public static function relationAnnotations(string $name, Relation|Attribute\Property\Relation $relation) : array
|
||||||
{
|
{
|
||||||
if ( $relation->isOneToOne() || $relation->isManyToMany() ) {
|
if ( $relation->isOneToOne() || $relation->isManyToMany() ) {
|
||||||
if ( ! $relation->hasBridge() ) {
|
if ( ! $relation->hasBridge() ) {
|
||||||
@ -292,8 +308,8 @@ class RelationBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
$bridgeEntity = Ulmus::resolveEntity($relation->bridge);
|
$bridgeEntity = Ulmus::resolveEntity($relation->bridge);
|
||||||
$bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, new Relation() );
|
$bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Attribute\Property\Relation::class, Relation::class ]);
|
||||||
$relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, new Relation() );
|
$relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Attribute\Property\Relation::class, Relation::class ]);
|
||||||
|
|
||||||
if ($relationRelation === null) {
|
if ($relationRelation === null) {
|
||||||
throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}");
|
throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}");
|
||||||
|
@ -4,6 +4,8 @@ namespace Ulmus;
|
|||||||
|
|
||||||
use Generator;
|
use Generator;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
|
||||||
abstract class Ulmus
|
abstract class Ulmus
|
||||||
{
|
{
|
||||||
public static string $repositoryClass = "\\Ulmus\\Repository";
|
public static string $repositoryClass = "\\Ulmus\\Repository";
|
||||||
@ -16,6 +18,8 @@ abstract class Ulmus
|
|||||||
|
|
||||||
public static Entity\ObjectInstanciator $objectInstanciator;
|
public static Entity\ObjectInstanciator $objectInstanciator;
|
||||||
|
|
||||||
|
public static CacheInterface $cache;
|
||||||
|
|
||||||
public static array $resolved = [];
|
public static array $resolved = [];
|
||||||
|
|
||||||
public static function iterateQueryBuilder(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) : Generator
|
public static function iterateQueryBuilder(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) : Generator
|
||||||
@ -104,7 +108,7 @@ abstract class Ulmus
|
|||||||
|
|
||||||
public static function resolveEntity(string $entityClass) : Common\EntityResolver
|
public static function resolveEntity(string $entityClass) : Common\EntityResolver
|
||||||
{
|
{
|
||||||
return static::$resolved[$entityClass] ?? static::$resolved[$entityClass] = new Common\EntityResolver($entityClass);
|
return static::$resolved[$entityClass] ?? static::$resolved[$entityClass] = new Common\EntityResolver($entityClass, static::$cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function repository(string $entityClass, string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository
|
public static function repository(string $entityClass, string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository
|
||||||
|
Loading…
x
Reference in New Issue
Block a user