Passed
Push — master ( 8926af...beb5fc )
by Anton
02:16
created

CycleBootloader::defineDependencies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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