OrmBootstrapper::getBindings()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 10
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Admin\Bootstrappers\Orm;
6
7
use AbterPhp\Admin\Domain\Entities\AdminResource;
8
use AbterPhp\Admin\Domain\Entities\ApiClient;
9
use AbterPhp\Admin\Domain\Entities\LoginAttempt;
10
use AbterPhp\Admin\Domain\Entities\User;
11
use AbterPhp\Admin\Domain\Entities\UserGroup;
12
use AbterPhp\Admin\Domain\Entities\UserLanguage;
13
use AbterPhp\Admin\Orm\AdminResourceRepo;
14
use AbterPhp\Admin\Orm\ApiClientRepo;
15
use AbterPhp\Admin\Orm\DataMappers\AdminResourceSqlDataMapper;
16
use AbterPhp\Admin\Orm\DataMappers\ApiClientSqlDataMapper;
17
use AbterPhp\Admin\Orm\DataMappers\LoginAttemptSqlDataMapper;
18
use AbterPhp\Admin\Orm\DataMappers\UserGroupSqlDataMapper;
19
use AbterPhp\Admin\Orm\DataMappers\UserLanguageSqlDataMapper;
20
use AbterPhp\Admin\Orm\DataMappers\UserSqlDataMapper;
21
use AbterPhp\Admin\Orm\LoginAttemptRepo;
22
use AbterPhp\Admin\Orm\UserGroupRepo;
23
use AbterPhp\Admin\Orm\UserLanguageRepo;
24
use AbterPhp\Admin\Orm\UserRepo;
25
use AbterPhp\Framework\Orm\Ids\Generators\IdGeneratorRegistry;
26
use Opulence\Databases\ConnectionPools\ConnectionPool;
27
use Opulence\Databases\IConnection;
28
use Opulence\Ioc\Bootstrappers\Bootstrapper;
29
use Opulence\Ioc\Bootstrappers\ILazyBootstrapper;
30
use Opulence\Ioc\IContainer;
31
use Opulence\Ioc\IocException;
32
use Opulence\Orm\ChangeTracking\ChangeTracker;
33
use Opulence\Orm\ChangeTracking\IChangeTracker;
34
use Opulence\Orm\EntityRegistry;
35
use Opulence\Orm\Ids\Accessors\IdAccessorRegistry;
36
use Opulence\Orm\Ids\Accessors\IIdAccessorRegistry;
37
use Opulence\Orm\Ids\Generators\IIdGeneratorRegistry;
38
use Opulence\Orm\IUnitOfWork;
39
use Opulence\Orm\UnitOfWork;
40
use RuntimeException;
41
42
/**
43
 * Defines the ORM bootstrapper
44
 */
45
class OrmBootstrapper extends Bootstrapper implements ILazyBootstrapper
46
{
47
    /** @var array<string,string[]> */
48
    protected array $repoMappers = [
49
        AdminResourceRepo::class => [AdminResourceSqlDataMapper::class, AdminResource::class],
50
        LoginAttemptRepo::class  => [LoginAttemptSqlDataMapper::class, LoginAttempt::class],
51
        ApiClientRepo::class     => [ApiClientSqlDataMapper::class, ApiClient::class],
52
        UserGroupRepo::class     => [UserGroupSqlDataMapper::class, UserGroup::class],
53
        UserLanguageRepo::class  => [UserLanguageSqlDataMapper::class, UserLanguage::class],
54
        UserRepo::class          => [UserSqlDataMapper::class, User::class],
55
    ];
56
57
    /**
58
     * @return string[]
59
     */
60
    public function getBindings(): array
61
    {
62
        $baseBindings = [
63
            IChangeTracker::class,
64
            IIdAccessorRegistry::class,
65
            IIdGeneratorRegistry::class,
66
            IUnitOfWork::class,
67
        ];
68
69
        return array_merge($baseBindings, array_keys($this->repoMappers));
70
    }
71
72
    /**
73
     * @inheritdoc
74
     */
75
    public function registerBindings(IContainer $container)
76
    {
77
        try {
78
            $idAccessorRegistry  = new IdAccessorRegistry();
79
            $idGeneratorRegistry = new IdGeneratorRegistry();
80
            $changeTracker       = new ChangeTracker();
81
            $entityRegistry      = new EntityRegistry($idAccessorRegistry, $changeTracker);
82
            $unitOfWork          = new UnitOfWork(
83
                $entityRegistry,
84
                $idAccessorRegistry,
85
                $idGeneratorRegistry,
86
                $changeTracker,
87
                $container->resolve(IConnection::class)
88
            );
89
            $this->bindRepositories($container, $unitOfWork);
90
            $container->bindInstance(IIdAccessorRegistry::class, $idAccessorRegistry);
91
            $container->bindInstance(IIdGeneratorRegistry::class, $idGeneratorRegistry);
92
            $container->bindInstance(IChangeTracker::class, $changeTracker);
93
            $container->bindInstance(IUnitOfWork::class, $unitOfWork);
94
            $container->bindInstance(EntityRegistry::class, $entityRegistry);
95
        } catch (IocException $ex) {
96
            throw new RuntimeException('Failed to register ORM bindings', 0, $ex);
97
        }
98
    }
99
100
    /**
101
     * Binds repositories to the container
102
     *
103
     * @param IContainer  $container  The container to bind to
104
     * @param IUnitOfWork $unitOfWork The unit of work to use in repositories
105
     *
106
     * @throws IocException
107
     */
108
    protected function bindRepositories(IContainer $container, IUnitOfWork $unitOfWork)
109
    {
110
        $connectionPool  = $container->resolve(ConnectionPool::class);
111
        $readConnection  = $connectionPool->getReadConnection();
112
        $writeConnection = $connectionPool->getWriteConnection();
113
114
        foreach ($this->repoMappers as $repoClass => $classes) {
115
            $container->bindFactory(
116
                $repoClass,
117
                $this->createFactory(
118
                    $repoClass,
119
                    $classes[0],
120
                    $classes[1],
121
                    $readConnection,
122
                    $writeConnection,
123
                    $unitOfWork
124
                )
125
            );
126
        }
127
    }
128
129
    /**
130
     * @param string      $repoClass
131
     * @param string      $dataMapperClass
132
     * @param string      $entityClass
133
     * @param IConnection $readConnection
134
     * @param IConnection $writeConnection
135
     * @param IUnitOfWork $unitOfWork
136
     *
137
     * @return \Closure
138
     */
139
    private function createFactory(
140
        string $repoClass,
141
        string $dataMapperClass,
142
        string $entityClass,
143
        IConnection $readConnection,
144
        IConnection $writeConnection,
145
        IUnitOfWork $unitOfWork
146
    ): \Closure {
147
        return function () use (
148
            $repoClass,
149
            $dataMapperClass,
150
            $entityClass,
151
            $readConnection,
152
            $writeConnection,
153
            $unitOfWork
154
        ) {
155
            $dataMapper = new $dataMapperClass($readConnection, $writeConnection);
156
157
            return new $repoClass($entityClass, $dataMapper, $unitOfWork);
158
        };
159
    }
160
}
161