Follow us on Twitter X-Cart on Facebook Wiki
Shopping cart software Solutions for online shops and malls

Extending Tags Module without Breaking Search
 
Reply
   X-Cart forums > X-Cart 5 > Modifying the design and features (X-Cart 5)
 
Thread Tools Search this Thread
  #1  
Old 07-10-2018, 09:03 AM
 
xgarb xgarb is online now
 

eXpert
  
Join Date: Jul 2004
Location: UK
Posts: 252
 

Default Extending Tags Module without Breaking Search

I've created a module that extends the Tags module. Basically it does site-wide filtering on grouped tags.

The problem is the code below is breaking the search - I guess as I'm decorating a class that search uses. How can I use my querybuilder code below without breaking search?




PHP Code:
<?php

class Product extends \XLite\Model\Repo\Product implements \XLite\Base\IDecorator
{

    protected function 
prepareCndSubstring(\Doctrine\ORM\QueryBuilder $queryBuilder$value)
    {
        
        
$tagsGroupsArray // not important but is something like  array('animal' => 'cat-dog','colour' => 'red-blue-green','size' => 'small')
        
        
$queryBuilder->linkLeft('p.tags''t'); 
        
$queryBuilder->linkLeft('t.tag_groups''tg');
        
        
$this->addTranslationJoins($queryBuilder't''tt'$this->getTranslationCode());
    
        
$queryBuilder->addGroupBy('p.id');
        
        foreach (
$tagsGroupsArray as $key => $val) {
            
$inString str_replace("-""','"$val);
            
$queryBuilder->andHaving("SUM(CASE WHEN tt.name IN ('".$inString."') AND tg.group_name = '".$key."' THEN 1 ELSE 0 END  ) > 0");
        }
            
}
__________________
Core version: 5.3.xx
PHP: 5.6
MySQL: 5.5.50-cll
Web server: Apache
Reply With Quote
  #2  
Old 07-11-2018, 01:30 AM
 
xgarb xgarb is online now
 

eXpert
  
Join Date: Jul 2004
Location: UK
Posts: 252
 

Default Re: Extending Tags Module without Breaking Search

OK.. I've done it like this....

PHP Code:
<?php 

class Product extends \XLite\Model\Repo\Product implements \XLite\Base\IDecorator 


