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

There are no defined relations exception

I have been trying to figure out this issue for hours. For some reason I'm getting the following exception:

Phalcon\Mvc\Model\Exception: There are no defined relations for the model "eav\EavObjectValue" using alias "field"

There are 3 models involved - EavField (record already created before), EavObject (record created before within the same request) and EavObjectValue (has foreign key references to the other 2 tables, INSERT fails).

Here's the code excerpt with the non-relevant pieces removed:

class EavObjectValue extends Model
{
    public $ID;
    public $objectID;
    public $fieldID;
    public $numValue;
    public $stringValue;
    public $textValue;
    public $dateValue;

    public function initialize()
    {
        $this->belongsTo('objectID', 'eav\EavObject', 'ID', array('alias' => 'EavObject'));
        $this->belongsTo('fieldID', 'eav\EavField', 'ID', array('alias' => 'EavField'));
    }

    public function beforeCreate()
    {
        // checking that the referenced records exist in database
        var_dump($this->getEavObject());
        var_dump($this->getEavField());
    }
...

class EavObject extends Model
{
    public $ID;

    public function initialize()
    {
        $this->hasMany('ID', 'eav\EavObjectValue', 'objectID', array(
            'alias' => 'EavObjectValue',
            'foreignKey' => array(
                'action' => \Phalcon\Mvc\Model\Relation::ACTION_CASCADE
            )
        ));
    }
...

class EavField extends Model
{
    public $ID;

    public function initialize()
    {
        $this->hasMany('ID', 'eav\EavObjectValue', 'fieldID', array(
            'alias' => 'EavObjectValue',
            'foreignKey' => array(
                'action' => \Phalcon\Mvc\Model\Relation::ACTION_CASCADE
            )
        ));
    }

Here's the generated INSERT query:

         2250 Query DESCRIBE `EavObjectValue`
         2250 Query INSERT INTO `EavObjectValue` (`objectID`, `fieldID`, `numValue`, `stringValue`, `textValue`, `dateValue`) VALUES ('119', '26', null, null, null, '2013-10-25T21:00:00.000Z')
         2250 Query rollback

I'm certain that the EavObject exists because it's also referenced in other models for which the records are created within the same operation. When I try to execute the SQL manually, it works if I replace the objectID value with one already existing in the database, so it shouldn't be a foreign key related error coming from the database.

I don't really see what am I doing wrong. And the error message is strange, because there's no alias "field" defined, so I'm not sure where that comes from (fieldID column?). I would appreciate any suggestions.

I did some more testing and apparently simply creating a new instance that is referenced to previously created related records works fine:

$o = \eav\EavObject::getInstanceByID(72);
$f = \eav\EavField::getInstanceByID(26);
$val = new \eav\EavObjectValue();
$val->objectID = $o->getID();
$val->fieldID = $f->getID();
$val->numValue = 1;
$val->save();

When I change the fieldID value to something that does not exist in the database, I get an exception as I would expect, but a different one:

PDOException ERROR: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (hey.EavObjectValue, CONSTRAINT EavField_EavObjectValue FOREIGN KEY (fieldID) REFERENCES EavField (ID) ON DELETE CASCADE ON UPDATE CASCADE)

So the original question still stands - where might this exception come from?

Phalcon\Mvc\Model\Exception: There are no defined relations for the model "eav\EavObjectValue" using alias "field" 

After lots of trial&error I was able to get rid of that exception by adding this to EavObjectValue class:

protected function _postSaveRelatedRecords()
{
    return false;
}

However it still was not working properly, because of multiple issues:

  • For some reason Phalcon bundles the INSERT queries in a transaction
  • $eavObjectValue->save() still returns false, however getMessages() return an empty array - so it just "errors" without any specific messages
  • at the end of the request it rolls back the transaction instead of committing, even though there are no errors produced!

But! If I add this code at the end of the controller action, it will work just fine and all the records are there saved in the database!

$this->db->execute('commit');

As another notice, while exploring the var_dumped EavObjectValue instance i noticed that it has a "_related" property and it's value is array('field' => instanceof EavField). That explains how the "field" may have appeared in the exception, but not how it got there in the first place as the configured alias is EavField.

Apologies for the long posts, but apparently there are some bugs and hopefully this might be helpful to someone googling for this error.

There is another class called EavItem that references EavField as Field, however the EavItem class has no relation to EavObjectValue, other than that they both have a belongsTo relationship to EavField. Could this be a clue of the wrong alias name?

class EavItem extends Model
{
    public $valueID;
    public $objectID;
    public $fieldID;

    public function initialize()
    {
        $this->belongsTo('valueID', 'eav\EavValue', 'ID', array('alias' => 'Value'));
        $this->belongsTo('objectID', 'eav\EavObject', 'ID', array('alias' => 'Object'));
        $this->belongsTo('fieldID', 'eav\EavField', 'ID', array('alias' => 'Field'));
    }


98.9k

If there are errors saving the master record or one of its related records, you can get them as an array using $m->getMessages()

Yes, but the funny thing is that the array returned by getMessages() is empty even though save() returns false. Also, there are no actual database-level errors. As described above - if I force the commit, everything gets saved in the database correctly.



98.9k

Are you using 1.2.4?

I got same error. The problem was:

    public function afterFetch()
    {
        $this->router = Router::findFirst([
            'module = ?0 AND controller = ?1 AND action = ?2 AND actionId = ?3',
            'bind' => ['page', 'index', 'index', $this->id]
        ]);
        parent::afterFetch();
    }

I assigned router model to page model, but I hadn't registered a variable. So I got Phalcon\Mvc\Model\Exception: There are no defined relations for the model "modules\page\model\Page" using alias "router" exception.

I fixed it by declaring variable:

public $router;