ForeignKeyConstraint.php 10.5 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\DBAL\Schema;

5
use Doctrine\DBAL\Platforms\AbstractPlatform;
6 7 8
use function array_keys;
use function array_map;
use function in_array;
Sergei Morozov's avatar
Sergei Morozov committed
9
use function strrpos;
10 11
use function strtolower;
use function strtoupper;
Sergei Morozov's avatar
Sergei Morozov committed
12
use function substr;
13

14 15 16
/**
 * An abstraction class for a foreign key constraint.
 */
17 18
class ForeignKeyConstraint extends AbstractAsset implements Constraint
{
19
    /**
Benjamin Morel's avatar
Benjamin Morel committed
20 21
     * Instance of the referencing table the foreign key constraint is associated with.
     *
22
     * @var Table
23
     */
24
    protected $_localTable;
25 26

    /**
27 28 29 30
     * Asset identifier instances of the referencing table column names the foreign key constraint is associated with.
     * array($columnName => Identifier)
     *
     * @var Identifier[]
31
     */
32
    protected $_localColumnNames;
33 34

    /**
35 36 37
     * Table or asset identifier instance of the referenced table name the foreign key constraint is associated with.
     *
     * @var Table|Identifier
38
     */
39
    protected $_foreignTableName;
40 41

    /**
42 43 44 45
     * Asset identifier instances of the referenced table column names the foreign key constraint is associated with.
     * array($columnName => Identifier)
     *
     * @var Identifier[]
46
     */
47
    protected $_foreignColumnNames;
48

49 50 51 52 53
    /**
     * Options associated with the foreign key constraint.
     *
     * @var mixed[]
     */
54
    protected $_options;
55 56

    /**
57
     * Initializes the foreign key constraint.
58
     *
59
     * @param string[]     $localColumnNames   Names of the referencing table columns.
60
     * @param Table|string $foreignTableName   Referenced table.
61
     * @param string[]     $foreignColumnNames Names of the referenced table columns.
62
     * @param string|null  $name               Name of the foreign key constraint.
63
     * @param mixed[]      $options            Options associated with the foreign key constraint.
64
     */
65
    public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name = null, array $options = [])
66
    {
Sergei Morozov's avatar
Sergei Morozov committed
67 68 69
        if ($name !== null) {
            $this->_setName($name);
        }
Sergei Morozov's avatar
Sergei Morozov committed
70 71

        $this->_localColumnNames = $this->createIdentifierMap($localColumnNames);
72 73 74 75 76 77 78

        if ($foreignTableName instanceof Table) {
            $this->_foreignTableName = $foreignTableName;
        } else {
            $this->_foreignTableName = new Identifier($foreignTableName);
        }

Sergei Morozov's avatar
Sergei Morozov committed
79
        $this->_foreignColumnNames = $this->createIdentifierMap($foreignColumnNames);
80
        $this->_options            = $options;
81 82
    }

Sergei Morozov's avatar
Sergei Morozov committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    /**
     * @param string[] $names
     *
     * @return Identifier[]
     */
    private function createIdentifierMap(array $names) : array
    {
        $identifiers = [];

        foreach ($names as $name) {
            $identifiers[$name] = new Identifier($name);
        }

        return $identifiers;
    }

99
    /**
100 101 102
     * Returns the name of the referencing table
     * the foreign key constraint is associated with.
     *
103 104 105 106
     * @return string
     */
    public function getLocalTableName()
    {
107
        return $this->_localTable->getName();
108 109 110
    }

    /**
111 112 113
     * Sets the Table instance of the referencing table
     * the foreign key constraint is associated with.
     *
114
     * @param Table $table Instance of the referencing table.
Benjamin Morel's avatar
Benjamin Morel committed
115 116
     *
     * @return void
117 118 119
     */
    public function setLocalTable(Table $table)
    {
120
        $this->_localTable = $table;
121 122
    }

