folded-php/orm

View on GitHub
src/Model.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types = 1);

namespace Folded;

use OutOfRangeException;
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Database\Eloquent\Model as EloquentModel;

/**
 * Represents a class that reflects a table in the database.
 *
 * @since 0.1.0
 */
class Model extends EloquentModel
{
    /**
     * Wether the Eloquent bootstrap has been started or not.
     *
     * @since 0.1.0
     */
    private static bool $engineBooted = false;

    /**
     * Wether the Eloquent event system is started or not.
     *
     * @since 0.1.0
     * @see https://laravel.com/docs/7.x/eloquent#events For more information about the Eloquent event system.
     */
    private static bool $eventsEnabled = false;

    /**
     * Constructor.
     *
     * @param array<string, mixed> $attributes Fields and values to start with.
     *
     * @since 0.1.0
     *
     * @example
     * $post = new Post([
     *  "title" => "Something",
     *  "excerpt" => "My first post...",
     * ]);
     */
    public function __construct(array $attributes = [])
    {
        static::startEngine();

        parent::__construct($attributes);
    }

    /**
     * Reset the state of the object.
     * Useful for unit testing.
     *
     * @since 0.1.0
     *
     * @example
     * Model::clear();
     */
    public static function clear(): void
    {
        self::$engineBooted = false;
        self::$eventsEnabled = false;
    }

    /**
     * Disables the Eloquent event system for all the models.
     *
     * @since 0.1.0
     * @see https://laravel.com/docs/7.x/eloquent#events For more information about the Eloquent event system.
     *
     * @example
     * Model::disableEvents();
     */
    public static function disableEvents(): void
    {
        self::$eventsEnabled = false;
    }

    /**
     * Enables the Eloquent event system for all the models.
     *
     * @deprecated v0.1.1 Use Model::disableEvents() instead.
     * @since 0.1.0
     * @see https://laravel.com/docs/7.x/eloquent#events For more information about the Eloquent event system.
     *
     * @example
     * Model::enableEvent()
     */
    public static function enableEvent(): void
    {
        self::$eventsEnabled = true;
    }

    /**
     * Enables the Eloquent event system for all the models.
     *
     * @since 0.1.1
     * @see https://laravel.com/docs/7.x/eloquent#events For more information about the Eloquent event system.
     *
     * @example
     * Model::enableEvents()
     */
    public static function enableEvents(): void
    {
        self::$eventsEnabled = true;
    }

    /**
     * Instruct the paginate method to go to the desired page.
     *
     * Shortcut over the verbose ->paginate(15, ["*"], "page", $pageNumber = 2);
     *
     * @param int $pageNumber The page you want to go.
     *
     * @throws OutOfRangeException If the page number is below 1.
     *
     * @since 0.2.0
     *
     * @example
     * Model::toPage(2)->paginate(15);
     */
    public static function toPage(int $pageNumber): Builder
    {
        if ($pageNumber < 1) {
            throw new OutOfRangeException("page number must be greater or equal to 1");
        }

        AbstractPaginator::currentPageResolver(function () use ($pageNumber) {
            return $pageNumber;
        });

        return self::query();
    }

    /**
     * Starts the Eloquent engine.
     *
     * @since 0.1.0
     * @see https://laravel.com/docs/7.x/eloquent For more information about the Eloquent ORM.
     *
     * @example
     * Model::startEngine();
     */
    private static function startEngine(): void
    {
        if (static::$engineBooted) {
            return;
        }

        $connections = DatabaseConnections::getAll();

        $manager = new Manager();

        foreach ($connections as $index => $connection) {
            $connectionName = $index === 0 ? "default" : $connection["driver"];
            $manager->addConnection($connection, $connectionName);
        }

        if (self::$eventsEnabled) {
            // Set the event dispatcher used by Eloquent models... (optional)
            $manager->setEventDispatcher(new Dispatcher(new Container()));
        }

        // Make this Capsule instance available globally via static methods... (optional)
        $manager->setAsGlobal();
        $manager->bootEloquent();

        static::$engineBooted = true;
    }
}