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

Validation of domain before save (hasMany issue)

Hi, some good soul, please help. I am struggling with very basic thing.

I want to validate Domain entity before saving it.

I create object, set some stuff to it and then i need to access that stuff in validation method, the object is not saved yet. Simple attributes, hasOne and belongsTo relations are available, but hasMany and hasManyToMany are not. What can i do?

Validation on entities is useless without it, as i would need to check it "some other way around".

Thanks everyone.


$document = new Document();
$document->setType(new Type());
$document->setPages(array(new Page(), new Page()));
$document->save();

class Document ... {

    public function initialize() {
        $this->belongsTo('idType', 'Type', 'id', array('alias' => 'type'));
        $this->hasMany('id', 'Page', 'idDocument', array('alias' => 'pages'));
    }

    public function beforeSave() {
        $this->doValidate();
    }

    protected function doValidate() {

        // entity weren't saved yet

        // check if type is set
        $this->type; // yeah, there is a Type object here, i can check it

        // BUT: how can i check if there are some pages set?
        $this->pages; // empty Phalcon\Mvc\Model\Resultset\Simple

        // only ugly way i found is this        
        // not working (is empty) when validation model, that is fetched from DB and revalidated again
        // then i would need $this->getRelated("pages"), so i would need to script it heavilly
        $this->_related["pages"];
    }

}

Man, try to use standard ways of Models validation and using relations

https://docs.phalcon.io/en/latest/reference/models.html#storing-related-records https://docs.phalcon.io/en/latest/reference/models.html#validating-data-integrity

Validation is perfomed automatically on record save, if you will use validation method

edited Mar '16

I don't get your generic answer ("Man, see the docs").. Validation running it not the issue, HOW to validate is a problem for me.

So how would you check, if Document has at least one Page set up, before saving new Document?

Can you please draft it?

Thanks a lot.



1.4k
edited Mar '16

You need to show us better what you trying to accomplish. For example write your models, what is Document, what is Page, where it is, how did you use that. Because from what I read here I would just do:

Find *Pages* of *Document*.
Count *Pages*, if bigger than 0, **save**.

Just a logical math. Easier is better.

But I don't really know what you trying to make.

edited Mar '16

Ok, in terms of documentation terminology:

I want to create a new Robot and save it. But before this a want to validate the Robot (validation is implicitely called, that's cool). I understand the simple validators like "is the name of robot long enough?" can be used.

What i am struggling with: Every Robot has to consist of some Parts. I just want to do proper domain validation before saving. How can i validatate, that Robot has some Parts set? In other words, how to validate that any related model is set?

PresenceOf validator is not helping me for hasMany and hasManyToMany relation aliases (works only for hasOne).

The model is not saved yet, so how can i check that every related model is set before inserting to DB? How would you write validator like "Has the Robot at least one Part green and one Part red?"



47.7k

Do you mean "How do I create my own custom validation that I can execute beforeSave()?".

If this doesn't help then I'm sorry I don't realize the problem.


if ($robot->save() == false) {
    echo "Umh, We can't store robots right now: \n";
    foreach ($robot->getMessages() as $message) {
        echo $message, "\n";
    }
} else {
    echo "Great, a new robot was saved successfully!";
}

class Robot... {

    public function initialize() {
        ...
    }

    protected function validation() {
        if ($this->robotPartsNotSet(()) {
            $message = new \Phalcon\Mvc\Model\Message(
                "Not all robot parts that need to be set are present!",
                "robots_fk",
                "InvalidValue"
            );
            $this->appendMessage($message);
            return false;
        }
    }

    protected function robotPartsNotSet()
    {
        $robots_parts_set = ../code

        if($robot_parts_set) {
            return false;
        }

        return true;
    }

}

That $robots_parts_set = ../code is all i ask, how should i check it, when:

$parts = array(new Part("motor"), new Part("processor"));
$robot = new Robot();
$robot->setParts($parts);
  1. $this->parts is empty
  2. $this->getParts() is empty
  3. $this->getRelated("parts") is empty
  4. $this->_related["parts"] is ugly


47.7k
edited Mar '16

If you're relations are set right then I think this is correct.

$robot_part = \Common\Models\RobotPart();
$robot_part->part_id = 1234;

$robot = new \Common\Models\Robot();
$robot->robotPart = $robot_part;
$robot->save();

If you are using namespaces then you may have to define an alias.

  class Robot ... {
  initialize()
    {
        $this->hasMany("id", "Common\Models\RobotPart", "robot_id", array(
                    'alias' => 'RobotPart',
                    "message" => "Robot cannot be deleted as it still has parts."
                ));

    }
  }

Then:

$robot = \Common\Models\Robot::findFirst();
$robot_parts = $robot->getRobotPart();

foreach($robot_parts as $robot_part) {
    echo $robot_part->part_id;
}

Sorry, but your response is nonsense.

  • I know how to set parts to robot
  • I know how to define relationships and aliases
  • I know how to get parts of Robot, which is "foundFirst()"

I am trying to validate new Robot before it is even written to DB for the first time. How do you check, if Robot has Parts set, that you didn't forget to set it? How do you check, if Robot has exactly 3 parts, or if every of it's part name is unique etc.?

You are showing me how to save a Robot and then load the Robot and it's Parts.



9.3k
Accepted
answer

You have to validate it via

$this->_related["parts"]

because other methods are trying to load it from DB and will be empty on record creation

Thank you..