MigrationExtensionManager::applyExtensions()   B
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 11
rs 8.8571
cc 5
eloc 7
nc 4
nop 1
1
<?php
2
3
namespace RDV\Bundle\MigrationBundle\Migration;
4
5
use Doctrine\DBAL\Platforms\AbstractPlatform;
6
use RDV\Bundle\MigrationBundle\Migration\Extension\DatabasePlatformAwareInterface;
7
use RDV\Bundle\MigrationBundle\Migration\Extension\NameGeneratorAwareInterface;
8
use RDV\Bundle\MigrationBundle\Tools\DbIdentifierNameGenerator;
9
10
class MigrationExtensionManager
11
{
12
    const EXTENSION_AWARE_INTERFACE_SUFFIX = 'AwareInterface';
13
14
    /**
15
     * @var array {extension name} => [{extension}, {extension aware interface name}, {set extension method name}]
16
     */
17
    protected $extensions = [];
18
19
    /**
20
     * @var AbstractPlatform
21
     */
22
    protected $platform;
23
24
    /**
25
     * @var DbIdentifierNameGenerator
26
     */
27
    protected $nameGenerator;
28
29
    /**
30
     * @var bool
31
     */
32
    private $isDependenciesUpToDate = false;
33
34
    /**
35
     * Sets a database platform
36
     *
37
     * @param AbstractPlatform $platform
38
     */
39
    public function setDatabasePlatform(AbstractPlatform $platform)
40
    {
41
        $this->platform = $platform;
42
43
        foreach ($this->extensions as $extension) {
44
            if ($extension[0] instanceof DatabasePlatformAwareInterface) {
45
                $extension[0]->setDatabasePlatform($this->platform);
46
            }
47
        }
48
    }
49
50
    /**
51
     * Sets a database identifier name generator
52
     *
53
     * @param DbIdentifierNameGenerator $nameGenerator
54
     */
55
    public function setNameGenerator(DbIdentifierNameGenerator $nameGenerator)
56
    {
57
        $this->nameGenerator = $nameGenerator;
58
59
        foreach ($this->extensions as $extension) {
60
            if ($extension[0] instanceof NameGeneratorAwareInterface) {
61
                $extension[0]->setNameGenerator($this->nameGenerator);
62
            }
63
        }
64
    }
65
66
    /**
67
     * Registers an extension
68
     *
69
     * @param string $name      The extension name
70
     * @param object $extension The extension object
71
     */
72
    public function addExtension($name, $extension)
73
    {
74
        if ($this->platform && $extension instanceof DatabasePlatformAwareInterface) {
75
            $extension->setDatabasePlatform($this->platform);
76
        }
77
        if ($this->nameGenerator && $extension instanceof NameGeneratorAwareInterface) {
78
            $extension->setNameGenerator($this->nameGenerator);
79
        }
80
81
        $extensionAwareInterfaceName = $this->getExtensionAwareInterfaceName($extension);
82
        $this->extensions[$name] = [
83
            $extension,
84
            $extensionAwareInterfaceName,
85
            $this->getSetExtensionMethodName($extensionAwareInterfaceName)
86
        ];
87
88
        $this->isDependenciesUpToDate = false;
89
    }
90
91
    /**
92
     * Sets extensions to the given migration
93
     *
94
     * @param Migration $migration
95
     */
96
    public function applyExtensions(Migration $migration)
97
    {
98
        if ($this->platform && $migration instanceof DatabasePlatformAwareInterface) {
99
            $migration->setDatabasePlatform($this->platform);
100
        }
101
        if ($this->nameGenerator && $migration instanceof NameGeneratorAwareInterface) {
102
            $migration->setNameGenerator($this->nameGenerator);
103
        }
104
        $this->ensureExtensionDependenciesApplied();
105
        $this->applyExtensionDependencies($migration);
106
    }
107
108
    /**
109
     * Makes sure that links on depended each other extensions set
110
     */
111
    protected function ensureExtensionDependenciesApplied()
112
    {
113
        if (!$this->isDependenciesUpToDate) {
114
            foreach ($this->extensions as $extension) {
115
                $this->applyExtensionDependencies($extension[0]);
116
            }
117
            $this->isDependenciesUpToDate = true;
118
        }
119
    }
120
121
    /**
122
     * Sets extensions to the given object
123
     *
124
     * @param object $obj
125
     */
126
    protected function applyExtensionDependencies($obj)
127
    {
128
        foreach ($this->extensions as $extension) {
129
            if (is_a($obj, $extension[1])) {
130
                $setMethod = $extension[2];
131
                $obj->$setMethod($extension[0]);
132
            }
133
        }
134
    }
135
136
    /**
137
     * Gets an name of interface which should be used to register an extension in a migration class
138
     *
139
     * @param object $extension
140
     * @return string
141
     * @throws \RuntimeException if the interface is not found
142
     */
143
    protected function getExtensionAwareInterfaceName($extension)
144
    {
145
        $result = null;
146
147
        $extensionClassName = get_class($extension);
148
        while ($extensionClassName) {
149
            $extensionAwareInterfaceName = $extensionClassName . self::EXTENSION_AWARE_INTERFACE_SUFFIX;
150
            if (interface_exists($extensionAwareInterfaceName)) {
151
                $result = $extensionAwareInterfaceName;
152
                break;
153
            }
154
155
            $extensionClassName = get_parent_class($extensionClassName);
156
        }
157
158
        if (!$result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
159
            if (get_parent_class($extension)) {
160
                $msg = sprintf(
161
                    'The extension aware interface for neither "%s" not one of its parent classes was not found.',
162
                    get_class($extension)
163
                );
164
            } else {
165
                $msg = sprintf(
166
                    'The extension aware interface for "%s" was not found. Make sure that "%s" interface is declared.',
167
                    get_class($extension),
168
                    get_class($extension) . self::EXTENSION_AWARE_INTERFACE_SUFFIX
169
                );
170
            }
171
172
            throw new \RuntimeException($msg);
173
        }
174
175
        return $result;
176
    }
177
178
    /**
179
     * Gets a name of set extension method
180
     *
181
     * @param string $extensionAwareInterfaceName
182
     * @return string
183
     * @throws \RuntimeException if set method is not found
184
     */
185
    protected function getSetExtensionMethodName($extensionAwareInterfaceName)
186
    {
187
        $parts = explode('\\', $extensionAwareInterfaceName);
188
        $className = array_pop($parts);
189
        $extensionName = substr($className, 0, strlen($className) - strlen(self::EXTENSION_AWARE_INTERFACE_SUFFIX));
190
        $setMethodName = 'set' . $extensionName;
191
192
        if (!method_exists($extensionAwareInterfaceName, $setMethodName)) {
193
            throw new \RuntimeException(
194
                sprintf('The method "%s::%s" was not found.', $extensionAwareInterfaceName, $setMethodName)
195
            );
196
        }
197
198
        return $setMethodName;
199
    }
200
}
201