Víctor Martín
Víctor Martín

Reputation: 3450

How to show only per attribute

I'm trying to make a optics shop with PRESTASHOP, but I'm facing a problem. I've create 4 new columns in product and customer table (left eye diopter, right eye diopter, bridge length, leg length), the same in both tables.

What I want to do is when the shop load the products, compare this variables and if they are the same then show the product. This is to try to filter glasses to the client, only showing him the glasses that are compatible with him.

The original query is the next:

$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) AS quantity'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
                    product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
                    pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
                    il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
                    DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
                    INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
                FROM `'._DB_PREFIX_.'category_product` cp
                LEFT JOIN `'._DB_PREFIX_.'product` p
                    ON p.`id_product` = cp.`id_product`
                '.Shop::addSqlAssociation('product', 'p').
                (Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
                ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
                '.Product::sqlStock('p', 0).'
                LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
                    ON (product_shop.`id_category_default` = cl.`id_category`
                    AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
                LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
                    ON (p.`id_product` = pl.`id_product`
                    AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
                LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
                    ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
                LEFT JOIN `'._DB_PREFIX_.'image_lang` il
                    ON (image_shop.`id_image` = il.`id_image`
                    AND il.`id_lang` = '.(int)$id_lang.')
                LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
                    ON m.`id_manufacturer` = p.`id_manufacturer`
                WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
                    AND cp.`id_category` = '.(int)$this->id
                    .($active ? ' AND product_shop.`active` = 1' : '')
                    .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
                    .($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');

I'm trying to modify it, but I don't have very clear how to. And in consecuence, I'm doing wrong things. I've added the next left joins to the query.

LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON pa.`id_product` = p.`id_product`
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac.`id_product_attribute` = pa.`id_product_attribute`
LEFT JOIN `'._DB_PREFIX_.'attribute` attr ON attr.`id_attribute` = pac.`id_attribute`
LEFT JOIN `'._DB_PREFIX_.'attribute_lang` attr_lang ON (attr_lang.`id_attribute` = pac.`id_attribute` AND attr_lang.`id_lang` = '.(int)$id_lang.')LEFT JOIN `'._DB_PREFIX_.'attribute_group` attr_group ON attr_group.`id_attribute_group` = attr.`id_attribute_group`
LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` attr_group_lang ON attr_group_lang.`id_attribute_group` = attr.`id_attribute_group`

Thank you for any advice.

EDIT:

The new fields of the products are features inside prestashop (there aren't inside product table) sorry for the mistake.

I put the data model of prestashop for your info.

DataModel

EDIT 2:

I'm trying now to achieve this by using a module, so my php file of my module has the next code. I've follow the code from CategoryController.php, but I don't know how to remove a product if the conditions are not satisfied.

<?php

if (!defined('_PS_VERSION_'))
    exit;

class glassOptics extends Module
{
    /* @var boolean error */
    protected $_errors = false;

    public function __construct()
    {
        $this->name = 'glassOptics';
        $this->tab = 'front_office_features';
        $this->version = '1.0';
        $this->author = 'MAOL';
        $this->need_instance = 0;

        parent::__construct();

        $this->displayName = $this->l('glassOptics');
        $this->description = $this->l('...');
    }

    public function install()
    {
        if (!parent::install() OR
            !$this->veopticasCustomerDB('add') OR
            !$this->veopticasProductDB('add') OR            
            !$this->registerHook('hookActionProductListOverride')
            return false;
        return true;
    }

    public function uninstall()
    {
        if (!parent::uninstall() OR !$this->veopticasCustomerDB('remove') OR !$this->veopticasProductDB('remove'))
            return false;
        return true;
    }


    public function veopticasCustomerDB($method)
    {
        switch ($method) {
            case 'add': 
                $sql = 'CREATE TABLE IF EXISTS `'._DB_PREFIX_.'customer_optics_data` (
                `id_customer` int(10) UNSIGNED NOT NULL,
                `left_dioptrics` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `right_dioptrics` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `bridge` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `leg` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `glass_width` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `glass_height` decimal(20,6) NOT NULL DEFAULT '0.000000'
                ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8';

                break;

            case 'remove':
                $sql = 'DROP TABLE IF EXISTS `'._DB_PREFIX_ . 'customer_optics_data`';
                break;
        }

        if(!Db::getInstance()->Execute($sql))
            return false;
        return true;
    }

    public function veopticasProductDB($method)
    {
        switch ($method) {
            case 'add': 
                $sql = 'CREATE TABLE IF EXISTS `'._DB_PREFIX_.'product_optics_data` (
                `id_product` int(10) UNSIGNED NOT NULL,
                `left_dioptrics` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `right_dioptrics` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `bridge` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `leg` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `glass_width` decimal(20,6) NOT NULL DEFAULT '0.000000',
                `glass_height` decimal(20,6) NOT NULL DEFAULT '0.000000'
                ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8';

                break;

            case 'remove':
                $sql = 'DROP TABLE IF EXISTS `'._DB_PREFIX_ . 'product_optics_data`';
                break;
        }

        if(!Db::getInstance()->Execute($sql))
            return false;
        return true;
    }


    public function hookActionProductListOverride($params)
    {
        $customer_settings = glassOptics::getCustomerSettings($this->context->customer);

        if ($customer_settings) {
            // Inform the hook was executed
            $params['hookExecuted'] = true;

            // Filter products here, you are now overriding the default
            // functionality of CategoryController class.
            // You can see blocklayered module for more details.

            if ((isset($this->context->controller->display_column_left) && !$this->context->controller->display_column_left)
            && (isset($this->context->controller->display_column_right) && !$this->context->controller->display_column_right))
            return false;

            global $smarty;
            if (!Configuration::getGlobalValue('PS_LAYERED_INDEXED'))
                return;

            $categories_count = Db::getInstance()->getValue('
                SELECT COUNT(*)
                FROM '._DB_PREFIX_.'layered_category
                WHERE id_category = '.(int)Tools::getValue('id_category', Tools::getValue('id_category_layered', Configuration::get('PS_HOME_CATEGORY'))).'
                AND id_shop = '.(int) Context::getContext()->shop->id
            );

            if ($categories_count == 0)
                return;


            // List of product to overrride categoryController
            $params['catProducts'] = array();
            $selected_filters = $this->getSelectedFilters();
            $filter_block = $this->getFilterBlock($selected_filters);
            $title = '';

            if (is_array($filter_block['title_values']))
                foreach ($filter_block['title_values'] as $key => $val)
                    $title .= ' > '.$key.' '.implode('/', $val);

            $smarty->assign('categoryNameComplement', $title);
            $this->getProducts($selected_filters, $params['catProducts'], $params['nbProducts'], $p, $n, $pages_nb, $start, $stop, $range);
            // Need a nofollow on the pagination links?
            $smarty->assign('no_follow', $filter_block['no_follow']);

            foreach ($params['nbProducts'] as $product) {

                $product_settings = glassOptics::getProductSettings($product);

                if($product_settings){
                    $same_bridge            = ($product_settings->bridge == $customer_settings->bridge ? true : false);
                    $same_leg           = ($product_settings->leg == $customer_settings->leg ? true : false);
                    $same_glass_width   = ($product_settings->glass_width == $customer_settings->glass_width ? true : false);
                    $same_glass_heigth      = ($product_settings->glass_heigth == $customer_settings->glass_heigth ? true : false);
                }

            }

        }
    }
}

Upvotes: 0

Views: 1791

Answers (1)

Eihwaz
Eihwaz

Reputation: 1234

I'd recommend taking a different approach and use a module for that. You would create a module that upon installation creates a table_ something like customer_optics_data. Table structure could look something like this:

CREATE TABLE `'._DB_PREFIX_.'customer_optics_data` (
  `id_customer` int(10) UNSIGNED NOT NULL,
  `left_eye_diopter` int(10) UNSIGNED NOT NULL,
  `right_eye_diopter` int(10) UNSIGNED NOT NULL,
  `bridge_length` decimal(20,6) NOT NULL DEFAULT '0.000000',
  `leg_length` decimal(20,6) NOT NULL DEFAULT '0.000000'
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;

Then your module would hook onto actionProductListOverride hook, and this is where you would perform the check:

public function hookActionProductListOverride($params)
{
    $customer_settings = MyDiopterModuleHelperClass::getCustomerSettings($this->context->customer);

    if ($customer_settings) {
        $params['hookExecuted'] = true;

        // Filter products here, you are now overriding the default
        // functionality of CategoryController class.
        // You can see blocklayered module for more details.
    }
}

The module would have a helper class MyDiopterModuleHelperClass that is there to register and obtain data to/from the customer_optics_data table. This way you're not overriding the core, your updates will still function as normal, the worst thing that can happen is if the hook is suddenly removed from the future versions of PrestaShop, which is unlikely.

The module would also employ the following hooks:

  • displayCustomerIdentityForm - to display additional fields in My Personal information. This is where your customers would input their information for the module.

  • actionObjectCustomerAddAfter - this is where you would fetch that data from $_POST and save it in module's table

  • actionObjectCustomerUpdateAfter - this is where you would update the data if it has been changed by the customer or insert the data if for some reason it's not there.

Optionally, you could also hook the module onto displayAdminCustomersForm - to display the additional fields in the customers form in your back office.

Upvotes: 2

Related Questions