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

TypeError when looping through Resultset\Complex

I'm getting the following error when I try to execute a query that contains a leftJoin and therefore expects the 'right side' to be null in some cases.

Fatal error: Uncaught TypeError: Typed property Tax::$id must be int, null used in [...] Stack trace: #0 [internal function]: Phalcon\Mvc\Model::cloneResultMap(Object(Tax), Array, NULL, 0, false) #1 [internal function]: Phalcon\Mvc\Model\Resultset\Complex->current() #2 [...]

What I did is introduce explicit property types in my Models like so:

class Tax extends \Phalcon\Mvc\Model
{

    /**
     *
     * @var integer
     * @Primary
     * @Identity
     * @Column(column="id", type="integer", length=11, nullable=false)
     */
    protected int $id;

    ...
}

As you can see, the field 'id' cannot be null, among other fields.

What happens is, when I do a leftJoin to Tax table, sometimes the whole object needs to be null (doesn't exist). But instead a Tax object gets created anyway, with all fields set to null - which leads to TypeError being thrown.

The simplified query and loop in question:

$resulSet = DI::getDefault()->getModelsManager()->createBuilder()
            ->columns([
                'Value.*',
                'Tax.*',
            ])
            ->from(["Value" => 'Value'])
            ->leftJoin('Tax', 'Value.tax_id = Tax.id', 'Tax')
            ->getQuery()
            ->execute();

        foreach ($resultSet as $row) { // error gets thrown on this line for some rows
            ...
        }

Is this inteded behaviour? If yes, can it be overcome? Is there another way to do this and still keep the explicit typing in models?

Thanks


Additional info:

PHP Version 7.4.8

Phalcon Version 4.0.6

edited Aug '20

My guess is this would be intended behaviour. Depending on the rest of the context, I can think of a couple possible solutions:

  1. You could allow your typed property to be null
    protected ?int $id;

    Though that looks like it might break some annotations & documentation

  2. You could change the hydration mode of your query to return an array or a plain (non-model) object.
  3. You might be able to put an @ in front of the foreach. That's dirty though.