How to arrange an array to saveAll in CakePHP? - php

It's a little complicated to explain the way that I got the data from the view, but it arrives correctly to the controller.
I have 3 models: TourOpcione (this always save only one record), and TourOpcionOficina and TourOpcionServicio (these can save one or more records at time, and they have a foreign key to TourOpcione).
My problem is that I don't know what's the correct way to arrange the data in my controller before to save that. I want to avoid to use a loop, so I wish to save it with saveAll, or saveAssociated, or if this is not the case, accept any other way.
The explains around internet are confused.
I'm using CakePHP 2.6
Actually this is the array that I had created:
array
(
[TourOpcione] => Array
(
[opcion] => 1
[numeroPersonas] => 4
[total] => 2038
[tour_prospecto_id] => 12
)
[TourOpcionOficina] => Array
(
[0] => Array
(
[oficina_id] => 1623
)
[1] => Array
(
[oficina_id] => 1624
)
)
[TourOpcionServicio] => Array
(
[0] => Array
(
[servicio_id] => 6068
)
[1] => Array
(
[servicio_id] => 6067
)
)
)
Thanks in advice.
UPDATE
At this point, the TourOpcione is the only model who save the data. The other 2 doesn't.
Where can be my problem?
My models are the next (each class in his own model):
class tour_opcione extends AppModel {
public $name = 'TourOpcione';
public $hasMany = array(
'TourOpcionServicio' => array(
'className' => 'TourOpcionServicio',
'foreignKey' => 'tour_opcione_id',
),
'TourOpcionOficina' => array(
'className' => 'TourOpcionOficina',
'foreignKey' => 'tour_opcione_id',
)
);
}
class tour_opcion_servicio extends AppModel {
public $name = 'TourOpcionServicio';
public $belongsTo = array(
'TourOpcione' => array(
'className' => 'TourOpcione',
'foreignKey' => 'tour_opcione_id'
)
);
}
class tour_opcion_oficina extends AppModel {
public $name = 'TourOpcionOficina';
public $belongsTo = array(
'TourOpcione' => array(
'className' => 'TourOpcione',
'foreignKey' => 'tour_opcione_id'
)
);
}

Related

CakePHP Relational models: Completely ignoring model