123 124 125 126 127 128 129 130
    /**
     * @return Table
     */
    public function getLocalTable()
    {
        return $this->_localTable;
    }

131
    /**
132 133 134
     * Returns the names of the referencing table columns
     * the foreign key constraint is associated with.
     *
135
     * @return string[]
136
     */
137
    public function getLocalColumns()
138
    {
139 140 141 142 143 144 145 146 147 148 149
        return array_keys($this->_localColumnNames);
    }

    /**
     * Returns the quoted representation of the referencing table column names
     * the foreign key constraint is associated with.
     *
     * But only if they were defined with one or the referencing table column name
     * is a keyword reserved by the platform.
     * Otherwise the plain unquoted value as inserted is returned.
     *
150
     * @param AbstractPlatform $platform The platform to use for quotation.
151
     *
152
     * @return string[]
153 154 155
     */
    public function getQuotedLocalColumns(AbstractPlatform $platform)
    {
156
        $columns = [];
157 158 159 160 161 162

        foreach ($this->_localColumnNames as $column) {
            $columns[] = $column->getQuotedName($platform);
        }

        return $columns;
163 164
    }

165 166 167
    /**
     * Returns unquoted representation of local table column names for comparison with other FK
     *
168
     * @return string[]
169 170 171
     */
    public function getUnquotedLocalColumns()
    {
172
        return array_map([$this, 'trimQuotes'], $this->getLocalColumns());
173 174 175 176 177
    }

    /**
     * Returns unquoted representation of foreign table column names for comparison with other FK
     *
178
     * @return string[]
179 180 181
     */
    public function getUnquotedForeignColumns()
    {
182
        return array_map([$this, 'trimQuotes'], $this->getForeignColumns());
183 184
    }

185
    /**
Benjamin Morel's avatar
Benjamin Morel committed
186
     * {@inheritdoc}
187
     *
188
     * @see getLocalColumns
189
     */
190 191
    public function getColumns()
    {
192 193 194 195 196 197 198 199 200 201 202 203 204
        return $this->getLocalColumns();
    }

    /**
     * Returns the quoted representation of the referencing table column names
     * the foreign key constraint is associated with.
     *
     * But only if they were defined with one or the referencing table column name
     * is a keyword reserved by the platform.
     * Otherwise the plain unquoted value as inserted is returned.
     *
     * @see getQuotedLocalColumns
     *
205 206
     * @param AbstractPlatform $platform The platform to use for quotation.
     *
207
     * @return string[]
208 209 210 211
     */
    public function getQuotedColumns(AbstractPlatform $platform)
    {
        return $this->getQuotedLocalColumns($platform);
212 213
    }

214
    /**
215 216 217
     * Returns the name of the referenced table
     * the foreign key constraint is associated with.
     *
218 219 220 221
     * @return string
     */
    public function getForeignTableName()
    {
222
        return $this->_foreignTableName->getName();
223 224
    }

225
    /**
Benjamin Morel's avatar
Benjamin Morel committed
226
     * Returns the non-schema qualified foreign table name.
227 228 229 230 231
     *
     * @return string
     */
    public function getUnqualifiedForeignTableName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
232 233 234 235
        $name     = $this->_foreignTableName->getName();
        $position = strrpos($name, '.');

        if ($position !== false) {
236
            $name = substr($name, $position + 1);
Sergei Morozov's avatar
Sergei Morozov committed
237
        }
238

Sergei Morozov's avatar
Sergei Morozov committed
239
        return strtolower($name);
240 241
    }

242
    /**
243 244 245 246 247 248
     * Returns the quoted representation of the referenced table name
     * the foreign key constraint is associated with.
     *
     * But only if it was defined with one or the referenced table name
     * is a keyword reserved by the platform.
     * Otherwise the plain unquoted value as inserted is returned.
249
     *
250
     * @param AbstractPlatform $platform The platform to use for quotation.
251
     *
252 253 254 255
     * @return string
     */
    public function getQuotedForeignTableName(AbstractPlatform $platform)
    {
256
        return $this->_foreignTableName->getQuotedName($platform);
257 258
    }

