This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.

Kiko Balco
Kiko Balco

Hi guys, recently I have one issue during development of plugin in one of models.

I try to create custom Validation for one parameter, that requires some data from DB. I also create afterCreate function where I assume Validation already has been done and I start to assign some data.

Basically I count items in DB in validation and assign relations to that DB in afterCreate. But validation is failing as if the assign seem to already has begun. At least that's how it looks from numbers.

For example when I try to assign 13 items, but have only 12 spots available, I get correct error from validation with correct numbers. But when I try to assign 12 items and I have 12 slots I got error, that there is 0 slots available. When I try to assign 11, error says there's 1 available, when 10, 2 available and so on. When it gets to 6, it passes.

For Validation I use custom validation rule that I created in plugin.

To my eyes it looks like it might be issue with Eloquent ORM (maybe delayed async access to DB table) or I don't understand life cycle of Model object well. Does Validation runs after afterCreate function? Or some kind of promise in assigning those relations. I'm not that experienced to figure it out.

Do you have experiences with something similiar?

Here is my code: Validation Rule:

class DrawEntryCountRule
{

    public function validate($attribute, $value, $params, $validator)
    {
        // Check if there is enough entries for prizes
        $items_count = $this->getItemsCount($value);

        $data = $validator->getData();
        $valid_entry_count = Entry::whereBetween('created_at', [$data["date_from"], $data["date_to"]])
                                    ->valid()
                                    ->notDrawn()
                                    ->count();

        if ($valid_entry_count < $items_count) {
            return false;
        }       
        return true;
    }
}

afterCreate function in Model:

public function afterCreate()
    {
        // Hneď po vytvorení aj vylosovať ceny
        $items_count = $this->getDrawItemsCount($this->draw_items);

        $winningEntries = Entry::whereBetween('created_at', [$this->date_from, $this->date_to])
                                    ->valid()
                                    ->notDrawn()
                                    ->inRandomOrder()
                                    ->take($items_count)
                                    ->get();

        $nextId = 0;
        foreach ($this->draw_items as $item) {
            for ($i = 0; $i < $item["count"]; $i++) { 
                $win = new Win();

                $win->entry = $winningEntries[$nextId];
                $win->draw  = $this;
                $win->prize = Prize::whereId($item["item"])->first();

                // THESE TWO LINES OF CODE ARE MAKING PROBLEM
                $win->entry->is_drawn = true;
                $win->entry->save();

                $win->prize->drawn_count++;
                $win->prize->save();

                $nextId++;

                $win->save();
            }
        }

        $this->save();
    }

Last updated

Kiko Balco
Kiko Balco

Okay, I fixed it. It was quite a stupid mistake. Problem was, that in afterCreate a saved current model at the end, which was not neccesery as it will be saved automatically later in model life cycle.

And I forgot that validation happens also before saving, not just creating. This create cycle of validations, which was root of the problem.

Simply removing

$this->save();

from the end of afterCreate function solved it :)

daftspunky
daftspunky

Ah, yes. That is true and calling save() might create an infinite loop in the logic. Glad you got it solved!

1-3 of 3

You cannot edit posts or make replies: the forum has moved to talk.octobercms.com.