1<?php
2
3namespace Doctrine\DBAL\Schema;
4
5use Doctrine\DBAL\Platforms\AbstractPlatform;
6use function array_merge;
7
8/**
9 * Schema Diff.
10 */
11class SchemaDiff
12{
13    /** @var Schema|null */
14    public $fromSchema;
15
16    /**
17     * All added namespaces.
18     *
19     * @var string[]
20     */
21    public $newNamespaces = [];
22
23    /**
24     * All removed namespaces.
25     *
26     * @var string[]
27     */
28    public $removedNamespaces = [];
29
30    /**
31     * All added tables.
32     *
33     * @var Table[]
34     */
35    public $newTables = [];
36
37    /**
38     * All changed tables.
39     *
40     * @var TableDiff[]
41     */
42    public $changedTables = [];
43
44    /**
45     * All removed tables.
46     *
47     * @var Table[]
48     */
49    public $removedTables = [];
50
51    /** @var Sequence[] */
52    public $newSequences = [];
53
54    /** @var Sequence[] */
55    public $changedSequences = [];
56
57    /** @var Sequence[] */
58    public $removedSequences = [];
59
60    /** @var ForeignKeyConstraint[] */
61    public $orphanedForeignKeys = [];
62
63    /**
64     * Constructs an SchemaDiff object.
65     *
66     * @param Table[]     $newTables
67     * @param TableDiff[] $changedTables
68     * @param Table[]     $removedTables
69     */
70    public function __construct($newTables = [], $changedTables = [], $removedTables = [], ?Schema $fromSchema = null)
71    {
72        $this->newTables     = $newTables;
73        $this->changedTables = $changedTables;
74        $this->removedTables = $removedTables;
75        $this->fromSchema    = $fromSchema;
76    }
77
78    /**
79     * The to save sql mode ensures that the following things don't happen:
80     *
81     * 1. Tables are deleted
82     * 2. Sequences are deleted
83     * 3. Foreign Keys which reference tables that would otherwise be deleted.
84     *
85     * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all.
86     *
87     * @return string[]
88     */
89    public function toSaveSql(AbstractPlatform $platform)
90    {
91        return $this->_toSql($platform, true);
92    }
93
94    /**
95     * @return string[]
96     */
97    public function toSql(AbstractPlatform $platform)
98    {
99        return $this->_toSql($platform, false);
100    }
101
102    /**
103     * @param bool $saveMode
104     *
105     * @return string[]
106     */
107    protected function _toSql(AbstractPlatform $platform, $saveMode = false)
108    {
109        $sql = [];
110
111        if ($platform->supportsSchemas()) {
112            foreach ($this->newNamespaces as $newNamespace) {
113                $sql[] = $platform->getCreateSchemaSQL($newNamespace);
114            }
115        }
116
117        if ($platform->supportsForeignKeyConstraints() && $saveMode === false) {
118            foreach ($this->orphanedForeignKeys as $orphanedForeignKey) {
119                $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTable());
120            }
121        }
122
123        if ($platform->supportsSequences() === true) {
124            foreach ($this->changedSequences as $sequence) {
125                $sql[] = $platform->getAlterSequenceSQL($sequence);
126            }
127
128            if ($saveMode === false) {
129                foreach ($this->removedSequences as $sequence) {
130                    $sql[] = $platform->getDropSequenceSQL($sequence);
131                }
132            }
133
134            foreach ($this->newSequences as $sequence) {
135                $sql[] = $platform->getCreateSequenceSQL($sequence);
136            }
137        }
138
139        $foreignKeySql = [];
140        foreach ($this->newTables as $table) {
141            $sql = array_merge(
142                $sql,
143                $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES)
144            );
145
146            if (! $platform->supportsForeignKeyConstraints()) {
147                continue;
148            }
149
150            foreach ($table->getForeignKeys() as $foreignKey) {
151                $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table);
152            }
153        }
154        $sql = array_merge($sql, $foreignKeySql);
155
156        if ($saveMode === false) {
157            foreach ($this->removedTables as $table) {
158                $sql[] = $platform->getDropTableSQL($table);
159            }
160        }
161
162        foreach ($this->changedTables as $tableDiff) {
163            $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff));
164        }
165
166        return $sql;
167    }
168}
169