    protected function 
prepareCndSubstring(\Doctrine\ORM\QueryBuilder $queryBuilder$value
    { 
    if (
$_GET['target'] != 'search'){         
        
$tagsGroupsArray // not important but is something like  array('animal' => 'cat-dog','colour' => 'red-blue-green','size' => 'small') 
         
        
$queryBuilder->linkLeft('p.tags''t');  
        
$queryBuilder->linkLeft('t.tag_groups''tg'); 
         
        
$this->addTranslationJoins($queryBuilder't''tt'$this->getTranslationCode()); 
     
        
$queryBuilder->addGroupBy('p.id'); 
         
        foreach (
$tagsGroupsArray as $key => $val) { 
            
$inString str_replace("-""','"$val); 
            
$queryBuilder->andHaving("SUM(CASE WHEN tt.name IN ('".$inString."') AND tg.group_name = '".$key."' THEN 1 ELSE 0 END  ) > 0"); 
        } 
         }
    if (
$_GET['target'] == 'search'){        
    
parent::prepareCndSubstring($queryBuilder$value);
    }            
}

The problem now is that getItemsCount() is counting all the products in the store while the page (the Itemlist) shows the correct result.

I don't know why getData() finds the products based on the tags correctly but it doesn't count the number of results.
__________________
Core version: 5.3.xx
PHP: 5.6
MySQL: 5.5.50-cll
Web server: Apache
Reply With Quote
  #3  
Old 07-11-2018, 05:48 AM
  tony_sologubov's Avatar 
tony_sologubov tony_sologubov is online now
 

X-Cart team
  
Join Date: Jan 2009
Posts: 2,367
 

Default Re: Extending Tags Module without Breaking Search

Hi @xgarb,

You do not need to change prepareCndSubstring() method in this case at all. You should define a new condition in your ItemsList, e.g. TagsSubstring and then add the handler of this condition to \XLite\Model\Repo\Product class.

See more about conditions here:
https://devs.x-cart.com/getting_star...#method-search

See example of adding such condition to ItemsList here:
https://devs.x-cart.com/basics/itemslist_in_admin_area/

see how we define getSearchCondition() method there.

Please, let me know if it makes sense to you.

If it is unclear what I am trying to explain, please let me know. I will be happy to help.

Tony
__________________
Found a bug in X-Cart? Post it to our bug tracker!
Know how to make X-Cart better? Suggest an idea!
Reply With Quote

The following 2 users thank tony_sologubov for this useful post:
mcupka (07-11-2018), xgarb (07-12-2018)
  #4  
Old 07-12-2018, 06:51 AM
 
xgarb xgarb is online now
 

eXpert
  
Join Date: Jul 2004
Location: UK
Posts: 252
 

Default Re: Extending Tags Module without Breaking Search

Thanks for the tips. This is what I have so far...

Controller
PHP Code:
namespace XLite\Module\XCExample\SearchRepoDemo\Controller\Customer;
 
class 
ItemsListDemo extends \XLite\Controller\Customer\ACustomer
{
    public function 
getTitle()
    {
        return 
'Hello World';
    }


Repo
PHP Code:
namespace XLite\Module\XCExample\SearchRepoDemo\Model\Repo;

abstract class 
Product extends \XLite\Model\Repo\Product implements \XLite\Base\IDecorator
{
    const 
P_MORE_THAN_10 'moreThan10';
    const 
P_HAS_TAGS 'hasTags';
    
    protected function 
getHandlingSearchParams()
    {
        
$params parent::getHandlingSearchParams();

        
$params[] = self::P_MORE_THAN_10;
        
$params[] = self::P_HAS_TAGS;
        
        return 
$params;
    }    
    
    protected function 
prepareCndHasTags(\Doctrine\ORM\QueryBuilder $queryBuilder)
    {
        
$result $queryBuilder;    
        
        
$path 'approvals/atex-mcerts'//$value;
        
$tagsInUrl explode('/'$path);
        
        
$tagsGroupsArray = [];
        while (
count($tagsInUrl)) {
            
$tagsGroupsArray[array_shift($tagsInUrl)] = array_shift($tagsInUrl);
        }
            
        
$result->linkLeft('p.tags''t'); 
        
$result->linkLeft('t.tag_groups''tg');
        
        
$this->addTranslationJoins($result't''tt'$this->getTranslationCode());

        
$result->addGroupBy('p.id');
        
        
        foreach (
$tagsGroupsArray as $key => $val) {
            
$inString str_replace("-""','"$val);
            
$result->andHaving("SUM(CASE WHEN tt.name IN ('".$inString."') AND tg.group_name = '".$key."' THEN 1 ELSE 0 END  ) > 0");
        }
    
        return 
$result;
    }    
    
    protected function 
prepareCndMoreThan10(\Doctrine\ORM\QueryBuilder $queryBuilder$value)
    {
        
$result $queryBuilder;

        if (
$value) {
            
$result
                
->andWhere('p.price > :price')
                ->
setParameter('price'10.00);
        }

        return 
$result;
    }


Tag Model
PHP Code:
namespace XLite\Module\XCExample\SearchRepoDemo\Model;

class 
Tag extends \XLite\Module\XC\ProductTags\Model\Tag implements \XLite\Base\IDecorator
{

    
/**
     * 
     * @var \XLite\Module\XCExample\SearchRepoDemo\Model\TagGroup
     * @ManyToOne  (targetEntity="XLite\Module\XCExample\SearchRepoDemo\Model\TagGroup", inversedBy="tags")
     * @JoinColumn (name="group_id", referencedColumnName="id")     
     */
    
protected $tag_groups;    


Tag Group Model
PHP Code:
namespace XLite\Module\XCExample\SearchRepoDemo\Model;

/**
 * The "TagGroup" model class
 *
 * @Entity
 * @Table  (name="tag_groups")
 */
class TagGroup extends \XLite\Model\AEntity
{

    
/**
     * Unique ID
     *
     * @var integer
     *
     * @Id
     * @GeneratedValue (strategy="AUTO")
     * @Column         (type="integer", options={ "unsigned": true })
     */
    
protected $id;
     
    
/**
     * @Column (type="string", length=255)
     */
    
protected $group_name;


    
/**
     * Returns id
     *
     * @return string
     */
    
public function getId()
    {
        return 
$this->id;
    }    
        
    
/**
     * Set text
     *
     * @param string $value Value
     *
     * @return void
     */
    
public function setText($value)
    {
        
$this->text $value;
    }
    
    
/**
     * Returns text
     *
     * @return string
     */
    
public function getText()
    {
        return 
$this->text;
    }


ItemsList
PHP Code:
namespace XLite\Module\XCExample\SearchRepoDemo\View\ItemsList\Customer;

class 
ItemsListDemo extends \XLite\View\ItemsList\Product\Customer\Search
{
    const 
SORT_BY_MODE_PRICE 'p.price';

    protected function 
defineRepositoryName()
    {
        return 
'\XLite\Model\Product';
    }
    
    public static function 
getAllowedTargets()
    {
        return 
array_merge(parent::getAllowedTargets(), array('items_list_demo'));
    }
    

    public function 
__construct(array $params = array())
    {
        
$this->sortByModes += array(
            static::
SORT_BY_MODE_PRICE  => 'Price',
        );

        
parent::__construct($params);
    }

    protected function 
getSortByModeDefault()
    {
        return static::
SORT_BY_MODE_PRICE;
    }

    protected function 
getSearchCondition()
    {
        
$result parent::getSearchCondition();

        
$result->{\XLite\Model\Repo\Product::P_ORDER_BY} = $this->getOrderBy();
        
$result->moreThan10 true;
        
$result->hasTags true;

        return 
$result;
    }


I have the following error:

[Semantical Error] line 0, col 314 near 'tt WHERE p.enabled': Error: 'tt' is already defined.

from this code

PHP Code:
protected function prepareCndSubstring(\Doctrine\ORM\QueryBuilder $queryBuilder$value)
    {
        
$queryBuilder->linkLeft('p.tags''t');
        
$this->addTranslationJoins($queryBuilder't''tt'$this->getTranslationCode());

        
parent::prepareCndSubstring($queryBuilder$value);
    } 

in this file: XLite\Module\XC\ProductTags\Model\Repo\Product

I'm not sure what to do to stop the querybuilder adding the code in ProductTags repo?

T
__________________
Core version: 5.3.xx
PHP: 5.6
MySQL: 5.5.50-cll
Web server: Apache
Reply With Quote
  #5  
Old 07-13-2018, 07:14 AM
  tony_sologubov's Avatar 
tony_sologubov tony_sologubov is online now
 

X-Cart team
  
Join Date: Jan 2009
Posts: 2,367
 

Default Re: Extending Tags Module without Breaking Search

Hi @xgarb,

Perfect, seems like the mod is almost complete!
I do not think you need this 'moreThan10' condition though.

This error seems to be caused by a bug. The addTranslationJoins() method should have used linkLeft() method instead of leftJoin() one. I will report that.

As a workaround solution, try to add the following method to your \XLite\Module\XCExample\SearchRepoDemo\Model\Repo\ Product class

PHP Code:
protected function addTranslationJoins($queryBuilder$alias$translationsAlias$code)
    {
        
$queryBuilder->linkLeft(
            
$alias '.translations',
            
$translationsAlias
        
);

        return 
$queryBuilder;
    } 

Please, let me know if it fixes the problem.

Tony


Quote:
Originally Posted by xgarb
I have the following error:

[Semantical Error] line 0, col 314 near 'tt WHERE p.enabled': Error: 'tt' is already defined.

from this code

PHP Code:
protected function prepareCndSubstring(\Doctrine\ORM\QueryBuilder $queryBuilder$value)
    {
        
$queryBuilder->linkLeft('p.tags''t');
        
$this->addTranslationJoins($queryBuilder't''tt'$this->getTranslationCode());

        
parent::prepareCndSubstring($queryBuilder$value);
    } 

in this file: XLite\Module\XC\ProductTags\Model\Repo\Product

I'm not sure what to do to stop the querybuilder adding the code in ProductTags repo?

T
__________________
Found a bug in X-Cart? Post it to our bug tracker!
Know how to make X-Cart better? Suggest an idea!
Reply With Quote
  #6  
Old 07-13-2018, 08:02 AM
 
xgarb xgarb is online now
 

eXpert
  
Join Date: Jul 2004
Location: UK
Posts: 252
 

Default Re: Extending Tags Module without Breaking Search

That change gives me a 500 error with Allowed memory size of 268435456 bytes exhausted in the log.

I think it's something to do with this in my Product Repo..

$this->addTranslationJoins($result, 't', 'tt', $this->getTranslationCode());

and the same code in the prepareCndSubstring() method of the X-cart Tags module.

Due to both extending \XLite\Model\Repo\Product maybe.
__________________
Core version: 5.3.xx
PHP: 5.6
MySQL: 5.5.50-cll
Web server: Apache
Reply With Quote
  #7  
Old Today, 03:47 AM
  tony_sologubov's Avatar 
tony_sologubov tony_sologubov is online now
 

X-Cart team
  
Join Date: Jan 2009
Posts: 2,367
 

Default Re: Extending Tags Module without Breaking Search

Hi @xgarb,

I tried the same solution on my X-Cart and it worked out properly. However, this error might be caused by the fact that MySQL query is too heavy and Doctrine cannot handle it properly on your server.

When you received this Allowed memory size of 268435456 bytes exhausted error, were there any hints about what might be causing it? Maybe some backtrace?

Tony

Quote:
Originally Posted by xgarb
That change gives me a 500 error with Allowed memory size of 268435456 bytes exhausted in the log.

I think it's something to do with this in my Product Repo..

$this->addTranslationJoins($result, 't', 'tt', $this->getTranslationCode());

and the same code in the prepareCndSubstring() method of the X-cart Tags module.

Due to both extending \XLite\Model\Repo\Product maybe.
__________________
Found a bug in X-Cart? Post it to our bug tracker!
Know how to make X-Cart better? Suggest an idea!
Reply With Quote
  #8  
Old Today, 04:02 AM
 
xgarb xgarb is online now
 

eXpert
  
Join Date: Jul 2004
Location: UK
Posts: 252
 

Default Re: Extending Tags Module without Breaking Search

This is the X-cart PHP log...

Code:
<?php die(1); ?> [16-Jul-2018 12:56:35] Error (code: 1): Allowed memory size of 268435456 bytes exhausted (tried to allocate 20480 bytes) Server API: fpm-fcgi; Request method: GET; URI: /x5-tags-test/?target=items_list_demo; Backtrace: #0 Includes\ErrorHandler::logInfo() called at [/home/xxxx/public_html/x5-tags-test/Includes/ErrorHandler.php:403] #1 Includes\ErrorHandler::handleError() called at [/home/xxxx/public_html/x5-tags-test/Includes/ErrorHandler.php:388] #2 Includes\ErrorHandler::shutdown()

So not much help. The query was working when I was just over-riding the prepareCndSubstring but I didn't get the correct count value and as you've shown it's not really the right way to do this.

I could add some logging into the prepareCndSubstring() method of the X-cart Tags module to see what it's doing?
__________________
Core version: 5.3.xx
PHP: 5.6
MySQL: 5.5.50-cll
Web server: Apache
Reply With Quote
Reply
   X-Cart forums > X-Cart 5 > Modifying the design and features (X-Cart 5)


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -8. The time now is 02:29 PM.

   

 
X-Cart forums © 2001-2018