259
    /**
260 261 262
     * Returns the names of the referenced table columns
     * the foreign key constraint is associated with.
     *
263
     * @return string[]
264
     */
265
    public function getForeignColumns()
266
    {
267 268 269 270 271 272 273 274 275 276 277
        return array_keys($this->_foreignColumnNames);
    }

    /**
     * Returns the quoted representation of the referenced table column names
     * the foreign key constraint is associated with.
     *
     * But only if they were defined with one or the referenced table column name
     * is a keyword reserved by the platform.
     * Otherwise the plain unquoted value as inserted is returned.
     *
278
     * @param AbstractPlatform $platform The platform to use for quotation.
279
     *
280
     * @return string[]
281 282 283
     */
    public function getQuotedForeignColumns(AbstractPlatform $platform)
    {
284
        $columns = [];
285 286 287 288 289 290

        foreach ($this->_foreignColumnNames as $column) {
            $columns[] = $column->getQuotedName($platform);
        }

        return $columns;
291 292
    }

293 294 295 296 297 298
    /**
     * Returns whether or not a given option
     * is associated with the foreign key constraint.
     *
     * @param string $name Name of the option to check.
     *
299
     * @return bool
300
     */
301 302
    public function hasOption($name)
    {
303
        return isset($this->_options[$name]);
304 305
    }

306 307 308 309 310 311 312
    /**
     * Returns an option associated with the foreign key constraint.
     *
     * @param string $name Name of the option the foreign key constraint is associated with.
     *
     * @return mixed
     */
313 314
    public function getOption($name)
    {
315
        return $this->_options[$name];
316
    }
317

318
    /**
319
     * Returns the options associated with the foreign key constraint.
320
     *
321
     * @return mixed[]
322 323 324
     */
    public function getOptions()
    {
325
        return $this->_options;
326 327
    }

328
    /**
329 330
     * Returns the referential action for UPDATE operations
     * on the referenced table the foreign key constraint is associated with.
331 332 333 334 335
     *
     * @return string|null
     */
    public function onUpdate()
    {
336
        return $this->onEvent('onUpdate');
337 338 339
    }

    /**
340 341
     * Returns the referential action for DELETE operations
     * on the referenced table the foreign key constraint is associated with.
342 343 344 345 346
     *
     * @return string|null
     */
    public function onDelete()
    {
347
        return $this->onEvent('onDelete');
348 349 350
    }

    /**
351 352 353 354 355
     * Returns the referential action for a given database operation
     * on the referenced table the foreign key constraint is associated with.
     *
     * @param string $event Name of the database operation/event to return the referential action for.
     *
356 357
     * @return string|null
     */
358
    private function onEvent($event)
359
    {
360 361
        if (isset($this->_options[$event])) {
            $onEvent = strtoupper($this->_options[$event]);
362

363
            if (! in_array($onEvent, ['NO ACTION', 'RESTRICT'])) {
364 365 366
                return $onEvent;
            }
        }
367

368
        return null;
369
    }
370 371 372 373 374 375 376 377 378

    /**
     * Checks whether this foreign key constraint intersects the given index columns.
     *
     * Returns `true` if at least one of this foreign key's local columns
     * matches one of the given index's columns, `false` otherwise.
     *
     * @param Index $index The index to be checked against.
     *
379
     * @return bool
380 381 382 383 384 385 386 387 388 389 390 391 392
     */
    public function intersectsIndexColumns(Index $index)
    {
        foreach ($index->getColumns() as $indexColumn) {
            foreach ($this->_localColumnNames as $localColumn) {
                if (strtolower($indexColumn) === strtolower($localColumn->getName())) {
                    return true;
                }
            }
        }

        return false;
    }
393
}