I have a pretty simple relational model setup. When using $this->model->find('all',$params), the results do not return the complete relational data set. I'm pulling my hair out here.
Here's my table setup:
Table qs_skus:
id (AI, PK)
sku_name
profile
...
Table net_lengths_in_skus:
id (AI,PK)
quick_ship_skus_id
net_lengths_id
Table net_lengths
id (AI,PK)
name
The way the models are configured are:
Model QuickShipSku $hasMany=array('NetLengthsInSku')
Model NetLengthsInSku $hasOne='NetLength'
All models have $actAs = array('Containable')
When doing the following, I get only the first relationship queried, the last relationship is completely ignored:
$model = $this->QuickShipSku->find('all',
array(
'contain' => array(
'NetLengthsInSku' => array('NetLength')
)
);
Output:
Array
(
[0] => Array
(
[QuickShipSku] => Array
(
[id] => 3
[sku_name] => 1112-8
[product_name] => Product A
[sku_specie_id] => 1
[members_ft] => 8
[profile] => Profile Description
)
[NetLengthsInSku] => Array
(
[0] => Array
(
[id] => 10
[quick_ship_skus_id] => 3
[quick_ship_net_length_id] => 1
)
)
)
)
For each NetLengthsInSku there should be a NetLength, but it's not even being queried.
Any ideas?
What you have here is a many to many relationship. That means an association called hasAndBelongsToMany.
If you are using Cake 2.x you should have something like this:
class QsSku extends AppModel {
public $hasAndBelongsToMany = array(
'NetLength' =>
array(
'className' => 'NetLength',
'joinTable' => 'net_lengths_in_skus',
'foreignKey' => 'quick_ship_skus_id',
'associationForeignKey' => 'net_lengths_id',
)
);
}
You should do something similar to your NetLength model as well.

CakePHP Issue with saveAll()

I'm having a problem with CakePHP's saveAll() I was hoping someone could shed some light on.
I have a form which collects information to be saved for two models... Person and Inquiry. I believe the data are being sent correctly, but it's simply not saving the Inquiry data. It's returning a validation error, but there is no validation set up in the Inquiry model, and if I remove 'deep' => true from the People controller, it saves those fields fine.
Data It Posts
Array
(
[Person] => Array
(
[first_name] => Test
[middle_name] =>
[last_name] => User
[gender] => M
[date_of_birth] => Array
(
[month] => 02
[day] => 07
[year] => 1994
)
[address] => 1234 Main St
[address_apt] =>
[address_city] => Somewhere
[address_state] => OH
[address_zip] => 304982
[address_country] => US
[phone_cell] => (555) 555-5555
[permission_to_text] => 1
[phone_home] => (555) 555-5556
[email_address] => test#user.com
[preferred_contact] => text_cell
[Inquiry] => Array
(
[admit_type] => FR
[admit_term] => FA2014
[parent_first_name] => Mom
[parent_last_name] => User
[parent_email] => mom#user.com
[hs_name] => Columbus Downtown High School
[hs_ceeb_id] => 365210
[hs_homeschooled] => 0
[hs_grad_year] => Array
(
[year] => 2014
)
[coll_name] =>
[coll_ceeb_id] =>
[coll_major] =>
[coll_year] =>
[admit_major] => 1
[admit_minor] => 4
)
[social_facebook] =>
)
)
Value of $this->Person->validationErrors after Posting
Array
(
[Inquiry] => Array
(
[hs_homeschooled] => Array
(
)
[coll_name] => Array
(
)
[coll_ceeb_id] => Array
(
)
[coll_major] => Array
(
)
[coll_year] => Array
(
)
)
)
Model - Inquiry
<?php
class Inquiry extends AppModel {
public $belongsTo = array('Person');
}
Controller
<?php
class PeopleController extends AppController {
public $helpers = array('Html', 'Form', 'Country', 'State', 'Major', 'Minor', 'Term');
public function index() {
if ($this->request->is('post')) {
$this->Person->create();
if ($this->Person->saveAll($this->request->data, array('deep' => true))) {
print_r($this->request->data);
$this->Session->setFlash(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
print_r($errors = $this->Person->validationErrors);
$this->set('errors', $errors = $this->Person->validationErrors);
$this->Session->setFlash(__('Unable to add.'));
}
}
}
Model::saveAll() is a wrapper of saveMany or saveAssociated.
Since you're not passing data in a numerical indexed array, i.e.
array(
0 => array(...),
1 => array(...),
)
it means saveAssociated is called. What you're apparently trying to do is to save a new Person together with the associations (Inquiry). If you read through the manual you'll come to this paragraph:
If neither of the associated model records exists in the system yet
(for example, you want to save a new User and their related Profile
records at the same time), you’ll need to first save the primary, or
parent model.
So you obviously need to save the Person first and then all associations.

Using multiple Models Find() CakePHP

I have these tables:
table: CREATORS
obs.:I've also tried that way:
table: POSTS
CreatorModel.php
class CreatorModel extends AppModel {
public $actsAs = array('Containable');
public $hasOne = array('Post');
}
PostModel.php
class PostModel extends AppModel {
public $actsAs = array('Containable');
public $hasOne = array('Creator');
}
IndexController.php
$this->set('posts', $this->Post->find());
index.ctp
var_dump($posts);
Following the CakeBook session about Associations
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
I should receive that response in view:
Array
(
[Post] => Array
(
[id] => 1
[creator_id] => 1
[tags] =>
[title] => Teste
[post] => Maromba
[created] => 2013-04-29 19:14:32
[modified] => 2013-04-29 19:14:32
)
[Creator] => Array
(
[creator_id] => 1
[creator] => Alexandre Moraes
)
)
But i receive this:
Array
(
[Post] => Array
(
[id] => 1
[creator_id] => 1
[tags] =>
[title] => Teste
[post] => Maromba
[created] => 2013-04-29 19:14:32
[modified] => 2013-04-29 19:14:32
)
)
So, any ideas what i'm doing wrong?
In the db
CREATORS TABLE
---
id | creator
Creator.php
class Creator extends AppModel {
public $actsAs = array('Containable');
public $hasOne = array('Post');
}
Post.php
class Post extends AppModel {
public $actsAs = array('Containable');
public $belongsTo= array('Creator');
}
Please note the naming of the models and the association type in Post.php
IndexController.php
$this->set('posts', $this->Post->find('all', array('contain'=>array('Creator')));
Doing those changes, the array returned should be the one you're expecting.
You'll need a setup the correct relationships for your models. You're essentially looking to do a join between the two tables. Check out this answer: https://stackoverflow.com/a/5080026/2297744 I believe it's pretty similar to what you're trying to do.
The quick and dirty version would look something like this:
$this->Post->find('all', array(
'joins' => array(
array(
'table' => 'creators',
'alias' => 'CreatorJoin',
'type' => 'inner',
'conditions' => array(
'CreatorJoin.id = Post.creator'
)
)
)
);
But I'd recommend reading the full answer I linked to and using the first (more correct) example.

CakePhp model relationships not providing reverse references

currently my model relation ships are set up in the following fashion
class Post extends AppModel {
var $name = 'Post';
var $displayField = 'title';
var $hasMany = array('Comment');
var $belongsTo = array('User');
}
class User extends AppModel {
var $name = 'User';
var $displayField = 'username';
var $hasMany = array('Post', 'Comment');
}
class Comment extends AppModel {
var $name = 'Comment';
var $displayField = 'id';
var $belongsTo = array('User', 'Post');
}
when i am trying to refer to the username in the comments section on my posts view
it errors out saying invalid index and upon further inestigation i have noticed that my model is not including the user info as a back reference for my comments only the user information is being included for the posts
the resulting array looks like this:
Array
(
[Post] => Array
(
[id] => 1
[title] => test post
[user_id] => 1
[body] => this is a test post
[date_posted] => 0000-00-00 00:00:00
[url_slug] => this-is-a-test-post
)
[User] => Array
(
[id] => 1
[username] => admin
[password] => e7b9f7bc09beee85947ef987d7df49df136c7c38
[first_name] => Chris
[last_name] => McGrath
[roles] => Admin
[email] => admin#thissite.com
[last_login] => 0000-00-00 00:00:00
[member_since] => 0000-00-00 00:00:00
[FacebookProfile] =>
[TwitterUserName] =>
)
[Comment] => Array
(
[0] => Array
(
[id] => 5
[post_id] => 1
[user_id] => 1 //expecting this to pull user model for each
[comment] => test comment
)
)
)
my question is is this being caused by something i am doing incorrectly in the model associations, is this a limitation of the model framework or should i be grabbing user manually from the user model in this type of instance
Try doing something like this:
$this->Post->recursive = 2; //This will get all the comments and their relationships
$post = $this->Post->read(null,$post_id); //The way you were getting your post.
debug($post); // You will see what it gets
EDIT:
You can try this too:
$this->Post->Comment->recursive = 2;
using recursive = 2 is never a good idea.
$this->Post->find(
'first',
array(
'conditions' => array(
'Post.id' => $id
),
'contain' => array(
'User',
'Comment' => array(
'User' => array(
'fields' => array(
'User.id',
'User.name'
)
)
)
)
)
);
http://book.cakephp.org/view/1323/Containable

CakePHP containable doesn't filter in a proper way

Like the example in cakephp manual, http://book.cakephp.org/view/1323/Containable#Containing-deeper-associations-1325, i need to fetch data from a model through a condition on its association model.
I have:
Model Language:
class Language extends AppModel {
var $name = 'Language';
var $actsAs = array('Containable');
var $hasMany = array(
'LanguageTranslation' => array(
'className' => 'LanguageTranslation',
'foreignKey' => 'language_id'
)
);
}
And the association, ModelTranslation
class LanguageTranslation extends AppModel {
var $name = 'LanguageTranslation';
var $belongsTo = array(
'Language'
);
}
when i do:
$language_array = $this->controller->Language->find('all', array(
'contain' => "LanguageTranslation.id = 1"
));
i receive all the languages, not only one (because id in LanguageTranslation is unique). The result need to be one!
SO, with
debug($language_array);
result is:
Array
(
[0] => Array
(
[Language] => Array
(
[id] => 1
[code] => it
[locale] => ita
)
[LanguageTranslation] => Array
(
[0] => Array
(
[id] => 1
[language_id] => 1
[language] => italiano
)
)
)
[1] => Array
(
[Language] => Array
(
[id] => 2
[code] => en
[locale] => eng
)
[LanguageTranslation] => Array
(
)
)
[2] => Array
(
[Language] => Array
(
[id] => 3
[code] => de
[locale] => ger
)
[LanguageTranslation] => Array
(
)
)
)
Why i don't catch only the Language with id = 1?
linkable behavior will do the trick.
You can download it on:
https://github.com/rafaelbandeira3/linkable
MODEL
var $actsAs = array('Linkable');
CONTROLLER
$language_array = $this->Language->find('all', array(
'link' => array('LanguageTranslation'),
'conditions' => array("LanguageTranslation.id = 1")
));
The conditions in containable apply only to the models inside the containment. Because the main query doesn't have any conditions it fetches every row in the table. In general you don't use containable to restrict the main query but to limit the way the query goes through the containment tree (very handy when you need to go through 3-4 levels of recursiveness where the results can get quite bloated if not contained).
In this case in particular if you are trying to get the data of a certain Language/LanguageTranslation pair, you can just pull the data from the LanguageTranslation model.
$this->Language->LanguageTranslation->find(
'first',
array(
'conditions' => array( 'LanguageTranslation.id' => 1 ),
'recursive' => 1
)
);
In regards to Juhana's answer: (which initially calls find on the Language Model), You can supply conditions for the parent model which target child models.
Contain in a separate call.
<?php
$this->Language->contain(array(
'LanguageTranslation'
));
$lang = $this->Language->find('first', array(
'conditions' => array('LanguageTranslation.id' => 1)
));
?>
Contain in one call.
<?php
$lang = $this->Language->find('first', array(
'conditions' => array('LanguageTranslation.id' => 1),
'contain' => array('LanguageTranslation')
));
?>
If you need to apply conditions to the child models just add the conditions array to the child model's index in the contain call. For example:
<?php
$this->Language->contain(array(
'LanguageTranslation' => array(
'conditions' => array('<LanguageTranslationConditionHere>')
)
));
?>
Hope this helps!
-Andrew

Categories