- WIP on notes 2.x
This commit is contained in:
parent
2de3139c80
commit
f3be11a590
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Classes;
|
|
||||||
|
|
||||||
class Collation implements \Notes\Annotation {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Classes;
|
|
||||||
|
|
||||||
class Method implements \Notes\Annotation {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Classes;
|
|
||||||
|
|
||||||
class Table implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $name;
|
|
||||||
|
|
||||||
public string $database;
|
|
||||||
|
|
||||||
public string $schema;
|
|
||||||
|
|
||||||
public string $adapter;
|
|
||||||
|
|
||||||
public string $engine;
|
|
||||||
|
|
||||||
public function __construct($name = null, $engine = null)
|
|
||||||
{
|
|
||||||
if ( $name !== null ) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $engine !== null ) {
|
|
||||||
$this->engine = $engine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Field implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $type;
|
|
||||||
|
|
||||||
public string $name;
|
|
||||||
|
|
||||||
public int|string $length;
|
|
||||||
|
|
||||||
public int $precision;
|
|
||||||
|
|
||||||
public array $attributes = [];
|
|
||||||
|
|
||||||
public bool $nullable;
|
|
||||||
|
|
||||||
public /* mixed */ $default;
|
|
||||||
|
|
||||||
public bool $readonly = false;
|
|
||||||
|
|
||||||
public function __construct(? string $type = null, ? int $length = null)
|
|
||||||
{
|
|
||||||
if ( $type !== null ) {
|
|
||||||
$this->type = $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $length !== null ) {
|
|
||||||
$this->length = $length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Bigint extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "bigint", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Blob extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "blob", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class CreatedAt extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->nullable = false;
|
|
||||||
$this->type = "timestamp";
|
|
||||||
$this->attributes['default'] = "CURRENT_TIMESTAMP";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Date extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct(? string $type = "date", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Datetime extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct(? string $type = "datetime", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since we need consistancy between the declaration of our ID and FK fields, it
|
|
||||||
* was decided to extend the Id class instead of Field for this case.
|
|
||||||
*/
|
|
||||||
class ForeignKey extends PrimaryKey {
|
|
||||||
|
|
||||||
public function __construct(? string $type = null, ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
|
|
||||||
unset($this->nullable);
|
|
||||||
$this->attributes['primary_key'] = false;
|
|
||||||
$this->attributes['auto_increment'] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Id extends \Ulmus\Annotation\Property\Field\PrimaryKey {
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->attributes['unsigned'] = true;
|
|
||||||
$this->attributes['auto_increment'] = true;
|
|
||||||
|
|
||||||
parent::__construct('bigint');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Longblob extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "longblob", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Longtext extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "longtext", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Mediumblob extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "mediumblob", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Mediumtext extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "mediumtext", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class PrimaryKey extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct(? string $type = null, ? int $length = null)
|
|
||||||
{
|
|
||||||
$this->nullable = false;
|
|
||||||
$this->attributes['primary_key'] = true;
|
|
||||||
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Text extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "text", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Time extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct(? string $type = "time", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Blob extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "tinyblob", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class Tinyint extends \Ulmus\Annotation\Property\Field
|
|
||||||
{
|
|
||||||
public function __construct(? string $type = "tinyint", ? int $length = null)
|
|
||||||
{
|
|
||||||
parent::__construct($type, $length);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Field;
|
|
||||||
|
|
||||||
class UpdatedAt extends \Ulmus\Annotation\Property\Field {
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->nullable = true;
|
|
||||||
$this->type = "timestamp";
|
|
||||||
$this->attributes['update'] = "CURRENT_TIMESTAMP";
|
|
||||||
$this->attributes['default'] = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Filter implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $method;
|
|
||||||
|
|
||||||
public function __construct(string $method = null)
|
|
||||||
{
|
|
||||||
if ( $method !== null ) {
|
|
||||||
$this->method = $method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class FilterJoin implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $method;
|
|
||||||
|
|
||||||
public function __construct(string $method = null)
|
|
||||||
{
|
|
||||||
if ( $method !== null ) {
|
|
||||||
$this->method = $method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class GroupBy implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public array $fields = [];
|
|
||||||
|
|
||||||
public function __construct(...$field)
|
|
||||||
{
|
|
||||||
if ( $field ) {
|
|
||||||
$this->fields = $field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Having extends Where {}
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Join implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $type;
|
|
||||||
|
|
||||||
public string|Stringable $key;
|
|
||||||
|
|
||||||
public string|Stringable $foreignKey;
|
|
||||||
|
|
||||||
public string $entity;
|
|
||||||
|
|
||||||
public string $alias;
|
|
||||||
|
|
||||||
public function __construct(? string $type = null, /*? string|Stringable*/ $key = null, /*? string|Stringable*/ $foreignKey = null)
|
|
||||||
{
|
|
||||||
if ($type !== null) {
|
|
||||||
$this->type = $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($key !== null) {
|
|
||||||
$this->key = $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($foreignKey !== null) {
|
|
||||||
$this->foreignKey = $foreignKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class On extends Where {}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
use Ulmus\Query;
|
|
||||||
|
|
||||||
class OrWhere extends Where {
|
|
||||||
|
|
||||||
public function __construct(/* ? Stringable */ $field = null, $value = null, ? string $operator = null, ? string $condition = null)
|
|
||||||
{
|
|
||||||
parent::__construct($field, $value, $operator, Query\Where::CONDITION_OR);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class OrderBy implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $field;
|
|
||||||
|
|
||||||
public string $order = "ASC";
|
|
||||||
|
|
||||||
public function __construct(string $field = null, string $order = null)
|
|
||||||
{
|
|
||||||
if ( $field !== null ) {
|
|
||||||
$this->field = $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $order !== null ) {
|
|
||||||
$this->order = $order;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Relation implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public string $type;
|
|
||||||
|
|
||||||
public /*stringable*/ $key;
|
|
||||||
|
|
||||||
public /* callable */ $generateKey;
|
|
||||||
|
|
||||||
public /*stringable*/ $foreignKey;
|
|
||||||
|
|
||||||
public array $foreignKeys;
|
|
||||||
|
|
||||||
public string $bridge;
|
|
||||||
|
|
||||||
public /*stringable*/ $bridgeKey;
|
|
||||||
|
|
||||||
public /*stringable*/ $bridgeForeignKey;
|
|
||||||
|
|
||||||
public string $entity;
|
|
||||||
|
|
||||||
public string $join;
|
|
||||||
|
|
||||||
public string $function = "loadAll";
|
|
||||||
|
|
||||||
public function __construct(string $type = null)
|
|
||||||
{
|
|
||||||
if ( $type !== null ) {
|
|
||||||
$this->type = $type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function entity() {
|
|
||||||
try {
|
|
||||||
$e = $this->entity;
|
|
||||||
} catch (\Throwable $ex) {
|
|
||||||
throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new $e();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function bridge() {
|
|
||||||
$e = $this->bridge;
|
|
||||||
|
|
||||||
return new $e();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function normalizeType() : string
|
|
||||||
{
|
|
||||||
return strtolower(str_replace(['-', '_', ' '], '', $this->type));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isOneToOne() : bool
|
|
||||||
{
|
|
||||||
return $this->normalizeType() === 'onetoone';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isOneToMany() : bool
|
|
||||||
{
|
|
||||||
return $this->normalizeType() === 'onetomany';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isManyToMany() : bool
|
|
||||||
{
|
|
||||||
return $this->normalizeType() === 'manytomany';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function function() : string
|
|
||||||
{
|
|
||||||
if ($this->function) {
|
|
||||||
return $this->function;
|
|
||||||
}
|
|
||||||
elseif ($this->isOneToOne()) {
|
|
||||||
return 'load';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'loadAll';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasBridge() : bool
|
|
||||||
{
|
|
||||||
return isset($this->bridge);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property\Relation;
|
|
||||||
|
|
||||||
class Ignore implements \Notes\Annotation {}
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class Virtual extends Field {
|
|
||||||
|
|
||||||
public bool $readonly = true;
|
|
||||||
|
|
||||||
public \Closure $closure;
|
|
||||||
|
|
||||||
public string $method;
|
|
||||||
|
|
||||||
public function __construct(? \Closure $closure = null)
|
|
||||||
{
|
|
||||||
if ( $closure !== null ) {
|
|
||||||
$this->closure = $closure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
use Ulmus\Query;
|
|
||||||
|
|
||||||
class Where implements \Notes\Annotation {
|
|
||||||
|
|
||||||
public /* stringable */ $field;
|
|
||||||
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public string $operator;
|
|
||||||
|
|
||||||
public string $condition;
|
|
||||||
|
|
||||||
public function __construct(/* ? Stringable */ $field = null, $value = null, ? string $operator = null, ? string $condition = null)
|
|
||||||
{
|
|
||||||
if ( $field !== null ) {
|
|
||||||
$this->field = $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $value !== null ) {
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->operator = $operator !== null ? $operator : Query\Where::OPERATOR_EQUAL;
|
|
||||||
$this->condition = $condition !== null ? $condition : Query\Where::CONDITION_AND;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Ulmus\Annotation\Property;
|
|
||||||
|
|
||||||
class WithJoin implements \Notes\Annotation {
|
|
||||||
|
|
||||||
protected array $joins;
|
|
||||||
|
|
||||||
public function __construct(/*Stringable|array|null*/ $joins = null)
|
|
||||||
{
|
|
||||||
if ( $joins ) {
|
|
||||||
$this->joins = (array)$joins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property;
|
||||||
use Ulmus\Attribute\Attribute;
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
#[\Attribute]
|
#[\Attribute]
|
||||||
class Join {
|
class Join implements ResettablePropertyInterface {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $type,
|
public string $type,
|
||||||
public null|string|\Stringable|array $key = null,
|
public null|string|\Stringable|array $key = null,
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property;
|
||||||
use Ulmus\Attribute\Attribute;
|
use Ulmus\Attribute\Attribute;
|
||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
class Relation {
|
class Relation implements ResettablePropertyInterface {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public Relation\RelationTypeEnum|string $type,
|
public Relation\RelationTypeEnum|string $type,
|
||||||
public \Stringable|string|array $key = "",
|
public \Stringable|string|array $key = "",
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
|
interface ResettablePropertyInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Ulmus\Attribute\Property;
|
namespace Ulmus\Attribute\Property;
|
||||||
|
|
||||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
class Virtual extends Field {
|
class Virtual extends Field implements ResettablePropertyInterface {
|
||||||
|
|
||||||
public bool $readonly = true;
|
public bool $readonly = true;
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,11 @@ use Notes\Common\ReflectedClass;
|
||||||
use Notes\Common\ReflectedProperty;
|
use Notes\Common\ReflectedProperty;
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Ulmus\Ulmus,
|
use Ulmus\Ulmus,
|
||||||
Ulmus\Annotation\Classes\Table,
|
Ulmus\Attribute\Obj\Table,
|
||||||
Ulmus\Annotation\Property\Field,
|
Ulmus\Attribute\Obj\AdapterAttributeInterface,
|
||||||
Ulmus\Annotation\Property\Virtual,
|
Ulmus\Attribute\Property\Field,
|
||||||
Ulmus\Annotation\Property\Relation,
|
Ulmus\Attribute\Property\Relation,
|
||||||
Ulmus\Attribute;
|
Ulmus\Attribute\Property\Virtual;
|
||||||
|
|
||||||
use Notes\Annotation;
|
|
||||||
|
|
||||||
use Notes\ObjectReflection;
|
use Notes\ObjectReflection;
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@ class EntityResolver {
|
||||||
$this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
|
$this->reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : ? ReflectedProperty
|
public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : null|ReflectedProperty
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
return $this->fieldList($fieldKey)[$name] ?? null;
|
return $this->fieldList($fieldKey)[$name] ?? null;
|
||||||
|
@ -51,7 +49,7 @@ class EntityResolver {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchField($name) : null|array
|
public function searchField($name) : null|ReflectedProperty
|
||||||
{
|
{
|
||||||
return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false);
|
return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false);
|
||||||
}
|
}
|
||||||
|
@ -62,8 +60,8 @@ class EntityResolver {
|
||||||
|
|
||||||
foreach($this->reflectedClass->getProperties(true) as $item) {
|
foreach($this->reflectedClass->getProperties(true) as $item) {
|
||||||
foreach($item->getAttributes() as $tag) {
|
foreach($item->getAttributes() as $tag) {
|
||||||
if ( $tag->object instanceof Attribute\Property\Field ) {
|
if ( $tag->object instanceof Field ) {
|
||||||
if ( $skipVirtual && $tag->object instanceof Attribute\Property\Virtual ) {
|
if ( $skipVirtual && $tag->object instanceof Virtual ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +100,7 @@ class EntityResolver {
|
||||||
try{
|
try{
|
||||||
if ( $property ) {
|
if ( $property ) {
|
||||||
foreach($property->getAttributes() as $tag) {
|
foreach($property->getAttributes() as $tag) {
|
||||||
if ( $tag->object instanceof Relation or $tag->object instanceof Attribute\Property\Relation ) {
|
if ( $tag->object instanceof Relation ) {
|
||||||
return $property;
|
return $property;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +154,7 @@ class EntityResolver {
|
||||||
return $table->name ?? "";
|
return $table->name ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tableAnnotation($required = false) : null|Table|Attribute\Obj\Table
|
public function tableAnnotation($required = false) : null|Table
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getTableAttribute() ) {
|
if ( null === $table = $this->getTableAttribute() ) {
|
||||||
if ($required) {
|
if ($required) {
|
||||||
|
@ -167,7 +165,7 @@ class EntityResolver {
|
||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function databaseName() : ? string
|
public function databaseName() : null|string
|
||||||
{
|
{
|
||||||
return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null;
|
return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +194,7 @@ class EntityResolver {
|
||||||
return $this->sqlAdapter();
|
return $this->sqlAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function schemaName(bool $required = false) : ? string
|
public function schemaName(bool $required = false) : null|string
|
||||||
{
|
{
|
||||||
if ( null === $table = $this->getTableAttribute() ) {
|
if ( null === $table = $this->getTableAttribute() ) {
|
||||||
throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation");
|
throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation");
|
||||||
|
@ -209,10 +207,10 @@ class EntityResolver {
|
||||||
return $table->schema ?? null;
|
return $table->schema ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPrimaryKeyField() : ? array
|
public function getPrimaryKeyField() : null|array
|
||||||
{
|
{
|
||||||
foreach($this->fieldList() as $key => $value) {
|
foreach($this->fieldList() as $key => $value) {
|
||||||
$field = $this->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
|
$field = $this->searchFieldAnnotation($key, [ Field::class ]);
|
||||||
if ( null !== $field ) {
|
if ( null !== $field ) {
|
||||||
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
if ( false !== ( $field->attributes['primary_key'] ?? false ) ) {
|
||||||
return [ $key => $field ];
|
return [ $key => $field ];
|
||||||
|
@ -235,55 +233,15 @@ class EntityResolver {
|
||||||
|
|
||||||
protected function getAdapterInterfaceAttribute() : null|object
|
protected function getAdapterInterfaceAttribute() : null|object
|
||||||
{
|
{
|
||||||
return $this->getAttributeImplementing(Attribute\Obj\AdapterAttributeInterface::class);
|
return $this->getAttributeImplementing(AdapterAttributeInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getTableAttribute()
|
protected function getTableAttribute()
|
||||||
{
|
{
|
||||||
return $this->getAttributeImplementing(Attribute\Obj\Table::class) ?: $this->getAnnotationFromClassname( Table::class, false );
|
return $this->getAttributeImplementing(Table::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getAttributeImplementing(string $interface) : null|object
|
||||||
* Transform an annotation into it's object's counterpart
|
|
||||||
*/
|
|
||||||
public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object
|
|
||||||
{
|
|
||||||
exit(__FILE__);
|
|
||||||
if ( $name = $this->uses[$className] ?? false ) {
|
|
||||||
foreach(array_reverse($this->class['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->properties as $item) {
|
|
||||||
foreach(array_reverse($item['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->methods as $item) {
|
|
||||||
foreach(array_reverse($item['tags']) as $item) {
|
|
||||||
if ( $item['tag'] === $name ) {
|
|
||||||
return $this->instanciateAnnotationObject($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($throwError) {
|
|
||||||
throw new \TypeError("Annotation `$className` could not be found within your object `{$this->entityClass}`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ($throwError) {
|
|
||||||
throw new \InvalidArgumentException("Class `$className` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAttributeImplementing(string $interface) : ? object
|
|
||||||
{
|
{
|
||||||
foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) {
|
foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) {
|
||||||
if ($item->object instanceof $interface) {
|
if ($item->object instanceof $interface) {
|
||||||
|
@ -293,14 +251,4 @@ class EntityResolver {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($tagDefinition instanceof \ReflectionAttribute) {
|
|
||||||
$obj = $tagDefinition->newInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\Entity;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
use Ulmus\Attribute\Property\Field;
|
||||||
|
use Ulmus\Attribute\Property\Relation;
|
||||||
|
use Ulmus\Common\EntityField;
|
||||||
|
use Ulmus\Common\EntityResolver;
|
||||||
|
use Ulmus\Ulmus;
|
||||||
|
|
||||||
|
class DatasetHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected EntityResolver $entityResolver,
|
||||||
|
protected bool $entityStrictFieldsDeclaration = false,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function pull(object $entity) : Generator
|
||||||
|
{
|
||||||
|
foreach($this->entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
|
||||||
|
$annotation = $this->entityResolver->searchFieldAnnotation($key,[ Field::class ]);
|
||||||
|
|
||||||
|
if ( $entity->__isset($key) ) {
|
||||||
|
yield $annotation->name ?? $key => $entity->$key;
|
||||||
|
}
|
||||||
|
elseif ( $field->allowsNull() ) {
|
||||||
|
yield $annotation->name ?? $key => null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function push(iterable $dataset) : Generator|array
|
||||||
|
{
|
||||||
|
$unmatched = [];
|
||||||
|
|
||||||
|
foreach($dataset as $key => $value) {
|
||||||
|
$field = $this->entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $this->entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
|
||||||
|
|
||||||
|
if ( $field === null ) {
|
||||||
|
if ($this->entityStrictFieldsDeclaration ) {
|
||||||
|
throw new \Exception("Field `$key` can not be found within your entity ".static::class);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$unmatched[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $field->getTypes()[0];
|
||||||
|
|
||||||
|
if ( is_null($value) ) {
|
||||||
|
yield $field->name => null;
|
||||||
|
}
|
||||||
|
elseif ( $field->expectType('array') ) {
|
||||||
|
if ( is_string($value)) {
|
||||||
|
if (substr($value, 0, 1) === "a") {
|
||||||
|
|
||||||
|
yield $field->name => unserialize($value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$data = json_decode($value, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== \JSON_ERROR_NONE) {
|
||||||
|
throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $field->name => $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( is_array($value) ) {
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( EntityField::isScalarType($type->type) ) {
|
||||||
|
|
||||||
|
if ( $type->type === 'string' ) {
|
||||||
|
$annotation = $this->entityResolver->searchFieldAnnotation($field->name, [ Field::class ] );
|
||||||
|
|
||||||
|
if ( $annotation->length ?? null ) {
|
||||||
|
$value = mb_substr($value, 0, $annotation->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( $type->type === 'bool' ) {
|
||||||
|
$value = (bool) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
elseif ( $value instanceof \UnitEnum ) {
|
||||||
|
yield $field->name => $value;
|
||||||
|
}
|
||||||
|
elseif (enum_exists($type->type)) {
|
||||||
|
yield $field->name => $type->type::from($value);
|
||||||
|
}
|
||||||
|
elseif ( ! $type->builtIn ) {
|
||||||
|
try {
|
||||||
|
yield $field->name => Ulmus::instanciateObject($type->type, [ $value ]);
|
||||||
|
}
|
||||||
|
catch(\Error $e) {
|
||||||
|
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $unmatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pullRelation(object $entity) : Generator
|
||||||
|
{
|
||||||
|
foreach($this->entityResolver->reflectedClass->getProperties(true) as $name => $field){
|
||||||
|
$relation = $this->entityResolver->searchFieldAnnotation($name, [ Relation::class ] );
|
||||||
|
|
||||||
|
if ($relation) {
|
||||||
|
$ignore = $this->entityResolver->searchFieldAnnotation($name, [ Relation\Ignore::class ] );
|
||||||
|
|
||||||
|
if ($ignore && $ignore->ignoreExport) {
|
||||||
|
if ( $relation->isOneToOne() ) {
|
||||||
|
# @TODO TO INCLUDED INTO getTypes() RETURNED CLASS WHEN DONE !
|
||||||
|
yield $name => ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# empty collection
|
||||||
|
yield $name => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
# @TODO Must fix recursive bug.. this last check is way too basic to work
|
||||||
|
if ( $entity->__isset($name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
||||||
|
if ( null !== $value = $entity->__isset($name) ?? null ) {
|
||||||
|
if ( is_iterable($value) ) {
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
foreach($value as $entityObj) {
|
||||||
|
$list[] = $entityObj->entityGetDataset(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $name => $list;
|
||||||
|
}
|
||||||
|
elseif ( is_object($value) ) {
|
||||||
|
yield $name => $value->entityGetDataset(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,15 @@ namespace Ulmus;
|
||||||
|
|
||||||
use Notes\Attribute\Ignore;
|
use Notes\Attribute\Ignore;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Ulmus\{Common\EntityResolver, Common\EntityField, Entity\EntityInterface, QueryBuilder\QueryBuilderInterface};
|
use Ulmus\{Attribute\Property\Join,
|
||||||
|
Attribute\Property\Relation,
|
||||||
|
Attribute\Property\ResettablePropertyInterface,
|
||||||
|
Attribute\Property\Virtual,
|
||||||
|
Common\EntityResolver,
|
||||||
|
Common\EntityField,
|
||||||
|
Entity\DatasetHandler,
|
||||||
|
Entity\EntityInterface,
|
||||||
|
QueryBuilder\QueryBuilderInterface};
|
||||||
use Ulmus\SearchRequest\{Attribute\SearchParameter,
|
use Ulmus\SearchRequest\{Attribute\SearchParameter,
|
||||||
SearchMethodEnum,
|
SearchMethodEnum,
|
||||||
SearchRequestInterface,
|
SearchRequestInterface,
|
||||||
|
@ -14,6 +22,9 @@ use Ulmus\SearchRequest\{Attribute\SearchParameter,
|
||||||
trait EntityTrait {
|
trait EntityTrait {
|
||||||
use EventTrait;
|
use EventTrait;
|
||||||
|
|
||||||
|
#[Ignore]
|
||||||
|
public array $entityLoadedDataset = [];
|
||||||
|
|
||||||
#[Ignore]
|
#[Ignore]
|
||||||
protected bool $entityStrictFieldsDeclaration = false;
|
protected bool $entityStrictFieldsDeclaration = false;
|
||||||
|
|
||||||
|
@ -21,14 +32,23 @@ trait EntityTrait {
|
||||||
protected array $entityDatasetUnmatchedFields = [];
|
protected array $entityDatasetUnmatchedFields = [];
|
||||||
|
|
||||||
#[Ignore]
|
#[Ignore]
|
||||||
public array $entityLoadedDataset = [];
|
protected DatasetHandler $datasetHandler;
|
||||||
|
|
||||||
#[Ignore]
|
#[Ignore]
|
||||||
public function __construct(array $dataset = null) {
|
public function __construct(iterable|null $dataset = null)
|
||||||
|
{
|
||||||
|
$this->initializeEntity($dataset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Ignore]
|
||||||
|
public function initializeEntity(iterable|null $dataset = null) : void
|
||||||
|
{
|
||||||
if ($dataset) {
|
if ($dataset) {
|
||||||
$this->entityFillFromDataset($dataset);
|
$this->fromArray($dataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->datasetHandler = new DatasetHandler(static::resolveEntity(), $this->entityStrictFieldsDeclaration);
|
||||||
|
|
||||||
$this->resetVirtualProperties();
|
$this->resetVirtualProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,98 +57,55 @@ trait EntityTrait {
|
||||||
{
|
{
|
||||||
$loaded = $this->isLoaded();
|
$loaded = $this->isLoaded();
|
||||||
|
|
||||||
$entityResolver = $this->resolveEntity();
|
$handler = $this->datasetHandler->push($dataset);
|
||||||
|
|
||||||
foreach($dataset as $key => $value) {
|
foreach($handler as $field => $value) {
|
||||||
$field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
|
$this->$field = $value;
|
||||||
|
}
|
||||||
|
|
||||||
# Temp. fix, incoming patch soon
|
$this->entityDatasetUnmatchedFields = $handler->getReturn();
|
||||||
$type = $field->getTypes()[0];
|
|
||||||
|
|
||||||
if ( $field === null ) {
|
# Keeping original data to diff on UPDATE query
|
||||||
if ($this->entityStrictFieldsDeclaration ) {
|
if ( ! $loaded ) {
|
||||||
throw new \Exception("Field `$key` can not be found within your entity ".static::class);
|
$this->entityLoadedDataset = array_change_key_case(is_array($dataset) ? $dataset : iterator_to_array($dataset), \CASE_LOWER);
|
||||||
}
|
}
|
||||||
else {
|
elseif ($overwriteDataset) {
|
||||||
$this->entityDatasetUnmatchedFields[$key] = $value;
|
$this->entityLoadedDataset = array_change_key_case(is_array($dataset) ? $dataset : iterator_to_array($dataset), \CASE_LOWER) + $this->entityLoadedDataset;
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ( is_null($value) ) {
|
|
||||||
$this->{$field->name} = null;
|
|
||||||
}
|
|
||||||
elseif ( $field->expectType('array') ) {
|
|
||||||
if ( is_string($value)) {
|
|
||||||
if (substr($value, 0, 1) === "a") {
|
|
||||||
$this->{$field->name} = unserialize($value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$data = json_decode($value, true);
|
|
||||||
|
|
||||||
if (json_last_error() !== \JSON_ERROR_NONE) {
|
|
||||||
throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->{$field->name} = $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ( is_array($value) ) {
|
|
||||||
$this->{$field->name} = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ( EntityField::isScalarType($type->type) ) {
|
|
||||||
|
|
||||||
if ( $type->type === 'string' ) {
|
|
||||||
$annotation = $entityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ] );
|
|
||||||
|
|
||||||
if ( $annotation->length ?? null ) {
|
|
||||||
$value = mb_substr($value, 0, $annotation->length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ( $type->type === 'bool' ) {
|
|
||||||
$value = (bool) $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->{$field->name} = $value;
|
|
||||||
}
|
|
||||||
elseif ( $value instanceof \UnitEnum ) {
|
|
||||||
$this->{$field->name} = $value;
|
|
||||||
}
|
|
||||||
elseif (enum_exists($type->type)) {
|
|
||||||
$this->{$field->name} = $type->type::from($value);
|
|
||||||
}
|
|
||||||
elseif ( ! $type->builtIn ) {
|
|
||||||
try {
|
|
||||||
$this->{$field->name} = Ulmus::instanciateObject($type->type, [ $value ]);
|
|
||||||
}
|
|
||||||
catch(\Error $e) {
|
|
||||||
$f = $type->type;
|
|
||||||
throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Keeping original data to diff on UPDATE query
|
|
||||||
if ( ! $loaded /* || $isLoadedDataset */ ) {
|
|
||||||
#if ( $field !== null ) {
|
|
||||||
# $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() );
|
|
||||||
# $this->entityLoadedDataset[$annotation ? $annotation->name : $field['name']] = $dataset; # <--------- THIS TO FIX !!!!!!
|
|
||||||
#}
|
|
||||||
$this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER);
|
|
||||||
}
|
|
||||||
elseif ($overwriteDataset) {
|
|
||||||
$this->entityLoadedDataset = iterator_to_array(array_change_key_case($dataset, \CASE_LOWER)) + $this->entityLoadedDataset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Ignore]
|
||||||
|
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false, bool $rewriteValue = true) : array
|
||||||
|
{
|
||||||
|
if ( $returnSource ) {
|
||||||
|
return $this->entityLoadedDataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataset = [];
|
||||||
|
|
||||||
|
foreach($this->datasetHandler->pull($this) as $field => $value) {
|
||||||
|
$dataset[$field] = $rewriteValue ? static::repository()->adapter->adapter()->writableValue($value) : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($includeRelations) {
|
||||||
|
foreach($this->datasetHandler->pullRelation($this) as $field => $object) {
|
||||||
|
$dataset[$field] = $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dataset;
|
||||||
|
}
|
||||||
|
|
||||||
#[Ignore]
|
#[Ignore]
|
||||||
public function resetVirtualProperties() : self
|
public function resetVirtualProperties() : self
|
||||||
{
|
{
|
||||||
foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $prop => $property) {
|
foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $field => $property) {
|
||||||
foreach($property->attributes as $tag) {
|
foreach($property->attributes as $tag) {
|
||||||
if ( in_array(strtolower($tag->tag), [ 'relation', 'join', 'virtual' ] ) ) {
|
|
||||||
unset($this->$prop);
|
if ( $tag->object instanceof ResettablePropertyInterface ) {
|
||||||
|
unset($this->$field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,74 +123,6 @@ trait EntityTrait {
|
||||||
return $this->entityFillFromDataset($dataset);
|
return $this->entityFillFromDataset($dataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false, bool $rewriteValue = true) : array
|
|
||||||
{
|
|
||||||
if ( $returnSource ) {
|
|
||||||
return $this->entityLoadedDataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dataset = [];
|
|
||||||
|
|
||||||
$entityResolver = $this->resolveEntity();
|
|
||||||
|
|
||||||
foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) {
|
|
||||||
$annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class ]);
|
|
||||||
|
|
||||||
if ( isset($this->$key) ) {
|
|
||||||
$dataset[$annotation->name ?? $key] = $rewriteValue ?
|
|
||||||
static::repository()->adapter->adapter()->writableValue($this->$key)
|
|
||||||
:
|
|
||||||
$this->$key;
|
|
||||||
}
|
|
||||||
elseif ( $field->allowsNull() ) {
|
|
||||||
$dataset[$annotation->name ?? $key] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($includeRelations) {
|
|
||||||
foreach($entityResolver->reflectedClass->getProperties(true) as $name => $field){
|
|
||||||
$relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] );
|
|
||||||
|
|
||||||
if ($relation) {
|
|
||||||
$ignore = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation\Ignore::class ] );
|
|
||||||
|
|
||||||
if ($ignore && $ignore->ignoreExport) {
|
|
||||||
if ( $relation->isOneToOne() ) {
|
|
||||||
# empty object
|
|
||||||
$dataset[$name] = ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# empty collection
|
|
||||||
$dataset[$name] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
# @TODO Must fix recursive bug.. this last check is way too basic to work
|
|
||||||
if ( isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
|
||||||
if ( null !== $value = $this->$name ?? null ) {
|
|
||||||
if ( is_iterable($value) ) {
|
|
||||||
$list = [];
|
|
||||||
|
|
||||||
foreach($value as $entity) {
|
|
||||||
$list[] = $entity->entityGetDataset(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dataset[$name] = $list;
|
|
||||||
}
|
|
||||||
elseif ( is_object($value) ) {
|
|
||||||
$dataset[$name] = $value->entityGetDataset(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $dataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Ignore]
|
#[Ignore]
|
||||||
public function toArray($includeRelations = false, array $filterFields = null, bool $rewriteValue = true) : array
|
public function toArray($includeRelations = false, array $filterFields = null, bool $rewriteValue = true) : array
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,20 +2,13 @@
|
||||||
|
|
||||||
namespace Ulmus\Repository;
|
namespace Ulmus\Repository;
|
||||||
|
|
||||||
use Ulmus\{Attribute\Property\Field,
|
use Ulmus\{
|
||||||
Ulmus,
|
Ulmus, Query, Common\EntityResolver, Repository, Event,
|
||||||
Annotation,
|
};
|
||||||
Attribute,
|
|
||||||
Query,
|
|
||||||
Common,
|
|
||||||
Common\EntityResolver,
|
|
||||||
Repository,
|
|
||||||
Event,
|
|
||||||
EntityCollection};
|
|
||||||
|
|
||||||
use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, };
|
use Ulmus\Attribute\Property\{
|
||||||
|
Filter, Join, OrderBy, Relation, Virtual, Where, WithJoin,
|
||||||
use Closure;
|
};
|
||||||
|
|
||||||
class RelationBuilder
|
class RelationBuilder
|
||||||
{
|
{
|
||||||
|
@ -64,7 +57,7 @@ class RelationBuilder
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class , Relation::class ] ) ) {
|
if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Relation::class ] ) ) {
|
||||||
return $this->instanciateEmptyObject($name, $relation);
|
return $this->instanciateEmptyObject($name, $relation);
|
||||||
}
|
}
|
||||||
elseif ($virtual = $this->resolveVirtual($name)) {
|
elseif ($virtual = $this->resolveVirtual($name)) {
|
||||||
|
@ -77,7 +70,7 @@ class RelationBuilder
|
||||||
|
|
||||||
protected function resolveVirtual(string $name) : mixed
|
protected function resolveVirtual(string $name) : mixed
|
||||||
{
|
{
|
||||||
if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) {
|
if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, Virtual::class))) {
|
||||||
try {
|
try {
|
||||||
$arguments = [ $this->entity ];
|
$arguments = [ $this->entity ];
|
||||||
|
|
||||||
|
@ -98,11 +91,11 @@ class RelationBuilder
|
||||||
|
|
||||||
protected function resolveRelation(string $name) : mixed
|
protected function resolveRelation(string $name) : mixed
|
||||||
{
|
{
|
||||||
if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ) ) ) {
|
if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Relation::class ] ) ) ) {
|
||||||
$this->orders = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ] );
|
$this->orders = $this->resolver->searchFieldAnnotationList($name, [ OrderBy::class ] );
|
||||||
$this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ] );
|
$this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Where::class ] );
|
||||||
$this->filters = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Filter::class, Filter::class ] );
|
$this->filters = $this->resolver->searchFieldAnnotationList($name, [ Filter::class ] );
|
||||||
$this->joins = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\WithJoin::class, WithJoin::class ] );
|
$this->joins = $this->resolver->searchFieldAnnotationList($name, [ WithJoin::class ] );
|
||||||
|
|
||||||
switch( true ) {
|
switch( true ) {
|
||||||
case $relation->isOneToOne():
|
case $relation->isOneToOne():
|
||||||
|
@ -178,22 +171,22 @@ class RelationBuilder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function instanciateEmptyEntity(string $name, Relation|Attribute\Property\Relation $relation) : object
|
protected function instanciateEmptyEntity(string $name, Relation $relation) : object
|
||||||
{
|
{
|
||||||
$class = $relation->entity ?? $this->resolver->properties[$name]['type'];
|
$class = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
|
||||||
|
|
||||||
return new $class();
|
return new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function instanciateEmptyObject(string $name, Relation|Attribute\Property\Relation $relation) : object
|
protected function instanciateEmptyObject(string $name, Relation $relation) : object
|
||||||
{
|
{
|
||||||
switch( true ) {
|
switch( true ) {
|
||||||
case $relation->isOneToOne():
|
case $relation->isOneToOne():
|
||||||
return $this->instanciateEmptyEntity($name, $relation);
|
return $this->instanciateEmptyEntity($name, $relation);
|
||||||
|
|
||||||
case $relation->isOneToMany():
|
case $relation->isOneToMany():
|
||||||
return ($relation->entity ?? $this->resolver->properties[$name]['type'])::entityCollection();
|
return ($relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type)::entityCollection();
|
||||||
|
|
||||||
case $relation->isManyToMany():
|
case $relation->isManyToMany():
|
||||||
extract($this->relationAnnotations($name, $relation));
|
extract($this->relationAnnotations($name, $relation));
|
||||||
|
@ -206,14 +199,14 @@ class RelationBuilder
|
||||||
|
|
||||||
protected function fetchFromDataset($name, ? array $data = null) : object|bool
|
protected function fetchFromDataset($name, ? array $data = null) : object|bool
|
||||||
{
|
{
|
||||||
$annotation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Join::class, Annotation\Property\Join::class ]) ?:
|
$annotation = $this->resolver->searchFieldAnnotation($name, [ Join::class ]) ?:
|
||||||
$this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Annotation\Property\Relation::class ]);
|
$this->resolver->searchFieldAnnotation($name, [ Relation::class ]);
|
||||||
|
|
||||||
if ( $annotation ) {
|
if ( $annotation ) {
|
||||||
$vars = [];
|
$vars = [];
|
||||||
$len = strlen( $name ) + 1;
|
$len = strlen( $name ) + 1;
|
||||||
|
|
||||||
$isRelation = ( $annotation instanceof Relation ) || ( $annotation instanceof Attribute\Property\Relation );
|
$isRelation = $annotation instanceof Relation;
|
||||||
|
|
||||||
if ( $isRelation && $annotation->isManyToMany() ) {
|
if ( $isRelation && $annotation->isManyToMany() ) {
|
||||||
$entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
|
$entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity;
|
||||||
|
@ -259,12 +252,12 @@ class RelationBuilder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oneToOne(string $name, Relation|Attribute\Property\Relation $relation) : Repository
|
public function oneToOne(string $name, Relation $relation) : Repository
|
||||||
{
|
{
|
||||||
return $this->oneToMany($name, $relation)->limit(1);
|
return $this->oneToMany($name, $relation)->limit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository
|
public function oneToMany(string $name, Relation $relation) : Repository
|
||||||
{
|
{
|
||||||
$baseEntity = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
|
$baseEntity = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type;
|
||||||
|
|
||||||
|
@ -290,7 +283,7 @@ class RelationBuilder
|
||||||
return $this->applyFilter($this->repository, $name);
|
return $this->applyFilter($this->repository, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function manyToMany(string $name, Relation|Attribute\Property\Relation $relation, Relation|Attribute\Property\Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository
|
public function manyToMany(string $name, Relation $relation, Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository
|
||||||
{
|
{
|
||||||
extract($this->relationAnnotations($name, $relation));
|
extract($this->relationAnnotations($name, $relation));
|
||||||
|
|
||||||
|
@ -318,7 +311,7 @@ class RelationBuilder
|
||||||
return $this->applyFilter($this->repository, $name);
|
return $this->applyFilter($this->repository, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function relationAnnotations(string $name, Relation|Attribute\Property\Relation $relation) : array
|
public static function relationAnnotations(string $name, Relation $relation) : array
|
||||||
{
|
{
|
||||||
if ( $relation->isOneToOne() || $relation->isManyToMany() ) {
|
if ( $relation->isOneToOne() || $relation->isManyToMany() ) {
|
||||||
if ( ! $relation->hasBridge() ) {
|
if ( ! $relation->hasBridge() ) {
|
||||||
|
@ -326,14 +319,14 @@ class RelationBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
$bridgeEntity = Ulmus::resolveEntity($relation->bridge);
|
$bridgeEntity = Ulmus::resolveEntity($relation->bridge);
|
||||||
$bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Attribute\Property\Relation::class, Relation::class ]);
|
$bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Relation::class ]);
|
||||||
$relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Attribute\Property\Relation::class, Relation::class ]);
|
$relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ 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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
$relationRelation->entity ??= $relation->bridge::resolveEntity()->properties[$relation->foreignField]['type'];
|
$relationRelation->entity ??= $relation->bridge::resolveEntity()->reflectedClass->getProperties()[$relation->foreignField]->getTypes()[0]->type;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'bridgeEntity' => $bridgeEntity,
|
'bridgeEntity' => $bridgeEntity,
|
||||||
|
|
Loading…
Reference in New Issue