[BUGFIX] Some methods in t3lib_TSparser should be static
[Packages/TYPO3.CMS.git] / typo3 / sysext / em / classes / database / class.tx_em_database.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
6 * (c) 2010 Steffen Kamper <info@sk-typo3.de>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 *
18 * This script is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
25 /**
26 * class.tx_em_database.php
27 *
28 * Module: Extension manager - DB access
29 *
30 * @author Marcus Krause <marcus#exp2010@t3sec.info>
31 * @author Steffen Kamper <info@sk-typo3.de>
32 */
33
34 /**
35 * DB access class for extension manager.
36 *
37 * Contains static methods for DB operations.
38 *
39 * @author Marcus Krause <marcus#exp2010@t3sec.info>
40 * @author Steffen Kamper <info@sk-typo3.de>
41 *
42 * @since 2010-02-27
43 * @package TYPO3
44 * @subpackage EM
45 */
46 final class tx_em_Database {
47
48 const MULTI_LINEBREAKS = "\n\n\n";
49
50 const TABLE_REPOSITORY = 'sys_ter';
51
52 const TABLE_EXTENSION = 'cache_extensions';
53
54
55 /**
56 * Get the count of extensions in cache_extensions from a repository.
57 *
58 * If $repository parameter is obmitted, sum of all extensions will be
59 * returned.
60 *
61 * @access public
62 * @param integer $repository (optional) repository uid of extensions to count
63 * @return integer sum of extensions in database
64 */
65 public function getExtensionCountFromRepository($repository = NULL) {
66 if (is_null($repository)) {
67 return $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
68 'DISTINCT extkey',
69 self::TABLE_EXTENSION
70 );
71 } else {
72 return $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
73 'DISTINCT extkey',
74 self::TABLE_EXTENSION,
75 'repository=' . intval($repository)
76 );
77 }
78 }
79
80 /**
81 * Get extension list from cache_extensions
82 *
83 * @param int $repository
84 * @param string $addFields
85 * @param string $andWhere
86 * @param string $order
87 * @param string $limit
88 * @return array
89 */
90 public function getExtensionListFromRepository($repository, $addFields = '', $andWhere = '', $order = '', $limit = '') {
91 $ret = array();
92 $temp = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
93 'count(*) AS count',
94 'cache_extensions',
95 'repository=' . intval($repository) . $andWhere,
96 'extkey'
97 );
98 $ret['count'] = count($temp);
99
100 $ret['results'] = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
101 'cache_extensions.*, count(*) AS versions, cache_extensions.intversion AS maxintversion' .
102 ($addFields === '' ? '' : ',' . $addFields),
103 'cache_extensions JOIN cache_extensions AS ce ON cache_extensions.extkey = ce.extkey',
104 'cache_extensions.lastversion=1 AND cache_extensions.repository=' . intval($repository) . $andWhere,
105 'ce.extkey',
106 $order,
107 $limit
108 );
109 //debug($GLOBALS['TYPO3_DB']->debug_lastBuiltQuery);
110 return $ret;
111 }
112
113 /**
114 * Get versions of extension
115 *
116 * @param int $repository
117 * @param string $extKey
118 * @return array $versions
119 */
120 public function getExtensionVersionsFromRepository($repository, $extKey) {
121 $versions = array();
122 //TODO: implement
123 return $versions;
124 }
125
126 /**
127 * Function inserts a repository object into database.
128 *
129 * @access public
130 * @param tx_em_Repository $repository repository object
131 * @return void
132 */
133 public function updateRepository(tx_em_Repository $repository) {
134 $repositoryData = array(
135 'title' => $repository->getTitle(),
136 'description' => $repository->getDescription(),
137 'wsdl_url' => $repository->getWsdlUrl(),
138 'mirror_url' => $repository->getMirrorListUrl(),
139 'lastUpdated' => $repository->getLastUpdate(),
140 'extCount' => $repository->getExtensionCount(),
141 );
142 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
143 self::TABLE_REPOSITORY,
144 'uid=' . $repository->getId(),
145 $repositoryData
146 );
147
148 }
149
150
151 /**
152 * Function inserts a repository object into database.
153 *
154 * @access public
155 * @param tx_em_Repository $repository repository object
156 * @return integer UID of the newly inserted repository object
157 */
158 public function insertRepository(tx_em_Repository $repository) {
159 $repositoryData = array(
160 'title' => $repository->getTitle(),
161 'description' => $repository->getDescription(),
162 'wsdl_url' => $repository->getWsdlUrl(),
163 'mirror_url' => $repository->getMirrorListUrl(),
164 'lastUpdated' => $repository->getLastUpdate(),
165 'extCount' => $repository->getExtensionCount(),
166 );
167 $GLOBALS['TYPO3_DB']->exec_INSERTquery(
168 self::TABLE_REPOSITORY,
169 $repositoryData
170 );
171 return $GLOBALS['TYPO3_DB']->sql_insert_id();
172 }
173
174 /**
175 * Deletes given Repository
176 *
177 * @param tx_em_Repository $repository repository object
178 * @return void
179 */
180 public function deleteRepository(tx_em_Repository $repository) {
181 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
182 self::TABLE_REPOSITORY,
183 'uid=' . $repository->getId()
184 );
185 }
186
187 /**
188 * Updates ExtCount and lastUpdated in Repository eg after import
189 * @param int $extCount
190 * @param int $uid
191 * @return void
192 */
193 public function updateRepositoryCount($extCount, $uid = 1) {
194 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
195 self::TABLE_REPOSITORY,
196 'uid=' . intval($uid),
197 array (
198 'lastUpdated' => time(),
199 'extCount' => intval($extCount)
200 ));
201 }
202
203 /**
204 * Insert version
205 *
206 * @param $arrFields
207 * @return void
208 */
209 public function insertVersion(array $arrFields) {
210 $GLOBALS['TYPO3_DB']->exec_INSERTquery(self::TABLE_EXTENSION, $arrFields);
211 }
212
213 /**
214 * Update the lastversion field after update
215 *
216 * @param int $repositoryUid
217 * @return integer
218 */
219 public function insertLastVersion($repositoryUid = 1) {
220 $groupedRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
221 'extkey, version, max(intversion) maxintversion',
222 'cache_extensions',
223 'repository=' . intval($repositoryUid),
224 'extkey'
225 );
226 $extensions = count($groupedRows);
227
228 if ($extensions > 0) {
229 // set all to 0
230 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
231 'cache_extensions',
232 'lastversion=1 AND repository=' . intval($repositoryUid),
233 array('lastversion' => 0)
234 );
235
236 // Find latest version of extensions and set lastversion to 1 for these
237 foreach ($groupedRows as $row) {
238 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
239 'cache_extensions',
240 'extkey="' . $row['extkey'] . '" AND intversion="' . $row['maxintversion'] . '" AND repository=' . intval($repositoryUid),
241 array('lastversion' => 1)
242 );
243 }
244 }
245
246 return $extensions;
247 }
248
249
250 /**
251 * Method finds and returns repository fields identified by its UID.
252 *
253 * @access public
254 * @param int $uid repository UID
255 * @return array
256 */
257 public function getRepositoryByUID($uid) {
258 $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', self::TABLE_REPOSITORY, 'uid=' . intval($uid));
259
260 return $row;
261 }
262
263 /**
264 * Method finds and returns repository identified by its title
265 *
266 * @param $title
267 * @return array
268 */
269 public function getRepositoryByTitle($title) {
270 return $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
271 '*',
272 self::TABLE_REPOSITORY,
273 'title=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($title,
274 self::TABLE_REPOSITORY)
275 );
276 }
277
278 /**
279 * Get available repositories
280 *
281 * @param string $where
282 * @return array
283 */
284 public function getRepositories($where = NULL) {
285 return $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
286 '*',
287 self::TABLE_REPOSITORY,
288 $where ? $where : ''
289 );
290 }
291
292 /**
293 * Dump table content
294 * Is DBAL compliant, but the dump format is written as MySQL standard. If the INSERT statements should be imported in a DBMS using other quoting than MySQL they must first be translated. t3lib_sqlengine can parse these queries correctly and translate them somehow.
295 *
296 * @param string Table name
297 * @param array Field structure
298 * @return string SQL Content of dump (INSERT statements)
299 */
300 function dumpTableContent($table, $fieldStructure) {
301
302 // Substitution of certain characters (borrowed from phpMySQL):
303 $search = array('\\', '\'', "\x00", "\x0a", "\x0d", "\x1a");
304 $replace = array('\\\\', '\\\'', '\0', '\n', '\r', '\Z');
305
306 $lines = array();
307
308 // Select all rows from the table:
309 $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, '');
310
311 // Traverse the selected rows and dump each row as a line in the file:
312 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
313 $values = array();
314 foreach ($fieldStructure as $field => $structure) {
315 $values[] = isset($row[$field]) ? "'" . str_replace($search, $replace, $row[$field]) . "'" : 'NULL';
316 }
317 $lines[] = 'INSERT INTO ' . $table . ' VALUES (' . implode(', ', $values) . ');';
318 }
319
320 // Free DB result:
321 $GLOBALS['TYPO3_DB']->sql_free_result($result);
322
323 // Implode lines and return:
324 return implode(LF, $lines);
325 }
326
327 /**
328 * Gets the table and field structure from database.
329 * Which fields and which tables are determined from the ext_tables.sql file
330 *
331 * @param string Array with table.field values
332 * @return array Array of tables and fields splitted.
333 */
334 function getTableAndFieldStructure($parts) {
335 /** @var $instObj t3lib_install_Sql */
336 $instObj = t3lib_div::makeInstance('t3lib_install_Sql');
337 $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db);
338
339 $outTables = array();
340 foreach ($parts as $table) {
341 $sub = explode('.', $table);
342 if ($sub[0] && isset($dbFields[$sub[0]])) {
343 if ($sub[1]) {
344 $key = explode('KEY:', $sub[1], 2);
345 if (count($key) == 2 && !$key[0]) { // key:
346 if (isset($dbFields[$sub[0]]['keys'][$key[1]])) {
347 $outTables[$sub[0]]['keys'][$key[1]] = $dbFields[$sub[0]]['keys'][$key[1]];
348 }
349 } else {
350 if (isset($dbFields[$sub[0]]['fields'][$sub[1]])) {
351 $outTables[$sub[0]]['fields'][$sub[1]] = $dbFields[$sub[0]]['fields'][$sub[1]];
352 }
353 }
354 } else {
355 $outTables[$sub[0]] = $dbFields[$sub[0]];
356 }
357 }
358 }
359
360 return $outTables;
361 }
362
363
364 /**
365 * Makes a dump of the tables/fields definitions for an extension
366 *
367 * @param array Array with table => field/key definition arrays in
368 * @return string SQL for the table definitions
369 * @see dumpStaticTables()
370 */
371 function dumpTableAndFieldStructure($arr) {
372 $tables = array();
373
374 if (count($arr)) {
375
376 // Get file header comment:
377 $tables[] = self::dumpHeader();
378
379 // Traverse tables, write each table/field definition:
380 foreach ($arr as $table => $fieldKeyInfo) {
381 $tables[] = self::dumpTableHeader($table, $fieldKeyInfo);
382 }
383 }
384
385 // Return result:
386 return implode(LF . LF . LF, $tables);
387 }
388
389 /**
390 * Link to dump of database tables
391 *
392 * @param array $tablesArray
393 * @param string $extKey
394 * @param array $additionalLinkParameter
395 * @return string HTML
396 */
397 function dumpDataTablesLine($tablesArray, $extKey, $additionalLinkParameter = array()) {
398 $tables = array();
399 $tablesNA = array();
400 $allTables = array_keys($GLOBALS['TYPO3_DB']->admin_get_tables());
401
402 foreach ($tablesArray as $tableName) {
403 if (in_array($tableName, $allTables)) {
404 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $tableName);
405 $tables[$tableName] = '<tr><td>&nbsp;</td><td>
406 <a class="t3-link dumpLink" href="' .
407 htmlspecialchars(t3lib_div::linkThisScript(
408 array_merge(array(
409 'CMD[dumpTables]' => $tableName,
410 'CMD[showExt]' => $extKey,
411 ), $additionalLinkParameter)
412 )) .
413 '" title="' .
414 sprintf($GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_dump_table'),
415 $tableName) .
416 '">' . $tableName . '</a></td><td>&nbsp;&nbsp;&nbsp;</td><td>' .
417 sprintf($GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_number_of_records'),
418 $count) . '</td></tr>';
419 } else {
420 $tablesNA[$tableName] = '<tr><td>&nbsp;</td><td>' . $tableName . '</td><td>&nbsp;</td><td>' .
421 $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_table_not_there') . '</td></tr>';
422 }
423 }
424 $label = '<table border="0" cellpadding="0" cellspacing="0">' .
425 implode('', array_merge($tables, $tablesNA)) .
426 '</table>';
427 if (count($tables)) {
428 $label = '<a class="t3-link dumpLink" href="' .
429 htmlspecialchars(t3lib_div::linkThisScript(
430 array_merge(array(
431 'CMD[dumpTables]' => implode(',', array_keys($tables)),
432 'CMD[showExt]' => $extKey
433 ), $additionalLinkParameter)
434 )) .
435 '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_dump_all_tables') . '">' .
436 $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_download_all_data') . '</a><br /><br />' . $label;
437 }
438 else {
439 $label = $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:extBackup_nothing_to_dump') . '<br /><br />' . $label;
440 }
441 return $label;
442 }
443
444 /**
445 * Dump content for static tables
446 *
447 * @param string Comma list of tables from which to dump content
448 * @return string Returns the content
449 * @see dumpTableAndFieldStructure()
450 */
451 function dumpStaticTables($tableList) {
452 /** @var $instObj t3lib_install_Sql */
453 $instObj = t3lib_div::makeInstance('t3lib_install_Sql');
454 $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db);
455
456 $out = '';
457 $parts = t3lib_div::trimExplode(',', $tableList, TRUE);
458
459 // Traverse the table list and dump each:
460 foreach ($parts as $table) {
461 if (is_array($dbFields[$table]['fields'])) {
462 $header = self::dumpHeader();
463 $tableHeader = self::dumpTableHeader($table, $dbFields[$table], TRUE);
464 $insertStatements = self::dumpTableContent($table, $dbFields[$table]['fields']);
465 $out .= $header . self::MULTI_LINEBREAKS .
466 $tableHeader . self::MULTI_LINEBREAKS .
467 $insertStatements . self::MULTI_LINEBREAKS;
468 } else {
469 throw new RuntimeException(
470 'TYPO3 Fatal Error: ' . $GLOBALS['LANG']->getLL('dumpStaticTables_table_not_found'),
471 1270853983
472 );
473 }
474 }
475 unset($instObj);
476 return $out;
477 }
478
479 /**
480 * Header comments of the SQL dump file
481 *
482 * @return string Table header
483 */
484 function dumpHeader() {
485 return trim('
486 # TYPO3 Extension Manager dump 1.1
487 #
488 # Host: ' . TYPO3_db_host . ' Database: ' . TYPO3_db . '
489 #--------------------------------------------------------
490 ');
491 }
492
493 /**
494 * Dump CREATE TABLE definition
495 *
496 * @param string Table name
497 * @param array Field and key information (as provided from Install Tool class!)
498 * @param boolean If TRUE, add "DROP TABLE IF EXISTS"
499 * @return string Table definition SQL
500 */
501 function dumpTableHeader($table, $fieldKeyInfo, $dropTableIfExists = 0) {
502 $lines = array();
503 $dump = '';
504
505 // Create field definitions
506 if (is_array($fieldKeyInfo['fields'])) {
507 foreach ($fieldKeyInfo['fields'] as $fieldN => $data) {
508 $lines[] = ' ' . $fieldN . ' ' . $data;
509 }
510 }
511
512 // Create index key definitions
513 if (is_array($fieldKeyInfo['keys'])) {
514 foreach ($fieldKeyInfo['keys'] as $fieldN => $data) {
515 $lines[] = ' ' . $data;
516 }
517 }
518
519 // Compile final output:
520 if (count($lines)) {
521 $dump = trim('
522 #
523 # Table structure for table "' . $table . '"
524 #
525 ' . ($dropTableIfExists ? 'DROP TABLE IF EXISTS ' . $table . ';
526 ' : '') . 'CREATE TABLE ' . $table . ' (
527 ' . implode(',' . LF, $lines) . '
528 );');
529 }
530
531 return $dump;
532 }
533
534 }
535
536 ?>