Saving Associated Models with CakePHP - cakephp-2.0

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?

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));

Related

Inserting with empty string in cakePHP

i am new in cakePHP framework with version 2.0 my problem is when i save the data or insert the new record the field is empty or no data to be save how can i fix this. .
My Model
class Post extends AppModel{
public $name = 'posts';
}
My Controller
public function add(){
if($this->request->is('post')){
$this->Post->create();
if($this->Post->save($this->request->data)){
$this->Session->setFlash('The posts was saved');
$this->redirect('index');
}
}
}
My View
echo $this->Form->create('Create Posts');
echo $this->Form->input('title');
echo $this->Form->input('body');
echo $this->Form->end('Save Posts');
You need to put the validation rules in the Post model, Then you can check validate data or not in the controller action before save into model. See the following Model and controller
In Model
class Post extends AppModel{
public $name = 'posts';
public $validate = array(
'title' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'This is can'\t blank'
),
),
'body' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'This is can'\t blank'
),
),
);
}
In Controller
public function add(){
if($this->request->is('post')){
$this->Post->create();
$this->Post->set($this->request->data);
if ($this->Post->validates()) {
// it validated logic
if($this->Post->save($this->request->data)){
$this->Session->setFlash('The posts was saved');
$this->redirect('index');
}
} else {
// didn't validate logic
$errors = $this->Post->validationErrors;
}
}
}

Simple CakePHP search action

I want a simple search feature that can search the current selected results on the model's index page. I have created a model Search which has no actual table:
class Search extends AppModel {
protected $_schema = array(
'search_term' => array('type' => 'string' , 'null' => true, 'default' => '', 'length' => '255'),
'model' => array('type' => 'string' , 'null' => true, 'default' => '', 'length' => '255'),
);
public $useTable = false;
public $validate = array(
'search_term' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'Please enter a search term'
),
'between' => array(
'rule' => array('between',3,30),
'message' => 'Please enter a search term greater than 3 characters.'
)
)
);
}
In any index.ctp view I have this with a hidden input field with the model's name:
echo $this->Form->create('Search, array('action' => 'search'));
echo $this->Form->input('search_term', array('label'=> 'Search'));
echo $this->Form->input('model', array('type'=> 'hidden', 'value'=>$this->params['controller']));
echo $this->Form->end(__('Submit'));
In the SearchesController:
public function search() {
$conditions = null;
if( $this->request->is('post') ) {
$searchModel = $this->request->data[$this->modelClass]['model'];
...
$this->{$this->modelClass}->useTable = Inflector::tableize($searchModel);
...
$this->paginate = array('conditions'=>array($groups,'OR' => $conditions));
$this->set($searchModel, $this->paginate());
$this->render("/$searchModel/index");
}
Problem is paginate is returning an array with the model labelled as 'Search' (understandably because of the useTable call) and not say Groups or Users, the model's being searched. Any way to relabel the array returned from paginate to the model being searched ? The alternative is to modify all the index.ctp files or create a results.ctp for each model.
I wouldn’t create another model merely for searching; it’s a hack and not extendable.
In the past, I’ve just used parameters (usually in the query string) to alter the conditions array (whether it’s a normal find operation of a paginate operation). An example:
<?php
class ItemsController extends AppController {
public function index() {
$conditions = array();
if (isset($this->request->query['search'])) {
$conditions['Item.title'] = $this->request->query['search'];
}
$items = $this->Item->find('all', array(
'conditions' => $conditions
));
$this->set(compact('items'));
}
}
Hopefully the above demonstrates this approach.

How to save HABTM association in CakePhp?

I have a Product model and an Image model. They have an HABTM association.
Some Images exist but they are not linked to the product.
Now when I save a Product I would like to link it to some unlinked images using an array of images IDs (I MUST use this array).
Here's my code:
class Image extends AppModel {
public $useTable = 'images';
var $hasAndBelongToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'products_images',
'foreignKey' => 'id_image',
'associationForeignKey' => 'id_product'
)
);
}
class Product extends AppModel {
public $useTable = 'products';
var $hasAndBelongToMany = array(
'Image' => array(
'className' => 'Image',
'joinTable' => 'products_images',
'foreignKey' => 'id_product',
'associationForeignKey' => 'id_image'
)
);
}
class productsController extends AppController {
public $name = 'Products';
public $uses = array('Products', 'File');
public function add() {
if (!empty($this->data)) {
$this->Product->create();
if ($this->AnnuncioImmobiliare->save($this->request->data)) {
$idProduct = $this->Product->getLastInsertID();
$this->request->data['imagesIds'] = array("1", "2", "3");
if(isset($this->request->data['imagesIds'])){
foreach($this->request->data['imagesIds'] as $imageId){
$this->Image->id = $imageId;
$this->Image->save(array('Product'=>array('id'=>$idProduct)));
}
}
}
}
}
}
This doesn't work. Where am I wrong?
1) you didn't provide the data, so we can't verify it's in the correct format.
2) you're using "save()" not "saveAll()" or "saveMany()" or "saveAssociated()". Just using "save()" will not save any associated model data.
I found a solution myself!
I observed how CakePHP handles $this->data->response array when data is passed using an input automagically created for HABTM associations and I found the array should be formatted like this:
array(
'Product' => array(
'name' => 'myProduct',
'id' => ''
),
'Image' => array(
'Image'=>array(
0 => '1',
1 => '2',
2 => '3'
)
)
)
So the correct code for the controller is
class productsController extends AppController {
public $name = 'Products';
public $uses = array('Products', 'File');
public function add() {
if (!empty($this->data)) {
$this->Product->create();
if (isset($this->request->data['imagesIds'])) {
$this->request->data['Image'] = array('Image' => $this->request->data['imagesIds']);
}
if ($this->AnnuncioImmobiliare->save($this->request->data)) {
/* success */
}
}
}
}
That's it! I hope you find this useful.

