Zian Choy
Zian Choy

Reputation: 2894

Saving Associated Models with CakePHP

I'm trying to build on the example code at http://book.cakephp.org/2.0/en/models/saving-your-data.html in the section that starts off with "Saving Related Model Data (hasOne, hasMany, belongsTo)". However, I'm getting the following error message when I call unset:

Indirect modification of overloaded property AppModel::$MealContent has no effect [APP\Controller\MealsController.php, line 15] Attempt to modify property of non-object [APP\Controller\MealsController.php, line 15]

Naturally, the data isn't saved either.

As you can see, my application doesn't have Companies or Accounts. Instead, I have Meals and MealContents but the relationships seem to have been set up the same. Obviously, there's a problem somewhere though so here's some code.

Meals.php:

class Meals extends Entry {

    public $hasMany = 'MealContents';
    public $validate = array(
        'Timestamp' => array(
            'validDate' => array(
                'rule' => array('garbageDateChecker'),
                'required' => true,
                'message' => 'The date could not be understood.'),
            'noTimeTravel' => array(
                'rule' => array('noTimeTravel'),
                'required' => true,
                'message' => 'You cannot enter times in the future.')
        )
    );

}

MealContents.php:

class MealContents extends Entry {

    public $belongsTo = 'Meals';
    public $validate = array(
        'Meals_ID' => array(
            'notEmpty' => array(
                'rule' => 'notEmpty',
                'required' => true,
                'message' => 'This field cannot be blank')
        ),
        'Item_ID' => array(
            'notEmpty' => array(
                'rule' => 'notEmpty',
                'required' => true,
                'message' => 'This field cannot be blank')
        )
    );

}

And finally, the controller's index() function:

public function index() {
        $this->set('title_for_layout', "Food Log");
        if ($this->request->is('post')) {
            $this->Meal->create();

            unset($this->Meal->MealContent->validate['Meals_ID']);
            if ($this->Meal->saveAssociated($this->request->data)) {
                $this->Session->setFlash('The meal was logged.');
                $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash("Couldn't save the meal.");
            }
        }
    }

Entry.php

abstract class Entry extends AppModel {

    public function garbageDateChecker($dateToCheck) {
        date_default_timezone_set("America/Tijuana");
        $result = TRUE;

        try {
            new DateTime($dateToCheck['Timestamp']);
        } catch (Exception $e) {
            $result = FALSE;
        }

        return $result;
    }

    public function noTimeTravel($dateToCheck) {
        date_default_timezone_set("America/Tijuana");
        $result = TRUE;

        $objectifiedDateToCheck = new DateTime($dateToCheck['Timestamp']);
        $currentTime = new DateTime("now");

        if ($objectifiedDateToCheck > $currentTime) {
            $result = FALSE;
        }

        return $result;
    }

}

I'm pretty sure the save() failure isn't due to the validation because even when I comment out the validation rule and the unset() line, the data isn't saved.

It would be easy to blame it on bad data or a screwed up view. However, the data looks OK:

$this->request->data
--MealContents
---[0]
-----[Food_Item_ID] = "0"
--Meals
---[Comments] = ""
---[Timestamp]
-----[day] = "12"
-----[hour] = ...

What have I missed when I read the CakePHP book?

Upvotes: 0

Views: 1035

Answers (1)

roswell
roswell

Reputation: 11

In all of your model class declarations, you should be extending the AppModel class not "Entry". Also, you need to change your model names to singular nouns. Meal instead of Meals.

class Meal extends AppModel {

    //your model's code

}

class MealContent extends AppModel {

    //your model's code

}

In your controller, if you would like to skip validation on the saveAssociated call, you can pass an options array, with element "validate" set to False as the second parameter. You should never use unset on your model like that as it will affect the rest of your app.

$this->Meal->saveAssociated($this->request->data, array("validate" => false));

Upvotes: 1

Related Questions