????JFIF??x?x????'
| Server IP : 104.21.30.238  /  Your IP : 216.73.216.83 Web Server : LiteSpeed System : Linux premium151.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64 User : tempvsty ( 647) PHP Version : 8.0.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /././home/tempvsty/./pontiacques.org/wp-content/plugins/give/src/Framework/Models/ | 
| Upload File : | 
<?php
namespace Give\Framework\Models;
use Give\Framework\Exceptions\Primitives\InvalidArgumentException;
use ReflectionClass;
/**
 * Eager load model relationships for more performant queries.
 *
 * As opposed to "lazy" loading, which queries the database for a relationship when it is accessed,
 * "eager" loading queries the database for the relationship of all queried models, with a single query.
 * This prevents a "N+1" problem, where a query is executed for each model, but using query optimization.
 *
 * @since 3.5.0
 *
 * @template M
 */
class EagerLoader
{
    /**
     * @since 3.5.0
     * @var ReflectionClass<M>
     */
    protected $reflection;
    /**
     * @since 3.5.0
     * @var ModelQueryBuilder
     */
    protected $modelQuery;
    /**
     * @since 3.5.0
     * @var ModelQueryBuilder
     */
    protected $eagerLoadedQuery;
    /**
     * @since 3.5.0
     * @var string
     */
    protected $relationshipKey;
    /**
     * @since 3.5.0
     * @var string
     */
    protected $foreignKey;
    /**
     * @var mixed
     */
    protected $foreignAttribute;
    /**
     * @since 3.5.0
     *
     * @param class-string<M> $modelClass
     * @param class-string<M> $eagerLoadedModelClass
     * @param string $relationshipKey
     * @param string $foreignKey
     * @param string|null $foreignAttribute
     */
    public function __construct(string $modelClass, string $eagerLoadedModelClass, string $relationshipKey, string $foreignKey, string $foreignAttribute = null)
    {
        if (!is_subclass_of($modelClass, Model::class)) {
            throw new InvalidArgumentException("$modelClass must be an instance of " . Model::class);
        }
        if (!is_subclass_of($eagerLoadedModelClass, Model::class)) {
            throw new InvalidArgumentException("$eagerLoadedModelClass must be an instance of " . Model::class);
        }
        $this->reflection = new ReflectionClass($modelClass);
        $this->modelQuery = $modelClass::query();
        $this->relationshipKey = $relationshipKey;
        $this->eagerLoadedQuery = $eagerLoadedModelClass::query();
        $this->foreignKey = $foreignKey;
        $this->foreignAttribute = $foreignAttribute ?? $foreignKey;
    }
    /**
     * @since 3.5.0
     */
    public function __call($name, $arguments)
    {
        $this->modelQuery->$name(...$arguments);
        return $this;
    }
    /**
     * This method wraps the `get()` method of the underlying ModelQueryBuilder.
     * It uses the results to query the related models and pre-set the cachedRelations property.
     *
     * @since 3.5.0
     *
     * @return M|null
     */
    public function get()
    {
        $model = $this->modelQuery->get();
        $eagerLoadedModels = $this->eagerLoadedQuery
            ->where($this->foreignKey, $model->id)
            ->getAll();
        $this->setEagerLoadedModels($model, $eagerLoadedModels);
        return $model;
    }
    /**
     * This method wraps the `getAll()` method of the underlying ModelQueryBuilder.
     * It uses the results to query the related models and pre-set the cachedRelations property.
     *
     * @since 3.5.0
     *
     * @return M[]|null
     */
    public function getAll()
    {
        $models = $this->modelQuery->getAll();
        $eagerLoadedModels = $this->eagerLoadedQuery
            ->whereIn($this->foreignKey, array_column($models, 'id'))
            ->getAll();
        foreach($models as $model) {
            $this->setEagerLoadedModels($model, array_filter($eagerLoadedModels, function($eagerLoadedModel) use ($model) {
                return $eagerLoadedModel->{$this->foreignAttribute} === $model->id;
            }));
        }
        return $models;
    }
    /**
     * The cachedRelations property is protected and cannot be accessed directly.
     * This method uses reflection to set the cachedRelations property on the model.
     *
     * @since 3.5.0
     *
     * @param Model $model
     * @param array $eagerLoadedModels
     */
    protected function setEagerLoadedModels(Model $model, array $eagerLoadedModels): void
    {
        $property = $this->reflection
            ->getParentClass()
            ->getProperty('cachedRelations');
        $property->setAccessible(true);
        $cachedRelations = $property->getValue($model);
        $cachedRelations[$this->relationshipKey] = $eagerLoadedModels;
        $property->setValue($model, $cachedRelations);
    }
}