Contao\Theme::extractThemeFiles PHP Method

extractThemeFiles() protected method

Extract the theme files and write the data to the database
protected extractThemeFiles ( array $arrFiles, array $arrDbFields )
$arrFiles array
$arrDbFields array
    protected function extractThemeFiles($arrFiles, $arrDbFields)
    {
        foreach ($arrFiles as $strZipFile) {
            $xml = null;
            // Open the archive
            $objArchive = new \ZipReader($strZipFile);
            // Extract all files
            while ($objArchive->next()) {
                // Load the XML file
                if ($objArchive->file_name == 'theme.xml') {
                    $xml = new \DOMDocument();
                    $xml->preserveWhiteSpace = false;
                    $xml->loadXML($objArchive->unzip());
                    continue;
                }
                // Limit file operations to files and the templates directory
                if (strncmp($objArchive->file_name, 'files/', 6) !== 0 && strncmp($objArchive->file_name, 'tl_files/', 9) !== 0 && strncmp($objArchive->file_name, 'templates/', 10) !== 0) {
                    \Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidFile'], $objArchive->file_name));
                    continue;
                }
                // Extract the files
                try {
                    \File::putContent($this->customizeUploadPath($objArchive->file_name), $objArchive->unzip());
                } catch (\Exception $e) {
                    \Message::addError($e->getMessage());
                }
            }
            // Continue if there is no XML file
            if (!$xml instanceof \DOMDocument) {
                \Message::addError(sprintf($GLOBALS['TL_LANG']['tl_theme']['missing_xml'], basename($strZipFile)));
                continue;
            }
            $arrMapper = array();
            $tables = $xml->getElementsByTagName('table');
            $arrNewFolders = array();
            // Extract the folder names from the XML file
            for ($i = 0; $i < $tables->length; $i++) {
                if ($tables->item($i)->getAttribute('name') == 'tl_theme') {
                    $fields = $tables->item($i)->childNodes->item(0)->childNodes;
                    for ($k = 0; $k < $fields->length; $k++) {
                        if ($fields->item($k)->getAttribute('name') == 'folders') {
                            $arrNewFolders = \StringUtil::deserialize($fields->item($k)->nodeValue);
                            break;
                        }
                    }
                    break;
                }
            }
            // Sync the new folder(s)
            if (!empty($arrNewFolders) && is_array($arrNewFolders)) {
                foreach ($arrNewFolders as $strFolder) {
                    $strCustomized = $this->customizeUploadPath($strFolder);
                    if (\Dbafs::shouldBeSynchronized($strCustomized)) {
                        \Dbafs::addResource($strCustomized);
                    }
                }
            }
            // Lock the tables
            $arrLocks = array('tl_files' => 'WRITE', 'tl_theme' => 'WRITE', 'tl_style_sheet' => 'WRITE', 'tl_style' => 'WRITE', 'tl_module' => 'WRITE', 'tl_layout' => 'WRITE', 'tl_image_size' => 'WRITE', 'tl_image_size_item' => 'WRITE');
            // Load the DCAs of the locked tables (see #7345)
            foreach (array_keys($arrLocks) as $table) {
                $this->loadDataContainer($table);
            }
            $this->Database->lockTables($arrLocks);
            // Get the current auto_increment values
            $tl_files = $this->Database->getNextId('tl_files');
            $tl_theme = $this->Database->getNextId('tl_theme');
            $tl_style_sheet = $this->Database->getNextId('tl_style_sheet');
            $tl_style = $this->Database->getNextId('tl_style');
            $tl_module = $this->Database->getNextId('tl_module');
            $tl_layout = $this->Database->getNextId('tl_layout');
            $tl_image_size = $this->Database->getNextId('tl_image_size');
            $tl_image_size_item = $this->Database->getNextId('tl_image_size_item');
            // Build the mapper data (see #8326)
            for ($i = 0; $i < $tables->length; $i++) {
                $rows = $tables->item($i)->childNodes;
                $table = $tables->item($i)->getAttribute('name');
                // Skip invalid tables
                if (!in_array($table, array_keys($arrLocks))) {
                    continue;
                }
                // Loop through the rows
                for ($j = 0; $j < $rows->length; $j++) {
                    $fields = $rows->item($j)->childNodes;
                    // Loop through the fields
                    for ($k = 0; $k < $fields->length; $k++) {
                        // Increment the ID
                        if ($fields->item($k)->getAttribute('name') == 'id') {
                            $arrMapper[$table][$fields->item($k)->nodeValue] = ${$table}++;
                            break;
                        }
                    }
                }
            }
            // Loop through the tables
            for ($i = 0; $i < $tables->length; $i++) {
                $rows = $tables->item($i)->childNodes;
                $table = $tables->item($i)->getAttribute('name');
                // Skip invalid tables
                if (!in_array($table, array_keys($arrLocks))) {
                    continue;
                }
                // Get the order fields
                $objDcaExtractor = \DcaExtractor::getInstance($table);
                $arrOrder = $objDcaExtractor->getOrderFields();
                // Loop through the rows
                for ($j = 0; $j < $rows->length; $j++) {
                    $set = array();
                    $fields = $rows->item($j)->childNodes;
                    // Loop through the fields
                    for ($k = 0; $k < $fields->length; $k++) {
                        $value = $fields->item($k)->nodeValue;
                        $name = $fields->item($k)->getAttribute('name');
                        // Skip NULL values
                        if ($value == 'NULL') {
                            continue;
                        } elseif ($name == 'id') {
                            $value = $arrMapper[$table][$value];
                        } elseif ($name == 'pid') {
                            if ($table == 'tl_style') {
                                $value = $arrMapper['tl_style_sheet'][$value];
                            } elseif ($table == 'tl_image_size_item') {
                                $value = $arrMapper['tl_image_size'][$value];
                            } else {
                                $value = $arrMapper['tl_theme'][$value];
                            }
                        } elseif ($name == 'fallback') {
                            $value = '';
                        } elseif ($table == 'tl_layout' && $name == 'stylesheet') {
                            $stylesheets = \StringUtil::deserialize($value);
                            if (is_array($stylesheets)) {
                                foreach (array_keys($stylesheets) as $key) {
                                    $stylesheets[$key] = $arrMapper['tl_style_sheet'][$stylesheets[$key]];
                                }
                                $value = serialize($stylesheets);
                            }
                        } elseif ($table == 'tl_layout' && $name == 'modules') {
                            $modules = \StringUtil::deserialize($value);
                            if (is_array($modules)) {
                                foreach ($modules as $key => $mod) {
                                    if ($mod['mod'] > 0) {
                                        $modules[$key]['mod'] = $arrMapper['tl_module'][$mod['mod']];
                                    }
                                }
                                $value = serialize($modules);
                            }
                        } elseif (($table == 'tl_theme' || $table == 'tl_style_sheet') && $name == 'name') {
                            $objCount = $this->Database->prepare("SELECT COUNT(*) AS count FROM " . $table . " WHERE name=?")->execute($value);
                            if ($objCount->count > 0) {
                                $value = preg_replace('/( |\\-)[0-9]+$/', '', $value);
                                $value .= ($table == 'tl_style_sheet' ? '-' : ' ') . ${$table};
                            }
                        } elseif (($table == 'tl_style_sheet' || $table == 'tl_style' || $table == 'tl_files' && $name == 'path') && strpos($value, 'files') !== false) {
                            $tmp = \StringUtil::deserialize($value);
                            if (is_array($tmp)) {
                                foreach ($tmp as $kk => $vv) {
                                    $tmp[$kk] = $this->customizeUploadPath($vv);
                                }
                                $value = serialize($tmp);
                            } else {
                                $value = $this->customizeUploadPath($value);
                            }
                        } elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'fileTree' && !$GLOBALS['TL_DCA'][$table]['fields'][$name]['eval']['multiple']) {
                            if (!$value) {
                                $value = null;
                                // Contao >= 3.2
                            } else {
                                // Do not use the FilesModel here – tables are locked!
                                $objFile = $this->Database->prepare("SELECT uuid FROM tl_files WHERE path=?")->limit(1)->execute($this->customizeUploadPath($value));
                                $value = $objFile->uuid;
                            }
                        } elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'fileTree' || in_array($name, $arrOrder)) {
                            $tmp = \StringUtil::deserialize($value);
                            if (is_array($tmp)) {
                                foreach ($tmp as $kk => $vv) {
                                    // Do not use the FilesModel here – tables are locked!
                                    $objFile = $this->Database->prepare("SELECT uuid FROM tl_files WHERE path=?")->limit(1)->execute($this->customizeUploadPath($vv));
                                    $tmp[$kk] = $objFile->uuid;
                                }
                                $value = serialize($tmp);
                            }
                        } elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'imageSize') {
                            $imageSizes = \StringUtil::deserialize($value, true);
                            if (!empty($imageSizes)) {
                                if (is_numeric($imageSizes[2])) {
                                    $imageSizes[2] = $arrMapper['tl_image_size'][$imageSizes[2]];
                                }
                            }
                            $value = serialize($imageSizes);
                        }
                        $set[$name] = $value;
                    }
                    // Skip fields that are not in the database (e.g. because of missing extensions)
                    foreach ($set as $k => $v) {
                        if (!in_array($k, $arrDbFields[$table])) {
                            unset($set[$k]);
                        }
                    }
                    // Create the templates folder even if it is empty (see #4793)
                    if ($table == 'tl_theme' && isset($set['templates']) && strncmp($set['templates'], 'templates/', 10) === 0 && !is_dir(TL_ROOT . '/' . $set['templates'])) {
                        new \Folder($set['templates']);
                    }
                    // Update tl_files (entries have been created by the Dbafs class)
                    if ($table == 'tl_files') {
                        $this->Database->prepare("UPDATE {$table} %s WHERE path=?")->set($set)->execute($set['path']);
                    } else {
                        $this->Database->prepare("INSERT INTO {$table} %s")->set($set)->execute();
                    }
                }
            }
            // Unlock the tables
            $this->Database->unlockTables();
            // Update the style sheets
            $this->import('StyleSheets');
            $this->StyleSheets->updateStyleSheets();
            // Notify the user
            \Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_theme']['theme_imported'], basename($strZipFile)));
            // HOOK: add custom logic
            if (isset($GLOBALS['TL_HOOKS']['extractThemeFiles']) && is_array($GLOBALS['TL_HOOKS']['extractThemeFiles'])) {
                $intThemeId = empty($arrMapper['tl_theme']) ? null : reset($arrMapper['tl_theme']);
                foreach ($GLOBALS['TL_HOOKS']['extractThemeFiles'] as $callback) {
                    \System::importStatic($callback[0])->{$callback[1]}($xml, $objArchive, $intThemeId, $arrMapper);
                }
            }
            unset($tl_files, $tl_theme, $tl_style_sheet, $tl_style, $tl_module, $tl_layout, $tl_image_size, $tl_image_size_item);
        }
        \System::setCookie('BE_PAGE_OFFSET', 0, 0);
        /** @var SessionInterface $objSession */
        $objSession = \System::getContainer()->get('session');
        $objSession->remove('uploaded_themes');
        // Redirect
        $this->redirect(str_replace('&key=importTheme', '', \Environment::get('request')));
    }