diff --git a/classes/Controller.php b/classes/Controller.php index e32c63639..134419b6f 100644 --- a/classes/Controller.php +++ b/classes/Controller.php @@ -25,6 +25,9 @@ * International Registered Trademark & Property of PrestaShop SA */ +/** + * @since 1.5.0 + */ abstract class ControllerCore { /** @@ -57,6 +60,11 @@ abstract class ControllerCore */ protected $displayFooter = false; + /** + * @var bool If ajax parameter is detected in request, set this flag to true + */ + protected $ajax = false; + /** * Initialize the page */ @@ -64,7 +72,6 @@ abstract class ControllerCore /** * Do the page treatment : post process, ajax process, etc. - * Enter description here ... */ abstract public function action(); @@ -92,16 +99,19 @@ abstract class ControllerCore public function __construct() { + $this->displayHeader(true); + $this->displayFooter(true); $this->context = Context::getContext(); + $this->ajax = Tools::getValue('ajax') || Tools::isSubmit('ajax'); } /** - * Start controller process + * Start controller process (this method shouldn't be overriden !) */ public function run() { $this->init(); - $this->action(); + $this->action(array('titi'), $this); $this->display(); } diff --git a/classes/Dispatcher.php b/classes/Dispatcher.php index 6f8609cb2..bb44d62ca 100644 --- a/classes/Dispatcher.php +++ b/classes/Dispatcher.php @@ -236,8 +236,8 @@ class DispatcherCore $this->getController(); $controllers = Dispatcher::getControllers($this->controller_directories); - if (!$this->controller || $this->controller == 'index') - $this->controller = (defined('_PS_ADMIN_DIR_')) ? 'adminhome' : 'index'; + if (!$this->controller) + $this->controller = $this->default_controller; // For retrocompatibility with admin/tabs/ old system if (isset($controllers[$this->controller]) && defined('_PS_ADMIN_DIR_') && file_exists(_PS_ADMIN_DIR_.'/tabs/'.$controllers[$this->controller].'.php')) @@ -251,7 +251,14 @@ class DispatcherCore $this->controller = $this->controller_not_found; // Instantiate controller - Controller::getController($controllers[$this->controller])->run(); + try + { + Controller::getController($controllers[$this->controller])->run(); + } + catch (PrestashopException $e) + { + $e->displayMessage(); + } } /** @@ -448,8 +455,8 @@ class DispatcherCore if ($this->use_routes && !$controller) { if (!$this->request_uri) - return 'pagenotfound'; - $controller = 'index'; + return $this->controller_not_found; + $controller = $this->default_controller; // Add empty route as last route to prevent this greedy regexp to match request uri before right time if ($this->empty_route) diff --git a/classes/FrontController.php b/classes/FrontController.php index 10968697c..91646f920 100755 --- a/classes/FrontController.php +++ b/classes/FrontController.php @@ -333,28 +333,27 @@ class FrontControllerCore extends Controller $this->context->cart = $cart; $this->context->currency = $currency; $this->context->controller = $this; - - $this->displayHeader(); - $this->displayFooter(); } public function action() { - // For retrocompatibility - if (method_exists($this, 'preProcess')) + /*// For retrocompatibility with versions before 1.5, preProcess support will be removed on next release + if (method_exists(get_class($this), 'preProcess')) { - Tools::displayAsDeprecated('Method preProcess() is deprecated in controllers, use method postProcess() instead'); - $this->preProcess(); - } + $reflection = new ReflectionClass($this); + if (!in_array($reflection->getMethod('preProcess')->class, array('FrontController', 'FrontControllerCore'))) + { + Tools::displayAsDeprecated('Method preProcess() is deprecated in controllers, use method postProcess() instead'); + $this->preProcess(); + } + }*/ - if (Tools::getValue('ajax') == 'true') + if ($this->ajax) { $this->displayHeader(false); $this->displayFooter(false); - $this->ajaxProcess(); } - else - $this->postProcess(); + $this->preProcess(); // Prepare generation of page display $this->processHeader(); @@ -362,11 +361,7 @@ class FrontControllerCore extends Controller $this->processFooter(); } - public function ajaxProcess() - { - } - - public function postProcess() + public function preProcess() { } diff --git a/controllers/front/AddressController.php b/controllers/front/AddressController.php index 0573d4850..3e7cb175f 100644 --- a/controllers/front/AddressController.php +++ b/controllers/front/AddressController.php @@ -25,9 +25,6 @@ * International Registered Trademark & Property of PrestaShop SA */ -if(Configuration::get('VATNUMBER_MANAGEMENT') AND file_exists(_PS_MODULE_DIR_.'vatnumber/vatnumber.php')) - include_once(_PS_MODULE_DIR_.'vatnumber/vatnumber.php'); - class AddressControllerCore extends FrontController { public $auth = true; @@ -36,33 +33,48 @@ class AddressControllerCore extends FrontController public $authRedirection = 'addresses'; public $ssl = true; + /** + * @var Address Current address + */ protected $_address; + /** + * Set default medias for this controller + */ + public function setMedia() + { + parent::setMedia(); + $this->addJS(_THEME_JS_DIR_.'tools/statesManagement.js'); + } + + /** + * Initialize address controller + * @see FrontController::init() + */ public function init() { parent::init(); - if ($back = Tools::getValue('back')) - $this->context->smarty->assign('back', Tools::safeOutput($back)); - if ($mod = Tools::getValue('mod')) - $this->context->smarty->assign('mod', Tools::safeOutput($mod)); - - if (Tools::isSubmit('ajax') AND Tools::isSubmit('type')) + // Get address ID + $id_address = 0; + if ($this->ajax && Tools::isSubmit('type')) { - if (Tools::getValue('type') == 'delivery') - $id_address = isset($this->context->cart->id_address_delivery) ? (int)$this->context->cart->id_address_delivery : 0; - elseif (Tools::getValue('type') == 'invoice') - $id_address = (isset($this->context->cart->id_address_invoice) AND $this->context->cart->id_address_invoice != $this->context->cart->id_address_delivery) ? (int)$this->context->cart->id_address_invoice : 0; + if (Tools::getValue('type') == 'delivery' && isset($this->context->cart->id_address_delivery)) + $id_address = (int)$this->context->cart->id_address_delivery; + else if (Tools::getValue('type') == 'invoice' && isset($this->context->cart->id_address_invoice) + && $this->context->cart->id_address_invoice != $this->context->cart->id_address_delivery) + $id_address = (int)$this->context->cart->id_address_invoice; else exit; } else $id_address = (int)Tools::getValue('id_address', 0); + // Initialize address if ($id_address) { - $this->_address = new Address((int)$id_address); - if (Validate::isLoadedObject($this->_address) AND Customer::customerHasAddress($this->context->customer->id, (int)($id_address))) + $this->_address = new Address($id_address); + if (Validate::isLoadedObject($this->_address) && Customer::customerHasAddress($this->context->customer->id, $id_address)) { if (Tools::isSubmit('delete')) { @@ -74,137 +86,29 @@ class AddressControllerCore extends FrontController Tools::redirect('index.php?controller=addresses'); $this->errors[] = Tools::displayError('This address cannot be deleted.'); } - $this->context->smarty->assign(array('address' => $this->_address, 'id_address' => (int)$id_address)); } - elseif (Tools::isSubmit('ajax')) + else if ($this->ajax) exit; else Tools::redirect('index.php?controller=addresses'); } + } + + /** + * Start forms process + * @see FrontController::preProcess() + */ + public function preProcess() + { if (Tools::isSubmit('submitAddress')) + $this->processSubmitAddress(); + else if (!Validate::isLoadedObject($this->_address) && Validate::isLoadedObject($this->context->customer)) { - $address = new Address(); - $this->errors = $address->validateController(); - $address->id_customer = (int)$this->context->customer->id; - - if (!Tools::getValue('phone') AND !Tools::getValue('phone_mobile')) - $this->errors[] = Tools::displayError('You must register at least one phone number'); - if (!$country = new Country((int)$address->id_country) OR !Validate::isLoadedObject($country)) - die(Tools::displayError()); - - /* US customer: normalize the address */ - if($address->id_country == Country::getByIso('US')) - { - include_once(_PS_TAASC_PATH_.'AddressStandardizationSolution.php'); - $normalize = new AddressStandardizationSolution; - $address->address1 = $normalize->AddressLineStandardization($address->address1); - $address->address2 = $normalize->AddressLineStandardization($address->address2); - } - - $zip_code_format = $country->zip_code_format; - if ($country->need_zip_code) - { - if (($postcode = Tools::getValue('postcode')) AND $zip_code_format) - { - $zip_regexp = '/^'.$zip_code_format.'$/ui'; - $zip_regexp = str_replace(' ', '( |)', $zip_regexp); - $zip_regexp = str_replace('-', '(-|)', $zip_regexp); - $zip_regexp = str_replace('N', '[0-9]', $zip_regexp); - $zip_regexp = str_replace('L', '[a-zA-Z]', $zip_regexp); - $zip_regexp = str_replace('C', $country->iso_code, $zip_regexp); - if (!preg_match($zip_regexp, $postcode)) - $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' '.Tools::displayError('is invalid.').'
'.Tools::displayError('Must be typed as follows:').' '.str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $zip_code_format))); - } - elseif ($zip_code_format) - $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' '.Tools::displayError('is required.'); - elseif ($postcode AND !preg_match('/^[0-9a-zA-Z -]{4,9}$/ui', $postcode)) - $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' '.Tools::displayError('is invalid.').'
'.Tools::displayError('Must be typed as follows:').' '.str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $zip_code_format))); - } - if ($country->isNeedDni() AND (!Tools::getValue('dni') OR !Validate::isDniLite(Tools::getValue('dni')))) - $this->errors[] = Tools::displayError('Identification number is incorrect or has already been used.'); - elseif (!$country->isNeedDni()) - $address->dni = NULL; - if (Configuration::get('PS_TOKEN_ENABLE') == 1 AND - strcmp(Tools::getToken(false), Tools::getValue('token')) AND - $this->context->customer->isLogged(true) === true) - $this->errors[] = Tools::displayError('Invalid token'); - - if ((int)($country->contains_states) AND !(int)($address->id_state)) - $this->errors[] = Tools::displayError('This country requires a state selection.'); - - if (!sizeof($this->errors)) - { - if (isset($id_address)) - { - $country = new Country((int)($address->id_country)); - if (Validate::isLoadedObject($country) AND !$country->contains_states) - $address->id_state = 0; - $address_old = new Address((int)$id_address); - if (Validate::isLoadedObject($address_old) AND Customer::customerHasAddress($this->context->customer->id, (int)$address_old->id)) - { - if ($address_old->isUsed()) - { - $address_old->delete(); - if (!Tools::isSubmit('ajax')) - { - $to_update = false; - if ($this->context->cart->id_address_invoice == $address_old->id) - { - $to_update = true; - $this->context->cart->id_address_invoice = 0; - } - if ($this->context->cart->id_address_delivery == $address_old->id) - { - $to_update = true; - $this->context->cart->id_address_delivery = 0; - } - if ($to_update) - $this->context->cart->update(); - } - } - else - { - $address->id = (int)($address_old->id); - $address->date_add = $address_old->date_add; - } - } - } - elseif ($this->context->customer->is_guest) - Tools::redirect('index.php?controller=addresses'); - - if ($result = $address->save()) - { - /* In order to select this new address : order-address.tpl */ - if ((bool)(Tools::getValue('select_address', false)) == true OR (Tools::isSubmit('ajax') AND Tools::getValue('type') == 'invoice')) - { - /* This new adress is for invoice_adress, select it */ - $this->context->cart->id_address_invoice = (int)($address->id); - $this->context->cart->update(); - } - if (Tools::isSubmit('ajax')) - { - $return = array( - 'hasError' => !empty($this->errors), - 'errors' => $this->errors, - 'id_address_delivery' => $this->context->cart->id_address_delivery, - 'id_address_invoice' => $this->context->cart->id_address_invoice - ); - die(Tools::jsonEncode($return)); - } - Tools::redirect($back ? ($mod ? $back.'&back='.$mod : $back) : 'addresses.php'); - } - $this->errors[] = Tools::displayError('An error occurred while updating your address.'); - } + $_POST['firstname'] = $this->context->customer->firstname; + $_POST['lastname'] = $this->context->customer->lastname; } - elseif (!$id_address) - { - if (Validate::isLoadedObject($this->context->customer)) - { - $_POST['firstname'] = $this->context->customer->firstname; - $_POST['lastname'] = $this->context->customer->lastname; - } - } - if (Tools::isSubmit('ajax') AND sizeof($this->errors)) + + if ($this->ajax && count($this->errors)) { $return = array( 'hasError' => !empty($this->errors), @@ -214,83 +118,252 @@ class AddressControllerCore extends FrontController } } - public function setMedia() + /** + * Process changes on an address + */ + protected function processSubmitAddress() { - parent::setMedia(); - $this->addJS(_THEME_JS_DIR_.'tools/statesManagement.js'); + if ($this->context->customer->is_guest) + Tools::redirect('index.php?controller=addresses'); + + $address = new Address(); + $this->errors = $address->validateController(); + $address->id_customer = (int)$this->context->customer->id; + + // Check page token + if (Configuration::get('PS_TOKEN_ENABLE') == 1 && strcmp(Tools::getToken(false), Tools::getValue('token')) && $this->context->customer->isLogged(true)) + $this->errors[] = Tools::displayError('Invalid token'); + + // Check phone + if (!Tools::getValue('phone') && !Tools::getValue('phone_mobile')) + $this->errors[] = Tools::displayError('You must register at least one phone number'); + + // Check country + if (!($country = new Country($address->id_country)) || !Validate::isLoadedObject($country)) + throw new PrestashopException('Country cannot be loaded with address->id_country'); + + if ((int)$country->contains_states && !(int)$address->id_state) + $this->errors[] = Tools::displayError('This country requires a state selection.'); + + // US customer: normalize the address + if ($address->id_country == Country::getByIso('US')) + { + include_once(_PS_TAASC_PATH_.'AddressStandardizationSolution.php'); + $normalize = new AddressStandardizationSolution; + $address->address1 = $normalize->AddressLineStandardization($address->address1); + $address->address2 = $normalize->AddressLineStandardization($address->address2); + } + + // Check country zip code + $zip_code_format = $country->zip_code_format; + if ($country->need_zip_code) + { + if (($postcode = Tools::getValue('postcode')) && $zip_code_format) + { + $zip_regexp = '/^'.$zip_code_format.'$/ui'; + $zip_regexp = str_replace(' ', '( |)', $zip_regexp); + $zip_regexp = str_replace('-', '(-|)', $zip_regexp); + $zip_regexp = str_replace('N', '[0-9]', $zip_regexp); + $zip_regexp = str_replace('L', '[a-zA-Z]', $zip_regexp); + $zip_regexp = str_replace('C', $country->iso_code, $zip_regexp); + if (!preg_match($zip_regexp, $postcode)) + $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' ' + .Tools::displayError('is invalid.').'
'.Tools::displayError('Must be typed as follows:') + .' '.str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $zip_code_format))); + } + else if ($zip_code_format) + $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' '.Tools::displayError('is required.'); + else if ($postcode AND !preg_match('/^[0-9a-zA-Z -]{4,9}$/ui', $postcode)) + $this->errors[] = ''.Tools::displayError('Zip/ Postal code').' '.Tools::displayError('is invalid.') + .'
'.Tools::displayError('Must be typed as follows:').' ' + .str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $zip_code_format))); + } + + // Check country DNI + if ($country->isNeedDni() && (!Tools::getValue('dni') || !Validate::isDniLite(Tools::getValue('dni')))) + $this->errors[] = Tools::displayError('Identification number is incorrect or has already been used.'); + else if (!$country->isNeedDni()) + $address->dni = NULL; + + // Don't continue this process if we have errors ! + if ($this->errors) + return; + + // If we edit this address, delete old address and create a new one + if (Validate::isLoadedObject($this->_address)) + { + if (Validate::isLoadedObject($country) && !$country->contains_states) + $address->id_state = 0; + $address_old = $this->_address; + if (Customer::customerHasAddress($this->context->customer->id, (int)$address_old->id)) + { + if ($address_old->isUsed()) + { + $address_old->delete(); + if (!Tools::isSubmit('ajax')) + { + $to_update = false; + if ($this->context->cart->id_address_invoice == $address_old->id) + { + $to_update = true; + $this->context->cart->id_address_invoice = 0; + } + if ($this->context->cart->id_address_delivery == $address_old->id) + { + $to_update = true; + $this->context->cart->id_address_delivery = 0; + } + if ($to_update) + $this->context->cart->update(); + } + } + else + { + $address->id = (int)($address_old->id); + $address->date_add = $address_old->date_add; + } + } + } + + // Save address + if ($result = $address->save()) + { + // In order to select this new address : order-address.tpl + if ((bool)Tools::getValue('select_address', false) || ($this->ajax && Tools::getValue('type') == 'invoice')) + { + // This new adress is for invoice_adress, select it + $this->context->cart->id_address_invoice = (int)$address->id; + $this->context->cart->update(); + } + + if ($this->ajax) + { + $return = array( + 'hasError' => (bool)$this->errors, + 'errors' => $this->errors, + 'id_address_delivery' => $this->context->cart->id_address_delivery, + 'id_address_invoice' => $this->context->cart->id_address_invoice + ); + die(Tools::jsonEncode($return)); + } + + // Redirect to old page or current page + if ($back = Tools::getValue('back')) + { + $mod = Tools::getValue('mod'); + Tools::redirect('index.php?controller='.$back.($mod ? '&back='.$mod : '')); + } + else + Tools::redirect('index.php?controller=addresses'); + Tools::redirect($mod ? $back.'&back='.$mod : $back); + } + $this->errors[] = Tools::displayError('An error occurred while updating your address.'); } + /** + * Assign template vars related to page content + * @see FrontController::process() + */ public function process() { - parent::process(); - /* Secure restriction for guest */ if ($this->context->customer->is_guest) Tools::redirect('index.php?controller=addresses'); - if (Tools::isSubmit('id_country') AND Tools::getValue('id_country') != NULL AND is_numeric(Tools::getValue('id_country'))) - $selectedCountry = (int)Tools::getValue('id_country'); - elseif (isset($this->_address) AND isset($this->_address->id_country) AND !empty($this->_address->id_country) AND is_numeric($this->_address->id_country)) - $selectedCountry = (int)$this->_address->id_country; - elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) + $this->assignCountries(); + $this->assignVatNumber(); + $this->assignAddressFormat(); + + // Assign common vars + $this->context->smarty->assign(array( + 'ajaxurl' => _MODULE_DIR_, + 'errors' => $this->errors, + 'token' => Tools::getToken(false), + 'select_address' => (int)Tools::getValue('select_address'), + 'address' => $this->_address, + 'id_address' => (Validate::isLoadedObject($this->_address)) ? $this->_address->id : 0, + )); + + if ($back = Tools::getValue('back')) + $this->context->smarty->assign('back', Tools::safeOutput($back)); + if ($mod = Tools::getValue('mod')) + $this->context->smarty->assign('mod', Tools::safeOutput($mod)); + + $this->setTemplate(_PS_THEME_DIR_.'address.tpl'); + } + + /** + * Assign template vars related to countries display + */ + protected function assignCountries() + { + // Get selected country + if (Tools::isSubmit('id_country') && !is_null(Tools::getValue('id_country')) && is_numeric(Tools::getValue('id_country'))) + $selected_country = (int)Tools::getValue('id_country'); + else if (isset($this->_address) && isset($this->_address->id_country) && !empty($this->_address->id_country) && is_numeric($this->_address->id_country)) + $selected_country = (int)$this->_address->id_country; + else if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $array = preg_split('/,|-/', $_SERVER['HTTP_ACCEPT_LANGUAGE']); - if (!Validate::isLanguageIsoCode($array[0]) OR !($selectedCountry = Country::getByIso($array[0]))) - $selectedCountry = (int)Configuration::get('PS_COUNTRY_DEFAULT'); + if (!Validate::isLanguageIsoCode($array[0]) || !($selected_country = Country::getByIso($array[0]))) + $selected_country = (int)Configuration::get('PS_COUNTRY_DEFAULT'); } else - $selectedCountry = (int)Configuration::get('PS_COUNTRY_DEFAULT'); + $selected_country = (int)Configuration::get('PS_COUNTRY_DEFAULT'); + // Generate countries list if (Configuration::get('PS_RESTRICT_DELIVERED_COUNTRIES')) $countries = Carrier::getDeliveredCountries($this->context->language->id, true, true); else $countries = Country::getCountries($this->context->language->id, true); - $countriesList = ''; - foreach ($countries AS $country) - $countriesList .= ''; - - if ((Configuration::get('VATNUMBER_MANAGEMENT') AND file_exists(_PS_MODULE_DIR_.'vatnumber/vatnumber.php')) && VatNumber::isApplicable(Configuration::get('PS_COUNTRY_DEFAULT'))) - $this->context->smarty->assign('vat_display', 2); - else if(Configuration::get('VATNUMBER_MANAGEMENT')) - $this->context->smarty->assign('vat_display', 1); - else - $this->context->smarty->assign('vat_display', 0); - - $this->context->smarty->assign('ajaxurl', _MODULE_DIR_); - - $this->context->smarty->assign('vatnumber_ajax_call', (int)file_exists(_PS_MODULE_DIR_.'vatnumber/ajax.php')); + // @todo use helper + $list = ''; + foreach ($countries as $country) + { + $selected = ($country['id_country'] == $selected_country) ? 'selected="selected"' : ''; + $list .= ''; + } + // Assign vars $this->context->smarty->assign(array( - 'countries_list' => $countriesList, + 'countries_list' => $list, 'countries' => $countries, - 'errors' => $this->errors, - 'token' => Tools::getToken(false), - 'select_address' => (int)(Tools::getValue('select_address')) )); - - $this->setTemplate(_PS_THEME_DIR_.'address.tpl'); } - protected function _processAddressFormat() + /** + * Assign template vars related to address format + */ + protected function assignAddressFormat() { - $id_country = is_null($this->_address)? 0 : (int)$this->_address->id_country; - $dlv_adr_fields = AddressFormat::getOrderedAddressFields($id_country, true, true); $this->context->smarty->assign('ordered_adr_fields', $dlv_adr_fields); } - public function displayHeader($display = true) + /** + * Assign template vars related to vat number + * @todo move this in vatnumber module ! + */ + protected function assignVatNumber() { - if (Tools::getValue('ajax') != 'true') - parent::displayHeader(); - } + $vat_number_exists = file_exists(_PS_MODULE_DIR_.'vatnumber/vatnumber.php'); + $vat_number_management = Configuration::get('VATNUMBER_MANAGEMENT'); + if ($vat_number_management && $vat_number_exists) + include_once(_PS_MODULE_DIR_.'vatnumber/vatnumber.php'); - public function displayFooter($display = true) - { - if (Tools::getValue('ajax') != 'true') - parent::displayFooter(); + if ($vat_number_management && $vat_number_exists && VatNumber::isApplicable(Configuration::get('PS_COUNTRY_DEFAULT'))) + $vat_display = 2; + else if ($vat_number_management) + $vat_display = 1; + else + $vat_display = 0; + + $this->context->smarty->assign(array( + 'vatnumber_ajax_call' => (int)file_exists(_PS_MODULE_DIR_.'vatnumber/ajax.php'), + 'vat_display' => $vat_display, + )); } }