We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Phalcon\Mvc\Model::find() together with Phalcon\Mvc\Model\Query\Builder

Hi all,

I'm having the following problem:

https://stackoverflow.com/questions/18950757/phalcon-mvc-modelfind-together-with-phalcon-mvc-model-query-builder

Can anyone comment on it?

Thanks, Temuri



98.9k

Actually find() does not accept a query builder as parameter, it accepts an array of parameters, if you want to use the query builder, you can use:


//find
$user->getModelsManager()->createBuilder()
    ->from('users')
    ->where('email = :email:', ['email' => '[email protected]'])
    ->andWhere('record_status = :status:', ['status' => 1]) 
    ->getQuery()
    ->execute();

//find first
$user->getModelsManager()->createBuilder()
    ->from('users')
    ->where('email = :email:', ['email' => '[email protected]'])
    ->andWhere('record_status = :status:', ['status' => 1]) 
    ->getQuery()
    ->execute()
    ->getFirst();   


51.3k

@Phalcon:

While it's disappointing that I cannot feed Query to ::find() method, what you are suggesting will certainly work.

The problem arises when I define one-to-many relationship of models and load related objects with $parent->getRelated($childModel);

I need the same behaviour there - only load $childModel that has record_status=1.

I saw that getRelated uses findFirst() and I tried the following trick in my AbstractModel class:

    public static function findFirst($parameters = null)
    {
        if (is_array($parameters)) {
            $idx = 1;
            while (array_key_exists($idx, $parameters)) {
                $idx++;
            }
            $parameters[$idx] = '[record_status] = ?' . $idx;
            $parameters['bind'][$idx] = self::RECORD_STATUS_ACTIVE;
        }
        return parent::findFirst($parameters);
    }

However, that didn't work. PDO exception is being raised: "SQLSTATE[HY093]: Invalid parameter number: parameter was not defined".

And probably that's because immediately before calling parent's findFirst:

    $this->queryString = "SELECT `users`.`id`,  `users`.`record_status` FROM `users` WHERE `users`.`id` = :0 LIMIT 1";

No trace of second parameter there, being added "artificially" (on a side note - why do I have $this scope at all in a static method?!!!).

Any suggestions?

Thanks, Temuri



98.9k

I'm not sure about the logic, but this would work:

public static function findFirst($parameters = null)
{
    if (is_array($parameters)) {
        $idx = 1;
        $conditions = array();
        while (array_key_exists($idx, $parameters)) {
            $idx++;
        }
        $conditions[$idx] = '[record_status] = ?' . $idx;
        $parameters['bind'][$idx] = self::RECORD_STATUS_ACTIVE;
        $parameters['conditions'] = join(' AND ', $conditions);
    }
    return parent::findFirst($parameters);
}


51.3k

Thanks... That did the trick. Here's the final code:

    public static function findFirst($parameters = null)
    {
        if (is_array($parameters) && !isset($parameters['conditions']) && isset($parameters[0])) {
            $params = [
                'conditions' => null,
                'bind' => null,
            ];
            $idx = 0;
            while (array_key_exists($idx, $parameters)) {
                $params['conditions'] .= $parameters[$idx] . ' AND ';
                if (isset($parameters['bind'][$idx])) {
                    $params['bind'][$idx] = $parameters['bind'][$idx];
                }
                $idx++;
            }
            $params['conditions'] .= ' [record_status] = ?' . $idx;
            $params['bind'][$idx] = self::RECORD_STATUS_ACTIVE;
            $parameters = $params;
            unset($params);
        }
        return parent::findFirst($parameters);
    }