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