1 <?php
2
3 require_once("core/model/DB.php");
4
5 6 7 8 9 10 11 12 13
14 class DatabaseAdmin extends Controller {
15
16
17 static $allowed_actions = array(
18 'index',
19 'build',
20 'cleanup',
21 'testinstall',
22 'import'
23 );
24
25 function init() {
26 parent::init();
27
28
29
30
31
32 $canAccess = (
33 Director::isDev()
34 || !Security::database_is_ready()
35 || Director::is_cli()
36 || Permission::check("ADMIN")
37 );
38 if(!$canAccess) {
39 return Security::permissionFailure($this,
40 "This page is secured and you need administrator rights to access it. " .
41 "Enter your credentials below and we will send you right along.");
42 }
43 }
44
45 46 47 48 49
50 function groupedDataClasses() {
51
52 $allClasses = get_declared_classes();
53 foreach($allClasses as $class) {
54 if(get_parent_class($class) == "DataObject")
55 $rootClasses[$class] = array();
56 }
57
58
59 foreach($allClasses as $class) {
60 if(!isset($rootClasses[$class]) && is_subclass_of($class, "DataObject")) {
61 foreach($rootClasses as $rootClass => $dummy) {
62 if(is_subclass_of($class, $rootClass)) {
63 $rootClasses[$rootClass][] = $class;
64 break;
65 }
66 }
67 }
68 }
69 return $rootClasses;
70 }
71
72
73 74 75
76 function index() {
77 echo "<h2>Database Administration Helpers</h2>";
78 echo "<p><a href=\"build\">Add missing database fields (similar to sanity check).</a></p>";
79 echo "<p><a href=\"../images/flush\">Flush <b>all</b> of the generated images.</a></p>";
80 }
81
82
83 84 85
86 function build() {
87
88 increase_time_limit_to(600);
89
90
91 ManifestBuilder::create_manifest_file();
92 require(MANIFEST_FILE);
93
94 if(isset($_GET['returnURL'])) {
95 echo "<p>Setting up the database; you will be returned to your site shortly....</p>";
96 $this->doBuild(true);
97 echo "<p>Done!</p>";
98 Director::redirect($_GET['returnURL']);
99 } else {
100 if(!Director::is_cli() && Director::urlParam('Controller') == __CLASS__) {
101 echo '<p style="color: red;"><i>db/build</i> has been deprecated. Please use <b>dev/build</b> instead.</p>';
102 }
103 $this->doBuild(isset($_REQUEST['quiet']) || isset($_REQUEST['from_installer']), !isset($_REQUEST['dont_populate']));
104 }
105 }
106
107 108 109
110 static function autoBuild() {
111 $dataClasses = ClassInfo::subclassesFor('DataObject');
112 $lastBuilt = self::lastBuilt();
113 foreach($dataClasses as $class) {
114 if(filemtime(getClassFile($class)) > $lastBuilt) {
115 $da = new DatabaseAdmin();
116 $da->doBuild(true);
117 return;
118 }
119 }
120 }
121
122
123 124 125 126 127 128
129 static function lastBuilt() {
130 $file = TEMP_FOLDER . '/database-last-generated-' .
131 str_replace(array('\\','/',':'), '.' , Director::baseFolder());
132
133 if(file_exists($file)) {
134 return filemtime($file);
135 }
136 }
137
138
139 140 141 142 143 144
145 function doBuild($quiet = false, $populate = true, $testMode = false) {
146 if($quiet) {
147 DB::quiet();
148 } else {
149 $conn = DB::getConn();
150 $databaseName = (method_exists($conn, 'currentDatabase')) ? $conn->currentDatabase() : "";
151
152 if(Director::is_cli()) echo "\n\nBuilding Database $databaseName\n\n";
153 else echo "<h2>Building Database $databaseName</h2>";
154 }
155
156
157 if(!DB::isActive()) {
158 if(!$quiet) {
159 echo '<p><b>Creating database</b></p>';
160 }
161 global $databaseConfig;
162 $parameters = $databaseConfig ? $databaseConfig : $_REQUEST['db'];
163 $connect = DB::getConnect($parameters);
164 $username = $parameters['username'];
165 $password = $parameters['password'];
166 $database = $parameters['database'];
167
168 if(!$database) {
169 user_error("No database name given; please give a value for \$databaseConfig['database']", E_USER_ERROR);
170 }
171
172 DB::createDatabase($connect, $username, $password, $database);
173 }
174
175
176 $dataClasses = ClassInfo::subclassesFor('DataObject');
177 array_shift($dataClasses);
178
179 if(!$quiet) {
180 if(Director::is_cli()) echo "\nCREATING DATABASE TABLES\n\n";
181 else echo "\n<p><b>Creating database tables</b></p>\n\n";
182 }
183
184 $conn = DB::getConn();
185 $conn->beginSchemaUpdate();
186 foreach($dataClasses as $dataClass) {
187
188 if(class_exists($dataClass)) {
189 $SNG = singleton($dataClass);
190 if($testMode || !($SNG instanceof TestOnly)) {
191 if(!$quiet) {
192 if(Director::is_cli()) echo " * $dataClass\n";
193 else echo "<li>$dataClass</li>\n";
194 }
195 $SNG->requireTable();
196 }
197 }
198 }
199 $conn->endSchemaUpdate();
200 ClassInfo::reset_db_cache();
201
202 if($populate) {
203 if(!$quiet) {
204 if(Director::is_cli()) echo "\nCREATING DATABASE RECORDS\n\n";
205 else echo "\n<p><b>Creating database records</b></p>\n\n";
206 }
207
208 foreach($dataClasses as $dataClass) {
209
210
211 if(strpos($dataClass,'Test_') === false && class_exists($dataClass)) {
212 if(!$quiet) {
213 if(Director::is_cli()) echo " * $dataClass\n";
214 else echo "<li>$dataClass</li>\n";
215 }
216
217 singleton($dataClass)->requireDefaultRecords();
218 }
219 }
220 }
221
222 touch(TEMP_FOLDER . '/database-last-generated-' .
223 str_replace(array('\\', '/', ':'), '.', Director::baseFolder()));
224
225 if(isset($_REQUEST['from_installer'])) {
226 echo "OK";
227 }
228
229 if(!$quiet) echo "<p>Database build completed!</p>";
230 ClassInfo::reset_db_cache();
231 }
232
233 234 235 236
237 function clearAllData() {
238 $tables = DB::getConn()->tableList();
239 foreach($tables as $table) {
240 if(method_exists(DB::getConn(), 'clearTable')) DB::getConn()->clearTable($table);
241 else DB::query("TRUNCATE \"$table\"");
242 }
243 }
244
245
246 247 248
249 function testinstall() {
250 echo "OK";
251 }
252
253
254 255 256 257
258 function cleanup() {
259 $allClasses = get_declared_classes();
260 foreach($allClasses as $class) {
261 if(get_parent_class($class) == 'DataObject') {
262 $baseClasses[] = $class;
263 }
264 }
265
266 foreach($baseClasses as $baseClass) {
267
268 $subclasses = ClassInfo::subclassesFor($baseClass);
269 unset($subclasses[0]);
270 foreach($subclasses as $k => $subclass) {
271 if(DataObject::database_fields($subclass)) {
272 unset($subclasses[$k]);
273 }
274 }
275
276 if($subclasses) {
277 $records = DB::query("SELECT * FROM \"$baseClass\"");
278
279
280 foreach($subclasses as $subclass) {
281 $recordExists[$subclass] =
282 DB::query("SELECT \"ID\" FROM \"$subclass\"")->keyedColumn();
283 }
284
285 foreach($records as $record) {
286 foreach($subclasses as $subclass) {
287 $id = $record['ID'];
288 if(($record['ClassName'] != $subclass) &&
289 (!is_subclass_of($record['ClassName'], $subclass)) &&
290 (isset($recordExists[$subclass][$id]))) {
291 $sql = "DELETE FROM \"$subclass\" WHERE \"ID\" = $record[ID]";
292 echo "<li>$sql";
293 DB::query($sql);
294 }
295 }
296 }
297 }
298 }
299 }
300
301 }
302
303 ?>
304
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-