diff --git a/src/AliasedExpression.php b/src/AliasedExpression.php index dca03bc..4a14e2e 100644 --- a/src/AliasedExpression.php +++ b/src/AliasedExpression.php @@ -7,7 +7,7 @@ class AliasedExpression extends Expression { /** @var string */ - protected $alias; + protected string $alias; /** * Create a new database expression diff --git a/src/Behavior/Binary.php b/src/Behavior/Binary.php index 43e3e11..75fd294 100644 --- a/src/Behavior/Binary.php +++ b/src/Behavior/Binary.php @@ -11,15 +11,13 @@ use ipl\Stdlib\Filter\Condition; use UnexpectedValueException; -use function ipl\Stdlib\get_php_type; - /** * Support hex filters for binary columns and PHP resource (in) / bytea hex format (out) transformation for PostgreSQL */ class Binary extends PropertyBehavior implements QueryAwareBehavior, RewriteFilterBehavior { /** @var bool Whether the query is using a pgsql adapter */ - protected $isPostgres = true; + protected bool $isPostgres = true; public function fromDb($value, $key, $_) { diff --git a/src/Behavior/BoolCast.php b/src/Behavior/BoolCast.php index 3163ff9..bc65a0e 100644 --- a/src/Behavior/BoolCast.php +++ b/src/Behavior/BoolCast.php @@ -19,20 +19,20 @@ class BoolCast extends PropertyBehavior { /** @var mixed Database value for boolean `false` */ - protected $falseValue = 'n'; + protected mixed $falseValue = 'n'; /** @var mixed Database value for boolean `true` */ - protected $trueValue = 'y'; + protected mixed $trueValue = 'y'; /** @var bool Whether to throw an exception if the value is not equal to the value for false or true */ - protected $strict = true; + protected bool $strict = true; /** * Get the database value representing boolean `false` * * @return mixed */ - public function getFalseValue() + public function getFalseValue(): mixed { return $this->falseValue; } @@ -44,7 +44,7 @@ public function getFalseValue() * * @return $this */ - public function setFalseValue($falseValue): self + public function setFalseValue(mixed $falseValue): static { $this->falseValue = $falseValue; @@ -56,7 +56,7 @@ public function setFalseValue($falseValue): self * * @return mixed */ - public function getTrueValue() + public function getTrueValue(): mixed { return $this->trueValue; } @@ -68,7 +68,7 @@ public function getTrueValue() * * @return $this */ - public function setTrueValue($trueValue): self + public function setTrueValue(mixed $trueValue): static { $this->trueValue = $trueValue; @@ -92,7 +92,7 @@ public function isStrict(): bool * * @return $this */ - public function setStrict(bool $strict): self + public function setStrict(bool $strict): static { $this->strict = $strict; diff --git a/src/Behaviors.php b/src/Behaviors.php index 5c54350..d46a83e 100644 --- a/src/Behaviors.php +++ b/src/Behaviors.php @@ -16,32 +16,34 @@ class Behaviors implements IteratorAggregate { /** @var array Registered behaviors */ - protected $behaviors = []; + protected array $behaviors = []; /** @var RetrieveBehavior[] Registered retrieve behaviors */ - protected $retrieveBehaviors = []; + protected array $retrieveBehaviors = []; /** @var PersistBehavior[] Registered persist behaviors */ - protected $persistBehaviors = []; + protected array $persistBehaviors = []; /** @var PropertyBehavior[] Registered property behaviors */ - protected $propertyBehaviors = []; + protected array $propertyBehaviors = []; /** @var RewriteFilterBehavior[] Registered rewrite filter behaviors */ - protected $rewriteFilterBehaviors = []; + protected array $rewriteFilterBehaviors = []; /** @var RewriteColumnBehavior[] Registered rewrite column behaviors */ - protected $rewriteColumnBehaviors = []; + protected array $rewriteColumnBehaviors = []; /** @var RewritePathBehavior[] Registered rewrite path behaviors */ - protected $rewritePathBehaviors = []; + protected array $rewritePathBehaviors = []; /** * Add a behavior * - * @param PersistBehavior|PropertyBehavior|RetrieveBehavior|RewriteFilterBehavior $behavior + * @param Behavior $behavior + * + * @return void */ - public function add(Behavior $behavior) + public function add(Behavior $behavior): void { $this->behaviors[] = $behavior; @@ -86,8 +88,10 @@ public function getIterator(): Traversable * Apply all retrieve behaviors on the given model * * @param Model $model + * + * @return void */ - public function retrieve(Model $model) + public function retrieve(Model $model): void { foreach ($this->retrieveBehaviors as $behavior) { $behavior->retrieve($model); @@ -98,8 +102,10 @@ public function retrieve(Model $model) * Apply all persist behaviors on the given model * * @param Model $model + * + * @return void */ - public function persist(Model $model) + public function persist(Model $model): void { foreach ($this->persistBehaviors as $behavior) { $behavior->persist($model); @@ -114,7 +120,7 @@ public function persist(Model $model) * * @return mixed */ - public function retrieveProperty($value, $key) + public function retrieveProperty(mixed $value, string $key): mixed { foreach ($this->propertyBehaviors as $behavior) { $value = $behavior->retrieveProperty($value, $key); @@ -131,7 +137,7 @@ public function retrieveProperty($value, $key) * * @return mixed */ - public function persistProperty($value, $key) + public function persistProperty(mixed $value, string $key): mixed { foreach ($this->propertyBehaviors as $behavior) { $value = $behavior->persistProperty($value, $key); @@ -144,11 +150,11 @@ public function persistProperty($value, $key) * Rewrite the given filter condition * * @param Filter\Condition $condition - * @param string $relation Absolute path (with a trailing dot) of the model + * @param ?string $relation Absolute path (with a trailing dot) of the model * * @return Filter\Rule|null */ - public function rewriteCondition(Filter\Condition $condition, $relation = null) + public function rewriteCondition(Filter\Condition $condition, ?string $relation = null): ?Filter\Rule { $filter = null; foreach ($this->rewriteFilterBehaviors as $behavior) { @@ -164,12 +170,12 @@ public function rewriteCondition(Filter\Condition $condition, $relation = null) /** * Rewrite the given relation path * - * @param string $path - * @param string $relation Absolute path of the model + * @param string $path + * @param ?string $relation Absolute path of the model * * @return string|null */ - public function rewritePath($path, $relation = null) + public function rewritePath(string $path, ?string $relation = null): ?string { $newPath = null; foreach ($this->rewritePathBehaviors as $behavior) { @@ -185,12 +191,12 @@ public function rewritePath($path, $relation = null) /** * Rewrite the given column * - * @param string $column - * @param string $relation Absolute path of the model + * @param string $column + * @param ?string $relation Absolute path of the model * * @return mixed */ - public function rewriteColumn($column, $relation = null) + public function rewriteColumn(string $column, ?string $relation = null): mixed { $newColumn = null; foreach ($this->rewriteColumnBehaviors as $behavior) { diff --git a/src/ColumnDefinition.php b/src/ColumnDefinition.php index ddb8062..b324a97 100644 --- a/src/ColumnDefinition.php +++ b/src/ColumnDefinition.php @@ -3,15 +3,14 @@ namespace ipl\Orm; use InvalidArgumentException; -use LogicException; class ColumnDefinition { /** @var string The name of the column */ - protected $name; + protected string $name; /** @var ?string The label of the column */ - protected $label; + protected ?string $label = null; /** * Create a new column definition @@ -50,7 +49,7 @@ public function getLabel(): ?string * * @return $this */ - public function setLabel(?string $label): self + public function setLabel(?string $label): static { $this->label = $label; @@ -62,9 +61,11 @@ public function setLabel(?string $label): self * * @param array $options * - * @return self + * @return static + * + * @throws InvalidArgumentException If the given options do not provide a name */ - public static function fromArray(array $options): self + public static function fromArray(array $options): static { if (! isset($options['name'])) { throw new InvalidArgumentException('$options must provide a name'); diff --git a/src/Common/PropertiesWithDefaults.php b/src/Common/PropertiesWithDefaults.php index e8d3a84..3ee43da 100644 --- a/src/Common/PropertiesWithDefaults.php +++ b/src/Common/PropertiesWithDefaults.php @@ -4,14 +4,15 @@ use Closure; use Traversable; +use ipl\Stdlib\Properties; trait PropertiesWithDefaults { - use \ipl\Stdlib\Properties { - \ipl\Stdlib\Properties::getProperty as private parentGetProperty; + use Properties { + Properties::getProperty as private parentGetProperty; } - protected function getProperty($key) + protected function getProperty(string $key): mixed { if (isset($this->properties[$key]) && $this->properties[$key] instanceof Closure) { $this->setProperty($key, $this->properties[$key]($this, $key)); diff --git a/src/Common/SortUtil.php b/src/Common/SortUtil.php index a14ea2b..2a5addf 100644 --- a/src/Common/SortUtil.php +++ b/src/Common/SortUtil.php @@ -9,17 +9,17 @@ class SortUtil /** * Create the sort column(s) and direction(s) from the given sort spec * - * @param array|string $sort + * @param string|array $sort * * @return array Sort column(s) and direction(s) suitable for {@link OrderByInterface::orderBy()} */ - public static function createOrderBy($sort): array + public static function createOrderBy(string|array $sort): array { $columnsAndDirections = static::explodeSortSpec($sort); $orderBy = []; foreach ($columnsAndDirections as $columnAndDirection) { - list($column, $direction) = static::splitColumnAndDirection($columnAndDirection); + [$column, $direction] = static::splitColumnAndDirection($columnAndDirection); $orderBy[] = [$column, $direction]; } @@ -30,11 +30,11 @@ public static function createOrderBy($sort): array /** * Explode the given sort spec into its sort parts * - * @param array|string $sort + * @param string|array $sort * * @return array */ - public static function explodeSortSpec($sort) + public static function explodeSortSpec(string|array $sort): array { return Str::trimSplit(implode(',', (array) $sort)); } @@ -42,11 +42,11 @@ public static function explodeSortSpec($sort) /** * Normalize the given sort spec to a sort string * - * @param array|string $sort + * @param string|array $sort * * @return string */ - public static function normalizeSortSpec($sort) + public static function normalizeSortSpec(string|array $sort): string { return implode(',', static::explodeSortSpec($sort)); } @@ -58,7 +58,7 @@ public static function normalizeSortSpec($sort) * * @return array */ - public static function splitColumnAndDirection($sort) + public static function splitColumnAndDirection(string $sort): array { return Str::symmetricSplit($sort, ' ', 2); } diff --git a/src/Compat/FilterProcessor.php b/src/Compat/FilterProcessor.php index 1b3aab9..f4f215e 100644 --- a/src/Compat/FilterProcessor.php +++ b/src/Compat/FilterProcessor.php @@ -20,9 +20,9 @@ class FilterProcessor extends \ipl\Sql\Compat\FilterProcessor { - protected $baseJoins = []; + protected array $baseJoins = []; - protected $madeJoins = []; + protected array $madeJoins = []; /** * Require and resolve the filter rule and apply it on the query @@ -33,8 +33,10 @@ class FilterProcessor extends \ipl\Sql\Compat\FilterProcessor * * @param Filter\Rule $filter * @param Query $query + * + * @return void */ - public static function apply(Filter\Rule $filter, Query $query) + public static function apply(Filter\Rule $filter, Query $query): void { if ($query instanceof UnionQuery) { foreach ($query->getUnions() as $union) { @@ -71,7 +73,7 @@ public static function apply(Filter\Rule $filter, Query $query) * * @return void */ - public static function resolveFilter(Filter\Chain $filter, Query $query) + public static function resolveFilter(Filter\Chain $filter, Query $query): void { $processor = new static(); foreach ($query->getUtilize() as $path => $_) { @@ -81,8 +83,11 @@ public static function resolveFilter(Filter\Chain $filter, Query $query) $processor->requireAndResolveFilterColumns($filter, $query); } - protected function requireAndResolveFilterColumns(Filter\Rule $filter, Query $query, $forceOptimization = null) - { + protected function requireAndResolveFilterColumns( + Filter\Rule $filter, + Query $query, + ?bool $forceOptimization = null + ): MetaDataProvider|Filter\Rule|null { if ($filter instanceof Filter\Condition) { if ( $filter instanceof Exists @@ -90,7 +95,7 @@ protected function requireAndResolveFilterColumns(Filter\Rule $filter, Query $qu || $filter instanceof In || $filter instanceof NotIn ) { - return; + return null; } $resolver = $query->getResolver(); @@ -102,7 +107,7 @@ protected function requireAndResolveFilterColumns(Filter\Rule $filter, Query $qu $filter->metaData()->set('columnPath', $column); - list($relationPath, $columnName) = preg_split('/\.(?=[^.]+$)/', $column); + [$relationPath, $columnName] = preg_split('/\.(?=[^.]+$)/', $column); $subject = null; $relations = new AppendIterator(); @@ -270,7 +275,7 @@ protected function requireAndResolveFilterColumns(Filter\Rule $filter, Query $qu $subQueryFilters[] = [$baseFilters ?: $generalRules, $count, false]; } - foreach ($subQueryFilters as list($filters, $count, $negate)) { + foreach ($subQueryFilters as [$filters, $count, $negate]) { $subQueryFilter = null; if ($count !== null) { $aggregateFilter = Filter::any(); @@ -387,5 +392,7 @@ function ($relationFilter) use ($rule) { $filter->remove($rule); } } + + return null; } } diff --git a/src/Contract/PersistBehavior.php b/src/Contract/PersistBehavior.php index a6db05d..50a6952 100644 --- a/src/Contract/PersistBehavior.php +++ b/src/Contract/PersistBehavior.php @@ -14,5 +14,5 @@ interface PersistBehavior extends Behavior * * @param Model $model */ - public function persist(Model $model); + public function persist(Model $model): void; } diff --git a/src/Contract/PropertyBehavior.php b/src/Contract/PropertyBehavior.php index c828458..6242c20 100644 --- a/src/Contract/PropertyBehavior.php +++ b/src/Contract/PropertyBehavior.php @@ -8,7 +8,7 @@ abstract class PropertyBehavior implements RetrieveBehavior, PersistBehavior { /** @var array Property names of which the value should be processed */ - protected $properties; + protected array $properties; /** * PropertyBehavior constructor @@ -24,7 +24,7 @@ public function __construct(array $properties) } } - public function retrieve(Model $model) + public function retrieve(Model $model): void { foreach ($this->properties as $key => $ctx) { if ($model->hasProperty($key)) { @@ -33,7 +33,7 @@ public function retrieve(Model $model) } } - public function persist(Model $model) + public function persist(Model $model): void { foreach ($this->properties as $key => $ctx) { try { @@ -52,7 +52,7 @@ public function persist(Model $model) * * @return mixed */ - public function retrieveProperty($value, $key) + public function retrieveProperty(mixed $value, string $key): mixed { if (! isset($this->properties[$key])) { return $value; @@ -69,7 +69,7 @@ public function retrieveProperty($value, $key) * * @return mixed */ - public function persistProperty($value, $key) + public function persistProperty(mixed $value, string $key): mixed { if (! isset($this->properties[$key])) { return $value; diff --git a/src/Contract/RetrieveBehavior.php b/src/Contract/RetrieveBehavior.php index 884d074..be3c037 100644 --- a/src/Contract/RetrieveBehavior.php +++ b/src/Contract/RetrieveBehavior.php @@ -14,5 +14,5 @@ interface RetrieveBehavior extends Behavior * * @param Model $model */ - public function retrieve(Model $model); + public function retrieve(Model $model): void; } diff --git a/src/Defaults.php b/src/Defaults.php index aa2d517..15deab0 100644 --- a/src/Defaults.php +++ b/src/Defaults.php @@ -8,7 +8,7 @@ class Defaults implements IteratorAggregate { /** @var array Registered defaults */ - protected $defaults = []; + protected array $defaults = []; /** * Iterate over the defaults @@ -31,7 +31,7 @@ public function getIterator(): Traversable * * @return $this */ - public function add(string $property, $default): self + public function add(string $property, mixed $default): static { $this->defaults[$property] = $default; diff --git a/src/Exception/InvalidColumnException.php b/src/Exception/InvalidColumnException.php index cd320c6..8fb9344 100644 --- a/src/Exception/InvalidColumnException.php +++ b/src/Exception/InvalidColumnException.php @@ -8,10 +8,10 @@ class InvalidColumnException extends Exception { /** @var string The column name */ - protected $column; + protected string $column; /** @var Model The target model */ - protected $model; + protected Model $model; /** * Create a new InvalidColumnException @@ -19,9 +19,9 @@ class InvalidColumnException extends Exception * @param string $column The column name * @param Model $model The target model */ - public function __construct($column, Model $model) + public function __construct(string $column, Model $model) { - $this->column = (string) $column; + $this->column = $column; $this->model = $model; parent::__construct(sprintf( @@ -36,7 +36,7 @@ public function __construct($column, Model $model) * * @return string */ - public function getColumn() + public function getColumn(): string { return $this->column; } @@ -46,7 +46,7 @@ public function getColumn() * * @return Model */ - public function getModel() + public function getModel(): Model { return $this->model; } diff --git a/src/Exception/InvalidRelationException.php b/src/Exception/InvalidRelationException.php index 215b704..6cfe121 100644 --- a/src/Exception/InvalidRelationException.php +++ b/src/Exception/InvalidRelationException.php @@ -8,10 +8,10 @@ class InvalidRelationException extends Exception { /** @var string The relation name */ - protected $relation; + protected string $relation; - /** @var Model The target model */ - protected $model; + /** @var ?Model The target model */ + protected ?Model $model = null; /** * Create a new InvalidRelationException @@ -19,9 +19,9 @@ class InvalidRelationException extends Exception * @param string $relation The relation name * @param ?Model $model The target model */ - public function __construct($relation, ?Model $model = null) + public function __construct(string $relation, ?Model $model = null) { - $this->relation = (string) $relation; + $this->relation = $relation; $this->model = $model; parent::__construct(sprintf( @@ -36,7 +36,7 @@ public function __construct($relation, ?Model $model = null) * * @return string */ - public function getRelation() + public function getRelation(): string { return $this->relation; } @@ -44,9 +44,9 @@ public function getRelation() /** * Get the target model * - * @return Model + * @return ?Model */ - public function getModel() + public function getModel(): ?Model { return $this->model; } diff --git a/src/Hydrator.php b/src/Hydrator.php index 63b3ff2..827bac4 100644 --- a/src/Hydrator.php +++ b/src/Hydrator.php @@ -2,8 +2,8 @@ namespace ipl\Orm; -use InvalidArgumentException; use ipl\Orm\Exception\InvalidRelationException; +use InvalidArgumentException; /** * Hydrates raw database rows into concrete model instances. @@ -11,13 +11,13 @@ class Hydrator { /** @var array Additional hydration rules for the model's relations */ - protected $hydrators = []; + protected array $hydrators = []; /** @var array> Map of columns to referencing paths */ - protected $columnToTargetMap = []; + protected array $columnToTargetMap = []; /** @var Query The query the hydration rules are for */ - protected $query; + protected Query $query; /** * Create a new Hydrator @@ -36,12 +36,12 @@ public function __construct(Query $query) * * @return $this * - * @throws \InvalidArgumentException If a hydrator for the given path already exists + * @throws InvalidArgumentException If a hydrator for the given path already exists */ - public function add($path) + public function add(string $path): static { if (isset($this->hydrators[$path])) { - throw new \InvalidArgumentException("Hydrator for path '$path' already exists"); + throw new InvalidArgumentException("Hydrator for path '$path' already exists"); } $resolver = $this->query->getResolver(); @@ -106,12 +106,12 @@ protected function updateColumnToTargetMap(string $path, array $columnToProperty * * @return Model */ - public function hydrate(array $data, Model $model) + public function hydrate(array $data, Model $model): Model { $defaultsToApply = []; $columnToTargetMap = $this->columnToTargetMap; foreach ($this->hydrators as $path => $vars) { - list($target, $relation, $columnToPropertyMap, $defaults) = $vars; + [$target, $relation, $columnToPropertyMap, $defaults] = $vars; $subject = $model; if ($relation !== null) { @@ -200,7 +200,7 @@ public function hydrate(array $data, Model $model) } // Apply defaults last, otherwise we may evaluate them during hydration - foreach ($defaultsToApply as list($subject, $defaults)) { + foreach ($defaultsToApply as [$subject, $defaults]) { foreach ($defaults as $name => $default) { if (! $subject->hasProperty($name)) { $subject->$name = $default; @@ -221,8 +221,12 @@ public function hydrate(array $data, Model $model) * * @return array */ - protected function extractAndMap(array &$data, array $columnToPropertyMap, string $path, array &$columnToTargetMap) - { + protected function extractAndMap( + array &$data, + array $columnToPropertyMap, + string $path, + array &$columnToTargetMap + ): array { $extracted = []; foreach (array_intersect_key($columnToPropertyMap, $data) as $column => $property) { $extracted[$property] = $data[$column]; diff --git a/src/Query.php b/src/Query.php index 76cd8d3..14896d4 100644 --- a/src/Query.php +++ b/src/Query.php @@ -47,44 +47,44 @@ class Query implements Filterable, LimitOffsetInterface, OrderByInterface, Pagin */ public const ON_SELECT_ASSEMBLED = 'selectAssembled'; - /** @var int Count cache */ - protected $count; + /** @var ?int Count cache */ + protected ?int $count = null; /** @var Connection Database connection */ protected $db; /** @var string Class to return results as */ - protected $resultSetClass = ResultSet::class; + protected string $resultSetClass = ResultSet::class; /** @var Model Model to query */ protected $model; /** @var array Columns to select from the model (or its relations). If empty, all columns are selected */ - protected $columns = []; + protected array $columns = []; /** @var array Additional columns to select from the model (or its relations) */ - protected $withColumns = []; + protected array $withColumns = []; /** @var array Columns not to select from the model (or its relations) */ - protected $withoutColumns = []; + protected array $withoutColumns = []; /** @var bool Whether to peek ahead for more results */ - protected $peekAhead = false; + protected bool $peekAhead = false; - /** @var Resolver Column and relation resolver */ - protected $resolver; + /** @var ?Resolver Column and relation resolver */ + protected ?Resolver $resolver = null; - /** @var Select Base SELECT query */ - protected $selectBase; + /** @var ?Select Base SELECT query */ + protected ?Select $selectBase = null; /** @var Relation[] Relations to eager load */ - protected $with = []; + protected array $with = []; /** @var Relation[] Relations to utilize (join) */ - protected $utilize = []; + protected array $utilize = []; /** @var bool Whether to disable the default sorts of the model */ - protected $disableDefaultSort = false; + protected bool $disableDefaultSort = false; /** * Get the database connection @@ -103,7 +103,7 @@ public function getDb() * * @return $this */ - public function setDb(Connection $db) + public function setDb(Connection $db): static { $this->db = $db; @@ -115,7 +115,7 @@ public function setDb(Connection $db) * * @return string */ - public function getResultSetClass() + public function getResultSetClass(): string { return $this->resultSetClass; } @@ -129,12 +129,8 @@ public function getResultSetClass() * * @throws InvalidArgumentException If class is not an instance of {@link ResultSet} */ - public function setResultSetClass($class) + public function setResultSetClass(string $class): static { - if (! is_string($class)) { - throw new InvalidArgumentException('Argument $class must be a string'); - } - if (! (new ReflectionClass($class))->newInstanceWithoutConstructor() instanceof ResultSet) { throw new InvalidArgumentException( $class . ' must be an instance of ' . ResultSet::class @@ -159,11 +155,11 @@ public function getModel() /** * Set the model to query * - * @param $model + * @param Model $model * * @return $this */ - public function setModel(Model $model) + public function setModel(Model $model): static { $this->model = $model; $this->getResolver()->setAlias($model, $model->getTableAlias()); @@ -176,7 +172,7 @@ public function setModel(Model $model) * * @return array */ - public function getColumns() + public function getColumns(): array { return $this->columns; } @@ -188,7 +184,7 @@ public function getColumns() * * @return $this */ - public function setFilter(Filter\Chain $filter) + public function setFilter(Filter\Chain $filter): static { $this->filter = $filter; @@ -204,9 +200,9 @@ public function setFilter(Filter\Chain $filter) * * @return $this */ - public function disableDefaultSort($disable = true) + public function disableDefaultSort(bool $disable = true): static { - $this->disableDefaultSort = (bool) $disable; + $this->disableDefaultSort = $disable; return $this; } @@ -216,7 +212,7 @@ public function disableDefaultSort($disable = true) * * @return bool */ - public function defaultSortDisabled() + public function defaultSortDisabled(): bool { return $this->disableDefaultSort; } @@ -236,7 +232,7 @@ public function defaultSortDisabled() * * @return $this */ - public function columns($columns) + public function columns(string|array $columns): static { $this->columns = (array) $columns; $this->withColumns = []; @@ -255,7 +251,7 @@ public function columns($columns) * * @return $this */ - public function withColumns($columns) + public function withColumns(string|array $columns): static { $tableName = $this->getModel()->getTableAlias(); @@ -283,7 +279,7 @@ public function withColumns($columns) * * @return $this */ - public function withoutColumns($columns): self + public function withoutColumns(string|array $columns): static { $tableName = $this->getModel()->getTableAlias(); @@ -304,7 +300,7 @@ public function withoutColumns($columns): self * * @return Resolver */ - public function getResolver() + public function getResolver(): Resolver { if ($this->resolver === null) { $this->resolver = new Resolver($this); @@ -318,7 +314,7 @@ public function getResolver() * * @return Select */ - public function getSelectBase() + public function getSelectBase(): Select { if ($this->selectBase === null) { $this->selectBase = new Select(); @@ -336,7 +332,7 @@ public function getSelectBase() * * @return Relation[] */ - public function getWith() + public function getWith(): array { return $this->with; } @@ -348,7 +344,7 @@ public function getWith() * * @return $this */ - public function with($relations) + public function with(string|array $relations): static { $tableName = $this->getModel()->getTableAlias(); foreach ((array) $relations as $relation) { @@ -366,7 +362,7 @@ public function with($relations) * * @return $this */ - public function without($relations) + public function without(string|array $relations): static { $tableName = $this->getModel()->getTableAlias(); foreach ((array) $relations as $relation) { @@ -382,7 +378,7 @@ public function without($relations) * * @return Relation[] */ - public function getUtilize() + public function getUtilize(): array { return $this->utilize; } @@ -394,7 +390,7 @@ public function getUtilize() * * @return $this */ - public function utilize($path) + public function utilize(string $path): static { $path = $this->getResolver()->qualifyPath($path, $this->getModel()->getTableAlias()); $this->utilize[$path] = $this->getResolver()->resolveRelation($path); @@ -409,7 +405,7 @@ public function utilize($path) * * @return $this */ - public function omit($path) + public function omit(string $path): static { $path = $this->getResolver()->qualifyPath($path, $this->getModel()->getTableAlias()); unset($this->utilize[$path]); @@ -422,7 +418,7 @@ public function omit($path) * * @return Select */ - public function assembleSelect() + public function assembleSelect(): Select { $columns = $this->getColumns(); $model = $this->getModel(); @@ -500,7 +496,7 @@ public function assembleSelect() continue; } - foreach ($relation->resolve() as list($source, $target, $relatedKeys)) { + foreach ($relation->resolve() as [$source, $target, $relatedKeys]) { /** @var Model $source */ /** @var Model $target */ @@ -560,7 +556,7 @@ public function assembleSelect() * * @return Hydrator */ - public function createHydrator() + public function createHydrator(): Hydrator { $hydrator = new Hydrator($this); @@ -582,7 +578,7 @@ public function createHydrator() * * @throws InvalidArgumentException If the relation with the given name does not exist */ - public function derive($relation, Model $source) + public function derive($relation, Model $source): static { // TODO: Think of a way to merge derive() and createSubQuery() return $this->createSubQuery( @@ -602,7 +598,7 @@ public function derive($relation, Model $source) * * @return static */ - public function createSubQuery(Model $target, $targetPath, ?Model $from = null, bool $link = true) + public function createSubQuery(Model $target, string $targetPath, ?Model $from = null, bool $link = true): static { $subQuery = (new static()) ->setDb($this->getDb()) @@ -654,7 +650,7 @@ public function createSubQuery(Model $target, $targetPath, ?Model $from = null, * * @return array */ - public function dump() + public function dump(): array { return $this->getDb()->getQueryBuilder()->assembleSelect($this->assembleSelect()); } @@ -664,7 +660,7 @@ public function dump() * * @return ResultSet */ - public function execute() + public function execute(): ResultSet { $class = $this->getResultSetClass(); /** @var ResultSet $class Just for type hinting. $class is of course a string */ @@ -677,7 +673,7 @@ public function execute() * * @return Model|null Null in case there's no result */ - public function first() + public function first(): ?Model { return $this->execute()->current(); } @@ -692,9 +688,9 @@ public function first() * * @return $this */ - public function peekAhead($peekAhead = true) + public function peekAhead(bool $peekAhead = true): static { - $this->peekAhead = (bool) $peekAhead; + $this->peekAhead = $peekAhead; return $this; } @@ -702,9 +698,9 @@ public function peekAhead($peekAhead = true) /** * Yield the query's results * - * @return \Generator + * @return Generator */ - public function yieldResults() + public function yieldResults(): Generator { $select = $this->assembleSelect(); $stmt = $this->getDb()->select($select); @@ -739,11 +735,11 @@ public function getIterator(): Traversable * * @return SplObjectStorage */ - protected function groupColumnsByTarget(Generator $columns) + protected function groupColumnsByTarget(Generator $columns): SplObjectStorage { $columnStorage = new SplObjectStorage(); - foreach ($columns as list($target, $alias, $column)) { + foreach ($columns as [$target, $alias, $column]) { if (! $columnStorage->offsetExists($target)) { $resolved = new ArrayObject(); $columnStorage->offsetSet($target, $resolved); @@ -768,7 +764,7 @@ protected function groupColumnsByTarget(Generator $columns) * * @return $this */ - protected function order(Select $select) + protected function order(Select $select): static { $orderBy = $this->getOrderBy(); $defaultSort = []; @@ -791,7 +787,7 @@ protected function order(Select $select) $selectedColumns = $select->getColumns(); foreach ($orderBy as $part) { - list($column, $direction) = $part; + [$column, $direction] = $part; if (! $column instanceof ExpressionInterface && isset($selectedColumns[$column])) { // If it's a custom alias, we have no other way of knowing it, @@ -804,7 +800,7 @@ protected function order(Select $select) } } - foreach ($resolver->requireAndResolveColumns($columns) as list($model, $alias, $column)) { + foreach ($resolver->requireAndResolveColumns($columns) as [$model, $alias, $column]) { $direction = array_shift($directions); $selectColumns = $resolver->getSelectColumns($model); $tableName = $resolver->getAlias($model); diff --git a/src/Relation.php b/src/Relation.php index 1959363..2aca85c 100644 --- a/src/Relation.php +++ b/src/Relation.php @@ -2,7 +2,8 @@ namespace ipl\Orm; -use function ipl\Stdlib\get_php_type; +use Generator; +use UnexpectedValueException; /** * Relations represent the connection between models, i.e. the association between rows in one or more tables @@ -16,11 +17,11 @@ class Relation /** @var Model Source model */ protected $source; - /** @var string|array Column name(s) of the foreign key found in the target table */ - protected $foreignKey; + /** @var string|array|null Column name(s) of the foreign key found in the target table */ + protected string|array|null $foreignKey = null; - /** @var string|array Column name(s) of the candidate key in the source table which references the foreign key */ - protected $candidateKey; + /** @var string|array|null Column name(s) of the candidate key in the source table which references the foreign key */ + protected string|array|null $candidateKey = null; /** @var string Target model class */ protected $targetClass; @@ -29,13 +30,13 @@ class Relation protected $target; /** @var string Type of the JOIN used in the query */ - protected $joinType = 'INNER'; + protected string $joinType = 'INNER'; /** @var bool Whether this is the inverse of a relationship */ - protected $inverse; + protected bool $inverse = false; /** @var bool Whether this is a to-one relationship */ - protected $isOne = true; + protected bool $isOne = true; /** * Get the default column name(s) in the source table used to match the foreign key @@ -46,7 +47,7 @@ class Relation * * @return array */ - public static function getDefaultCandidateKey(Model $source) + public static function getDefaultCandidateKey(Model $source): array { return (array) $source->getKeyName(); } @@ -60,7 +61,7 @@ public static function getDefaultCandidateKey(Model $source) * * @return array */ - public static function getDefaultForeignKey(Model $source) + public static function getDefaultForeignKey(Model $source): array { $tableName = $source->getTableName(); @@ -77,7 +78,7 @@ function ($key) use ($tableName) { * * @return bool */ - public function isOne() + public function isOne(): bool { return $this->isOne; } @@ -99,7 +100,7 @@ public function getName() * * @return $this */ - public function setName($name) + public function setName(string $name): static { $this->name = $name; @@ -123,7 +124,7 @@ public function getSource() * * @return $this */ - public function setSource(Model $source) + public function setSource(Model $source): static { $this->source = $source; @@ -133,9 +134,9 @@ public function setSource(Model $source) /** * Get the column name(s) of the foreign key found in the target table * - * @return string|array Array if the foreign key is compound, string otherwise + * @return string|array|null Array if the foreign key is compound, string otherwise */ - public function getForeignKey() + public function getForeignKey(): string|array|null { return $this->foreignKey; } @@ -143,11 +144,11 @@ public function getForeignKey() /** * Set the column name(s) of the foreign key found in the target table * - * @param string|array $foreignKey Array if the foreign key is compound, string otherwise + * @param string|array|null $foreignKey Array if the foreign key is compound, string otherwise * * @return $this */ - public function setForeignKey($foreignKey) + public function setForeignKey(string|array|null $foreignKey): static { $this->foreignKey = $foreignKey; @@ -157,9 +158,9 @@ public function setForeignKey($foreignKey) /** * Get the column name(s) of the candidate key in the source table which references the foreign key * - * @return string|array Array if the candidate key is compound, string otherwise + * @return string|array|null Array if the candidate key is compound, string otherwise */ - public function getCandidateKey() + public function getCandidateKey(): string|array|null { return $this->candidateKey; } @@ -167,11 +168,11 @@ public function getCandidateKey() /** * Set the column name(s) of the candidate key in the source table which references the foreign key * - * @param string|array $candidateKey Array if the candidate key is compound, string otherwise + * @param string|array|null $candidateKey Array if the candidate key is compound, string otherwise * * @return $this */ - public function setCandidateKey($candidateKey) + public function setCandidateKey(string|array|null $candidateKey): static { $this->candidateKey = $candidateKey; @@ -194,21 +195,9 @@ public function getTargetClass() * @param string $targetClass * * @return $this - * - * @throws \InvalidArgumentException If the target model class is not of type string */ - public function setTargetClass($targetClass) + public function setTargetClass(string $targetClass): static { - if (! is_string($targetClass)) { - // Require a class name here instead of a concrete model in oder to prevent circular references when - // constructing relations - throw new \InvalidArgumentException(sprintf( - '%s() expects parameter 1 to be string, %s given', - __METHOD__, - get_php_type($targetClass) - )); - } - $this->targetClass = $targetClass; return $this; @@ -239,7 +228,7 @@ public function getTarget() * * @return $this */ - public function setTarget(Model $target) + public function setTarget(Model $target): static { $this->target = $target; @@ -251,7 +240,7 @@ public function setTarget(Model $target) * * @return string */ - public function getJoinType() + public function getJoinType(): string { return $this->joinType; } @@ -263,7 +252,7 @@ public function getJoinType() * * @return Relation */ - public function setJoinType($joinType) + public function setJoinType(string $joinType): static { $this->joinType = $joinType; @@ -277,10 +266,10 @@ public function setJoinType($joinType) * * @return array Candidate key-foreign key column name pairs * - * @throws \UnexpectedValueException If there's no candidate key to be found + * @throws UnexpectedValueException If there's no candidate key to be found * or the foreign key count does not match the candidate key count */ - public function determineKeys(Model $source) + public function determineKeys(Model $source): array { $candidateKey = (array) $this->getCandidateKey(); @@ -291,7 +280,7 @@ public function determineKeys(Model $source) } if (empty($candidateKey)) { - throw new \UnexpectedValueException(sprintf( + throw new UnexpectedValueException(sprintf( "Can't join relation '%s' in model '%s'. No candidate key found.", $this->getName(), get_class($source) @@ -307,7 +296,7 @@ public function determineKeys(Model $source) } if (count($foreignKey) !== count($candidateKey)) { - throw new \UnexpectedValueException(sprintf( + throw new UnexpectedValueException(sprintf( "Can't join relation '%s' in model '%s'." . " Foreign key count (%s) does not match candidate key count (%s).", $this->getName(), @@ -325,9 +314,9 @@ public function determineKeys(Model $source) * * Yields a three-element array consisting of the source model, target model and the join keys. * - * @return \Generator + * @return Generator */ - public function resolve() + public function resolve(): Generator { $source = $this->getSource(); diff --git a/src/Relation/BelongsTo.php b/src/Relation/BelongsTo.php index 1edcff3..1982f10 100644 --- a/src/Relation/BelongsTo.php +++ b/src/Relation/BelongsTo.php @@ -9,5 +9,5 @@ */ class BelongsTo extends Relation { - protected $inverse = true; + protected bool $inverse = true; } diff --git a/src/Relation/BelongsToMany.php b/src/Relation/BelongsToMany.php index fa69245..edf5bf1 100644 --- a/src/Relation/BelongsToMany.php +++ b/src/Relation/BelongsToMany.php @@ -2,13 +2,12 @@ namespace ipl\Orm\Relation; +use Generator; use ipl\Orm\Model; use ipl\Orm\Relation; use ipl\Orm\Relations; use LogicException; -use function ipl\Stdlib\get_php_type; - /** * Many-to-many relationship */ @@ -17,22 +16,22 @@ class BelongsToMany extends Relation /** @var string Relation class */ protected const RELATION_CLASS = HasMany::class; - protected $isOne = false; + protected bool $isOne = false; - /** @var string Name of the join table or junction model class */ - protected $throughClass; + /** @var ?string Name of the join table or junction model class */ + protected ?string $throughClass = null; /** @var ?string Alias for the join table or junction model class */ protected ?string $throughAlias = null; - /** @var Model The junction model */ - protected $through; + /** @var ?Model The junction model */ + protected ?Model $through = null; - /** @var string|array Column name(s) of the target model's foreign key found in the join table */ - protected $targetForeignKey; + /** @var string|array|null Column name(s) of the target model's foreign key found in the join table */ + protected string|array|null $targetForeignKey = null; - /** @var string|array Candidate key column name(s) in the target table which references the target foreign key */ - protected $targetCandidateKey; + /** @var string|array|null Candidate key column name(s) in the target table which references the target foreign key */ + protected string|array|null $targetCandidateKey = null; /** * Get the name of the join table or junction model class @@ -51,7 +50,7 @@ public function getThroughClass(): ?string * * @return $this */ - public function through(string $through): self + public function through(string $through): static { $this->throughClass = $through; @@ -75,7 +74,7 @@ public function getThroughAlias(): string * * @return $this */ - public function setThroughAlias(string $throughAlias): self + public function setThroughAlias(string $throughAlias): static { $this->throughAlias = $throughAlias; @@ -85,7 +84,9 @@ public function setThroughAlias(string $throughAlias): self /** * Get the junction model * - * @return Model|Junction + * @return Model + * + * @throws LogicException If no through class is configured */ public function getThrough(): Model { @@ -116,7 +117,7 @@ public function getThrough(): Model * * @return $this */ - public function setThrough(Model $through): self + public function setThrough(Model $through): static { $this->through = $through; @@ -126,9 +127,9 @@ public function setThrough(Model $through): self /** * Get the column name(s) of the target model's foreign key found in the join table * - * @return string|array Array if the foreign key is compound, string otherwise + * @return string|array|null Array if the foreign key is compound, string otherwise */ - public function getTargetForeignKey() + public function getTargetForeignKey(): string|array|null { return $this->targetForeignKey; } @@ -140,7 +141,7 @@ public function getTargetForeignKey() * * @return $this */ - public function setTargetForeignKey($targetForeignKey): self + public function setTargetForeignKey(string|array $targetForeignKey): static { $this->targetForeignKey = $targetForeignKey; @@ -150,9 +151,9 @@ public function setTargetForeignKey($targetForeignKey): self /** * Get the candidate key column name(s) in the target table which references the target foreign key * - * @return string|array Array if the foreign key is compound, string otherwise + * @return string|array|null Array if the foreign key is compound, string otherwise */ - public function getTargetCandidateKey() + public function getTargetCandidateKey(): string|array|null { return $this->targetCandidateKey; } @@ -164,14 +165,14 @@ public function getTargetCandidateKey() * * @return $this */ - public function setTargetCandidateKey($targetCandidateKey): self + public function setTargetCandidateKey(string|array $targetCandidateKey): static { $this->targetCandidateKey = $targetCandidateKey; return $this; } - public function resolve() + public function resolve(): Generator { $source = $this->getSource(); @@ -229,7 +230,7 @@ public function resolve() } } - protected function extractKey(array $possibleKey) + protected function extractKey(array $possibleKey): string|array|null { $filtered = array_filter($possibleKey); diff --git a/src/Relation/BelongsToOne.php b/src/Relation/BelongsToOne.php index afdfbec..5272bf3 100644 --- a/src/Relation/BelongsToOne.php +++ b/src/Relation/BelongsToOne.php @@ -9,5 +9,5 @@ class BelongsToOne extends BelongsToMany { protected const RELATION_CLASS = HasOne::class; - protected $isOne = true; + protected bool $isOne = true; } diff --git a/src/Relation/HasMany.php b/src/Relation/HasMany.php index 3e71e25..13d1abc 100644 --- a/src/Relation/HasMany.php +++ b/src/Relation/HasMany.php @@ -9,5 +9,5 @@ */ class HasMany extends Relation { - protected $isOne = false; + protected bool $isOne = false; } diff --git a/src/Relations.php b/src/Relations.php index e19306e..e924096 100644 --- a/src/Relations.php +++ b/src/Relations.php @@ -3,6 +3,7 @@ namespace ipl\Orm; use ArrayIterator; +use InvalidArgumentException; use ipl\Orm\Exception\InvalidRelationException; use ipl\Orm\Relation\BelongsTo; use ipl\Orm\Relation\BelongsToMany; @@ -20,7 +21,7 @@ class Relations implements IteratorAggregate { /** @var Relation[] */ - protected $relations = []; + protected array $relations = []; /** * Get whether a relation with the given name exists @@ -29,7 +30,7 @@ class Relations implements IteratorAggregate * * @return bool */ - public function has($name) + public function has(string $name): bool { return isset($this->relations[$name]); } @@ -41,9 +42,9 @@ public function has($name) * * @return Relation * - * @throws \InvalidArgumentException If the relation with the given name does not exist + * @throws InvalidArgumentException If the relation with the given name does not exist */ - public function get($name) + public function get(string $name): Relation { $this->assertRelationExists($name); @@ -57,9 +58,9 @@ public function get($name) * * @return $this * - * @throws \InvalidArgumentException If a relation with the given name already exists + * @throws InvalidArgumentException If a relation with the given name already exists */ - public function add(Relation $relation) + public function add(Relation $relation): static { $name = $relation->getName(); @@ -79,14 +80,14 @@ public function add(Relation $relation) * * @return BelongsTo|BelongsToOne|BelongsToMany|HasMany|HasOne|Relation * - * @throws \InvalidArgumentException If the target model class is not of type string + * @throws InvalidArgumentException If the target model class is not of type string */ - public function create($class, $name, $targetClass) + public function create(string $class, string $name, string $targetClass): Relation { $relation = new $class(); if (! $relation instanceof Relation) { - throw new \InvalidArgumentException(sprintf( + throw new InvalidArgumentException(sprintf( '%s() expects parameter 1 to be a subclass of %s, %s given', __METHOD__, Relation::class, @@ -97,7 +98,7 @@ public function create($class, $name, $targetClass) // Test target model $target = new $targetClass(); if (! $target instanceof Model) { - throw new \InvalidArgumentException(sprintf( + throw new InvalidArgumentException(sprintf( '%s() expects parameter 3 to be a subclass of %s, %s given', __METHOD__, Model::class, @@ -122,7 +123,7 @@ public function create($class, $name, $targetClass) * * @return HasOne */ - public function hasOne($name, $targetClass) + public function hasOne(string $name, string $targetClass): HasOne { /** @var HasOne $relation */ $relation = $this->create(HasOne::class, $name, $targetClass); @@ -140,7 +141,7 @@ public function hasOne($name, $targetClass) * * @return HasMany */ - public function hasMany($name, $targetClass) + public function hasMany(string $name, string $targetClass): HasMany { /** @var HasMany $relation */ $relation = $this->create(HasMany::class, $name, $targetClass); @@ -158,7 +159,7 @@ public function hasMany($name, $targetClass) * * @return BelongsTo */ - public function belongsTo($name, $targetClass) + public function belongsTo(string $name, string $targetClass): BelongsTo { /** @var BelongsTo $relation */ $relation = $this->create(BelongsTo::class, $name, $targetClass); @@ -194,7 +195,7 @@ public function belongsToOne(string $name, string $targetClass): BelongsToOne * * @return BelongsToMany */ - public function belongsToMany($name, $targetClass) + public function belongsToMany(string $name, string $targetClass): BelongsToMany { /** @var BelongsToMany $relation */ $relation = $this->create(BelongsToMany::class, $name, $targetClass); @@ -213,11 +214,15 @@ public function getIterator(): Traversable * Throw exception if a relation with the given name already exists * * @param string $name + * + * @return void + * + * @throws InvalidArgumentException */ - protected function assertRelationDoesNotYetExist($name) + protected function assertRelationDoesNotYetExist(string $name): void { if ($this->has($name)) { - throw new \InvalidArgumentException("Relation '$name' already exists"); + throw new InvalidArgumentException("Relation '$name' already exists"); } } @@ -225,8 +230,10 @@ protected function assertRelationDoesNotYetExist($name) * Throw exception if a relation with the given name does not exist * * @param string $name + * + * @throws InvalidArgumentException */ - protected function assertRelationExists($name) + protected function assertRelationExists(string $name): void { if (! $this->has($name)) { throw new InvalidRelationException($name); diff --git a/src/ResolvedExpression.php b/src/ResolvedExpression.php index 86883da..c1a2347 100644 --- a/src/ResolvedExpression.php +++ b/src/ResolvedExpression.php @@ -10,7 +10,7 @@ class ResolvedExpression extends Expression { /** @var Generator */ - protected $resolvedColumns; + protected Generator $resolvedColumns; /** * Create a resolved database expression @@ -28,7 +28,7 @@ public function __construct(ExpressionInterface $expr, Generator $resolvedColumn /** * @throws RuntimeException In case the columns are not qualified yet */ - public function getColumns() + public function getColumns(): array { if ($this->resolvedColumns->valid()) { throw new RuntimeException('Columns are not yet qualified'); @@ -42,7 +42,7 @@ public function getColumns() * * @return Generator */ - public function getResolvedColumns() + public function getResolvedColumns(): Generator { return $this->resolvedColumns; } diff --git a/src/Resolver.php b/src/Resolver.php index a055bfe..e054e48 100644 --- a/src/Resolver.php +++ b/src/Resolver.php @@ -10,48 +10,45 @@ use ipl\Orm\Exception\InvalidColumnException; use ipl\Orm\Exception\InvalidRelationException; use ipl\Orm\Relation\BelongsToMany; -use ipl\Orm\Relation\BelongsToOne; use ipl\Sql\ExpressionInterface; use LogicException; use OutOfBoundsException; use SplObjectStorage; -use function ipl\Stdlib\get_php_type; - /** * Column and relation resolver. Acts as glue between queries and models */ class Resolver { /** @var Query The query to resolve */ - protected $query; + protected Query $query; /** @var SplObjectStorage Model relations */ - protected $relations; + protected SplObjectStorage $relations; /** @var SplObjectStorage Model behaviors */ - protected $behaviors; + protected SplObjectStorage $behaviors; /** @var SplObjectStorage Model defaults */ - protected $defaults; + protected SplObjectStorage $defaults; /** @var SplObjectStorage Model aliases */ - protected $aliases; + protected SplObjectStorage $aliases; - /** @var string The alias prefix to use */ - protected $aliasPrefix; + /** @var ?string The alias prefix to use */ + protected ?string $aliasPrefix = null; /** @var SplObjectStorage Selectable columns from resolved models */ - protected $selectableColumns; + protected SplObjectStorage $selectableColumns; /** @var SplObjectStorage Select columns from resolved models */ - protected $selectColumns; + protected SplObjectStorage $selectColumns; /** @var SplObjectStorage Meta data from models and their direct relations */ - protected $metaData; + protected SplObjectStorage $metaData; /** @var SplObjectStorage Resolved relations */ - protected $resolvedRelations; + protected SplObjectStorage $resolvedRelations; /** * Create a new resolver @@ -79,7 +76,7 @@ public function __construct(Query $query) * * @return Relations */ - public function getRelations(Model $model) + public function getRelations(Model $model): Relations { if (! $this->relations->offsetExists($model)) { $relations = new Relations(); @@ -97,7 +94,7 @@ public function getRelations(Model $model) * * @return Behaviors */ - public function getBehaviors(Model $model) + public function getBehaviors(Model $model): Behaviors { if (! $this->behaviors->offsetExists($model)) { $behaviors = new Behaviors(); @@ -141,7 +138,7 @@ public function getDefaults(Model $model): Defaults * * @throws OutOfBoundsException If no alias exists for the given model */ - public function getAlias(Model $model) + public function getAlias(Model $model): string { if (! $this->aliases->offsetExists($model)) { throw new OutOfBoundsException(sprintf( @@ -161,7 +158,7 @@ public function getAlias(Model $model) * * @return $this */ - public function setAlias(Model $model, $alias) + public function setAlias(Model $model, string $alias): static { $this->aliases[$model] = $alias; @@ -171,9 +168,9 @@ public function setAlias(Model $model, $alias) /** * Get the alias prefix * - * @return string + * @return ?string */ - public function getAliasPrefix() + public function getAliasPrefix(): ?string { return $this->aliasPrefix; } @@ -185,7 +182,7 @@ public function getAliasPrefix() * * @return $this */ - public function setAliasPrefix($alias) + public function setAliasPrefix(string $alias): static { $this->aliasPrefix = $alias; @@ -200,7 +197,7 @@ public function setAliasPrefix($alias) * * @return bool */ - public function hasSelectableColumn(Model $subject, $column) + public function hasSelectableColumn(Model $subject, string $column): bool { if (! $this->selectableColumns->offsetExists($subject)) { $this->collectColumns($subject); @@ -221,7 +218,7 @@ public function hasSelectableColumn(Model $subject, $column) * * @return array */ - public function getSelectableColumns(Model $subject) + public function getSelectableColumns(Model $subject): array { if (! $this->selectableColumns->offsetExists($subject)) { $this->collectColumns($subject); @@ -237,7 +234,7 @@ public function getSelectableColumns(Model $subject) * * @return array Select columns suitable for {@link \ipl\Sql\Select::columns()} */ - public function getSelectColumns(Model $subject) + public function getSelectColumns(Model $subject): array { if (! $this->selectColumns->offsetExists($subject)) { $this->collectColumns($subject); @@ -253,7 +250,7 @@ public function getSelectColumns(Model $subject) * * @return array Column paths as keys (relative to $subject) and their meta data as values */ - public function getColumnDefinitions(Model $subject) + public function getColumnDefinitions(Model $subject): array { if (! $this->metaData->offsetExists($subject)) { $this->metaData->offsetSet($subject, $this->collectMetaData($subject)); @@ -307,7 +304,7 @@ public function getColumnDefinition(string $columnPath): ColumnDefinition * * @return string */ - public function qualifyColumnAlias($alias, $tableName) + public function qualifyColumnAlias(string $alias, string $tableName): string { return $tableName . '_' . $alias; } @@ -320,7 +317,7 @@ public function qualifyColumnAlias($alias, $tableName) * * @return string */ - public function qualifyColumn($column, $tableName) + public function qualifyColumn(string $column, string $tableName): string { return $tableName . '.' . $column; } @@ -333,25 +330,18 @@ public function qualifyColumn($column, $tableName) * * @return array * - * @throws InvalidArgumentException If $columns is not iterable * @throws InvalidArgumentException If $model is not passed and $columns is not a generator */ - public function qualifyColumns($columns, ?Model $model = null) + public function qualifyColumns(iterable $columns, ?Model $model = null): array { $target = $model ?: $this->query->getModel(); $targetAlias = $this->getAlias($target); - if (! is_iterable($columns)) { - throw new InvalidArgumentException( - sprintf('$columns is not iterable, got %s instead', get_php_type($columns)) - ); - } - $qualified = []; foreach ($columns as $alias => $column) { if (is_int($alias) && is_array($column)) { // $columns is $this->requireAndResolveColumns() - list($target, $alias, $columnName) = $column; + [$target, $alias, $columnName] = $column; $targetAlias = $this->getAlias($target); // Thanks to PHP 5.6 where `list` is evaluated from right to left. It will extract @@ -387,25 +377,18 @@ public function qualifyColumns($columns, ?Model $model = null) * * @return array * - * @throws InvalidArgumentException If $columns is not iterable * @throws InvalidArgumentException If $model is not passed and $columns is not a generator */ - public function qualifyColumnsAndAliases($columns, ?Model $model = null, $autoAlias = true) + public function qualifyColumnsAndAliases(iterable $columns, ?Model $model = null, bool $autoAlias = true): array { $target = $model ?: $this->query->getModel(); $targetAlias = $this->getAlias($target); - if (! is_iterable($columns)) { - throw new InvalidArgumentException( - sprintf('$columns is not iterable, got %s instead', get_php_type($columns)) - ); - } - $qualified = []; foreach ($columns as $alias => $column) { if (is_int($alias) && is_array($column)) { // $columns is $this->requireAndResolveColumns() - list($target, $alias, $columnName) = $column; + [$target, $alias, $columnName] = $column; $targetAlias = $this->getAlias($target); // Thanks to PHP 5.6 where `list` is evaluated from right to left. It will extract @@ -455,7 +438,7 @@ public function qualifyColumnsAndAliases($columns, ?Model $model = null, $autoAl * * @return string */ - public function qualifyPath($path, $tableName) + public function qualifyPath(string $path, string $tableName): string { $segments = explode('.', $path, 2); @@ -475,7 +458,7 @@ public function qualifyPath($path, $tableName) * * @return bool */ - public function isDistinctRelation($path) + public function isDistinctRelation(string $path): bool { foreach ($this->resolveRelations($path) as $relation) { if (! $relation->isOne()) { @@ -496,7 +479,7 @@ public function isDistinctRelation($path) * * @return Relation */ - public function resolveRelation($path, ?Model $subject = null) + public function resolveRelation(string $path, ?Model $subject = null): Relation { $subject = $subject ?: $this->query->getModel(); if (! $this->resolvedRelations->offsetExists($subject) || ! isset($this->resolvedRelations[$subject][$path])) { @@ -520,7 +503,7 @@ public function resolveRelation($path, ?Model $subject = null) * @throws InvalidArgumentException In case $path is not fully qualified * @throws InvalidRelationException In case a relation is unknown */ - public function resolveRelations($path, ?Model $subject = null) + public function resolveRelations(string $path, ?Model $subject = null): Generator { $relations = explode('.', $path); $subject = $subject ?: $this->query->getModel(); @@ -600,7 +583,7 @@ public function resolveRelations($path, ?Model $subject = null) * * @throws InvalidColumnException If a column does not exist */ - public function requireAndResolveColumns(array $columns, ?Model $model = null) + public function requireAndResolveColumns(array $columns, ?Model $model = null): Generator { $model = $model ?: $this->query->getModel(); $tableName = $model->getTableAlias(); @@ -739,8 +722,10 @@ public function requireAndResolveColumns(array $columns, ?Model $model = null) * Collect all selectable columns from the given model * * @param Model $subject + * + * @return void */ - protected function collectColumns(Model $subject) + protected function collectColumns(Model $subject): void { // Don't fail if Model::getColumns() also contains the primary key columns $columns = array_merge((array) $subject->getKeyName(), (array) $subject->getColumns()); @@ -768,8 +753,10 @@ protected function collectColumns(Model $subject) * @param Model $subject * * @return array + * + * @throws LogicException If a column definition's name differs from its array index */ - protected function collectMetaData(Model $subject) + protected function collectMetaData(Model $subject): array { $definitions = []; foreach ($subject->getColumnDefinitions() as $name => $data) { diff --git a/src/UnionQuery.php b/src/UnionQuery.php index a6405ce..b1860c1 100644 --- a/src/UnionQuery.php +++ b/src/UnionQuery.php @@ -6,22 +6,22 @@ class UnionQuery extends Query { - /** @var Query[] Underlying queries */ - private $unions; + /** @var ?Query[] Underlying queries */ + private ?array $unions = null; /** * Get the underlying queries * * @return Query[] */ - public function getUnions() + public function getUnions(): array { if ($this->unions === null) { $this->unions = []; /** @var UnionModel $model */ $model = $this->getModel(); - foreach ($model->getUnions() as list($target, $relations, $columns)) { + foreach ($model->getUnions() as [$target, $relations, $columns]) { /** @var class-string $target */ $query = $target::on($this->getDb()) ->columns($columns) @@ -35,7 +35,7 @@ public function getUnions() return $this->unions; } - public function getSelectBase() + public function getSelectBase(): Select { if ($this->selectBase === null) { $this->selectBase = new Select(); diff --git a/tests/BelongsToManyTest.php b/tests/BelongsToManyTest.php index 10ebdeb..ce552f4 100644 --- a/tests/BelongsToManyTest.php +++ b/tests/BelongsToManyTest.php @@ -39,7 +39,7 @@ public function testResolveDefaultKeys() $relations ->get('user') ->setSource($model) - ->resolve() as list($from, $to, $keys) + ->resolve() as [$from, $to, $keys] ) { reset($keys); $actual[] = [ @@ -76,7 +76,7 @@ public function testResolveRespectsCustomKeysInTroughModels() $relations ->get('user_custom_keys') ->setSource($model) - ->resolve() as list($from, $to, $keys) + ->resolve() as [$from, $to, $keys] ) { reset($keys); $actual[] = [ diff --git a/tests/RelationTest.php b/tests/RelationTest.php index 6a225c1..1148645 100644 --- a/tests/RelationTest.php +++ b/tests/RelationTest.php @@ -2,7 +2,6 @@ namespace ipl\Tests\Orm; -use InvalidArgumentException; use ipl\Orm\Relation; class RelationTest extends \PHPUnit\Framework\TestCase @@ -81,13 +80,6 @@ public function testGetTargetClassReturnsCorrectTargetClassIfSet() $this->assertSame($targetClass, $relation->getTargetClass()); } - public function testSetTargetClassThrowsInvalidArgumentExceptionIfNotString() - { - $this->expectException(InvalidArgumentException::class); - - (new Relation())->setTargetClass(new TestModel()); - } - public function testGetDefaultCandidateKeyReturnsEmptyArrayIfSourceModelsPrimaryKeyIsUnset() { $candidateKey = Relation::getDefaultCandidateKey(new TestModel()); diff --git a/tests/ResolverTest.php b/tests/ResolverTest.php index c982051..a7fbad4 100644 --- a/tests/ResolverTest.php +++ b/tests/ResolverTest.php @@ -3,7 +3,6 @@ namespace ipl\Tests\Orm; use ipl\Orm\Query; -use ipl\Orm\Resolver; use ipl\Sql\Expression; use ipl\Sql\QueryBuilder; use PHPUnit\Framework\TestCase; diff --git a/tests/SqlTest.php b/tests/SqlTest.php index ef3f2a8..372429c 100644 --- a/tests/SqlTest.php +++ b/tests/SqlTest.php @@ -382,7 +382,7 @@ public function assertSql($sql, $query, $values = null) // Reduce whitespaces to just one space $sql = preg_replace('/\s+/', ' ', trim($sql)); - list($stmt, $bind) = $this->queryBuilder->assemble($query); + [$stmt, $bind] = $this->queryBuilder->assemble($query); $this->assertSame($sql, $stmt);