0

I am trying to fetch Product where Low stock > Stock.

Why i am getting Wrong results in CakePHP Query ?

Using CakePHP Custom query it is working fine. but with default pagination query result are wrong.

I have association between Product and Category Model.

Controller code :

$condition = array('Product.status =' => 1, 'Product.is_deleted !=' => 1, 
'Product.low_stock_alert != ' => 0, 'Product.low_stock_alert >' => 'Product.stock');

    $this->paginate = array('fields' => array('Product.id', 'Product.name',
'Product.code', 'Product.stock_type','Product.low_stock_alert',
'Product.stock','category.name'),'conditions' => $condition, 'limit' => Configure::read('LIST_PROD_NUM_RECORDS'),'order' => 'Product.id ASC');

Query Generating :

SELECT `Product`.`id`, `Product`.`name`, `Product`.`code`, `Product`.`stock_type`,
`Product`.`stock`, `category`.`name` FROM `shopping`.`products` AS `Product` LEFT 
JOIN `shopping`.`categories` AS `Category` ON (`Product`.`category_id` = 
`Category`.`id`) LEFT JOIN `shopping`.`users` AS `AddedBy` ON (`Product`.`added_by` 
= `AddedBy`.`id`) LEFT JOIN `shopping`.`users` AS `ModifiedBy` ON 
(`Product`.`modified_by` = `ModifiedBy`.`id`) WHERE `Product`.`status` = 1 AND 
`Product`.`is_deleted` != 1 AND `Product`.`low_stock_alert` != 0 AND 
`Product`.`low_stock_alert` > 'Product.stock' ORDER BY `Product`.`id` ASC LIMIT 100

Model -> Product.php

class Product extends AppModel {

    public $name = 'Product';
    public $cacheQueries = false;
    public $actsAs = array('Containable');
    public $belongsTo = array(
        'Category' => array(
            'className' => 'Category',
            'foreignKey' => 'category_id',
            'fields' => array('name', 'description', 'stock_type', 'qrt_per', 'half_per', 'three_forth_per')
        ),
        'AddedBy' => array(
            'className' => 'User',
            'foreignKey' => 'added_by',
            'fields' => array('first_name', 'last_name', 'email')
        ),
        'ModifiedBy' => array(
            'className' => 'User',
            'foreignKey' => 'modified_by',
            'fields' => array('first_name', 'last_name', 'email')
        )
    );
}

Model -> Category.php

class Category extends AppModel {
    var $name = 'Category';
    public $cacheQueries = false;
    public $belongsTo = array(
        'AddedBy' => array(
            'className' => 'User',
            'foreignKey' => 'added_by',
            'fields' => array('first_name', 'last_name', 'email')
        ),
        'ModifiedBy' => array(
            'className' => 'User',
            'foreignKey' => 'modified_by',
            'fields' => array('first_name', 'last_name', 'email')
        )
    );
    public $hasMany = array(
        'Product' => array(
            'className' => 'Product',
            'order' => 'Product.created DESC'
        )
    );
}

Wrong Result:

enter image description here

But with this below Custom Query i am getting accurate result:

 $data = $this->Product->Query("SELECT products.*, categories.name, categories.description, categories.stock_type, categories.qrt_per, categories.half_per, categories.three_forth_per, AddedBy.first_name, AddedBy.last_name, AddedBy.email, ModifiedBy.first_name, ModifiedBy.last_name, ModifiedBy.email FROM sunnaair_kaziDB.products AS products LEFT JOIN sunnaair_kaziDB.categories AS categories ON (products.category_id = categories.id) LEFT JOIN sunnaair_kaziDB.users AS AddedBy ON (products.added_by = AddedBy.id) LEFT JOIN sunnaair_kaziDB.users AS ModifiedBy ON (products.modified_by = ModifiedBy.id) WHERE products.status = 1 AND products.is_deleted != 1 AND products.low_stock_alert != 0 AND products.low_stock_alert > products.stock ORDER BY products.id ASC LIMIT 50");

1 Answer 1

3

Your problem is with this condition:

'Product.low_stock_alert >' => 'Product.stock'

In Cake, 'Product.stock' is not read as a table name but as a literal string. Please see the subtle error in the generated SQL:

AND `Product`.`low_stock_alert` > 'Product.stock'

To fix it, please try changing the condition to:

'Product.low_stock_alert > Product.stock'

So the whole line becomes:

 $condition = array('Product.status =' => 1, 'Product.is_deleted !=' => 1, 
'Product.low_stock_alert != ' => 0, 'Product.low_stock_alert > Product.stock');

Remember the following: => is for escaping. Don't use this when comparing columns to columns. You could even just dump using => all together for these conditions as there is no vector for an SQL injection attack here.

Sign up to request clarification or add additional context in comments.

1 Comment

Hey James .. i appreciate your efforts. This problem takes my lot of time.Thankx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.