Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Aggregate queries generated through Model static methods ignore transaction parameter #15113

Closed
scrnjakovic opened this issue Jul 20, 2020 · 2 comments
Assignees
Labels
bug A bug report

Comments

@scrnjakovic
Copy link
Contributor

Describe the bug
While you can pass transaction instance to Model::find(), passing transaction to any method which generates aggregate query i.e. Model::sum() etc. will ignore transaction.

To Reproduce

$transaction = ...

$model = new Model();
$model->setTransaction($transaction);
$model->create();

$results = Model::find(
    ...
    'transaction' => $transaction
);

// ignores transaction
$result = Model::sum(
    ...
    'transaction' => $transaction
);

Details

  • Phalcon version: 3.4.1
@scrnjakovic scrnjakovic added bug A bug report status: unverified Unverified labels Jul 20, 2020
@scrnjakovic
Copy link
Contributor Author

scrnjakovic commented Jul 20, 2020

For those looking for a quick fix, here's a fixed Model that you'll need to use as a base model.

<?php

namespace My\Namespace;

use Phalcon\Mvc\Model as PhModel;
use Phalcon\Mvc\Model\ResultsetInterface;
use Phalcon\Mvc\Model\TransactionInterface;
use Phalcon\Di;

class Model extends PhModel
{
    /**
     * Generate a PHQL SELECT statement for an aggregate
     *
     * @param string function
     * @param string alias
     * @param array parameters
     * @return \Phalcon\Mvc\Model\ResultsetInterface
     */
    protected static function _groupResult($functionName, $alias, $parameters)
    {
        $dependencyInjector = Di::getDefault();
        $manager = $dependencyInjector->getShared("modelsManager");

        if (is_array($parameters) == false) {
            $params = [];
            if ($parameters !== null) {
                $params[] = $parameters;
            }
        } else {
            $params = $parameters;
            
        }
        $groupColumn = $params["column"] ?? null;
        if ($groupColumn === null) {
            $groupColumn = "*";
        }

        /**
         * Builds the columns to query according to the received parameters
         */
        $distinctColumn = $params["distinct"] ?? null;
        if ($distinctColumn) {
            $columns = $functionName . "(DISTINCT " . $distinctColumn . ") AS " . $alias;
        } else {
            $groupColumns = $params["group"] ?? null;
            if ($groupColumns) {
                $columns = $groupColumns . ", " . $functionName . "(" . $groupColumn . ") AS " . $alias;
            } else {
                $columns = $functionName . "(" . $groupColumn . ") AS " . $alias;
            }
        }

        /**
         * Builds a query with the passed parameters
         */
        $builder = $manager->createBuilder($params);
        $builder->columns($columns);
        $builder->from(get_called_class());

        $query = $builder->getQuery();
        
        // THIS WAS MISSING
        $transaction = $params[self::TRANSACTION_INDEX] ?? null;
        if ($transaction) {
            if ($transaction instanceof TransactionInterface) {
                $query->setTransaction($transaction);
            }
        }

        /**
         * Check for bind parameters
         */
        $bindParams = $params["bind"] ?? null;
        $bindTypes  = null;

        if ($bindParams) {
            $bindTypes = $params["bindTypes"] ?? null;
        }

        /**
         * Pass the cache options to the query
         */
        $cache = $params["cache"] ?? null;
        if ($cache) {
            $query->cache($cache);
        }

        /**
         * Execute the query
         */
        $resultset = $query->execute($bindParams, $bindTypes);

        /**
         * Return the full resultset if the query is grouped
         */
        if (isset($params["group"])) {
            return $resultset;
        }

        /**
         * Return only the value in the first result
         */
        $firstRow = $resultset->getFirst();
        return $firstRow->{$alias};
    }
    
    public static function sum($parameters = null)
    {
        return self::_groupResult("SUM", "sumatory", $parameters);
    }

    public static function average($parameters = null)
    {
        return self::_groupResult("AVG", "average", $parameters);
    }

    public static function minimum($parameters = null)
    {
        return self::_groupResult("MIN", "minimum", $parameters);
    }
    
    public static function maximum($parameters = null)
    {
        return self::_groupResult("MAX", "maximum", $parameters);
    }
    
    public static function count($parameters = null)
    {
        $result;

        $result = self::_groupResult("COUNT", "rowcount", $parameters);
        if (is_string($result)) {
            return (int) $result;
        }
        return $result;
    }
}

@zsilbi zsilbi self-assigned this Oct 1, 2020
@zsilbi zsilbi added the 4.1.0 label Oct 1, 2020
@zsilbi zsilbi removed the status: unverified Unverified label Oct 5, 2020
@niden
Copy link
Sponsor Member

niden commented Oct 6, 2020

Resolved with #15164

@niden niden closed this as completed Oct 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A bug report
Projects
None yet
Development

No branches or pull requests

3 participants