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\PackageArchive
;
7 use wcf\system\package\PackageInstallationSQLParser
;
11 * Executes the delivered sql file.
13 * @author Alexander Ebert
14 * @copyright 2001-2014 WoltLab GmbH
15 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
16 * @package com.woltlab.wcf
17 * @subpackage system.package.plugin
18 * @category Community Framework
20 class SQLPackageInstallationPlugin
extends AbstractPackageInstallationPlugin
{
22 * @see \wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
24 public $tableName = 'package_installation_sql_log';
27 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::install()
29 public function install() {
32 // extract sql file from archive
33 if ($queries = $this->getSQL($this->instruction
['value'])) {
34 $package = $this->installation
->getPackage();
36 // replace app1_ with app{WCF_N}_ in the table names for
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
);
44 $queries = str_replace($abbreviation.'1_', $abbreviation.WCF_N
.'_', $queries);
48 $parser = new PackageInstallationSQLParser($queries, $this->installation
->getPackage(), $this->installation
->getAction());
49 $conflicts = $parser->test();
50 if (!empty($conflicts) && (isset($conflicts['CREATE TABLE']) ||
isset($conflicts['DROP TABLE']))) {
51 $unknownCreateTable = isset($conflicts['CREATE TABLE']) ?
$conflicts['CREATE TABLE'] : array();
52 $unknownDropTable = isset($conflicts['DROP TABLE']) ?
$conflicts['DROP TABLE'] : array();
54 $errorMessage = "Can't";
55 if (!empty($unknownDropTable)) {
56 $errorMessage .= " drop unknown table";
57 if (count($unknownDropTable) > 1) {
60 $errorMessage .= " '".implode("', '", $unknownDropTable)."'";
62 if (!empty($unknownCreateTable)) {
63 if (!empty($unknownDropTable)) {
64 $errorMessage .= " and can't";
67 $errorMessage .= " overwrite unknown table";
68 if (count($unknownCreateTable) > 1) {
71 $errorMessage .= " '".implode("', '", $unknownCreateTable)."'";
74 throw new SystemException($errorMessage);
86 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::uninstall()
88 public function uninstall() {
89 // get logged sql tables/columns
91 FROM wcf".WCF_N
."_package_installation_sql_log
93 ORDER BY sqlIndex DESC, sqlColumn DESC";
94 $statement = WCF
::getDB()->prepareStatement($sql);
95 $statement->execute(array($this->installation
->getPackageID()));
97 while ($row = $statement->fetchArray()) {
101 // get all tablenames from database
102 $existingTableNames = WCF
::getDB()->getEditor()->getTablenames();
104 // delete or alter tables
105 foreach ($entries as $entry) {
106 // don't alter table if it should be dropped
107 if (!empty($entry['sqlColumn'])/* || !empty($entry['sqlIndex'])*/) {
109 foreach ($entries as $entry2) {
110 if ($entry['sqlTable'] == $entry2['sqlTable'] && empty($entry2['sqlColumn']) && empty($entry2['sqlIndex'])) {
114 if ($isDropped) continue;
117 if (!empty($entry['sqlTable']) && empty($entry['sqlColumn']) && empty($entry['sqlIndex'])) {
118 WCF
::getDB()->getEditor()->dropTable($entry['sqlTable']);
121 else if (in_array($entry['sqlTable'], $existingTableNames) && !empty($entry['sqlColumn'])) {
122 WCF
::getDB()->getEditor()->dropColumn($entry['sqlTable'], $entry['sqlColumn']);
125 else if (in_array($entry['sqlTable'], $existingTableNames) && !empty($entry['sqlIndex'])) {
126 if (substr($entry['sqlIndex'], -3) == '_fk') {
127 WCF
::getDB()->getEditor()->dropForeignKey($entry['sqlTable'], $entry['sqlIndex']);
130 WCF
::getDB()->getEditor()->dropIndex($entry['sqlTable'], $entry['sqlIndex']);
134 // delete from log table
139 * Extracts and returns the sql file.
140 * If the specified sql file was not found, an error message is thrown.
142 * @param string $filename
145 protected function getSQL($filename) {
146 // search sql files in package archive
147 if (($fileindex = $this->installation
->getArchive()->getTar()->getIndexByFilename($filename)) === false) {
148 throw new SystemException("SQL file '".$filename."' not found.");
151 // extract sql file to string
152 return $this->installation
->getArchive()->getTar()->extractToString($fileindex);
156 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::isValid()
158 public static function isValid(PackageArchive
$archive, $instruction) {
159 if (preg_match('~\.sql$~', $instruction)) {
160 // check if file actually exists
162 if ($archive->getTar()->getIndexByFilename($instruction) === false) {
166 catch (\SystemException
$e) {