diff --git a/config/smarty.config.inc.php b/config/smarty.config.inc.php index 87bb44c48..ceaefa02e 100644 --- a/config/smarty.config.inc.php +++ b/config/smarty.config.inc.php @@ -47,6 +47,10 @@ if (Configuration::get('PS_SMARTY_CONSOLE') == _PS_SMARTY_CONSOLE_OPEN_BY_URL_) else if (Configuration::get('PS_SMARTY_CONSOLE') == _PS_SMARTY_CONSOLE_OPEN_) $smarty->debugging = true; +/* Use this constant if you want to load smarty without all PrestaShop functions */ +if (defined('_PS_SMARTY_FAST_LOAD_') && _PS_SMARTY_FAST_LOAD_) + return; + if (defined('_PS_ADMIN_DIR_')) require_once (dirname(__FILE__).'/smartyadmin.config.inc.php'); else diff --git a/install-dev/classes/xmlLoader.php b/install-dev/classes/xmlLoader.php index 00cb3875b..80142bf7b 100644 --- a/install-dev/classes/xmlLoader.php +++ b/install-dev/classes/xmlLoader.php @@ -144,10 +144,7 @@ class InstallXmlLoader $this->ids = $ids; } - /** - * Read all XML files from data folder and populate tables - */ - public function populateFromXmlFiles() + public function getSortedEntities() { // Browse all XML files from data/xml directory $entities = array(); @@ -201,14 +198,19 @@ class InstallXmlLoader } while ($current != $sort_entities); + return $sort_entities; + } + + /** + * Read all XML files from data folder and populate tables + */ + public function populateFromXmlFiles() + { + $entities = $this->getSortedEntities(); + // Populate entities - foreach ($sort_entities as $entity) - { - if (method_exists($this, 'populateEntity'.Tools::toCamelCase($entity))) - $this->{'populateEntity'.Tools::toCamelCase($entity)}(); - else - $this->populateEntity($entity); - } + foreach ($entities as $entity) + $this->populateEntity($entity); } /** @@ -218,6 +220,12 @@ class InstallXmlLoader */ public function populateEntity($entity) { + if (method_exists($this, 'populateEntity'.Tools::toCamelCase($entity))) + { + $this->{'populateEntity'.Tools::toCamelCase($entity)}(); + return; + } + $xml = $this->loadEntity($entity); // Read list of fields diff --git a/install-dev/controllers/http/process.php b/install-dev/controllers/http/process.php index 61035703b..e23b54156 100644 --- a/install-dev/controllers/http/process.php +++ b/install-dev/controllers/http/process.php @@ -66,8 +66,9 @@ class InstallControllerHttpProcess extends InstallControllerHttp Context::getContext()->language = new Language(Configuration::get('PS_LANG_DEFAULT')); Context::getContext()->country = new Country('PS_COUNTRY_DEFAULT'); Context::getContext()->cart = new Cart(); - + define('_PS_SMARTY_FAST_LOAD_', true); require_once _PS_ROOT_DIR_.'/config/smarty.config.inc.php'; + Context::getContext()->smarty = $smarty; } @@ -83,6 +84,8 @@ class InstallControllerHttpProcess extends InstallControllerHttp $this->processGenerateSettingsFile(); else if (Tools::getValue('installDatabase') && !empty($this->session->process_validated['generateSettingsFile'])) $this->processInstallDatabase(); + else if (Tools::getValue('installDefaultData')) + $this->processInstallDefaultData(); else if (Tools::getValue('populateDatabase') && !empty($this->session->process_validated['installDatabase'])) $this->processPopulateDatabase(); else if (Tools::getValue('configureShop') && !empty($this->session->process_validated['populateDatabase'])) @@ -142,6 +145,20 @@ class InstallControllerHttpProcess extends InstallControllerHttp $this->ajaxJsonAnswer(true); } + /** + * PROCESS : installDefaultData + * Create default shop and languages + */ + public function processInstallDefaultData() + { + // @todo remove true in populateDatabase for 1.5.0 RC version + $result = $this->model_install->installDefaultData($this->session->shop_name, true); + + if (!$result || $this->model_install->getErrors()) + $this->ajaxJsonAnswer(false, $this->model_install->getErrors()); + $this->ajaxJsonAnswer(true); + } + /** * PROCESS : populateDatabase * Populate database with default data @@ -150,11 +167,8 @@ class InstallControllerHttpProcess extends InstallControllerHttp { $this->initializeContext(); - // @todo remove true in populateDatabase for 1.5.0 RC version - $result = $this->model_install->populateDatabase(true, array( - 'shop_name' => $this->session->shop_name - )); - + $this->model_install->xml_loader_ids = $this->session->xml_loader_ids; + $result = $this->model_install->populateDatabase(Tools::getValue('entity')); if (!$result || $this->model_install->getErrors()) $this->ajaxJsonAnswer(false, $this->model_install->getErrors()); $this->session->xml_loader_ids = $this->model_install->xml_loader_ids; @@ -202,10 +216,8 @@ class InstallControllerHttpProcess extends InstallControllerHttp { $this->initializeContext(); - // Remove all modules from module table, just in case - Db::getInstance()->delete(_DB_PREFIX_.'module'); - - if (!$this->model_install->installModules() || $this->model_install->getErrors()) + $result = $this->model_install->installModules(Tools::getValue('module')); + if (!$result || $this->model_install->getErrors()) $this->ajaxJsonAnswer(false, $this->model_install->getErrors()); $this->session->process_validated['installModules'] = true; $this->ajaxJsonAnswer(true); @@ -220,8 +232,9 @@ class InstallControllerHttpProcess extends InstallControllerHttp $this->initializeContext(); $this->model_install->xml_loader_ids = $this->session->xml_loader_ids; - if (!$this->model_install->installFixtures() || $this->model_install->getErrors()) + if (!$this->model_install->installFixtures(Tools::getValue('entity')) || $this->model_install->getErrors()) $this->ajaxJsonAnswer(false, $this->model_install->getErrors()); + $this->session->xml_loader_ids = $this->model_install->xml_loader_ids; $this->ajaxJsonAnswer(true); } @@ -290,15 +303,53 @@ class InstallControllerHttpProcess extends InstallControllerHttp */ public function display() { + $low_memory = Tools::getMemoryLimit() < Tools::getOctets('32M'); + + // We fill the process step used for Ajax queries $this->process_steps = array(); $this->process_steps[] = array('key' => 'generateSettingsFile', 'lang' => $this->l('Create settings.inc file')); $this->process_steps[] = array('key' => 'installDatabase', 'lang' => $this->l('Create database tables')); - $this->process_steps[] = array('key' => 'populateDatabase', 'lang' => $this->l('Populate database tables')); + $this->process_steps[] = array('key' => 'installDefaultData', 'lang' => $this->l('Create default shop and languages')); + + // If low memory, create subtasks for populateDatabase step (entity per entity) + $populate_step = array('key' => 'populateDatabase', 'lang' => $this->l('Populate database tables')); + if ($low_memory) + { + $populate_step['subtasks'] = array(); + $xml_loader = new InstallXmlLoader(); + foreach ($xml_loader->getSortedEntities() as $entity) + $populate_step['subtasks'][] = array('entity' => $entity); + } + + $this->process_steps[] = $populate_step; $this->process_steps[] = array('key' => 'configureShop', 'lang' => $this->l('Configure shop informations')); - $this->process_steps[] = array('key' => 'installModules', 'lang' => $this->l('Install modules')); + + + $install_modules = array('key' => 'installModules', 'lang' => $this->l('Install modules')); + if ($low_memory) + foreach ($this->model_install->getModulesList() as $module) + $install_modules['subtasks'][] = array('module' => $module); + $this->process_steps[] = $install_modules; + + // Fixtures are installed only if option is selected if ($this->session->install_type == 'full') - $this->process_steps[] = array('key' => 'installFixtures', 'lang' => $this->l('Install demonstration data')); + { + // If low memory, create subtasks for installFixtures step (entity per entity) + $fixtures_step = array('key' => 'installFixtures', 'lang' => $this->l('Install demonstration data')); + if ($low_memory) + { + $fixtures_step['subtasks'] = array(); + $xml_loader = new InstallXmlLoader(); + $xml_loader->setFixturesPath(); + foreach ($xml_loader->getSortedEntities() as $entity) + $fixtures_step['subtasks'][] = array('entity' => $entity); + } + $this->process_steps[] = $fixtures_step; + } + $this->process_steps[] = array('key' => 'installTheme', 'lang' => $this->l('Install theme')); + + // Mail is send only if option is selected if ($this->session->send_informations) $this->process_steps[] = array('key' => 'sendEmail', 'lang' => $this->l('Send information e-mail')); diff --git a/install-dev/init.php b/install-dev/init.php index 32bc9b02b..6456ebae8 100644 --- a/install-dev/init.php +++ b/install-dev/init.php @@ -66,55 +66,9 @@ require_once(_PS_INSTALL_PATH_.'classes/simplexml.php'); @set_time_limit(300); -class InstallLog -{ - /** - * @return InstallLog - */ - public function getInstance() - { - static $instance = null; +// Try to improve memory limit if it's under 32M +if (Tools::getMemoryLimit() < Tools::getOctets('32M')) + ini_set('memory_limit', '32M'); - if (!$instance) - $instance = new InstallLog(); - return $instance; - } - - protected $fd; - protected $data = array(); - protected $last_time; - protected $depth = 0; - - public function __construct() - { - $this->fd = fopen(_PS_INSTALL_PATH_.'log.txt', 'w'); - $this->last_time = microtime(true); - } - - public function write($id) - { - $str = str_pad("[$id]", 35, ' '); - if (isset($this->data[$id]['start'])) - $str .= str_pad(round(microtime(true) - $this->data[$id]['start'], 4).'ms', 10, ' '); - $str .= str_pad(round(microtime(true) - $this->last_time, 4).'ms', 10, ' '); - $this->data[$id]['str'] = str_repeat("\t", $this->depth - 1)."$str\n"; - $this->depth--; - } - - public function start($id) - { - $this->data[$id] = array('start' => microtime(true)); - $this->depth++; - } - - public function __destruct() - { - foreach ($this->data as $k => $info) - if (!isset($info['str'])) - $this->write($k); - - foreach ($this->data as $info) - fwrite($this->fd, $info['str']); - fclose($this->fd); - } -} +if (Tools::getMemoryLimit() < Tools::getOctets('16M')) + die('PrestaShop requires at least 16M of memory to run, please check the memory_limit directive in php.ini or contact your host provider'); diff --git a/install-dev/langs/fr/install.php b/install-dev/langs/fr/install.php index fe42995aa..eae51c073 100644 --- a/install-dev/langs/fr/install.php +++ b/install-dev/langs/fr/install.php @@ -55,6 +55,7 @@ return array( 'An error occurred while sending email, please verify your parameters' => 'Une erreur est survenue lors de l\'envoi de l\'e-mail, merci de vérifier vos paramètres', 'Create settings.inc file' => 'Création du fichier settings.inc', 'Create database tables' => 'Création des tables de la base', + 'Create default shop and languages ' => 'Création de la boutique par défaut et des langues', 'Populate database tables' => 'Remplissage des tables de la base', 'Configure shop informations' => 'Configuration de la boutique', 'Install modules' => 'Installation des modules', diff --git a/install-dev/models/install.php b/install-dev/models/install.php index a3757e908..4575ef126 100644 --- a/install-dev/models/install.php +++ b/install-dev/models/install.php @@ -137,16 +137,15 @@ class InstallModelInstall extends InstallAbstractModel } /** - * PROCESS : populateDatabase - * Populate database with default data + * PROCESS : installDefaultData + * Create default shop and languages */ - public function populateDatabase($clear_database = false, array $params = array()) + public function installDefaultData($shop_name, $clear_database = false) { if ($clear_database) $this->clearDatabase(true); // Install first shop - $shop_name = isset($params['shop_name']) ? $params['shop_name'] : 'Default'; if (!$this->createShop($shop_name)) return false; @@ -163,11 +162,31 @@ class InstallModelInstall extends InstallAbstractModel $flip_languages = array_flip($languages); Configuration::updateGlobalValue('PS_LANG_DEFAULT', $flip_languages[$this->language->getLanguageIso()]); + return true; + } + + /** + * PROCESS : populateDatabase + * Populate database with default data + */ + public function populateDatabase($entity = null) + { + Db::getInstance()->delete(_DB_PREFIX_.'timezone'); + $languages = array(); + foreach (Language::getLanguages(false) as $lang) + $languages[$lang['id_lang']] = $lang['iso_code']; // Install XML data (data/xml/ folder) $xml_loader = new InstallXmlLoader(); $xml_loader->setLanguages($languages); - $xml_loader->populateFromXmlFiles(); + + if (isset($this->xml_loader_ids) && $this->xml_loader_ids) + $xml_loader->setIds($this->xml_loader_ids); + + if ($entity) + $xml_loader->populateEntity($entity); + else + $xml_loader->populateFromXmlFiles(); if ($errors = $xml_loader->getErrors()) { $this->setError($errors); @@ -447,11 +466,7 @@ class InstallModelInstall extends InstallAbstractModel @unlink($dir.$file); } - /** - * PROCESS : installModules - * Install all modules in ~/modules/ directory - */ - public function installModules() + public function getModulesList() { // @todo REMOVE DEV MODE $modules = array(); @@ -532,6 +547,17 @@ class InstallModelInstall extends InstallAbstractModel ); } + return $modules; + } + + /** + * PROCESS : installModules + * Install all modules in ~/modules/ directory + */ + public function installModules($module = null) + { + $modules = $module ? array($module) : $this->getModulesList(); + $errors = array(); foreach ($modules as $module_name) { @@ -555,57 +581,8 @@ class InstallModelInstall extends InstallAbstractModel * PROCESS : installFixtures * Install fixtures (E.g. demo products) */ - public function installFixtures() + public function installFixtures($entity = null) { - // @todo REMOVE THIS - /*Db::getInstance()->delete('prefix_manufacturer'); - Db::getInstance()->delete('prefix_manufacturer_lang'); - Db::getInstance()->delete('prefix_supplier'); - Db::getInstance()->delete('prefix_supplier_lang'); - Db::getInstance()->delete('prefix_address'); - Db::getInstance()->delete('prefix_product'); - Db::getInstance()->delete('prefix_product_lang'); - Db::getInstance()->delete('prefix_category', 'id_category <> 1'); - Db::getInstance()->delete('prefix_category_product'); - Db::getInstance()->delete('prefix_category_lang', 'id_category <> 1'); - Db::getInstance()->delete('prefix_scene'); - Db::getInstance()->delete('prefix_scene_lang'); - Db::getInstance()->delete('prefix_scene_products'); - Db::getInstance()->delete('prefix_scene_category'); - Db::getInstance()->delete('prefix_attribute_group'); - Db::getInstance()->delete('prefix_attribute_group_lang'); - Db::getInstance()->delete('prefix_attribute'); - Db::getInstance()->delete('prefix_attribute_lang'); - Db::getInstance()->delete('prefix_product_attribute'); - Db::getInstance()->delete('prefix_product_attribute_combination'); - Db::getInstance()->delete('prefix_product_attribute_image'); - Db::getInstance()->delete('prefix_order_message'); - Db::getInstance()->delete('prefix_order_message_lang'); - Db::getInstance()->delete('prefix_feature'); - Db::getInstance()->delete('prefix_feature_lang'); - Db::getInstance()->delete('prefix_feature_value'); - Db::getInstance()->delete('prefix_feature_value_lang'); - Db::getInstance()->delete('prefix_feature_product'); - Db::getInstance()->delete('prefix_store'); - Db::getInstance()->delete('prefix_image'); - Db::getInstance()->delete('prefix_image_lang'); - Db::getInstance()->delete('prefix_tag'); - Db::getInstance()->delete('prefix_alias'); - Db::getInstance()->delete('prefix_customer'); - Db::getInstance()->delete('prefix_guest'); - Db::getInstance()->delete('prefix_connections'); - Db::getInstance()->delete('prefix_customer_group'); - Db::getInstance()->delete('prefix_cart'); - Db::getInstance()->delete('prefix_cart_product'); - Db::getInstance()->delete('prefix_orders'); - Db::getInstance()->delete('prefix_order_detail'); - Db::getInstance()->delete('prefix_order_history'); - Db::getInstance()->delete('prefix_range_price'); - Db::getInstance()->delete('prefix_range_weight'); - Db::getInstance()->delete('prefix_delivery'); - Db::getInstance()->delete('prefix_specific_price'); - Db::getInstance()->delete('prefix_tag');*/ - // Load class (use fixture class if one exists, or use InstallXmlLoader) if (file_exists(_PS_INSTALL_FIXTURES_PATH_.'apple/install.php')) { @@ -636,13 +613,22 @@ class InstallModelInstall extends InstallAbstractModel foreach (Language::getLanguages(false) as $lang) $languages[$lang['id_lang']] = $lang['iso_code']; $xml_loader->setLanguages($languages); - $xml_loader->populateFromXmlFiles(); + + if ($entity) + $xml_loader->populateEntity($entity); + else + $xml_loader->populateFromXmlFiles(); + if ($errors = $xml_loader->getErrors()) { $this->setError($errors); return false; } + // IDS from xmlLoader are stored in order to use them for fixtures + $this->xml_loader_ids = $xml_loader->getIds(); + unset($xml_loader); + // Index products in search tables Search::indexation(true); diff --git a/install-dev/theme/js/process.js b/install-dev/theme/js/process.js index dcf397d6e..c7090a17a 100644 --- a/install-dev/theme/js/process.js +++ b/install-dev/theme/js/process.js @@ -17,6 +17,8 @@ function start_install() $('.error_log').hide(); $('#progress_bar').show(); $('#progress_bar .installing').show(); + process_pixel = parseInt($('#progress_bar .total').css('width')) / process_steps.length; + process_install(); } @@ -52,11 +54,14 @@ function process_install(step) } else { - $('#progress_bar .total .progress').animate({'width': '+='+process_percent+'%'}, 500); - $('#progress_bar .total span').html(Math.ceil(current_step * process_percent)+'%'); + $('#progress_bar .total .progress').animate({'width': '+='+process_pixel+'px'}, 500); + $('#progress_bar .total span').html(Math.ceil(current_step * (100 / process_steps.length))+'%'); // Process next step - process_install(process_steps[current_step]); + if (process_steps[current_step].subtasks) + process_install_subtasks(process_steps[current_step]); + else + process_install(process_steps[current_step]); } } // An error occured during this step @@ -73,6 +78,63 @@ function process_install(step) }); } +function process_install_subtasks(step) +{ + $('.installing').hide().html(step.lang+' ...').fadeIn('slow'); + process_install_subtask(step, 0); +} + +function process_install_subtask(step, current_subtask) +{ + var params = {}; + params[step.key] = 'true'; + params['subtask'] = current_subtask; + $.each(step.subtasks[current_subtask], function(k, v) + { + params[k] = v; + }); + + $.ajax({ + url: 'index.php', + data: params, + dataType: 'json', + cache: false, + success: function(json) + { + // No error during this step + if (json && json.success === true) + { + current_subtask++; + var subtask_process_pixel = process_pixel / step.subtasks.length; + $('#progress_bar .total .progress').animate({'width': '+='+subtask_process_pixel+'px'}, 500); + $('#progress_bar .total span').html(Math.ceil((current_step * (100 / process_steps.length)) + Math.ceil(current_subtask * ((100 / process_steps.length) / step.subtasks.length)))+'%'); + + if (current_subtask >= step.subtasks.length) + { + current_step++; + $('#process_step_'+step.key).show().addClass('success'); + if (process_steps[current_step].subtasks) + process_install_subtasks(process_steps[current_step]); + else + process_install(process_steps[current_step]); + } + else + process_install_subtask(step, current_subtask); + } + // An error occured during this step + else + { + install_error(step, (json) ? json.message : ''); + } + }, + // An error HTTP (page not found, json not valid, etc.) occured during this step + error: function() + { + install_error(step); + } + }); +} + function install_error(step, errors) { current_step = 0; diff --git a/install-dev/theme/view.css b/install-dev/theme/view.css index bf849d04f..30121c5d8 100644 --- a/install-dev/theme/view.css +++ b/install-dev/theme/view.css @@ -704,7 +704,7 @@ ul#optional_update {list-style-type:none;} /* STEP 5 ******************************************/ #install_process_form{ - min-height: 260px; + min-height: 300px; } #progress_bar { display: none; diff --git a/install-dev/theme/views/process.phtml b/install-dev/theme/views/process.phtml index 4c96a1bc8..f42d20f09 100644 --- a/install-dev/theme/views/process.phtml +++ b/install-dev/theme/views/process.phtml @@ -4,7 +4,6 @@