Match data entered with data in the database CAKEPHP

I am stuck at the loop function of cakephp.
The logic is I need to compare the data entered by users with the data already in a table. I have two tables, one is Bookings and one is Inventories_Bookings. Below is my coding but it doesnot work. any help! Thanks
public function add2() {
if ($this->request->is('post')) {
foreach ($invbook as $invenbook)
{
if ($this->request->data['Booking']['bookings_location'] == $invenbook['InventoriesBooking']['test'])
{
$this->Session->setFlash(__('The booking cannot be created'));
$this->redirect(array('action' => 'add2'));
debug($this->request->data['Booking']['bookings_location'] == $invenbook['InventoriesBooking']['test']);
}
}
$this->Booking->create();
$invbook = $this->Booking->InventoriesBooking->find('list',array('fields' => array('InventoriesBooking.id', 'InventoriesBooking.test')));
$this->set(compact('invbook'));
}
}
I would use a custom validation function for this.
You are able to create your own functions in the model, and from here you can access the database to do the lookup. If it matches you can return true.
You can read about custom validation methods in the book.
There is an example of a rule like this using the db in the book.
Quoted for great justice.
class User extends AppModel {
public $validate = array(
'promotion_code' => array(
'rule' => array('limitDuplicates', 25),
'message' => 'This code has been used too many times.'
)
);
public function limitDuplicates($check, $limit) {
// $check will have value: array('promotion_code' => 'some-value')
// $limit will have value: 25
$existing_promo_count = $this->find('count', array(
'conditions' => $check,
'recursive' => -1
));
return $existing_promo_count < $limit;
}
}

Cakephp Auth problem : Undefined property: User::$alias

I keep getting this error over a day right now.
I search over and over , but i couldnt get an answer.
Probably i am making sometihing stupid.
Here is my enviroment;
UserController :
class UsersController extends AppController {
var $name = 'Users';
var $components = array('Email');
function login() {
}
function home() {
pre('login oldunuz');
}
function logout() {
$this->Session->setFlash(__('Goodbye!', true));
$this->redirect($this->Auth->logout());
}
....
}
AppController :
class AppController extends Controller {
var $components = array('Session','Auth');
function beforeFilter() {
$this->Auth->loginError = 'You didnt supply valid identification.';
$this->Auth->authError = 'You are not validated to see this location.';
$this->Auth->allowedActions = array('register','confirm');
$this->Auth->userScope = array('User.active' => 1);
}
function beforeRender() {
$this->set('User', $this->Session->read('Auth.User'));
}
}
UserModel:
class User extends AppModel {
var $name = 'User';
var $displayField = 'username';
var $validate = array(
'username' => array(
'notempty' => array(
'rule' => array('notempty'),
'message' => 'Username field can not be empty..',
),
'u_unique' => array(
'rule'=>array('isUnique'),
'message' => 'The username you selected, is being used please choose another one.'
)
),
'email' => array(
'email' => array(
'rule' => array('email'),
'message' => 'Please provide a valid email.',
),
'e_unique' => array(
'rule' => array('isUnique'),
'message' => 'The email you selected, is being used please choose another one.'
)
),
----
/* if you want i send more of this code */
}
I dont how to fix this,
But for helping, cakephp says :
The error portion is :
if ($key == null)
{
$model =& $this->getModel();
return array($model->alias => $this->Session->read($this->sessionKey));
}
if i make $model->alias = "User" then it works but where ever another $model->alias is used, it explodes same as before,
I hope you have an answer, thanks all,

Resources