Jump to content

how to override business-logic method that calls smarty fetch() or display()?


JuanTomas

Recommended Posts

(Using P-Shop 1.6.1.1)

 

It's easy to override methods that return raw data.  For instance, BlockNewProducts.php in the blocknewproducts module has the getNewProducts() method:

 

class BlockNewProducts extends Module{

...

    protected function getNewProducts()
        {
            // makes an array called $newProducts, which contains several product objects
            return $newProducts;
        }

...

}

 

So you can override like:

 

class BlockNewProductsOverride extends BlockNewProducts
{
    protected function getNewProducts()
    {
        $NewProducts = array();
        $BaseProducts = parent::getNewProducts();
        foreach ($BaseProducts as $product){
              // Add Custom Fields To Each Product Object

             $product['my-key']="My Most Excellent Value";

              // Push modified product objects onto a new array

             $NewProducts[] = $product ;

         }
         // Now the template can behave differently depending on the values in each product's my-key
         return $NewProducts ;
     }
}
 

But some modules don't have a separate method like this.  Consider BlockViewed.php in the blockviewed module.  Its hookRightColumn() method does all the work in the class.  You can skip most of the code, what's important is:

 

* The method is longish

* The method contains all the "business logic" for displaying viewed objects, and...

* The method calls display() at the end.   :o

 

class BlockViewed extends Module
{
    ...

    public function hookRightColumn($params)
    {
        $productsViewed = (isset($params['cookie']->viewed) && !empty($params['cookie']->viewed)) ? array_slice(array_reverse(explode(',', $params['cookie']->viewed)), 0, Configuration::get('PRODUCTS_VIEWED_NBR')) : array();

        if (count($productsViewed))
        {
            $defaultCover = Language::getIsoById($params['cookie']->id_lang).'-default';

            $productIds = implode(',', array_map('intval', $productsViewed));
            $productsImages = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
            SELECT MAX(image_shop.id_image) id_image, p.id_product, il.legend, product_shop.active, pl.name, pl.description_short, pl.link_rewrite, cl.link_rewrite AS category_rewrite
            FROM '._DB_PREFIX_.'product p
            '.Shop::addSqlAssociation('product', 'p').'
            LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product'.Shop::addSqlRestrictionOnLang('pl').')
            LEFT JOIN '._DB_PREFIX_.'image i ON (i.id_product = p.id_product)'.
            Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').'
            LEFT JOIN '._DB_PREFIX_.'image_lang il ON (il.id_image = image_shop.id_image AND il.id_lang = '.(int)($params['cookie']->id_lang).')
            LEFT JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = product_shop.id_category_default'.Shop::addSqlRestrictionOnLang('cl').')
            WHERE p.id_product IN ('.$productIds.')
            AND pl.id_lang = '.(int)($params['cookie']->id_lang).'
            AND cl.id_lang = '.(int)($params['cookie']->id_lang).'
            GROUP BY product_shop.id_product'
            );

            $productsImagesArray = array();
            foreach ($productsImages as $pi)
                $productsImagesArray[$pi['id_product']] = $pi;

            $productsViewedObj = array();
            foreach ($productsViewed as $productViewed)
            {
                $obj = (object)'Product';
                if (!isset($productsImagesArray[$productViewed]) || (!$obj->active = $productsImagesArray[$productViewed]['active']))
                    continue;
                else
                {
                    $obj->id = (int)($productsImagesArray[$productViewed]['id_product']);
                    $obj->id_image = (int)$productsImagesArray[$productViewed]['id_image'];
                    $obj->cover = (int)($productsImagesArray[$productViewed]['id_product']).'-'.(int)($productsImagesArray[$productViewed]['id_image']);
                    $obj->legend = $productsImagesArray[$productViewed]['legend'];
                    $obj->name = $productsImagesArray[$productViewed]['name'];
                    $obj->description_short = $productsImagesArray[$productViewed]['description_short'];
                    $obj->link_rewrite = $productsImagesArray[$productViewed]['link_rewrite'];
                    $obj->category_rewrite = $productsImagesArray[$productViewed]['category_rewrite'];
                    // $obj is not a real product so it cannot be used as argument for getProductLink()
                    $obj->product_link = $this->context->link->getProductLink($obj->id, $obj->link_rewrite, $obj->category_rewrite);

                    if (!isset($obj->cover) || !$productsImagesArray[$productViewed]['id_image'])
                    {
                        $obj->cover = $defaultCover;
                        $obj->legend = '';
                    }
                    $productsViewedObj[] = $obj;
                }
            }

            if (!count($productsViewedObj))
                return;

            $this->smarty->assign(array(
                'productsViewedObj' => $productsViewedObj,
                'mediumSize' => Image::getSize('medium')));

            return $this->display(__FILE__, 'blockviewed.tpl');
        }
        return;
    }

    ...

}

 

How is it possible to override this?  You'd literally have to copy the entire method into your override to add any functionality to it.  That kind of override will not play well with upgrades.

 

I think this is a violation of the MVC concept, because it couples the Model to the View so tightly that you can't floss in between.  Business logic belongs in a separate method where it can be safely overridden.  Any method making a display() call should be getting its input data from a separate "business logic" method.

 

This problem is widespread in Prestashop core modules and classes.  Is there something I'm missing here?  Is there an elegant way to override methods like this?

Edited by JuanTomas (see edit history)
Link to comment
Share on other sites

Hooks are usually a better way of overriding the business logic - when there's a suitable one available that is. Overriding the core classes themselves is also good. With these you can then manipulate the data at creation consistently.

 

As for modules such as those in your examples -  it would usually be better just implementing your own than overriding an existing one.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...