DeGraciaMathieu/
Manager
g4t.io

Manager Pattern Package for Laravel

92 stars by Paul Redmond

Implementation of the Manager pattern existing in Laravel framework.

README from DeGraciaMathieu/Manager Open on GitHub →

DeGraciaMathieu/Manager

Implementation of the Manager pattern existing in Laravel framework.

Installation

Manager 3.* 2.* 1.*
php ^8.1 :white_check_mark: :x: :x:
php 8.0.* :white_check_mark: :white_check_mark: :x:
php 7.* :x: :x: :white_check_mark:
composer require degraciamathieu/manager

Usage

This package offers an abstract class DeGraciaMathieu\Manager\Manager which needs to be extended to implement the creation of various Driver classes :

namespace App\Managers;

use DeGraciaMathieu\Manager\Manager;

class WeatherManager extends Manager {

    public function createOpenweathermapDriver() 
    {
        return new Openweathermap();
    }

    public function getDefaultDriver(): string
    {
        return 'openweathermap';
    }
}

A driver is a class integrating all the logic of an implementation, in our examples the interactions with the APIs of Openweathermap :

namespace App\Managers;

class Openweathermap {

    public function itsRainingNow(string $city): bool
    {   
        // call Openweathermap api to know if it is raining in this city

        return true;
    }
}

From now on, you can directly call the method of a driver directly from the manager :

(new WeatherManager())->itsRainingNow('Paris'); // true

The manager will call the itsRainingNow method of the default driver configured by the getDefaultDriver method.

You can also call any driver from the manager's driver method :

(new WeatherManager())->driver('openweathermap')->itsRainingNow('Paris');

Now if you want to create a new implementation, for example if you want to use Aerisweather APIs, you just have to create a new driver in your manager :

namespace App\Managers;

use DeGraciaMathieu\Manager\Manager;

class WeatherManager extends Manager {

    public function createOpenweathermapDriver()
    {
        return new Openweathermap();
    }

    public function createAerisweatherDriver()
    {
        return new Aerisweather();
    }

    public function getDefaultDriver(): string
    {
        return 'openweathermap';
    }
}

Tip, the getDefaultDriver method is the perfect place to use a configuration or environment variable !

Add an interface to the drivers

For more consistency it is advisable to implement an interface to the different drivers :

namespace App\Managers;

interface Driver {
    public function itsRainingNow(string $city): bool;
}

You obviously need to add this interface to your drivers.

namespace App\Managers;

use DeGraciaMathieu\Manager\Manager;

class WeatherManager extends Manager {

    public function createOpenweathermapDriver(): Driver
    {
        return new Openweathermap();
    }

    public function createAerisweatherDriver(): Driver
    {
        return new Aerisweather();
    }

    public function getDefaultDriver(): string
    {
        return 'openweathermap';
    }
}

Now you will be assured that each driver instantiated by the manager will have the same interface.

Repository class

To control side effects of drivers, it is advisable to create a class encapsulating the instance of a driver, this class is usually called Repository :

namespace App\Managers;

use DeGraciaMathieu\Manager\Manager;

class WeatherManager extends Manager {

    public function createOpenweathermapDriver(): Repository
    {
        $driver = new Openweathermap();

        return new Repository($driver);
    }

    public function createAerisweatherDriver(): Repository
    {
        $driver = new Aerisweather();

        return new Repository($driver);
    }

    public function getDefaultDriver(): string
    {
        return 'openweathermap';
    }
}

The repository is a class providing a bridge between your application and the driver :

namespace App\Managers;

class Repository {

    public function __construct(
        private Driver $driver,
    ){}

    public function itsRainingNow(string $city): bool
    {
        return $this->driver->itsRainingNow($city);
    }
}

This repository class is an anti-corruption layer

Thus, your application will never be aware of which driver it is handling, because it will always be encapsulated in a class repository.

The repository is also a good place if you need to add specific logic for all drivers.

Work with singleton

You can also cache the creation of Drivers with the $singleton property.

With the singleton property you will only create one instance of Openweathermap driver :

<?php

$weatherManager = new WeatherManager(singleton: true);

$weatherManager->driver('openweathermap')->itsRainingNow('Paris');
$weatherManager->driver('openweathermap')->itsRainingNow('Paris');
$weatherManager->driver('openweathermap')->itsRainingNow('Paris');

by default, singleton property value is False

Example with Laravel

Usage example of the pattern manager in a Laravel project.

More from the ecosystem

marcreichel/
laya-php
g4t.io
3 53

LayaPHP: Self-Hosted Text Classification for PHP and Laravel

Classify text in PHP without an LLM bill: typed decisions in 100+ languages, self-hosted. Laravel-ready SDK for Laya, a Jev AI alternative.

ai classification decision-engine
marcreichel/laya-php via Laravel News
Josh-Dovey/
postcodes-laravel
g4t.io
5 9

Postcodes for Laravel: GB Postcode Lookup and Geography Data

Postcodes for Laravel adds typed GB postcode lookups, validation, geography data, distance searches, and test fakes through the GB Postcodes API.

Josh-Dovey/postcodes-laravel via Laravel News
RedberryProducts/
mailbox-for-laravel
g4t.io
4 115

Mailbox for Laravel: Preview and Test Rendered Email

Mailbox for Laravel captures outgoing mail in a local dashboard and lets you test rendered HTML, recipients, and attachments with fluent assertions.

RedberryProducts/mailbox-for-laravel via Laravel News