Skip to content

Commit

Permalink
Merge branch '1.x' into feature/phpunit-10
Browse files Browse the repository at this point in the history
  • Loading branch information
srtfisher committed Nov 27, 2023
2 parents 281d3a6 + 3739abb commit aa56273
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 35 deletions.
21 changes: 8 additions & 13 deletions src/mantle/database/query/class-builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Builder class file.
*
* phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
* phpcs:disable Squiz.Commenting.FunctionComment
* phpcs:disable Squiz.Commenting.VariableComment.Missing, Squiz.Commenting.FunctionComment
* phpcs:disable PEAR.Functions.FunctionCallSignature.CloseBracketLine, PEAR.Functions.FunctionCallSignature.MultipleArguments, PEAR.Functions.FunctionCallSignature.ContentAfterOpenBracket
*
* @package Mantle
Expand All @@ -26,8 +26,6 @@
use Mantle\Support\Str;
use Mantle\Support\Traits\Conditionable;

use function Mantle\Support\Helpers\collect;

/**
* Builder Query Builder
*
Expand All @@ -41,9 +39,9 @@ abstract class Builder {
/**
* Model to build on.
*
* @var string[]|string
* @var class-string<TModel>|array<class-string<TModel>>
*/
protected $model;
protected array|string $model;

/**
* Result limit per-page.
Expand Down Expand Up @@ -132,9 +130,9 @@ abstract class Builder {
/**
* Storage of the found rows for a query.
*
* @var int
* @var int|null
*/
protected int $found_rows = 0;
protected ?int $found_rows = 0;

/**
* Relationships to eager load.
Expand Down Expand Up @@ -914,16 +912,13 @@ public function __call( $method, $args ) {
/**
* Collect all the model object names in an associative Collection.
*
* @return Collection Collection with object names as keys and model
* class names as values.
* @return Collection<string, class-string<\Mantle\Database\Model\Model>> Collection of model class names keyed by object name.
*/
public function get_model_object_names(): Collection {
return collect( (array) $this->model )
return ( new Collection( (array) $this->model ) ) // @phpstan-ignore-line should return
->combine( $this->model )
->map(
function ( $model ) {
return $model::get_object_name();
}
fn ( $model ) => $model::get_object_name(),
)
->flip();
}
Expand Down
190 changes: 190 additions & 0 deletions src/mantle/database/query/class-collection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?php
/**
* Collection class file
*
* phpcs:disable Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace
*
* @package Mantle
*/

namespace Mantle\Database\Query;

use Mantle\Database\Model\Model;
use Mantle\Support\Collection as Base_Collection;

/**
* Database Query Collection
*
* @template TKey of array-key
* @template TModel of \Mantle\Database\Model\Model
*
* @extends \Mantle\Support\Collection<TKey, TModel>
*/
class Collection extends Base_Collection {
/**
* Total number of rows found for the query.
*
* @var int|null
*/
public ?int $found_rows = null;

/**
* Set the total number of rows found for the query.
*
* @param int|null $found_rows Total number of rows found for the query.
* @return static
*/
public function with_found_rows( ?int $found_rows ): static {
$this->found_rows = $found_rows;

return $this;
}

/**
* Get the total number of rows found for the query.
*
* @return int|null
*/
public function found_rows(): ?int {
return $this->found_rows;
}

/**
* Retrieve the models in the collection.
*
* @return \Mantle\Support\Collection<int, class-string<TModel>>
*/
public function models(): Base_Collection {
return $this->map( fn ( $model ) => $model::class )->values()->unique();
}

/**
* Run a map over each of the items.
*
* @template TMapValue
*
* @param callable(TModel, TKey): TMapValue $callback The callback to run.
* @return \Mantle\Support\Collection<TKey, TMapValue>|static<TKey, TMapValue>
*/
public function map( callable $callback ) {
$result = parent::map( $callback );

if ( $result instanceof self ) {
$result->with_found_rows( $this->found_rows );
}

return $result->contains( fn ( $item ) => ! $item instanceof Model )
? $result->to_base()
: $result;
}

/**
* Run an associative map over each of the items.
*
* The callback should return an associative array with a single key/value pair.
*
* @template TMapWithKeysKey of array-key
* @template TMapWithKeysValue
*
* @param callable(TModel, TKey): array<TMapWithKeysKey, TMapWithKeysValue> $callback The callback to run.
* @return \Mantle\Support\Collection<TMapWithKeysKey, TMapWithKeysValue>|static<TMapWithKeysKey, TMapWithKeysValue>
*/
public function map_with_keys( callable $callback ) {
$result = parent::map_with_keys( $callback );

if ( $result instanceof self ) {
$result->with_found_rows( $this->found_rows );
}

return $result->contains( fn ( $item ) => ! $item instanceof Model )
? $result->to_base()
: $result;
}

/**
* The following methods are intercepted to always return base collections.
*/

/**
* Count the number of items in the collection by a field or using a callback.
*
* @param (callable(TModel, TKey): array-key)|string|null $count_by
* @return \Mantle\Support\Collection<array-key, int>
*/
public function count_by( $count_by = null ) {
return $this->to_base()->count_by( $count_by );
}

/**
* Collapse the collection of items into a single array.
*
* @return \Mantle\Support\Collection<int, mixed>
*/
public function collapse() {
return $this->to_base()->collapse();
}

/**
* Get a flattened array of the items in the collection.
*
* @param int|float $depth
* @return \Mantle\Support\Collection<int, mixed>
*/
public function flatten( $depth = INF ) {
return $this->to_base()->flatten( $depth );
}

/**
* Flip the items in the collection.
*
* @return \Mantle\Support\Collection<int|string, TKey>
*/
public function flip() {
return $this->to_base()->flip();
}

/**
* Get the keys of the collection items.
*
* @return \Mantle\Support\Collection<int, TKey>
*/
public function keys() {
return $this->to_base()->keys();
}

/**
* Pad collection to the specified length with a value.
*
* @template TPadValue
*
* @param int $size
* @param TPadValue $value
* @return \Mantle\Support\Collection<int, TModel|TPadValue>
*/
public function pad( $size, $value ) {
return $this->to_base()->pad( $size, $value );
}

/**
* Get an array with the values of a given key.
*
* @param string|array<array-key, string> $value
* @param string|null $key
* @return \Mantle\Support\Collection<array-key, mixed>
*/
public function pluck( $value, $key = null ) {
return $this->to_base()->pluck( $value, $key );
}

/**
* Zip the collection together with one or more arrays.
*
* @template TZipValue
*
* @param \Mantle\Contracts\Support\Arrayable<array-key, TZipValue>|iterable<array-key, TZipValue> ...$items
* @return static<int, static<TKey, TModel|TZipValue>>
*/
public function zip( ...$items ) { // @phpstan-ignore-line return
return $this->to_base()->zip( ...$items );
}
}
53 changes: 41 additions & 12 deletions src/mantle/database/query/class-post-query-builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Mantle\Database\Model\Term;
use Mantle\Database\Query\Concerns\Queries_Dates;
use Mantle\Support\Helpers;
use Mantle\Support\Collection;
use RuntimeException;
use WP_Term;

