Skip to content

Abstract Factory

Sakya edited this page Aug 1, 2022 · 2 revisions

Abstract Factory

It is recommended to use Laminas ServiceManager instead of PHP-DI as container provider

new Itseasy\Application([
   ...
   'container_provider' => Itseasy\ServiceManager\LaminasServiceManager::class
   ...
]);

Abstract factory will only be call when explicit factory definition is not found
The result of abstract factory then will be cache and become explicit factory definition in memory

Large and many Abstract Factory might cause slower performance in code execution
Note that Abstract Factory doesn't support constructor hence no dependency can be injected for the factory
Container can only be access when invoke is call

Example Abstract Factory

RepositoryAbstractServiceFactory

Auto Creating GenericRepository without defining Repository in the service factories
Rename Project to your Namespace

<?php

declare(strict_types=1);

namespace Project\Repository\Factory;

use Laminas\ServiceManager\Factory\AbstractFactoryInterface;
use Psr\Container\ContainerInterface;
use Itseasy\Repository\GenericRepository;
use Project\Database;

class RepositoryAbstractServiceFactory implements AbstractFactoryInterface
{
    public const SERVICE_SUFFIX = 'Repository';

    public function __invoke(
        ContainerInterface $container,
        $requestedName,
        ?array $options = null
    ) {
        $namespace = explode("\\", $requestedName);
        $repository = preg_split('/(?=[A-Z])/', end($namespace), -1, PREG_SPLIT_NO_EMPTY);
        array_pop($repository);
        $table_name = strtolower(implode("_", $repository));

        return new GenericRepository($container->get(Database::class), $table_name);
    }

    public function canCreate(ContainerInterface $container, $requestedName)
    {
        $namespace = explode("\\", $requestedName);
        if (strpos(end($namespace), self::SERVICE_SUFFIX) > -1) {
            return true;
        }
        return false;
    }
}

Then register abstract factories in the service.config.php2

<?php

return [
    "service" => [
        "abstract_factories" => [
             Project\Repository\Factory\RepositoryAbstractServiceFactory::class
        ]
    ]
];

Next time when we call a Repository in a Factory

...
// This will create repository class that mange database table "user_role" 
$container->get("UserRoleRepository"); 

// This will create repository class that mange database table "project" 
$container->get("ProjectRepository"); 
...
Clone this wiki locally