mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-11 09:48:40 +00:00
continue datamapper bug fixes
This commit is contained in:
parent
aa004569f5
commit
1e90a5ba9d
|
|
@ -32,7 +32,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $comment = '--';
|
||||
public string $comment = '--';
|
||||
|
||||
/**
|
||||
* String quotes style.
|
||||
|
|
@ -40,7 +40,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $valueQuotes = '\'';
|
||||
public string $valueQuotes = '\'';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -48,7 +48,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '"';
|
||||
public string $systemIdentifierStart = '"';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -56,7 +56,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = '"';
|
||||
public string $systemIdentifierEnd = '"';
|
||||
|
||||
/**
|
||||
* And operator.
|
||||
|
|
@ -64,7 +64,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $and = 'AND';
|
||||
public string $and = 'AND';
|
||||
|
||||
/**
|
||||
* Or operator.
|
||||
|
|
@ -72,7 +72,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $or = 'OR';
|
||||
public string $or = 'OR';
|
||||
|
||||
/**
|
||||
* Special keywords.
|
||||
|
|
@ -80,7 +80,7 @@ abstract class GrammarAbstract
|
|||
* @var string[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $specialKeywords = [
|
||||
public array $specialKeywords = [
|
||||
'COUNT(',
|
||||
'MAX(',
|
||||
'MIN(',
|
||||
|
|
@ -96,7 +96,7 @@ abstract class GrammarAbstract
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $datetimeFormat = 'Y-m-d H:i:s';
|
||||
public string $datetimeFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* Set the datetime format
|
||||
|
|
|
|||
|
|
@ -28,20 +28,81 @@ use phpOMS\DataStorage\Database\Query\OrderType;
|
|||
*/
|
||||
abstract class DataMapperAbstract
|
||||
{
|
||||
/**
|
||||
* Base mapper
|
||||
*
|
||||
* @var DataMapperFactory
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected DataMapperFactory $mapper;
|
||||
|
||||
/**
|
||||
* Mapper type (e.g. writer, reader, ...)
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected int $type = 0;
|
||||
|
||||
/**
|
||||
* Mapper depths.
|
||||
*
|
||||
* Mappers may have relations to other models (e.g. hasMany) which can have other relations, ...
|
||||
* The depths indicates how deep in the relation tree we are
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected int $depth = 1;
|
||||
|
||||
/**
|
||||
* Relations which should be loaded
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $with = [];
|
||||
|
||||
/**
|
||||
* Sort order
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $sort = [];
|
||||
|
||||
/**
|
||||
* Offset
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $offset = [];
|
||||
|
||||
/**
|
||||
* Limit
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $limit = [];
|
||||
|
||||
/**
|
||||
* Where conditions
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected array $where = [];
|
||||
|
||||
/**
|
||||
* Base query which is merged with the query in the mapper
|
||||
*
|
||||
* Sometimes you want to merge two queries together.
|
||||
*
|
||||
* @var null|Builder
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected ?Builder $query = null;
|
||||
|
||||
/**
|
||||
|
|
@ -52,12 +113,28 @@ abstract class DataMapperAbstract
|
|||
*/
|
||||
protected ConnectionAbstract $db;
|
||||
|
||||
/** Constructor.
|
||||
*
|
||||
* @param DataMapperFactory $mapper Base mapper
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(DataMapperFactory $mapper, ConnectionAbstract $db)
|
||||
{
|
||||
$this->mapper = $mapper;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a query which is merged with the internal query generation.
|
||||
*
|
||||
* @param Builder $query Query
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function query(Builder $query = null) : self
|
||||
{
|
||||
$this->query = $query;
|
||||
|
|
@ -65,7 +142,15 @@ abstract class DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
// Only for relations, no impact on anything else
|
||||
/**
|
||||
* Define model relations which should be loaded
|
||||
*
|
||||
* @param string $member Property name of the relation (e.g. hasMany, belongsTo, ...)
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function with(string $member) : self
|
||||
{
|
||||
$split = \explode('/', $member);
|
||||
|
|
@ -78,6 +163,16 @@ abstract class DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort order
|
||||
*
|
||||
* @param string $member Property name to sort by
|
||||
* @param string $order Order type (DESC/ASC)
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function sort(string $member, string $order = OrderType::DESC) : self
|
||||
{
|
||||
$split = \explode('/', $member);
|
||||
|
|
@ -91,6 +186,39 @@ abstract class DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the result offset
|
||||
*
|
||||
* @param int $offset Offset
|
||||
* @param string $member Property name to offset by ('' = base model, anything else for relations such as hasMany relations)
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function offset(int $offset = 0, string $member = '') : self
|
||||
{
|
||||
$split = \explode('/', $member);
|
||||
$memberSplit = \array_shift($split);
|
||||
|
||||
$this->offset[$memberSplit ?? ''][] = [
|
||||
'child' => \implode('/', $split),
|
||||
'offset' => $offset,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the result limit
|
||||
*
|
||||
* @param int $limit Limit
|
||||
* @param string $member Property name to limit by ('' = base model, anything else for relations such as hasMany relations)
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function limit(int $limit = 0, string $member = '') : self
|
||||
{
|
||||
$split = \explode('/', $member);
|
||||
|
|
@ -104,7 +232,19 @@ abstract class DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function where(string $member, mixed $value, string $logic = '=', string $comparison = 'AND') : self
|
||||
/**
|
||||
* Define the result filtering
|
||||
*
|
||||
* @param string $member Property name to filter by
|
||||
* @param mixed $value Filter value
|
||||
* @param string $logic Comparison logic (e.g. =, in, ...)
|
||||
* @param string $connector Filter connector (e.g. AND, OR, ...)
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function where(string $member, mixed $value, string $logic = '=', string $connector = 'AND') : self
|
||||
{
|
||||
$split = \explode('/', $member);
|
||||
$memberSplit = \array_shift($split);
|
||||
|
|
@ -113,12 +253,22 @@ abstract class DataMapperAbstract
|
|||
'child' => \implode('/', $split),
|
||||
'value' => $value,
|
||||
'logic' => $logic,
|
||||
'comparison' => $comparison,
|
||||
'comparison' => $connector,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate a mapper (e.g. child mapper, relation mapper) based on the current mapper information.
|
||||
*
|
||||
* @param DataMapperAbstract $mapper Relation mapper to populate
|
||||
* @param string $member Relation property (e.g. ownsOne, hasMany, ... property name)
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function createRelationMapper(self $mapper, string $member) : self
|
||||
{
|
||||
$relMapper = $mapper;
|
||||
|
|
@ -143,6 +293,16 @@ abstract class DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($this->offset[$member])) {
|
||||
foreach ($this->offset[$member] as $offset) {
|
||||
if ($offset['child'] === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relMapper->offset($offset['offset'], $offset['child']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->limit[$member])) {
|
||||
foreach ($this->limit[$member] as $limit) {
|
||||
if ($limit['child'] === '') {
|
||||
|
|
@ -201,5 +361,14 @@ abstract class DataMapperAbstract
|
|||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param mixed ...$options Data for the mapper
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract public function execute(...$options) : mixed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class DataMapperFactory
|
|||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function __construct()
|
||||
final private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -158,73 +158,199 @@ class DataMapperFactory
|
|||
{
|
||||
}
|
||||
|
||||
public static function db(ConnectionAbstract $db = null) : string
|
||||
/**
|
||||
* Set default database connection
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return class-string<self>
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function db(ConnectionAbstract $db) : string
|
||||
{
|
||||
self::$db = $db;
|
||||
|
||||
return static::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function reader(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return new ReadMapper(new static(), $db ?? self::$db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function get(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getRaw(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->getRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getRandom(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->getRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function count(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return Builder
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getQuery(ConnectionAbstract $db = null) : Builder
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create read mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return ReadMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getAll(ConnectionAbstract $db = null) : ReadMapper
|
||||
{
|
||||
return (new ReadMapper(new static(), $db ?? self::$db))->getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create write mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return WriteMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function writer(ConnectionAbstract $db = null) : WriteMapper
|
||||
{
|
||||
return new WriteMapper(new static(), $db ?? self::$db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create write mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return WriteMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function create(ConnectionAbstract $db = null) : WriteMapper
|
||||
{
|
||||
return (new WriteMapper(new static(), $db ?? self::$db))->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create update mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return UpdateMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function updater(ConnectionAbstract $db = null) : UpdateMapper
|
||||
{
|
||||
return new UpdateMapper(new static(), $db ?? self::$db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create update mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return UpdateMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function update(ConnectionAbstract $db = null) : UpdateMapper
|
||||
{
|
||||
return (new UpdateMapper(new static(), $db ?? self::$db))->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create delete mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return DeleteMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function remover(ConnectionAbstract $db = null) : DeleteMapper
|
||||
{
|
||||
return new DeleteMapper(new static(), $db ?? self::$db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create delete mapper
|
||||
*
|
||||
* @param ConnectionAbstract $db Database connection
|
||||
*
|
||||
* @return DeleteMapper
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function delete(ConnectionAbstract $db = null) : DeleteMapper
|
||||
{
|
||||
return (new DeleteMapper(new static(), $db ?? self::$db))->delete();
|
||||
|
|
@ -267,11 +393,11 @@ class DataMapperFactory
|
|||
/**
|
||||
* Create the empty base model
|
||||
*
|
||||
* @return mixed
|
||||
* @return object
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function createBaseModel() : mixed
|
||||
public static function createBaseModel() : object
|
||||
{
|
||||
$class = empty(static::MODEL) ? \substr(static::class, 0, -6) : static::MODEL;
|
||||
|
||||
|
|
@ -283,18 +409,6 @@ class DataMapperFactory
|
|||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model from mapper
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function getModelName() : string
|
||||
{
|
||||
return empty(static::MODEL) ? \substr(static::class, 0, -6) : static::MODEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id of object
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace phpOMS\DataStorage\Database\Mapper;
|
||||
|
||||
use phpOMS\DataStorage\Database\Exception\InvalidMapperException;
|
||||
use phpOMS\DataStorage\Database\Query\Builder;
|
||||
|
||||
/**
|
||||
|
|
@ -27,8 +26,15 @@ use phpOMS\DataStorage\Database\Query\Builder;
|
|||
* @link https://orange-management.org
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class DeleteMapper extends DataMapperAbstract
|
||||
final class DeleteMapper extends DataMapperAbstract
|
||||
{
|
||||
/**
|
||||
* Get delete mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function delete() : self
|
||||
{
|
||||
$this->type = MapperType::DELETE;
|
||||
|
|
@ -36,22 +42,37 @@ class DeleteMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param array ...$options Options to pass to the selete mapper
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function execute(...$options) : mixed
|
||||
{
|
||||
switch($this->type) {
|
||||
case MapperType::DELETE:
|
||||
/** @var object[] ...$options */
|
||||
return $this->executeDelete(...$options);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeDelete(mixed $obj) : mixed
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param object $obj Object to delete
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeDelete(object $obj) : mixed
|
||||
{
|
||||
if ($obj === null) {
|
||||
$obj = $this->mapper::get()->execute(); // todo: pass where conditions to read mapper
|
||||
}
|
||||
|
||||
$refClass = new \ReflectionClass($obj);
|
||||
$objId = $this->mapper::getObjectId($obj, $refClass);
|
||||
|
||||
|
|
@ -67,6 +88,15 @@ class DeleteMapper extends DataMapperAbstract
|
|||
return $objId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete model
|
||||
*
|
||||
* @param mixed $objId Object id to delete
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function deleteModel(mixed $objId) : void
|
||||
{
|
||||
$query = new Builder($this->db);
|
||||
|
|
@ -80,7 +110,18 @@ class DeleteMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
private function deleteSingleRelation(mixed $obj, \ReflectionClass $refClass, array $relation) : void
|
||||
/**
|
||||
* Delete ownsOne, belongsTo relations
|
||||
*
|
||||
* @param object $obj Object to delete
|
||||
* @param \ReflectionClass $refClass Reflection of object to delete
|
||||
* @param array $relation Relation data (e.g. ::BELONGS_TO, ::OWNS_ONE)
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function deleteSingleRelation(object $obj, \ReflectionClass $refClass, array $relation) : void
|
||||
{
|
||||
if (empty($relation)) {
|
||||
return;
|
||||
|
|
@ -95,7 +136,7 @@ class DeleteMapper extends DataMapperAbstract
|
|||
$mapper = $relData['mapper'];
|
||||
|
||||
/** @var self $relMapper */
|
||||
$relMapper = $this->createRelationMapper($mapper::delete(db: $this->db), $member);
|
||||
$relMapper = $this->createRelationMapper($mapper::delete(db: $this->db), $member);
|
||||
$relMapper->depth = $this->depth + 1;
|
||||
|
||||
$refProp = $refClass->getProperty($member);
|
||||
|
|
@ -109,6 +150,17 @@ class DeleteMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete hasMany
|
||||
*
|
||||
* @param \ReflectionClass $refClass Reflection of object to delete
|
||||
* @param object $obj Object to delete
|
||||
* @param mixed $objId Object id to delete
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function deleteHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void
|
||||
{
|
||||
if (empty($this->mapper::HAS_MANY)) {
|
||||
|
|
@ -121,7 +173,7 @@ class DeleteMapper extends DataMapperAbstract
|
|||
continue;
|
||||
}
|
||||
|
||||
$objIds = [];
|
||||
$objIds = [];
|
||||
$refProp = $refClass->getProperty($member);
|
||||
if (!$refProp->isPublic()) {
|
||||
$refProp->setAccessible(true);
|
||||
|
|
@ -165,6 +217,17 @@ class DeleteMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete has many relations if the relation is handled in a relation table
|
||||
*
|
||||
* @param string $member Property which contains the has many models
|
||||
* @param array $objIds Objects which are related to the parent object
|
||||
* @param mixed $objId Parent object id
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function deleteRelationTable(string $member, array $objIds = null, mixed $objId) : void
|
||||
{
|
||||
if ((empty($objIds) && $objIds !== null)
|
||||
|
|
|
|||
|
|
@ -25,10 +25,25 @@ use phpOMS\Utils\ArrayUtils;
|
|||
* @link https://orange-management.org
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class ReadMapper extends DataMapperAbstract
|
||||
final class ReadMapper extends DataMapperAbstract
|
||||
{
|
||||
private $columns = [];
|
||||
/**
|
||||
* Columns to load
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $columns = [];
|
||||
|
||||
/**
|
||||
* Create get mapper
|
||||
*
|
||||
* This makes execute() return a single object or an array of object depending the result size
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function get() : self
|
||||
{
|
||||
$this->type = MapperType::GET;
|
||||
|
|
@ -36,6 +51,13 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw result set
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getRaw() : self
|
||||
{
|
||||
$this->type = MapperType::GET_RAW;
|
||||
|
|
@ -43,6 +65,15 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create get mapper
|
||||
*
|
||||
* This makes execute() always return an array of objects (or an empty array)
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getAll() : self
|
||||
{
|
||||
$this->type = MapperType::GET_ALL;
|
||||
|
|
@ -50,6 +81,13 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create count mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function count() : self
|
||||
{
|
||||
$this->type = MapperType::COUNT_MODELS;
|
||||
|
|
@ -57,6 +95,13 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create random mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getRandom() : self
|
||||
{
|
||||
$this->type = MapperType::GET_RANDOM;
|
||||
|
|
@ -64,6 +109,13 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create find mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function find() : self
|
||||
{
|
||||
$this->type = MapperType::FIND;
|
||||
|
|
@ -71,6 +123,16 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the columns to load
|
||||
*
|
||||
* @param array $columns Columns to load
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @todo: consider to accept properties instead and then check ::COLUMNS which contian the property and ADD that array into $this->columns. Maybe also consider a rename from columns() to property()
|
||||
*/
|
||||
public function columns(array $columns) : self
|
||||
{
|
||||
$this->columns = $columns;
|
||||
|
|
@ -78,18 +140,30 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param mixed ...$options Options to pass to read mapper
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function execute(...$options) : mixed
|
||||
{
|
||||
switch($this->type) {
|
||||
case MapperType::GET:
|
||||
/** @var null|Builder ...$options */
|
||||
return $options !== null
|
||||
? $this->executeGet(...$options)
|
||||
: $this->executeGet();
|
||||
case MapperType::GET_RAW:
|
||||
/** @var null|Builder ...$options */
|
||||
return $options !== null
|
||||
? $this->executeGetRaw(...$options)
|
||||
: $this->executeGetRaw();
|
||||
case MapperType::GET_ALL:
|
||||
/** @var null|Builder ...$options */
|
||||
return $options !== null
|
||||
? $this->executeGetAll(...$options)
|
||||
: $this->executeGetAll();
|
||||
|
|
@ -102,15 +176,24 @@ class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
// @todo: consider to always return an array, this way we could remove executeGetAll
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param null|Builder $query Query to use instead of the internally generated query (carefuly, this doesn't merge with the internal query. If you want to merge it use ->query() instead)
|
||||
*
|
||||
* @return object|array
|
||||
*
|
||||
* @todo: consider to always return an array, this way we could remove executeGetAll
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeGet(Builder $query = null) : mixed
|
||||
{
|
||||
$primaryKeys = [];
|
||||
$primaryKeys = [];
|
||||
$memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal'];
|
||||
$emptyWhere = empty($this->where);
|
||||
$emptyWhere = empty($this->where);
|
||||
|
||||
if (isset($this->where[$memberOfPrimaryField])) {
|
||||
$keys = $this->where[$memberOfPrimaryField][0]['value'];
|
||||
$keys = $this->where[$memberOfPrimaryField][0]['value'];
|
||||
$primaryKeys = \array_merge(\is_array($keys) ? $keys : [$keys], $primaryKeys);
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +224,15 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param null|Builder $query Query to use instead of the internally generated query (carefuly, this doesn't merge with the internal query. If you want to merge it use ->query() instead)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeGetRaw(Builder $query = null) : array
|
||||
{
|
||||
$query ??= $this->getQuery();
|
||||
|
|
@ -162,6 +254,15 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $results === false ? [] : $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param null|Builder $query Query to use instead of the internally generated query (carefuly, this doesn't merge with the internal query. If you want to merge it use ->query() instead)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeGetAll(Builder $query = null) : array
|
||||
{
|
||||
$result = $this->executeGet($query);
|
||||
|
|
@ -205,8 +306,8 @@ class ReadMapper extends DataMapperAbstract
|
|||
/**
|
||||
* Get mapper specific builder
|
||||
*
|
||||
* @param Builder $query Query to fill
|
||||
* @param array $columns Columns to use
|
||||
* @param null|Builder $query Query to fill
|
||||
* @param array $columns Columns to use
|
||||
*
|
||||
* @return Builder
|
||||
*
|
||||
|
|
@ -223,7 +324,7 @@ class ReadMapper extends DataMapperAbstract
|
|||
if (\is_string($values)) {
|
||||
$query->selectAs($key, $values);
|
||||
} else {
|
||||
if (($values['writeonly'] ?? false) === false) {
|
||||
if (($values['writeonly'] ?? false) === false || isset($this->with[$values['internal']])) {
|
||||
$query->selectAs($this->mapper::TABLE . '_d' . $this->depth . '.' . $key, $key . '_d' . $this->depth);
|
||||
}
|
||||
}
|
||||
|
|
@ -235,9 +336,9 @@ class ReadMapper extends DataMapperAbstract
|
|||
|
||||
// where
|
||||
foreach ($this->where as $member => $values) {
|
||||
if(($col = $this->mapper::getColumnByMember($member)) !== null) {
|
||||
if (($col = $this->mapper::getColumnByMember($member)) !== null) {
|
||||
/* variable in model */
|
||||
foreach ($values as $index => $where) {
|
||||
foreach ($values as $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
continue;
|
||||
|
|
@ -248,7 +349,8 @@ class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
} elseif (isset($this->mapper::HAS_MANY[$member])) {
|
||||
/* variable in has many */
|
||||
foreach ($values as $index => $where) {
|
||||
/* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
continue;
|
||||
|
|
@ -272,8 +374,10 @@ class ReadMapper extends DataMapperAbstract
|
|||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
} elseif (isset($this->mapper::BELONGS_TO[$member])) {
|
||||
/* variable in belogns to */
|
||||
/* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $index => $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
|
|
@ -290,8 +394,10 @@ class ReadMapper extends DataMapperAbstract
|
|||
$this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth
|
||||
);
|
||||
}
|
||||
*/
|
||||
} elseif (isset($this->mapper::OWNS_ONE[$member])) {
|
||||
/* variable in owns one */
|
||||
/* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $index => $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
|
|
@ -307,6 +413,7 @@ class ReadMapper extends DataMapperAbstract
|
|||
$this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +457,7 @@ class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
/** @var self $relMapper */
|
||||
$relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member);
|
||||
$relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member);
|
||||
$relMapper->depth = $this->depth + 1;
|
||||
|
||||
$query = $relMapper->getQuery(
|
||||
|
|
@ -398,16 +505,14 @@ class ReadMapper extends DataMapperAbstract
|
|||
/**
|
||||
* Populate data.
|
||||
*
|
||||
* @param array $result Query result set
|
||||
* @param mixed $obj Object to populate
|
||||
* @param array $result Query result set
|
||||
* @param object $obj Object to populate
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @return object
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function populateAbstract(array $result, mixed $obj) : mixed
|
||||
public function populateAbstract(array $result, object $obj) : object
|
||||
{
|
||||
$refClass = new \ReflectionClass($obj);
|
||||
|
||||
|
|
@ -627,8 +732,6 @@ class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
// @todo: MUST handle if member is in with here!!!
|
||||
|
||||
if (isset($this->mapper::OWNS_ONE[$member]['column'])) {
|
||||
return $result[$mapper::getColumnByMember($this->mapper::OWNS_ONE[$member]['column']) . '_d' . $this->depth];
|
||||
}
|
||||
|
|
@ -637,8 +740,8 @@ class ReadMapper extends DataMapperAbstract
|
|||
return $mapper::createNullModel();
|
||||
}
|
||||
|
||||
/** @var class-string<DataMapperFactory> $ownsOneMapper */
|
||||
$ownsOneMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
/** @var self $ownsOneMapper */
|
||||
$ownsOneMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
$ownsOneMapper->depth = $this->depth + 1;
|
||||
|
||||
return $ownsOneMapper->populateAbstract($result, $mapper::createBaseModel());
|
||||
|
|
@ -663,7 +766,7 @@ class ReadMapper extends DataMapperAbstract
|
|||
/** @var class-string<DataMapperFactory> $mapper */
|
||||
$mapper = $this->mapper::BELONGS_TO[$member]['mapper'];
|
||||
|
||||
if (!isset($this->with[$member])) {
|
||||
if (!isset($this->with[$member])) {
|
||||
if (\array_key_exists($this->mapper::BELONGS_TO[$member]['external'] . '_d' . ($this->depth), $result)) {
|
||||
return isset($this->mapper::BELONGS_TO[$member]['column'])
|
||||
? $result[$this->mapper::BELONGS_TO[$member]['external'] . '_d' . ($this->depth)]
|
||||
|
|
@ -673,8 +776,6 @@ class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
// @todo: MUST handle if member is in with here!!! ???
|
||||
|
||||
if (isset($this->mapper::BELONGS_TO[$member]['column'])) {
|
||||
return $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['column']) . '_d' . $this->depth];
|
||||
}
|
||||
|
|
@ -688,16 +789,16 @@ class ReadMapper extends DataMapperAbstract
|
|||
// you want the profile but the account id is referenced
|
||||
// in this case you can get the profile by loading the profile based on the account reference column
|
||||
if (isset($this->mapper::BELONGS_TO[$member]['by'])) {
|
||||
/** @var class-string<DataMapperFactory> $belongsToMapper */
|
||||
$belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
/** @var self $belongsToMapper */
|
||||
$belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
$belongsToMapper->depth = $this->depth + 1;
|
||||
$belongsToMapper->where($this->mapper::BELONGS_TO[$member]['by'], $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['by']) . '_d' . $this->depth + 1], '=');
|
||||
|
||||
return $belongsToMapper->execute();
|
||||
}
|
||||
|
||||
/** @var class-string<DataMapperFactory> $belongsToMapper */
|
||||
$belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
/** @var self $belongsToMapper */
|
||||
$belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member);
|
||||
$belongsToMapper->depth = $this->depth + 1;
|
||||
|
||||
return $belongsToMapper->populateAbstract($result, $mapper::createBaseModel());
|
||||
|
|
@ -706,13 +807,13 @@ class ReadMapper extends DataMapperAbstract
|
|||
/**
|
||||
* Fill object with relations
|
||||
*
|
||||
* @param mixed $obj Object to fill
|
||||
* @param object $obj Object to fill
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function loadHasManyRelations(mixed $obj) : void
|
||||
public function loadHasManyRelations(object $obj) : void
|
||||
{
|
||||
if (empty($this->with)) {
|
||||
return;
|
||||
|
|
@ -770,15 +871,15 @@ class ReadMapper extends DataMapperAbstract
|
|||
$refProp = $refClass->getProperty($member);
|
||||
if (!$refProp->isPublic()) {
|
||||
$refProp->setAccessible(true);
|
||||
$refProp->setValue($obj, !\is_array($objects)
|
||||
$refProp->setValue($obj, !\is_array($objects) && ($many['conditional'] ?? false) === false
|
||||
? [$many['mapper']::getObjectId($objects) => $objects]
|
||||
: $objects
|
||||
: $objects // if conditional === true the obj will be asigned (e.g. has many localizations but only one is loaded for the model)
|
||||
);
|
||||
$refProp->setAccessible(false);
|
||||
} else {
|
||||
$obj->{$member} = !\is_array($objects)
|
||||
$obj->{$member} = !\is_array($objects) && ($many['conditional'] ?? false) === false
|
||||
? [$many['mapper']::getObjectId($objects) => $objects]
|
||||
: $objects;
|
||||
: $objects; // if conditional === true the obj will be asigned (e.g. has many localizations but only one is loaded for the model)
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -21,16 +21,20 @@ use phpOMS\Utils\ArrayUtils;
|
|||
/**
|
||||
* Update mapper (CREATE).
|
||||
*
|
||||
* @todo: allow to define single fields which should be updated (e.g. only description)
|
||||
* @todo: allow to define where clause if no object is loaded yet
|
||||
*
|
||||
* @package phpOMS\DataStorage\Database\Mapper
|
||||
* @license OMS License 1.0
|
||||
* @link https://orange-management.org
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class UpdateMapper extends DataMapperAbstract
|
||||
final class UpdateMapper extends DataMapperAbstract
|
||||
{
|
||||
/**
|
||||
* Create update mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function update() : self
|
||||
{
|
||||
$this->type = MapperType::UPDATE;
|
||||
|
|
@ -38,22 +42,37 @@ class UpdateMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param mixed ...$options Options to pass to update mapper
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function execute(...$options) : mixed
|
||||
{
|
||||
switch($this->type) {
|
||||
case MapperType::UPDATE:
|
||||
/** @var object ...$options */
|
||||
return $this->executeUpdate(...$options);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeUpdate(mixed $obj) : mixed
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param object $obj Object to update
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeUpdate(object $obj) : mixed
|
||||
{
|
||||
if (!isset($obj)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$refClass = new \ReflectionClass($obj);
|
||||
$objId = $this->mapper::getObjectId($obj, $refClass);
|
||||
|
||||
|
|
@ -72,6 +91,17 @@ class UpdateMapper extends DataMapperAbstract
|
|||
return $objId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update model
|
||||
*
|
||||
* @param object $obj Object to update
|
||||
* @param mixed $objId Id of the object to update
|
||||
* @param \ReflectionClass $refClass Reflection of the object ot update
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function updateModel(object $obj, mixed $objId, \ReflectionClass $refClass = null) : void
|
||||
{
|
||||
// Model doesn't have anything to update
|
||||
|
|
@ -87,7 +117,8 @@ class UpdateMapper extends DataMapperAbstract
|
|||
$propertyName = \stripos($column['internal'], '/') !== false ? \explode('/', $column['internal'])[0] : $column['internal'];
|
||||
if (isset($this->mapper::HAS_MANY[$propertyName])
|
||||
|| $column['internal'] === $this->mapper::PRIMARYFIELD
|
||||
|| ($column['readonly'] ?? false === true)
|
||||
|| (($column['readonly'] ?? false) === true && !isset($this->with[$propertyName]))
|
||||
|| (($column['writeonly'] ?? false) === true && !isset($this->with[$propertyName]))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -95,7 +126,7 @@ class UpdateMapper extends DataMapperAbstract
|
|||
$refClass = $refClass ?? new \ReflectionClass($obj);
|
||||
$property = $refClass->getProperty($propertyName);
|
||||
|
||||
if (!($isPublic = $property->isPublic())) {
|
||||
if (!($property->isPublic())) {
|
||||
$property->setAccessible(true);
|
||||
$tValue = $property->getValue($obj);
|
||||
$property->setAccessible(false);
|
||||
|
|
@ -104,26 +135,14 @@ class UpdateMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
if (isset($this->mapper::OWNS_ONE[$propertyName])) {
|
||||
$id = $this->updateOwnsOne($propertyName, $tValue);
|
||||
$id = \is_object($tValue) ? $this->updateOwnsOne($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
/**
|
||||
* @todo Orange-Management/phpOMS#232
|
||||
* If a model gets updated all it's relations are also updated.
|
||||
* This should be prevented if the relations didn't change.
|
||||
* No solution yet.
|
||||
*/
|
||||
$query->set([$this->mapper::TABLE . '.' . $column['name'] => $value]);
|
||||
} elseif (isset($this->mapper::BELONGS_TO[$propertyName])) {
|
||||
$id = $this->updateBelongsTo($propertyName, $tValue);
|
||||
$id = \is_object($tValue) ? $this->updateBelongsTo($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
/**
|
||||
* @todo Orange-Management/phpOMS#232
|
||||
* If a model gets updated all it's relations are also updated.
|
||||
* This should be prevented if the relations didn't change.
|
||||
* No solution yet.
|
||||
*/
|
||||
$query->set([$this->mapper::TABLE . '.' . $column['name'] => $value]);
|
||||
} elseif ($column['name'] !== $this->mapper::PRIMARYFIELD) {
|
||||
if (\stripos($column['internal'], '/') !== false) {
|
||||
|
|
@ -143,46 +162,70 @@ class UpdateMapper extends DataMapperAbstract
|
|||
$sth->execute();
|
||||
}
|
||||
} catch (\Throwable $t) {
|
||||
// @codeCoverageIgnoreStart
|
||||
echo $t->getMessage();
|
||||
echo $query->toSql();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
private function updateBelongsTo(string $propertyName, mixed $obj) : mixed
|
||||
/**
|
||||
* Update belongs to
|
||||
*
|
||||
* @param string $propertyName Name of the property to update
|
||||
* @param object $obj Object to update
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function updateBelongsTo(string $propertyName, object $obj) : mixed
|
||||
{
|
||||
if (!\is_object($obj)) {
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/** @var class-string<DataMapperFactory> $mapper */
|
||||
$mapper = $this->mapper::BELONGS_TO[$propertyName]['mapper'];
|
||||
|
||||
/** @var self $relMapper */
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper->depth = $this->depth + 1;
|
||||
|
||||
return $relMapper->execute($obj);
|
||||
}
|
||||
|
||||
private function updateOwnsOne(string $propertyName, mixed $obj) : mixed
|
||||
/**
|
||||
* Update owns one
|
||||
*
|
||||
* @param string $propertyName Name of the property to update
|
||||
* @param object $obj Object to update
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function updateOwnsOne(string $propertyName, object $obj) : mixed
|
||||
{
|
||||
if (!\is_object($obj)) {
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/** @var class-string<DataMapperFactory> $mapper */
|
||||
$mapper = $this->mapper::OWNS_ONE[$propertyName]['mapper'];
|
||||
|
||||
/** @var self $relMapper */
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper->depth = $this->depth + 1;
|
||||
|
||||
return $relMapper->execute($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update has many relations
|
||||
*
|
||||
* @param \ReflectionClass $refClass Reflection of the object containing the relations
|
||||
* @param object $obj Object which contains the relations
|
||||
* @param mixed $objId Object id which contains the relations
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function updateHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void
|
||||
{
|
||||
// @todo: what if has_one has a has_many child (see readmapper, we already solved this here)
|
||||
if (empty($this->with) || empty($this->mapper::HAS_MANY)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -230,7 +273,7 @@ class UpdateMapper extends DataMapperAbstract
|
|||
// already in db
|
||||
if (!empty($primaryKey)) {
|
||||
/** @var self $relMapper */
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName);
|
||||
$relMapper->depth = $this->depth + 1;
|
||||
|
||||
$relMapper->execute($value);
|
||||
|
|
@ -255,13 +298,23 @@ class UpdateMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
$objsIds[$propertyName][$key] = $mapper::create(db: $this->db)->execute($value); // @todo: pass where
|
||||
$objsIds[$propertyName][$key] = $mapper::create(db: $this->db)->execute($value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateRelationTable($objsIds, $objId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update has many relations if the relation is handled in a relation table
|
||||
*
|
||||
* @param array $objsIds Objects which should be related to the parent object
|
||||
* @param mixed $objId Parent object id
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function updateRelationTable(array $objsIds, mixed $objId) : void
|
||||
{
|
||||
foreach ($this->mapper::HAS_MANY as $member => $many) {
|
||||
|
|
@ -288,7 +341,7 @@ class UpdateMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
$sth->execute();
|
||||
$result = $sth->fetchAll(\PDO::FETCH_COLUMN);
|
||||
$result = $sth->fetchAll(\PDO::FETCH_COLUMN);
|
||||
|
||||
$removes = \array_diff($result, \array_values($objsIds[$member] ?? []));
|
||||
$adds = \array_diff(\array_values($objsIds[$member] ?? []), $result);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,15 @@ use phpOMS\Utils\ArrayUtils;
|
|||
* @link https://orange-management.org
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class WriteMapper extends DataMapperAbstract
|
||||
final class WriteMapper extends DataMapperAbstract
|
||||
{
|
||||
/**
|
||||
* Create create mapper
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function create() : self
|
||||
{
|
||||
$this->type = MapperType::CREATE;
|
||||
|
|
@ -36,22 +43,37 @@ class WriteMapper extends DataMapperAbstract
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute mapper
|
||||
*
|
||||
* @param mixed ...$options Model to create
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function execute(...$options) : mixed
|
||||
{
|
||||
switch($this->type) {
|
||||
case MapperType::CREATE:
|
||||
/** @var object ...$options */
|
||||
return $this->executeCreate(...$options);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function executeCreate(mixed $obj) : mixed
|
||||
/**
|
||||
* Create object
|
||||
*
|
||||
* @param object $obj Object to create
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function executeCreate(object $obj) : mixed
|
||||
{
|
||||
if (!isset($obj)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$refClass = new \ReflectionClass($obj);
|
||||
|
||||
if ($this->mapper::isNullModel($obj)) {
|
||||
|
|
@ -72,6 +94,16 @@ class WriteMapper extends DataMapperAbstract
|
|||
return $objId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create model
|
||||
*
|
||||
* @param object $obj Object to create
|
||||
* @param \ReflectionClass $refClass Reflection of the object to create
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function createModel(object $obj, \ReflectionClass $refClass) : mixed
|
||||
{
|
||||
$query = new Builder($this->db);
|
||||
|
|
@ -93,12 +125,12 @@ class WriteMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
if (isset($this->mapper::OWNS_ONE[$propertyName])) {
|
||||
$id = $this->createOwnsOne($propertyName, $tValue);
|
||||
$id = \is_object($tValue) ? $this->createOwnsOne($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
$query->insert($column['name'])->value($value);
|
||||
} elseif (isset($this->mapper::BELONGS_TO[$propertyName])) {
|
||||
$id = $this->createBelongsTo($propertyName, $tValue);
|
||||
$id = \is_object($tValue) ? $this->createBelongsTo($propertyName, $tValue) : $tValue;
|
||||
$value = $this->parseValue($column['type'], $id);
|
||||
|
||||
$query->insert($column['name'])->value($value);
|
||||
|
|
@ -131,9 +163,12 @@ class WriteMapper extends DataMapperAbstract
|
|||
$sth = $this->db->con->prepare($query->toSql());
|
||||
$sth->execute();
|
||||
} catch (\Throwable $t) {
|
||||
// @codeCoverageIgnoreStart
|
||||
\var_dump($t->getMessage());
|
||||
\var_dump($a = $query->toSql());
|
||||
|
||||
return -1;
|
||||
// @codeCoverageIgnoreEND
|
||||
}
|
||||
|
||||
$objId = empty($id = $this->mapper::getObjectId($obj, $refClass)) ? $this->db->con->lastInsertId() : $id;
|
||||
|
|
@ -142,7 +177,17 @@ class WriteMapper extends DataMapperAbstract
|
|||
return $objId;
|
||||
}
|
||||
|
||||
private function createOwnsOne(string $propertyName, mixed $obj) : mixed
|
||||
/**
|
||||
* Create owns one model
|
||||
*
|
||||
* @param string $propertyName Name of the owns one property
|
||||
* @param object $obj Object which contains the owns one model
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function createOwnsOne(string $propertyName, object $obj) : mixed
|
||||
{
|
||||
if (!\is_object($obj)) {
|
||||
return $obj;
|
||||
|
|
@ -159,7 +204,17 @@ class WriteMapper extends DataMapperAbstract
|
|||
return $primaryKey;
|
||||
}
|
||||
|
||||
private function createBelongsTo(string $propertyName, mixed $obj) : mixed
|
||||
/**
|
||||
* Create belongs to model
|
||||
*
|
||||
* @param string $propertyName Name of the belongs to property
|
||||
* @param object $obj Object which contains the belongs to model
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function createBelongsTo(string $propertyName, object $obj) : mixed
|
||||
{
|
||||
if (!\is_object($obj)) {
|
||||
return $obj;
|
||||
|
|
@ -187,15 +242,26 @@ class WriteMapper extends DataMapperAbstract
|
|||
$mapper = $this->mapper::BELONGS_TO[$propertyName]['mapper'];
|
||||
$primaryKey = $mapper::getObjectId($obj);
|
||||
|
||||
// @todo: the $mapper::create() might cause a problem is 'by' is set. because we don't want to create this obj but the child obj.
|
||||
// @todo: the $mapper::create() might cause a problem if 'by' is set. because we don't want to create this obj but the child obj.
|
||||
return empty($primaryKey) ? $mapper::create(db: $this->db)->execute($obj) : $primaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create has many models
|
||||
*
|
||||
* @param \ReflectionClass $refClass Reflection of the object to create
|
||||
* @param object $obj Object to create
|
||||
* @param mixed $objId Id of the parent object
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function createHasMany(\ReflectionClass $refClass, object $obj, mixed $objId) : void
|
||||
{
|
||||
foreach ($this->mapper::HAS_MANY as $propertyName => $rel) {
|
||||
if (!isset($this->mapper::HAS_MANY[$propertyName]['mapper'])) {
|
||||
throw new InvalidMapperException();
|
||||
throw new InvalidMapperException(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$property = $refClass->getProperty($propertyName);
|
||||
|
|
@ -303,6 +369,17 @@ class WriteMapper extends DataMapperAbstract
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create has many relations if the relation is handled in a relation table
|
||||
*
|
||||
* @param string $propertyName Property which contains the has many models
|
||||
* @param array $objsIds Objects which should be related to the parent object
|
||||
* @param mixed $objId Parent object id
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function createRelationTable(string $propertyName, array $objsIds, mixed $objId) : void
|
||||
{
|
||||
if (empty($objsIds) || !isset($this->mapper::HAS_MANY[$propertyName]['external'])) {
|
||||
|
|
@ -332,8 +409,10 @@ class WriteMapper extends DataMapperAbstract
|
|||
$sth->execute();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// @codeCoverageIgnoreStart
|
||||
\var_dump($e->getMessage());
|
||||
\var_dump($relQuery->toSql());
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1307,10 +1307,6 @@ class Builder extends BuilderAbstract
|
|||
*/
|
||||
public function on(string | array $columns, string | array $operator = null, string | array $values = null, string | array $boolean = 'and', string $table = null) : self
|
||||
{
|
||||
if ($operator !== null && !\is_array($operator) && !\in_array(\strtolower($operator), self::OPERATORS)) {
|
||||
throw new \InvalidArgumentException('Unknown operator.');
|
||||
}
|
||||
|
||||
if (!\is_array($columns)) {
|
||||
$columns = [$columns];
|
||||
$operator = [$operator];
|
||||
|
|
@ -1408,10 +1404,12 @@ class Builder extends BuilderAbstract
|
|||
|
||||
$sth->execute();
|
||||
} catch (\Throwable $t) {
|
||||
// @codeCoverageIgnoreStart
|
||||
\var_dump($t->getMessage());
|
||||
\var_dump($this->toSql());
|
||||
|
||||
$sth = null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $sth;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class MysqlGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '`';
|
||||
public string $systemIdentifierStart = '`';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -40,7 +40,7 @@ class MysqlGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = '`';
|
||||
public string $systemIdentifierEnd = '`';
|
||||
|
||||
/**
|
||||
* Compile random.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class SQLiteGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = '`';
|
||||
public string $systemIdentifierEnd = '`';
|
||||
|
||||
/**
|
||||
* Compile random.
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class SqlServerGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '[';
|
||||
public string $systemIdentifierStart = '[';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -40,7 +40,7 @@ class SqlServerGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = ']';
|
||||
public string $systemIdentifierEnd = ']';
|
||||
|
||||
/**
|
||||
* Compile random.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class MysqlGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '`';
|
||||
public string $systemIdentifierStart = '`';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -41,7 +41,7 @@ class MysqlGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = '`';
|
||||
public string $systemIdentifierEnd = '`';
|
||||
|
||||
/**
|
||||
* Compile remove
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class SQLiteGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '`';
|
||||
public string $systemIdentifierStart = '`';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -38,5 +38,5 @@ class SQLiteGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = '`';
|
||||
public string $systemIdentifierEnd = '`';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class SqlServerGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierStart = '[';
|
||||
public string $systemIdentifierStart = '[';
|
||||
|
||||
/**
|
||||
* System identifier.
|
||||
|
|
@ -38,5 +38,5 @@ class SqlServerGrammar extends Grammar
|
|||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $systemIdentifierEnd = ']';
|
||||
public string $systemIdentifierEnd = ']';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ class CountryMapper extends DataMapperFactory
|
|||
* @since 1.0.0
|
||||
*/
|
||||
public const COLUMNS = [
|
||||
'country_id' => ['name' => 'country_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'country_name' => ['name' => 'country_name', 'type' => 'string', 'internal' => 'name'],
|
||||
'country_code2' => ['name' => 'country_code2', 'type' => 'string', 'internal' => 'code2'],
|
||||
'country_code3' => ['name' => 'country_code3', 'type' => 'string', 'internal' => 'code3'],
|
||||
'country_numeric' => ['name' => 'country_numeric', 'type' => 'int', 'internal' => 'numeric'],
|
||||
'country_region' => ['name' => 'country_region', 'type' => 'string', 'internal' => 'region'],
|
||||
'country_developed' => ['name' => 'country_developed', 'type' => 'bool', 'internal' => 'isDeveloped'],
|
||||
'country_id' => ['name' => 'country_id', 'type' => 'int', 'internal' => 'id'],
|
||||
'country_name' => ['name' => 'country_name', 'type' => 'string', 'internal' => 'name'],
|
||||
'country_code2' => ['name' => 'country_code2', 'type' => 'string', 'internal' => 'code2'],
|
||||
'country_code3' => ['name' => 'country_code3', 'type' => 'string', 'internal' => 'code3'],
|
||||
'country_numeric' => ['name' => 'country_numeric', 'type' => 'int', 'internal' => 'numeric'],
|
||||
'country_region' => ['name' => 'country_region', 'type' => 'string', 'internal' => 'region'],
|
||||
'country_developed' => ['name' => 'country_developed', 'type' => 'bool', 'internal' => 'isDeveloped'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ namespace phpOMS\Localization;
|
|||
*/
|
||||
final class NullLocalization extends Localization
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id Model id
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
$this->id = $id;
|
||||
|
|
|
|||
|
|
@ -639,10 +639,15 @@ final class ModuleManager
|
|||
*
|
||||
* @param string $module Module name
|
||||
*
|
||||
* @return \phpOMS\Module\ModuleAbstract
|
||||
* @return object|\phpOMS\Module\ModuleAbstract
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @todo Remove docblock type hint hack "object".
|
||||
* The return type object is only used to stop the annoying warning that a method doesn't exist
|
||||
* if you chain call the methods part of the returned ModuleAbstract implementation.
|
||||
* Remove it once alternative inline type hinting is possible for the specific returned implementation
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function get(string $module) : ModuleAbstract
|
||||
|
|
|
|||
|
|
@ -125,28 +125,29 @@ class File extends FileAbstract implements FileInterface
|
|||
{
|
||||
$exists = self::exists($con, $path);
|
||||
|
||||
// @todo: consider to use the php://memory way, used in the seUpBeforeClass in the test
|
||||
if ((ContentPutMode::hasFlag($mode, ContentPutMode::APPEND) && $exists)
|
||||
|| (ContentPutMode::hasFlag($mode, ContentPutMode::PREPEND) && $exists)
|
||||
|| (ContentPutMode::hasFlag($mode, ContentPutMode::REPLACE) && $exists)
|
||||
|| (!$exists && ContentPutMode::hasFlag($mode, ContentPutMode::CREATE))
|
||||
) {
|
||||
$tmpFile = 'file' . \mt_rand();
|
||||
if (ContentPutMode::hasFlag($mode, ContentPutMode::APPEND) && $exists) {
|
||||
\file_put_contents($tmpFile, self::get($con, $path) . $content);
|
||||
$content = self::get($con, $path) . $content;
|
||||
} elseif (ContentPutMode::hasFlag($mode, ContentPutMode::PREPEND) && $exists) {
|
||||
\file_put_contents($tmpFile, $content . self::get($con, $path));
|
||||
$content = $content . self::get($con, $path);
|
||||
} else {
|
||||
if (!Directory::exists($con, \dirname($path))) {
|
||||
Directory::create($con, \dirname($path), 0755, true);
|
||||
}
|
||||
|
||||
\file_put_contents($tmpFile, $content);
|
||||
}
|
||||
|
||||
\ftp_put($con, $path, $tmpFile, \FTP_BINARY);
|
||||
$fp = \fopen('php://memory', 'r+');
|
||||
\fwrite($fp, $content);
|
||||
\rewind($fp);
|
||||
|
||||
\ftp_fput($con, $path, $fp);
|
||||
\fclose($fp);
|
||||
|
||||
\ftp_chmod($con, 0755, $path);
|
||||
\unlink($tmpFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,55 +39,7 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->model = new BaseModel();
|
||||
$this->modelArray = [
|
||||
'id' => 0,
|
||||
'string' => 'Base',
|
||||
'int' => 11,
|
||||
'bool' => false,
|
||||
'null' => null,
|
||||
'float' => 1.3,
|
||||
'json' => [1, 2, 3],
|
||||
'jsonSerializable' => new class() implements \JsonSerializable {
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return [1, 2, 3];
|
||||
}
|
||||
},
|
||||
'datetime' => new \DateTime('2005-10-11'),
|
||||
'datetime_null' => null,
|
||||
'conditional' => '',
|
||||
'ownsOneSelf' => [
|
||||
'id' => 0,
|
||||
'string' => 'OwnsOne',
|
||||
],
|
||||
'belongsToOne' => [
|
||||
'id' => 0,
|
||||
'string' => 'BelongsTo',
|
||||
],
|
||||
'hasManyDirect' => [
|
||||
[
|
||||
'id' => 0,
|
||||
'string' => 'ManyToManyDirect',
|
||||
'to' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 0,
|
||||
'string' => 'ManyToManyDirect',
|
||||
'to' => 0,
|
||||
],
|
||||
],
|
||||
'hasManyRelations' => [
|
||||
[
|
||||
'id' => 0,
|
||||
'string' => 'ManyToManyRel',
|
||||
],
|
||||
[
|
||||
'id' => 0,
|
||||
'string' => 'ManyToManyRel',
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->model = new BaseModel();
|
||||
|
||||
$GLOBALS['dbpool']->get()->con->prepare(
|
||||
'CREATE TABLE `test_base` (
|
||||
|
|
@ -231,10 +183,17 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
*/
|
||||
public function testRead() : void
|
||||
{
|
||||
$id = BaseModelMapper::create()->execute($this->model);
|
||||
$id = BaseModelMapper::create()->execute($this->model);
|
||||
|
||||
/** @var BaseModel $modelR */
|
||||
$modelR = BaseModelMapper::get()->where('id', $id)->execute();
|
||||
$modelR = BaseModelMapper::get()
|
||||
->with('belongsToOne')
|
||||
->with('ownsOneSelf')
|
||||
->with('hasManyDirect')
|
||||
->with('hasMnayRelations')
|
||||
->with('conditional')
|
||||
->where('id', $id)
|
||||
->execute();
|
||||
|
||||
self::assertEquals($this->model->getId(), $modelR->getId());
|
||||
self::assertEquals($this->model->string, $modelR->string);
|
||||
|
|
@ -292,19 +251,6 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
self::assertEquals($model2->getId(), $by->getId());
|
||||
}
|
||||
|
||||
public function testGetCached() : void
|
||||
{
|
||||
$id = BaseModelMapper::create()->execute($this->model);
|
||||
|
||||
/** @var BaseModel $modelR */
|
||||
$modelR = BaseModelMapper::get()->where('id', $id)->execute();
|
||||
|
||||
/** @var BaseModel $modelR2 */
|
||||
$modelR2 = BaseModelMapper::get()->where('id', $id)->execute();
|
||||
|
||||
self::assertEquals($modelR->getId(), $modelR2->getId());
|
||||
}
|
||||
|
||||
public function testGetNewest() : void
|
||||
{
|
||||
$model1 = new BaseModel();
|
||||
|
|
@ -415,7 +361,7 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
public function testUpdate() : void
|
||||
{
|
||||
$id = BaseModelMapper::create()->execute($this->model);
|
||||
$modelR = BaseModelMapper::get()->where('id', $id)->execute();
|
||||
$modelR = BaseModelMapper::get()->with('hasManyDirect')->with('hasManyRelations')->where('id', $id)->execute();
|
||||
|
||||
$modelR->string = 'Update';
|
||||
$modelR->int = '321';
|
||||
|
|
@ -425,7 +371,7 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
$modelR->datetime = new \DateTime('now');
|
||||
$modelR->datetime_null = null;
|
||||
|
||||
$id2 = BaseModelMapper::update()->execute($modelR);
|
||||
$id2 = BaseModelMapper::update()->with('hasManyDirect')->with('hasManyRelations')->execute($modelR);
|
||||
$modelR2 = BaseModelMapper::get()->where('id', $id2)->execute();
|
||||
|
||||
self::assertEquals($modelR->string, $modelR2->string);
|
||||
|
|
@ -435,11 +381,6 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
self::assertEquals($modelR->null, $modelR2->null);
|
||||
self::assertEquals($modelR->datetime->format('Y-m-d'), $modelR2->datetime->format('Y-m-d'));
|
||||
self::assertNull($modelR2->datetime_null);
|
||||
|
||||
/**
|
||||
* @todo Orange-Management/phpOMS#226
|
||||
* Test the update of a model with relations (update relations).
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -454,17 +395,11 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
*/
|
||||
public function testDelete() : void
|
||||
{
|
||||
/*
|
||||
$id = BaseModelMapper::create()->execute($this->model);
|
||||
BaseModelMapper::delete($this->model);
|
||||
BaseModelMapper::delete()->with('belongsToOne')->with('ownsOneSelf')->with('hasManyRelations')->execute($this->model);
|
||||
$modelR = BaseModelMapper::get()->where('id', $id)->execute();
|
||||
|
||||
self::assertInstanceOf('phpOMS\tests\DataStorage\Database\TestModel\NullBaseModel', $modelR);
|
||||
*/
|
||||
/**
|
||||
* @todo Orange-Management/phpOMS#225
|
||||
* Test the deletion of a model with relations (deleting relations).
|
||||
*/
|
||||
}
|
||||
|
||||
public function testDeleteHasManyRelation() : void
|
||||
|
|
@ -482,4 +417,24 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
|
|||
|
||||
self::assertCount($count1 - 1, $base->hasManyRelations);
|
||||
}
|
||||
|
||||
public function testReader() : void
|
||||
{
|
||||
self::assertInstanceOf('phpOMS\DataStorage\Database\Mapper\ReadMapper', BaseModelMapper::reader());
|
||||
}
|
||||
|
||||
public function testWriter() : void
|
||||
{
|
||||
self::assertInstanceOf('phpOMS\DataStorage\Database\Mapper\WriteMapper', BaseModelMapper::writer());
|
||||
}
|
||||
|
||||
public function testUpdater() : void
|
||||
{
|
||||
self::assertInstanceOf('phpOMS\DataStorage\Database\Mapper\UpdateMapper', BaseModelMapper::updater());
|
||||
}
|
||||
|
||||
public function testRemover() : void
|
||||
{
|
||||
self::assertInstanceOf('phpOMS\DataStorage\Database\Mapper\DeleteMapper', BaseModelMapper::remover());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ declare(strict_types=1);
|
|||
namespace phpOMS\tests\DataStorage\Database\Query;
|
||||
|
||||
use phpOMS\DataStorage\Database\Connection\MysqlConnection;
|
||||
use phpOMS\DataStorage\Database\Connection\PostgresConnection;
|
||||
use phpOMS\DataStorage\Database\Connection\SQLiteConnection;
|
||||
use phpOMS\DataStorage\Database\Connection\SqlServerConnection;
|
||||
use phpOMS\DataStorage\Database\Query\Builder;
|
||||
use phpOMS\DataStorage\Database\Query\Parameter;
|
||||
|
||||
|
|
@ -25,45 +28,56 @@ use phpOMS\DataStorage\Database\Query\Parameter;
|
|||
*/
|
||||
final class BuilderTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected $con;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
public function dbConnectionProvider() : array
|
||||
{
|
||||
$this->con = new MysqlConnection($GLOBALS['CONFIG']['db']['core']['masters']['admin']);
|
||||
return [
|
||||
[new MysqlConnection($GLOBALS['CONFIG']['db']['core']['masters']['admin'])],
|
||||
[new PostgresConnection($GLOBALS['CONFIG']['db']['core']['postgresql']['admin'])],
|
||||
[new SQLiteConnection($GLOBALS['CONFIG']['db']['core']['sqlite']['admin'])],
|
||||
[new SqlServerConnection($GLOBALS['CONFIG']['db']['core']['mssql']['admin'])],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql selects form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlSelect() : void
|
||||
public function testSelect($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` as t FROM `a` as b WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] as t FROM [a] as b WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->selectAs('a.test', 't')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT DISTINCT `a`.`test` FROM `a` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT DISTINCT [a].[test] FROM [a] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->distinct()->from('a')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'abc\';';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test], [b].[test] FROM [a], [b] WHERE [a].[test] = \'abc\';';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test', 'b.test')->from('a', 'b')->where('a.test', '=', 'abc')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$query = new Builder($con);
|
||||
$datetime = new \DateTime('now');
|
||||
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'' . $datetime->format('Y-m-d H:i:s') . '\';';
|
||||
$sql = 'SELECT [a].[test], [b].[test] FROM [a], [b] WHERE [a].[test] = \'' . $datetime->format('Y-m-d H:i:s')
|
||||
. '\';';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test', 'b.test')->from('a', 'b')->where('a.test', '=', $datetime)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = \'abc\' ORDER BY `a`.`test` ASC, `b`.`test` DESC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test], [b].[test] FROM [a], [b] WHERE [a].[test] = \'abc\' ORDER BY [a].[test] ASC, [b].[test] DESC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql,
|
||||
$query->select('a.test', 'b.test')
|
||||
->from('a', 'b')
|
||||
|
|
@ -72,8 +86,9 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
|
|||
->toSql()
|
||||
);
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test`, `b`.`test` FROM `a`, `b` WHERE `a`.`test` = :abcValue ORDER BY `a`.`test` ASC, `b`.`test` DESC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test], [b].[test] FROM [a], [b] WHERE [a].[test] = :abcValue ORDER BY [a].[test] ASC, [b].[test] DESC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql,
|
||||
$query->select('a.test', 'b.test')
|
||||
->from('a', 'b')
|
||||
|
|
@ -83,429 +98,598 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
|
|||
);
|
||||
|
||||
self::assertEquals($query->toSql(), $query->__toString());
|
||||
}
|
||||
|
||||
$query = new Builder($this->con);
|
||||
public function testRandomMysql() : void
|
||||
{
|
||||
$con = new MysqlConnection($GLOBALS['CONFIG']['db']['core']['masters']['admin']);
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` as b WHERE `a`.`test` = 1 ORDER BY \rand() LIMIT 1;';
|
||||
self::assertEquals($sql, $query->random('a.test')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
|
||||
}
|
||||
|
||||
public function testRandomPostgresql() : void
|
||||
{
|
||||
$con = new PostgresConnection($GLOBALS['CONFIG']['db']['core']['postgresql']['admin']);
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT "a"."test" FROM "a" as b ORDER BY RANDOM() LIMIT 1;';
|
||||
self::assertEquals($sql, $query->random('a.test')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
|
||||
}
|
||||
|
||||
public function testRandomSQLite() : void
|
||||
{
|
||||
$con = new SQLiteConnection($GLOBALS['CONFIG']['db']['core']['sqlite']['admin']);
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` as b ORDER BY RANDOM() LIMIT 1;';
|
||||
self::assertEquals($sql, $query->random('a.test')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
|
||||
}
|
||||
|
||||
public function testRandomSqlServer() : void
|
||||
{
|
||||
$con = new SqlServerConnection($GLOBALS['CONFIG']['db']['core']['mssql']['admin']);
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT TOP 1 [a].[test] FROM [a] as b ORDER BY IDX FETCH FIRST 1 ROWS ONLY;';
|
||||
self::assertEquals($sql, $query->random('a.test')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql orders form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlOrder() : void
|
||||
public function testOrder($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` DESC;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] DESC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->newest('a.test')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` ASC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] ASC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->oldest('a.test')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` DESC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] DESC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->orderBy('a.test', 'DESC')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` ASC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] ASC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->orderBy('a.test', 'ASC')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` DESC, `a`.`test2` DESC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] DESC, [a].[test2] DESC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->orderBy(['a.test', 'a.test2'], ['DESC', 'DESC'])->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 ORDER BY `a`.`test` ASC, `a`.`test2` ASC;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 ORDER BY [a].[test] ASC, [a].[test2] ASC;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->orderBy(['a.test', 'a.test2'], 'ASC')->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql offsets and limits form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlOffsetLimit() : void
|
||||
public function testOffsetLimit($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 LIMIT 3;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 LIMIT 3;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->limit(3)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OFFSET 3;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OFFSET 3;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->offset(3)->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql groupings form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlGroup() : void
|
||||
public function testGroup($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 GROUP BY `a`;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 GROUP BY [a];';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->groupBy('a')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 GROUP BY `a`, `b`;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 GROUP BY [a], [b];';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->groupBy('a')->groupBy('b')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$query = new Builder($con);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->groupBy('a', 'b')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = :test GROUP BY `a`, `b`;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = :test GROUP BY [a], [b];';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', new Parameter('test'))->groupBy('a', 'b')->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql wheres form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlWheres() : void
|
||||
public function testWheres($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 0;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 0;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', false)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', true)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = \'string\';';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = \'string\';';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 'string')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1.23;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1.23;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1.23)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 AND `a`.`test2` = 2;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 AND [a].[test2] = 2;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->where('a.test2', '=', 2, 'and')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 AND `a`.`test2` = 2;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 AND [a].[test2] = 2;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->andWhere('a.test2', '=', 2)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` = 2;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] = 2;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->where('a.test2', '=', 2, 'or')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` = 2;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] = 2;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->orWhere('a.test2', '=', 2)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` IS NULL;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] IS NULL;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->whereNull('a.test2', 'or')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` IS NOT NULL;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] IS NOT NULL;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->whereNotNull('a.test2', 'or')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` IN (1, 2, 3);';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] IN (1, 2, 3);';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->whereIn('a.test2', [1, 2, 3], 'or')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = 1 OR `a`.`test2` IN (\'a\', \'b\', \'c\');';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = 1 OR [a].[test2] IN (\'a\', \'b\', \'c\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', 1)->whereIn('a.test2', ['a', 'b', 'c'], 'or')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` WHERE `a`.`test` = :testWhere OR `a`.`test2` IN (\'a\', :bValue, \'c\');';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] WHERE [a].[test] = :testWhere OR [a].[test2] IN (\'a\', :bValue, \'c\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->where('a.test', '=', new Parameter('testWhere'))->whereIn('a.test2', ['a', new Parameter('bValue'), 'c'], 'or')->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql joins form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlJoins() : void
|
||||
public function testJoins($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->join('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` JOIN `b` ON `a`.`id` = `b`.`id` OR `a`.`id2` = `b`.`id2` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] JOIN [b] ON [a].[id] = [b].[id] OR [a].[id2] = [b].[id2] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->join('b')->on('a.id', '=', 'b.id')->orOn('a.id2', '=', 'b.id2')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` JOIN `b` ON `a`.`id` = `b`.`id` AND `a`.`id2` = `b`.`id2` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] JOIN [b] ON [a].[id] = [b].[id] AND [a].[id2] = [b].[id2] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->join('b')->on('a.id', '=', 'b.id')->andOn('a.id2', '=', 'b.id2')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` LEFT JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] LEFT JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->leftJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` LEFT OUTER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] LEFT OUTER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->leftOuterJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` LEFT INNER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] LEFT INNER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->leftInnerJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` RIGHT JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] RIGHT JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->rightJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` RIGHT OUTER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] RIGHT OUTER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->rightOuterJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` RIGHT INNER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] RIGHT INNER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->rightInnerJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` OUTER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] OUTER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->outerJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` INNER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] INNER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->innerJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` CROSS JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] CROSS JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->crossJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` FULL JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] FULL JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->fullJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'SELECT `a`.`test` FROM `a` FULL OUTER JOIN `b` ON `a`.`id` = `b`.`id` WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'SELECT [a].[test] FROM [a] FULL OUTER JOIN [b] ON [a].[id] = [b].[id] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->select('a.test')->from('a')->fullOuterJoin('b')->on('a.id', '=', 'b.id')->where('a.test', '=', 1)->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql inserts form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlInsert() : void
|
||||
public function testInsert($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'INSERT INTO `a` VALUES (1, \'test\');';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'INSERT INTO [a] VALUES (1, \'test\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->insert()->into('a')->values(1, 'test')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'INSERT INTO `a` VALUES (1, \'test\');';
|
||||
$query = new Builder($con);
|
||||
$sql = 'INSERT INTO [a] VALUES (1, \'test\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->insert()->into('a')->value([1, 'test'])->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'INSERT INTO `a` (`test`, `test2`) VALUES (1, \'test\');';
|
||||
$query = new Builder($con);
|
||||
$sql = 'INSERT INTO [a] ([test], [test2]) VALUES (1, \'test\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->insert('test', 'test2')->into('a')->values(1, 'test')->toSql());
|
||||
self::assertEquals([[1, 'test']], $query->getValues());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'INSERT INTO `a` (`test`, `test2`) VALUES (1, \'test\'), (2, \'test2\');';
|
||||
$query = new Builder($con);
|
||||
$sql = 'INSERT INTO [a] ([test], [test2]) VALUES (1, \'test\'), (2, \'test2\');';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->insert('test', 'test2')->into('a')->values(1, 'test')->values(2, 'test2')->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'INSERT INTO `a` (`test`, `test2`) VALUES (:test, :test2);';
|
||||
$query = new Builder($con);
|
||||
$sql = 'INSERT INTO [a] ([test], [test2]) VALUES (:test, :test2);';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->insert('test', 'test2')->into('a')->values(new Parameter('test'), new Parameter('test2'))->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql deletes form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlDelete() : void
|
||||
public function testDelete($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'DELETE FROM `a` WHERE `a`.`test` = 1;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'DELETE FROM [a] WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->delete()->from('a')->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'DELETE FROM `a` WHERE `a`.`test` = :testVal;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'DELETE FROM [a] WHERE [a].[test] = :testVal;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->delete()->from('a')->where('a.test', '=', new Parameter('testVal'))->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Mysql updates form a valid query
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testMysqlUpdate() : void
|
||||
public function testUpdate($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'UPDATE `a` SET `a`.`test` = 1, `a`.`test2` = 2 WHERE `a`.`test` = 1;';
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
$sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = 2 WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->update('a')->set(['a.test' => 1])->set(['a.test2' => 2])->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'UPDATE `a` SET `a`.`test` = 1, `a`.`test2` = 2 WHERE `a`.`test` = 1;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = 2 WHERE [a].[test] = 1;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->update('a')->sets('a.test', 1)->sets('a.test2', 2)->where('a.test', '=', 1)->toSql());
|
||||
|
||||
$query = new Builder($this->con);
|
||||
$sql = 'UPDATE `a` SET `a`.`test` = 1, `a`.`test2` = :test2 WHERE `a`.`test` = :test3;';
|
||||
$query = new Builder($con);
|
||||
$sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = :test2 WHERE [a].[test] = :test3;';
|
||||
$sql = \str_replace(['[', ']'], [$iS, $iE], $sql);
|
||||
self::assertEquals($sql, $query->update('a')->set(['a.test' => 1])->set(['a.test2' => new Parameter('test2')])->where('a.test', '=', new Parameter('test3'))->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Raw queries get output as defined
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testRawInputOutput() : void
|
||||
public function testRawInputOutput($con) : void
|
||||
{
|
||||
$query = new Builder($this->con);
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con);
|
||||
self::assertEquals('SELECT test.val FROM test;', $query->raw('SELECT test.val FROM test;')->toSql());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries allow selects
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyRawSelect() : void
|
||||
public function testReadOnlyRawSelect($con) : void
|
||||
{
|
||||
$query = new Builder($this->con, true);
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$query = new Builder($con, true);
|
||||
self::assertInstanceOf(Builder::class, $query->raw('SELECT * from oms;'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow drops
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyRawDrop() : void
|
||||
public function testReadOnlyRawDrop($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->raw('DROP DATABASE oms;');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow deletes
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyRawDelete() : void
|
||||
public function testReadOnlyRawDelete($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->raw('DELETE oms;');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow creates
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyRawCreate() : void
|
||||
public function testReadOnlyRawCreate($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->raw('CREATE oms;');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow modifications
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyRawAlter() : void
|
||||
public function testReadOnlyRawAlter($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->raw('ALTER oms;');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow inserts
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyInsert() : void
|
||||
public function testReadOnlyInsert($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->insert('test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow updates
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyUpdate() : void
|
||||
public function testReadOnlyUpdate($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Read only queries don't allow deletes
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testReadOnlyDelete() : void
|
||||
public function testReadOnlyDelete($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Invalid select types throw a InvalidArgumentException
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testInvalidSelectParameter() : void
|
||||
public function testInvalidSelectParameter($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->select(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Invalid from types throw a InvalidArgumentException
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testInvalidFromParameter() : void
|
||||
public function testInvalidFromParameter($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->from(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Invalid group types throw a InvalidArgumentException
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testInvalidGroupByParameter() : void
|
||||
public function testInvalidGroupByParameter($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->groupBy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Invalid where operators throw a InvalidArgumentException
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testInvalidWhereOperator() : void
|
||||
public function testInvalidWhereOperator($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->where('a', 'invalid', 'b');
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Invalid join operators throw a InvalidArgumentException
|
||||
* @group framework
|
||||
* @dataProvider dbConnectionProvider
|
||||
*/
|
||||
public function testInvalidJoinOperator() : void
|
||||
public function testInvalidJoinOperator($con) : void
|
||||
{
|
||||
$iS = $con->getGrammar()->systemIdentifierStart;
|
||||
$iE = $con->getGrammar()->systemIdentifierEnd;
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$query = new Builder($this->con, true);
|
||||
$query = new Builder($con, true);
|
||||
$query->join('b')->on('a', 'invalid', 'b');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ class BaseModelMapper extends DataMapperFactory
|
|||
*/
|
||||
public const BELONGS_TO = [
|
||||
'belongsToOne' => [
|
||||
'mapper' => BelongsToModelMapper::class,
|
||||
'external' => 'test_base_belongs_to_one',
|
||||
'mapper' => BelongsToModelMapper::class,
|
||||
'external' => 'test_base_belongs_to_one',
|
||||
],
|
||||
];
|
||||
|
||||
public const OWNS_ONE = [
|
||||
'ownsOneSelf' => [
|
||||
'mapper' => OwnsOneModelMapper::class,
|
||||
'external' => 'test_base_owns_one_self',
|
||||
'mapper' => OwnsOneModelMapper::class,
|
||||
'external' => 'test_base_owns_one_self',
|
||||
],
|
||||
];
|
||||
|
||||
|
|
@ -67,29 +67,47 @@ class BaseModelMapper extends DataMapperFactory
|
|||
*/
|
||||
public const HAS_MANY = [
|
||||
'hasManyDirect' => [
|
||||
'mapper' => ManyToManyDirectModelMapper::class,
|
||||
'table' => 'test_has_many_direct',
|
||||
'self' => 'test_has_many_direct_to',
|
||||
'external' => null,
|
||||
'mapper' => ManyToManyDirectModelMapper::class,
|
||||
'table' => 'test_has_many_direct',
|
||||
'self' => 'test_has_many_direct_to',
|
||||
'external' => null,
|
||||
],
|
||||
'hasManyRelations' => [
|
||||
'mapper' => ManyToManyRelModelMapper::class,
|
||||
'table' => 'test_has_many_rel_relations',
|
||||
'external' => 'test_has_many_rel_relations_src',
|
||||
'self' => 'test_has_many_rel_relations_dest',
|
||||
'mapper' => ManyToManyRelModelMapper::class,
|
||||
'table' => 'test_has_many_rel_relations',
|
||||
'external' => 'test_has_many_rel_relations_src',
|
||||
'self' => 'test_has_many_rel_relations_dest',
|
||||
],
|
||||
'conditional' => [
|
||||
'mapper' => ConditionalMapper::class,
|
||||
'table' => 'test_conditional',
|
||||
'self' => 'test_conditional_base',
|
||||
'column' => 'title',
|
||||
'external' => null,
|
||||
'mapper' => ConditionalMapper::class,
|
||||
'table' => 'test_conditional',
|
||||
'self' => 'test_conditional_base',
|
||||
'column' => 'title',
|
||||
'external' => null,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'test_base';
|
||||
|
||||
/**
|
||||
* Created at.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const CREATED_AT = 'test_base_datetime';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='test_base_id';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,19 @@ class BelongsToModelMapper extends DataMapperFactory
|
|||
'test_belongs_to_one_string' => ['name' => 'test_belongs_to_one_string', 'type' => 'string', 'internal' => 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'test_belongs_to_one';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='test_belongs_to_one_id';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,19 @@ class ManyToManyDirectModelMapper extends DataMapperFactory
|
|||
'test_has_many_direct_to' => ['name' => 'test_has_many_direct_to', 'type' => 'int', 'internal' => 'to'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'test_has_many_direct';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='test_has_many_direct_id';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,19 @@ class ManyToManyRelModelMapper extends DataMapperFactory
|
|||
'test_has_many_rel_string' => ['name' => 'test_has_many_rel_string', 'type' => 'string', 'internal' => 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'test_has_many_rel';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='test_has_many_rel_id';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,19 @@ class OwnsOneModelMapper extends DataMapperFactory
|
|||
'test_owns_one_string' => ['name' => 'test_owns_one_string', 'type' => 'string', 'internal' => 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Primary table.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const TABLE = 'test_owns_one';
|
||||
|
||||
/**
|
||||
* Primary field name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public const PRIMARYFIELD ='test_owns_one_id';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* Orange Management
|
||||
*
|
||||
* PHP Version 8.0
|
||||
*
|
||||
* @package Template
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://orange-management.org
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
return [1, 2, 3];
|
||||
|
|
|
|||
|
|
@ -1,2 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* Orange Management
|
||||
*
|
||||
* PHP Version 8.0
|
||||
*
|
||||
* @package Template
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://orange-management.org
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
return '<strong>Test</strong>';
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user