Passed
Push — master ( c58a59...826990 )
by Anton
02:19
created

CycleBootloader::bindRepositories()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 4
nc 3
nop 2
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
declare(strict_types=1);
9
10
namespace Spiral\Bootloader\Cycle;
11
12
use Cycle\ORM\Config\RelationConfig;
13
use Cycle\ORM\Factory;
14
use Cycle\ORM\FactoryInterface;
15
use Cycle\ORM\ORM;
16
use Cycle\ORM\ORMInterface;
17
use Cycle\ORM\PromiseFactoryInterface;
18
use Cycle\ORM\SchemaInterface;
19
use Cycle\ORM\Select;
20
use Cycle\ORM\Transaction;
21
use Cycle\ORM\TransactionInterface;
22
use Spiral\Boot\Bootloader\Bootloader;
23
use Spiral\Boot\Bootloader\DependedInterface;
24
use Spiral\Boot\FinalizerInterface;
25
use Spiral\Bootloader\Database\DatabaseBootloader;
26
use Spiral\Core\Container;
27
use Spiral\Cycle\SelectInjector;
28
use Spiral\Database\DatabaseProviderInterface;
29
30
final class CycleBootloader extends Bootloader implements DependedInterface
31
{
32
    public const BINDINGS = [
33
        TransactionInterface::class => Transaction::class,
34
    ];
35
36
    public const SINGLETONS = [
37
        ORMInterface::class     => [self::class, 'orm'],
38
        FactoryInterface::class => [self::class, 'factory'],
39
    ];
40
41
    /**
42
     * @param Container            $container
43
     * @param FinalizerInterface   $finalizer
44
     * @param SchemaInterface|null $schema
45
     */
46
    public function boot(Container $container, FinalizerInterface $finalizer, SchemaInterface $schema = null)
47
    {
48
        $finalizer->addFinalizer(function () use ($container) {
49
            if ($container->hasInstance(ORMInterface::class)) {
50
                $container->get(ORMInterface::class)->getHeap()->clean();
51
            }
52
        });
53
54
        $container->bindInjector(Select::class, SelectInjector::class);
55
56
        if ($schema !== null) {
57
            $this->bindRepositories($container, $schema);
58
        }
59
    }
60
61
    /**
62
     * Create container bindings to resolve repositories by they class names.
63
     *
64
     * @param Container       $container
65
     * @param SchemaInterface $schema
66
     */
67
    public function bindRepositories(Container $container, SchemaInterface $schema)
68
    {
69
        foreach ($schema->getRoles() as $role) {
70
            $repository = $schema->define($role, SchemaInterface::REPOSITORY);
71
            if ($repository === Select\Repository::class || $repository === null) {
72
                // default repository can not be wired
73
                continue;
74
            }
75
76
            // initiate all repository dependencies using factory method forwarded to ORM
77
            $container->bindSingleton($repository, function (ORMInterface $orm) use ($role) {
78
                return $orm->getRepository($role);
79
            });
80
        }
81
    }
82
83
    /**
84
     * @return array
85
     */
86
    public function defineDependencies(): array
87
    {
88
        return [
89
            DatabaseBootloader::class,
90
            SchemaBootloader::class
91
        ];
92
    }
93
94
    /**
95
     * @param FactoryInterface             $factory
96
     * @param SchemaInterface              $schema
97
     * @param PromiseFactoryInterface|null $promiseFactory
98
     * @return ORMInterface
99
     */
100
    protected function orm(
101
        FactoryInterface $factory,
102
        SchemaInterface $schema = null,
103
        PromiseFactoryInterface $promiseFactory = null
104
    ): ORMInterface {
105
        $orm = new ORM($factory, $schema);
106
107
        if ($promiseFactory !== null) {
108
            return $orm->withPromiseFactory($promiseFactory);
109
        }
110
111
        return $orm;
112
    }
113
114
    /**
115
     * @param DatabaseProviderInterface $dbal
116
     * @param Container                 $container
117
     * @return FactoryInterface
118
     */
119
    protected function factory(DatabaseProviderInterface $dbal, Container $container): FactoryInterface
120
    {
121
        return new Factory($dbal, RelationConfig::getDefault(), $container, $container);
122
    }
123
}