Course HasMany Lesson.
I am trying to save a lesson in a Course view, but want to automatically assign the current course_id without them having to select it.
How do I do that?
Here is my Courses view controller:
public function view($id = null) {
if (!$this->Course->exists($id)) {
throw new NotFoundException(__('Invalid course'));
}
$options = array('conditions' => array('Course.' . $this->Course->primaryKey => $id));
$this->set('course', $this->Course->find('first', $options));
//Adding Lesson from Course View
if ($this->request->is('post')) {
$this->Course->Lesson->create();
if ($this->Course->Lesson->save($this->request->data)) {
$this->Session->setFlash(__('The lesson has been saved.'), array ('class' => 'alert alert-success'));
return $this->redirect(array('controller'=> 'lessons', 'action' => 'view', $this->Course->Lesson->id));
} else {
$this->Session->setFlash(__('The lesson could not be saved. Please, try again.'), array ('class' => 'alert alert-danger'));
}
}
$courses = $this->Course->Lesson->Course->find('list');
$this->set(compact('courses'));
}
Currently, it's saving the lesson but not passing the course_id to the new lesson.
Lesson Model:
public $belongsTo = array(
'Course' => array(
'className' => 'Course',
'foreignKey' => 'course_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Course Model:
public $hasMany = array(
'Lesson' => array(
'className' => 'Lesson',
'foreignKey' => 'course_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
This is basically a duplicate of CakePHP: Securely setting a default value on a form.
Check my answer there or read the blog article I've wrote after that answer.
Related
I've made a forum using CakePHP while following a tutorial and would like to expand it.
Currently, in a post it allows me to comment, but they are displayed as newest -> oldest, so it doesn't make as much sense and I would like to reverse this.
This is the current association I have, I'm pretty new to PHP/Cake so I'm not sure where to go from here, any help is very appreciated!
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'forum_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
For those asking this is the function in my controller:
public function add($topicId=null) {
if ($this->request->is('post')) {
$this->request->data['Post']['user_id'] = $this->Auth->user('id');
if ($this->Post->save($this->request->data)) {
$this->Session->setFlash(__('Post has been created'));
$this->redirect(array('controller'=>'topics','action'=>'view',$this->request->data['Post']['topic_id']));
}
} else {
if (!$this->Post->Topic->exists($topicId)) {
throw new NotFoundException(__('Invalid topic'));
}
$this->Post->Topic->recursive = -1;
$topic = $this->Post->Topic->read(null,$topicId);
$this->Post->Forum->recursive = -1;
$forum = $this->Post->Forum->read(null,$topic['Topic']['forum_id']);
$this->set('topic',$topic);
$this->set('forum',$forum);
}
}
Something like this should do it:
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'forum_id',
'dependent' => false,
'order' => 'Post.created ASC' //order the Posts in ascending order based on whe they were created
)
Assuming you have a created column in your database table.
Edit:
You can find more info in the CakePHP documentation http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Avoid using read(), it is better to use find('first'). So you could rewrite your queries like:-
$this->Post->Topic->find('first', array(
'contain' => array(
'Post' => array(
'order' => array(
'Post.created' => 'asc',
'Post.id' => 'asc'
)
)
)
));
Passing an array instead of a string for order allows you to sort by multiple conditions. The above example would create the following ORDER SQL:-
ORDER BY Post.created ASC, Post.id ASC
You can also define a default ordering on the model itself which can be very useful:-
class Post extends AppModel {
public $order = array('Post.created' => 'asc', 'Post.id' => 'asc');
}
I want to add a new record in a table called TutorsSubject. This table is created from HABTM relationship of Tutor and Subject. Anyway I load the subject names in a text box and I can select a subject name but I cant add a new record. I need to set the id of the tutor_id.
There are 3 fields in the tutorsSubject table called id,tutor_id and subject_id. I only need to select in 1 field which is the subject_id from a list of names found in the subject table, and then set the tutor_id manually.
Currently I am able to select from a list of subject names but I cant add a new record with the subject name and set tutor_id.
Error: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails
class TutorsSubjectsController extends AppController {
public function tutoradd() {
$this->loadModel('Subject');
$options['recursive']=-1;
$options['fields']=array('Subject.name');
$te2= $this->Subject->find('list',$options);
debug($te2);
$this->set( 'te',$te2);
//put is for edit and post for new record
if ($this->request->is('post')) {
$this->request->data['TutorsSubject']['tutor_id']=2;
debug($this->request->data);
if ($this->TutorsSubject->save($this->request->data)) {
$this->Session->setFlash(__('Your post has been updated.'));
return $this->redirect(array('controller' => 'tutors','action' => 'tutordetails'));
}
$this->Session->setFlash(__('Unable to update your post.'));
}
//View which works fine as it displays the list
echo $this->Form->create('TutorsSubject', array('type' => 'post'));
echo $this->Form->input('tutorsSubject.subject_id', array('options' => $te));
echo $this->Form->end('Save Post');
//model subject
public $hasAndBelongsToMany = array(
'Tutor' => array(
'className' => 'Tutor',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'subject_id',
'associationForeignKey' => 'tutor_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
//model tutor
public $hasAndBelongsToMany = array(
'Subject' => array(
'className' => 'Subject',
'joinTable' => 'tutors_subjects',
'foreignKey' => 'tutor_id',
'associationForeignKey' => 'subject_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
);
I have two models. They are DisnotificationUpdate and DisNotification.
DisnotificationUpdate relations are as below.
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'Login', 'userid'),
'notifi' => array(self::BELONGS_TO, 'Disnotification', 'notifi_id'),
);
}
It's attributes are as following.
public function attributeLabels()
{
return array(
'id' => 'ID',
'notifi_id' => 'Notifi',
'view' => 'View',
'userid' => 'Userid',
);
}
Disnotification model has following attributes.
public function attributeLabels()
{
return array(
'id' => 'ID',
'notification' => 'Notification',
'owner' => 'Owner',
'workspace_id' => 'Workspace',
'postID' => 'Post',
'pDate' => 'P Date',
);
}
I want to select values from DisnotificationUpdate and order by values using 'pDate' in DisNotification.
I tried as following.
$dataProvider=DisnotificationUpdate::model()->findAll(array(
'condition' => 'userid=:userid',
'order' => 'notifi.pDate ASC',
'limit'=>10,
'params' => array(':userid' => $myid)
));
But it is giving an error saying, "Unknown column 'notifi.pDate' in 'order clause'". What I am doing wrong? Thanks.
You need to eager load related model
$dataProvider=DisnotificationUpdate::model()->findAll(array(
'with' => array('notifi'),
'condition' => 'userid=:userid',
'order' => 'notifi.pDate ASC',
'limit'=>10,
'params' => array(':userid' => $myid)
));
I'm trying to traverse the relations on CakePHP models.
This is the database:
I can access product attributes (product->attributes) on a product model but I cannot access the product attributes on Ad model (ad->product->attributes).
Here is my code:
//Product Model
class Product extends AppModel {
public $useTable = 'products';
public $displayField = 'name';
public $hasAndBelongsToMany = array(
'Attributes' =>
array(
'className' => 'Attribute',
'joinTable' => 'product_has_attributes',
'foreignKey' => 'products_id',
'associationForeignKey' => 'attributes_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'product_has_attributes'
)
);
public $hasMany = array(
'Ads' => array(
'className' => 'Ad',
'foreignKey' => 'Products_id',
'conditions' => '',
'order' => '',
'limit' => '',
'dependent' => true
)
);
//Ad Model
class Ad extends AppModel {
public $displayField = 'Name';
public $belongsTo = array(
'Product' => array(
'className' => 'Products',
'foreignKey' => 'products_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
//Attribute Model
class Attribute extends AppModel {
public $displayField = 'name';
public $hasAndBelongsToMany = array(
'Products' =>
array(
'className' => 'Product',
'joinTable' => 'product_has_attributes',
'foreignKey' => 'attributes_id',
'associationForeignKey' => 'products_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'product_has_attributes'
)
);
// Products controller -> Action View
class ProductsController extends AppController {
public function view($id = null) {
if (!$this->Product->exists($id)) {
throw new NotFoundException(__('Invalid product'));
}
$options = array('conditions' => array('Product.' . $this->Product->primaryKey => $id));
$this->set('product', $this->Product->find('first', $options));
}
}
// Ads controller -> Action View
class AdsController extends AppController {
public function view($id = null) {
if (!$this->Ad->exists($id)) {
throw new NotFoundException(__('Invalid ad'));
}
$options = array('conditions' => array('Ad.' . $this->Ad->primaryKey => $id));
$this->set('ad', $this->Ad->find('first', $options));
}
And here is what I do in the views:
//Products Views: snipet of view.ctp
print_r ($product);
// this prints rhe product and all associated attributes
//Ads Views: snipet of view.ctp
print_r ($ad['Product']);
//this will print only the product fields, but not the attributes associated to the product
What is wrong? How do I access the relation Ad->product->attribute from my Ad model?
I can think of a couple of simple ways to accomplish this.
First:
class AdsController extends AppController {
if (!$this->Ad->exists($id)) {
throw new NotFoundException(__('Invalid ad'));
}
$options = array(
'conditions' => array('Ad.' . $this->Ad->primaryKey => $id),
'recursive' => 1, // or more
);
$this->set('ad', $this->Ad->find('first', $options));
}
That would be the simplest code change to make sure you get attributes that are related to the product that is returned.
Otherwise, you alluded to this in your question. You can access related Models through the model, so:
$this->Ad->Product->find(...);
I have had issues with Cake not liking my find conditions when using related models in conditions, and I'm not sure of the proper syntax, but if you wanted to pursue that, I'm sure you can track it down through the docs or by experimentation.
Finally, I would advise you to check into the ContainableBehavior, which will allow you to fine tune which fields are actually returned in the results. I hope this answers your question!
Perhaps the problem could be that you're not using CakePHP's conventions.
From the docs:
"new join table’s name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ )."
So, your join table should be named attributes_products.
Also, check your foreign keys. They should be in singular form.
attributes_products.id
attributes_products.product_id
attributes_products.attribute_id
Hopefully that solves the problem.
References:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm
http://book.cakephp.org/2.0/en/getting-started/cakephp-conventions.html#model-and-database-conventions
If I don't choose a file, time validation doesn't work and it doesn't show the message "invalid file".
this is action url:
http://localhost/carsdirectory/cars/create_ad
create_ad.ctp(view)
<?php echo $this->Form->create('Car', array('type' => 'file', 'action' => 'create_ad')); ?>
<?php echo $this->Form->file('CarImage.image_path')?>
<?php echo $this->Form->end(array('label' => 'Submit', 'name' => 'Submit', 'div' => array('class' => 'ls-submit')));?>
car_image.php(model)
<?php
class CarImage extends AppModel
{
var $name = 'CarImage';
var $belongsTo = 'Car';
var $validate = array(
'image_path' => array(
'rule' => array('extension', array('jpeg', 'jpg', 'png', 'gif')),
'allowEmpty' => false,
'required' => true,
'message' => 'invaid file'
),
'car_id' => array(
'rule' => "numeric",
'allowEmpty' => false,
'message' => 'Car details could not be saved'
)
);
}
?>
car_images(table)
Field -> 1) id 2) image_path 3)car_id
As I commented and suggested what seems right according to your scheme is that you have these associations:
Car model:
public $hasMany = array(
'CarImage' => array(
'className' => 'CarImage',
'foreignKey' => 'car_id',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
CarImage model:
public $belongsTo = array(
'Car' => array(
'className' => 'Car',
'foreignKey' => 'car_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Field for form, since you can have many files to uploaded (just make a new line with number increment):
echo $this->Form->file('CarImage.0.image_path');
To validate and upload files, is easier and more consistent making this in CarImage model (I don't sure if you needs car_id in $validate variable, if doesn't work, try remove car_id from $validate):
public $validate = array(
'image_path' => array(
'uploadFile' => array(
'rule' => array('uploadFile'),
'message' => 'Invalid file',
),
),
);
public function uploadFile($params) {
if ($params['image_path']['error'] == 0) {
$file = pathinfo($params['image_path']['name']);
if (in_array($file['extension'], array('jpeg', 'jpg', 'png', 'gif'))) {
$tmp_file = new File($params['image_path']['tmp_name']);
if ($tmp_file->copy('folder_inside_webroot' . DS . $file['basename'])) {
return true;
}
}
}
return false;
}
And your controller needs saveAll instead save:
if ($this->Car->saveAll($this->data)) {
// success
} else {
// failure
}
I hope it helps.