Search code examples
cakephpsubqueryconventionscakephp-3.1cakephp-3.x

Subqueries in CakePHP 3?


I have two tables products and product_categories that are associated through a third table, products_categories_products, according to CakePHP BelongsToMany conventions (Edit: these associations are established in ProductsTable.php and ProductCategoriesTable.php). I want to generate a list of product categories, using the image from the best selling products to represent each category.

I can achieve my desired outcome using the following function:

public function findImages(Query $query, array $options) {
    $query->select([
        'ProductCategories.id',
        'ProductCategories.name',
        'ProductCategories__image' => '(SELECT Products.image
        FROM product_categories_products AS ProductCategoriesProducts
        LEFT JOIN products AS Products
        ON ProductCategoriesProducts.product_id = Products.id
        WHERE ProductCategoriesProducts.product_category_id = ProductCategories.id
        ORDER BY Products.turnover DESC
        LIMIT 1)'
    ])->where([
        'ProductCategories.name <>' => 'Unsorted'
    ])->order([
        'ProductCategories.name'    => 'asc'
    ]);
    return $query;
}

Is this acceptable or is there a Cake-ier way to achieve my goal? I couldn't really find anything on the topic of crafting subqueries in CakePHP 3. I just stumbled into the above solution after a couple hours of frustration. Any advice appreciated!


Solution

  • Thanks to the link from user ndm_yesterday, I generated the following solution:

    public function findImages(Query $query, array $options) {
        $this->hasMany('ProductCategoriesProducts');
    
        $subquery = $this->ProductCategoriesProducts->find('all')->select([
            'Products.image'
        ])->join([
            [
                'table'     => 'products',
                'alias'     => 'Products',
                'type'      => 'LEFT',
                'conditions'=> [
                    'ProductCategoriesProducts.product_id = Products.id'
                ]
            ]
        ])->where([
            'ProductCategoriesProducts.product_category_id = ProductCategories.id'
        ])->order([
            'Products.turnover' => 'DESC'
        ])->limit(1);
    
        $query->select([
            'ProductCategories.id',
            'ProductCategories.name',
            'ProductCategories__image' => $subquery
        ])->where([
            'ProductCategories.name <>' => 'Unsorted'
        ])->order([
            'ProductCategories.name'    => 'asc'
        ]);
    
        return $query;
    }