| 1 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
/*
|
|
|
4 |
* $Id: PropelSQLTask.php 1262 2009-10-26 20:54:39Z francois $
|
|
|
5 |
*
|
|
|
6 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
7 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
8 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
9 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
10 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
11 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
12 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
13 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
14 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
15 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
16 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
17 |
*
|
|
|
18 |
* This software consists of voluntary contributions made by many individuals
|
|
|
19 |
* and is licensed under the LGPL. For more information please see
|
|
|
20 |
* <http://propel.phpdb.org>.
|
|
|
21 |
*/
|
|
|
22 |
|
|
|
23 |
include_once 'propel/engine/database/model/AppData.php';
|
|
|
24 |
|
|
|
25 |
/**
|
|
|
26 |
* The task for building SQL DDL based on the XML datamodel.
|
|
|
27 |
*
|
|
|
28 |
* This class uses the new DDLBuilder classes instead of the Capsule PHP templates.
|
|
|
29 |
*
|
|
|
30 |
* @author Hans Lellelid <hans@xmpl.org>
|
|
|
31 |
* @package propel.phing
|
|
|
32 |
*/
|
|
|
33 |
class PropelSQLTask extends AbstractPropelDataModelTask {
|
|
|
34 |
|
|
|
35 |
/**
|
|
|
36 |
* The properties file that maps an SQL file to a particular database.
|
|
|
37 |
* @var PhingFile
|
|
|
38 |
*/
|
|
|
39 |
private $sqldbmap;
|
|
|
40 |
|
|
|
41 |
/**
|
|
|
42 |
* Name of the database.
|
|
|
43 |
*/
|
|
|
44 |
private $database;
|
|
|
45 |
|
|
|
46 |
/**
|
|
|
47 |
* Set the sqldbmap.
|
|
|
48 |
* @param PhingFile $sqldbmap The db map.
|
|
|
49 |
*/
|
|
|
50 |
public function setSqlDbMap(PhingFile $sqldbmap)
|
|
|
51 |
{
|
|
|
52 |
$this->sqldbmap = $sqldbmap;
|
|
|
53 |
}
|
|
|
54 |
|
|
|
55 |
/**
|
|
|
56 |
* Get the sqldbmap.
|
|
|
57 |
* @return PhingFile $sqldbmap.
|
|
|
58 |
*/
|
|
|
59 |
public function getSqlDbMap()
|
|
|
60 |
{
|
|
|
61 |
return $this->sqldbmap;
|
|
|
62 |
}
|
|
|
63 |
|
|
|
64 |
/**
|
|
|
65 |
* Set the database name.
|
|
|
66 |
* @param string $database
|
|
|
67 |
*/
|
|
|
68 |
public function setDatabase($database)
|
|
|
69 |
{
|
|
|
70 |
$this->database = $database;
|
|
|
71 |
}
|
|
|
72 |
|
|
|
73 |
/**
|
|
|
74 |
* Get the database name.
|
|
|
75 |
* @return string
|
|
|
76 |
*/
|
|
|
77 |
public function getDatabase()
|
|
|
78 |
{
|
|
|
79 |
return $this->database;
|
|
|
80 |
}
|
|
|
81 |
|
|
|
82 |
/**
|
|
|
83 |
* Create the sql -> database map.
|
|
|
84 |
*
|
|
|
85 |
* @throws IOException - if unable to store properties
|
|
|
86 |
*/
|
|
|
87 |
protected function createSqlDbMap()
|
|
|
88 |
{
|
|
|
89 |
if ($this->getSqlDbMap() === null) {
|
|
|
90 |
return;
|
|
|
91 |
}
|
|
|
92 |
|
|
|
93 |
// Produce the sql -> database map
|
|
|
94 |
$sqldbmap = new Properties();
|
|
|
95 |
|
|
|
96 |
// Check to see if the sqldbmap has already been created.
|
|
|
97 |
if ($this->getSqlDbMap()->exists()) {
|
|
|
98 |
$sqldbmap->load($this->getSqlDbMap());
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
if ($this->packageObjectModel) {
|
|
|
102 |
// in this case we'll get the sql file name from the package attribute
|
|
|
103 |
$dataModels = $this->packageDataModels();
|
|
|
104 |
foreach ($dataModels as $package => $dataModel) {
|
|
|
105 |
foreach ($dataModel->getDatabases() as $database) {
|
|
|
106 |
$name = ($package ? $package . '.' : '') . 'schema.xml';
|
|
|
107 |
$sqlFile = $this->getMappedFile($name);
|
|
|
108 |
$sqldbmap->setProperty($sqlFile->getName(), $database->getName());
|
|
|
109 |
}
|
|
|
110 |
}
|
|
|
111 |
} else {
|
|
|
112 |
// the traditional way is to map the schema.xml filenames
|
|
|
113 |
$dmMap = $this->getDataModelDbMap();
|
|
|
114 |
foreach (array_keys($dmMap) as $dataModelName) {
|
|
|
115 |
$sqlFile = $this->getMappedFile($dataModelName);
|
|
|
116 |
if ($this->getDatabase() === null) {
|
|
|
117 |
$databaseName = $dmMap[$dataModelName];
|
|
|
118 |
} else {
|
|
|
119 |
$databaseName = $this->getDatabase();
|
|
|
120 |
}
|
|
|
121 |
$sqldbmap->setProperty($sqlFile->getName(), $databaseName);
|
|
|
122 |
}
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
try {
|
|
|
126 |
$sqldbmap->store($this->getSqlDbMap(), "Sqlfile -> Database map");
|
|
|
127 |
} catch (IOException $e) {
|
|
|
128 |
throw new IOException("Unable to store properties: ". $e->getMessage());
|
|
|
129 |
}
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
public function main() {
|
|
|
133 |
|
|
|
134 |
$this->validate();
|
|
|
135 |
|
|
|
136 |
if (!$this->mapperElement) {
|
|
|
137 |
throw new BuildException("You must use a <mapper/> element to describe how names should be transformed.");
|
|
|
138 |
}
|
|
|
139 |
|
|
|
140 |
if ($this->packageObjectModel) {
|
|
|
141 |
$dataModels = $this->packageDataModels();
|
|
|
142 |
} else {
|
|
|
143 |
$dataModels = $this->getDataModels();
|
|
|
144 |
}
|
|
|
145 |
|
|
|
146 |
// 1) first create a map of filenames to databases; this is used by other tasks like
|
|
|
147 |
// the SQLExec task.
|
|
|
148 |
$this->createSqlDbMap();
|
|
|
149 |
|
|
|
150 |
// 2) Now actually create the DDL based on the datamodel(s) from XML schema file.
|
|
|
151 |
$targetDatabase = $this->getTargetDatabase();
|
|
|
152 |
|
|
|
153 |
$generatorConfig = $this->getGeneratorConfig();
|
|
|
154 |
|
|
|
155 |
$builderClazz = $generatorConfig->getBuilderClassname('ddl');
|
|
|
156 |
|
|
|
157 |
foreach ($dataModels as $package => $dataModel) {
|
|
|
158 |
|
|
|
159 |
foreach ($dataModel->getDatabases() as $database) {
|
|
|
160 |
|
|
|
161 |
// Clear any start/end DLL
|
|
|
162 |
call_user_func(array($builderClazz, 'reset'));
|
|
|
163 |
|
|
|
164 |
// file we are going to create
|
|
|
165 |
if (!$this->packageObjectModel) {
|
|
|
166 |
$name = $dataModel->getName();
|
|
|
167 |
} else {
|
|
|
168 |
$name = ($package ? $package . '.' : '') . 'schema.xml';
|
|
|
169 |
}
|
|
|
170 |
|
|
|
171 |
$outFile = $this->getMappedFile($name);
|
|
|
172 |
|
|
|
173 |
$this->log("Writing to SQL file: " . $outFile->getPath());
|
|
|
174 |
|
|
|
175 |
// First add any "header" SQL
|
|
|
176 |
$ddl = call_user_func(array($builderClazz, 'getDatabaseStartDDL'));
|
|
|
177 |
|
|
|
178 |
foreach ($database->getTables() as $table) {
|
|
|
179 |
|
|
|
180 |
if (!$table->isSkipSql()) {
|
|
|
181 |
$builder = $generatorConfig->getConfiguredBuilder($table, 'ddl');
|
|
|
182 |
$this->log("\t+ " . $table->getName() . " [builder: " . get_class($builder) . "]");
|
|
|
183 |
$ddl .= $builder->build();
|
|
|
184 |
foreach ($builder->getWarnings() as $warning) {
|
|
|
185 |
$this->log($warning, Project::MSG_WARN);
|
|
|
186 |
}
|
|
|
187 |
} else {
|
|
|
188 |
$this->log("\t + (skipping) " . $table->getName());
|
|
|
189 |
}
|
|
|
190 |
|
|
|
191 |
} // foreach database->getTables()
|
|
|
192 |
|
|
|
193 |
// Finally check to see if there is any "footer" SQL
|
|
|
194 |
$ddl .= call_user_func(array($builderClazz, 'getDatabaseEndDDL'));
|
|
|
195 |
|
|
|
196 |
#var_dump($outFile->getAbsolutePath());
|
|
|
197 |
// Now we're done. Write the file!
|
|
|
198 |
file_put_contents($outFile->getAbsolutePath(), $ddl);
|
|
|
199 |
|
|
|
200 |
} // foreach database
|
|
|
201 |
} //foreach datamodels
|
|
|
202 |
|
|
|
203 |
} // main()
|
|
|
204 |
|
|
|
205 |
/**
|
|
|
206 |
* Packages the datamodels to one datamodel per package
|
|
|
207 |
*
|
|
|
208 |
* This applies only when the the packageObjectModel option is set. We need to
|
|
|
209 |
* re-package the datamodels to allow the database package attribute to control
|
|
|
210 |
* which tables go into which SQL file.
|
|
|
211 |
*
|
|
|
212 |
* @return array The packaged datamodels
|
|
|
213 |
*/
|
|
|
214 |
protected function packageDataModels() {
|
|
|
215 |
|
|
|
216 |
static $packagedDataModels;
|
|
|
217 |
|
|
|
218 |
if (is_null($packagedDataModels)) {
|
|
|
219 |
|
|
|
220 |
$dataModels = $this->getDataModels();
|
|
|
221 |
$dataModel = array_shift($dataModels);
|
|
|
222 |
$packagedDataModels = array();
|
|
|
223 |
|
|
|
224 |
$platform = $this->getGeneratorConfig()->getConfiguredPlatform();
|
|
|
225 |
|
|
|
226 |
foreach ($dataModel->getDatabases() as $db) {
|
|
|
227 |
foreach ($db->getTables() as $table) {
|
|
|
228 |
$package = $table->getPackage();
|
|
|
229 |
if (!isset($packagedDataModels[$package])) {
|
|
|
230 |
$dbClone = $this->cloneDatabase($db);
|
|
|
231 |
$dbClone->setPackage($package);
|
|
|
232 |
$ad = new AppData($platform);
|
|
|
233 |
$ad->setName($dataModel->getName());
|
|
|
234 |
$ad->addDatabase($dbClone);
|
|
|
235 |
$packagedDataModels[$package] = $ad;
|
|
|
236 |
}
|
|
|
237 |
$packagedDataModels[$package]->getDatabase($db->getName())->addTable($table);
|
|
|
238 |
}
|
|
|
239 |
}
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
return $packagedDataModels;
|
|
|
243 |
}
|
|
|
244 |
|
|
|
245 |
protected function cloneDatabase($db) {
|
|
|
246 |
|
|
|
247 |
$attributes = array (
|
|
|
248 |
'name' => $db->getName(),
|
|
|
249 |
'baseClass' => $db->getBaseClass(),
|
|
|
250 |
'basePeer' => $db->getBasePeer(),
|
|
|
251 |
'defaultIdMethod' => $db->getDefaultIdMethod(),
|
|
|
252 |
'defaultPhpNamingMethod' => $db->getDefaultPhpNamingMethod(),
|
|
|
253 |
'defaultTranslateMethod' => $db->getDefaultTranslateMethod(),
|
|
|
254 |
'heavyIndexing' => $db->getHeavyIndexing(),
|
|
|
255 |
);
|
|
|
256 |
|
|
|
257 |
$clone = new Database();
|
|
|
258 |
$clone->loadFromXML($attributes);
|
|
|
259 |
return $clone;
|
|
|
260 |
}
|
|
|
261 |
}
|