use function Mantle\Support\Helpers\collect;
Expand Down Expand Up @@ -117,7 +117,6 @@ public function get_query_args(): array {

return array_merge(
[
'fields' => 'ids',
'ignore_sticky_posts' => true,
'meta_query' => $this->meta_query, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'order' => $order,
Expand All @@ -130,6 +129,9 @@ public function get_query_args(): array {
],
$this->get_date_query_args(),
$this->wheres,
[
'fields' => 'ids',
]
);
}

Expand All @@ -148,14 +150,21 @@ public function get(): Collection {
fn () => $query->query( $this->get_query_args() ),
);

$this->found_rows = $query->found_posts;
$post_ids = $query->posts;
if ( empty( $query->found_posts ) && count( $query->posts ) > 0 ) {
$this->found_rows = null;
} else {
$this->found_rows = $query->found_posts;
}

$post_ids = $query->posts;

if ( empty( $post_ids ) ) {
return collect();
return ( new Collection() )->with_found_rows( $this->found_rows ); // @phpstan-ignore-line should return
}

$models = $this->get_models( $post_ids );
$models = $this
->get_models( $post_ids )
->with_found_rows( $this->found_rows );

// Return the models if there are no models or if multiple model instances
// are used. Eager loading does not currently support multiple models.
Expand Down Expand Up @@ -195,24 +204,32 @@ public function count(): int {
protected function get_models( array $post_ids ): Collection {
if ( is_array( $this->model ) ) {
$model_object_types = $this->get_model_object_names();
return collect( $post_ids )

return Collection::from( $post_ids )
->map(
function ( $post_id ) use ( $model_object_types ) {
$post_type = \get_post_type( $post_id );

if ( empty( $model_object_types[ $post_type ] ) ) {
throw new RuntimeException(
"Missing model for object type [{ $post_type }]."
);
}

if ( empty( $post_type ) ) {
return null;
}

return $model_object_types[ $post_type ]::find( $post_id );
}
)
->filter();
} else {
return collect( $post_ids )
->map( [ $this->model, 'find' ] )
->filter();
->filter()
->values();
}

return Collection::from( $post_ids )
->map( [ $this->model, 'find' ] )
->filter();
}

/**
Expand Down Expand Up @@ -295,6 +312,18 @@ public function orWhereTerm( ...$args ) {
return $this->whereTerm( ...$args );
}

/**
* Fetch the query with 'no_found_rows' set to a value.
*
* Setting to 'true' prevents counting all the available rows for a query.
*
* @param bool $value Whether to set 'no_found_rows' to true.
* @return static
*/
public function withNoFoundRows( bool $value = true ): static {
return $this->where( 'no_found_rows', $value );
}

/**
* Dump the SQL query being executed.
*
Expand Down
Loading

0 comments on commit aa56273

Please sign in to comment.