Fixed time zone calculation issue
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / package / plugin / SQLPackageInstallationPlugin.class.php
1 <?php
2 namespace wcf\system\package\plugin;
3 use wcf\data\package\Package;
4 use wcf\data\package\PackageList;
5 use wcf\system\exception\SystemException;
6 use wcf\system\package\PackageInstallationSQLParser;
7 use wcf\system\WCF;
8
9 /**
10 * Executes the delivered sql file.
11 *
12 * @author Alexander Ebert
13 * @copyright 2001-2014 WoltLab GmbH
14 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
15 * @package com.woltlab.wcf
16 * @subpackage system.package.plugin
17 * @category Community Framework
18 */
19 class SQLPackageInstallationPlugin extends AbstractPackageInstallationPlugin {
20 /**
21 * @see \wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
22 */
23 public $tableName = 'package_installation_sql_log';
24
25 /**
26 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::install()
27 */
28 public function install() {
29 parent::install();
30
31 // extract sql file from archive
32 if ($queries = $this->getSQL($this->instruction['value'])) {
33 $package = $this->installation->getPackage();
34
35 // replace app1_ with app{WCF_N}_ in the table names for
36 // all applications
37 $packageList = new PackageList();
38 $packageList->getConditionBuilder()->add('package.isApplication = ?', array(1));
39 $packageList->readObjects();
40 foreach ($packageList as $package) {
41 $abbreviation = Package::getAbbreviation($package->package);
42
43 $queries = str_replace($abbreviation.'1_', $abbreviation.WCF_N.'_', $queries);
44 }
45
46 // check queries
47 $parser = new PackageInstallationSQLParser($queries, $this->installation->getPackage(), $this->installation->getAction());
48 $conflicts = $parser->test();
49 if (!empty($conflicts) && (isset($conflicts['CREATE TABLE']) || isset($conflicts['DROP TABLE']))) {
50 $unknownCreateTable = isset($conflicts['CREATE TABLE']) ? $conflicts['CREATE TABLE'] : array();
51 $unknownDropTable = isset($conflicts['DROP TABLE']) ? $conflicts['DROP TABLE'] : array();
52
53 $errorMessage = "Can't";
54 if (!empty($unknownDropTable)) {
55 $errorMessage .= " drop unknown table";
56 if (count($unknownDropTable) > 1) {
57 $errorMessage .= "s";
58 }
59 $errorMessage .= " '".implode("', '", $unknownDropTable)."'";
60 }
61 if (!empty($unknownCreateTable)) {
62 if (!empty($unknownDropTable)) {
63 $errorMessage .= " and can't";
64 }
65
66 $errorMessage .= " overwrite unknown table";
67 if (count($unknownCreateTable) > 1) {
68 $errorMessage .= "s";
69 }
70 $errorMessage .= " '".implode("', '", $unknownCreateTable)."'";
71 }
72
73 throw new SystemException($errorMessage);
74 }
75
76 // execute queries
77 $parser->execute();
78
79 // log changes
80 $parser->log();
81 }
82 }
83
84 /**
85 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::uninstall()
86 */
87 public function uninstall() {
88 // get logged sql tables/columns
89 $sql = "SELECT *
90 FROM wcf".WCF_N."_package_installation_sql_log
91 WHERE packageID = ?
92 ORDER BY sqlIndex DESC, sqlColumn DESC";
93 $statement = WCF::getDB()->prepareStatement($sql);
94 $statement->execute(array($this->installation->getPackageID()));
95 $entries = array();
96 while ($row = $statement->fetchArray()) {
97 $entries[] = $row;
98 }
99
100 // get all tablenames from database
101 $existingTableNames = WCF::getDB()->getEditor()->getTablenames();
102
103 // delete or alter tables
104 foreach ($entries as $entry) {
105 // don't alter table if it should be dropped
106 if (!empty($entry['sqlColumn'])/* || !empty($entry['sqlIndex'])*/) {
107 $isDropped = false;
108 foreach ($entries as $entry2) {
109 if ($entry['sqlTable'] == $entry2['sqlTable'] && empty($entry2['sqlColumn']) && empty($entry2['sqlIndex'])) {
110 $isDropped = true;
111 }
112 }
113 if ($isDropped) continue;
114 }
115 // drop table
116 if (!empty($entry['sqlTable']) && empty($entry['sqlColumn']) && empty($entry['sqlIndex'])) {
117 WCF::getDB()->getEditor()->dropTable($entry['sqlTable']);
118 }
119 // drop column
120 else if (in_array($entry['sqlTable'], $existingTableNames) && !empty($entry['sqlColumn'])) {
121 WCF::getDB()->getEditor()->dropColumn($entry['sqlTable'], $entry['sqlColumn']);
122 }
123 // drop index
124 else if (in_array($entry['sqlTable'], $existingTableNames) && !empty($entry['sqlIndex'])) {
125 if (substr($entry['sqlIndex'], -3) == '_fk') {
126 WCF::getDB()->getEditor()->dropForeignKey($entry['sqlTable'], $entry['sqlIndex']);
127 }
128 else {
129 WCF::getDB()->getEditor()->dropIndex($entry['sqlTable'], $entry['sqlIndex']);
130 }
131 }
132 }
133 // delete from log table
134 parent::uninstall();
135 }
136
137 /**
138 * Extracts and returns the sql file.
139 * If the specified sql file was not found, an error message is thrown.
140 *
141 * @param string $filename
142 * @return string
143 */
144 protected function getSQL($filename) {
145 // search sql files in package archive
146 if (($fileindex = $this->installation->getArchive()->getTar()->getIndexByFilename($filename)) === false) {
147 throw new SystemException("SQL file '".$filename."' not found.");
148 }
149
150 // extract sql file to string
151 return $this->installation->getArchive()->getTar()->extractToString($fileindex);
152 }
153 }