I'm trying to insert the data of the following form in a table of database that is not the "default" one. However, i don't know how to do it, i'm still adapting to cakephp. I guess the form is done correctly and the names of the specific table on database are the ones in the inputs. But i'm not saying anywhere which table he should insert right? Is that not necessary? Or in case it's needed, what am i missing to specify the table i want?
<?php echo $this->Form->create('Ficha', array('action' => 'index')); ?>
//echo $this->Form->input('id_fichas', array('label' => 'Id Ficha:'));
echo $this->Form->input('class_subst', array('label' => 'Class mistura:'));
echo $this->Form->input('simbolos_perigo', array('label' => 'Símbolos:'));
echo $this->Form->input('frases_r', array('label' => 'Frases:'));
echo $this->Form->end('Finalizar Ficha'); ?>
By convention table objects will use a table that matches the lower cased and underscored version of the class name. In your case 'Ficha' will be mapped to 'fichas' table. If you want a different table you need to define it, based on the CakePHP version:
CakePHP 3.x
You can specify the table using the setTable() method:
class Example extends Table {
public function initialize(array $config) {
$this->setTable('my_table');
// Prior to 3.4.0 use 'table' method
// $this->table('my_table');
}
}
Link to 3.x docs
CakePHP 2.x
The attribute $useTable in your Model will do the magic:
<?php
App::uses('AppModel', 'Model');
class Example extends AppModel {
public $useTable = 'exmp'; // This model uses a database table 'exmp'
}
Link to 2.x docs
Related
I have two tables in a database, one as event(eventID,name,location), and the other one as eventImages(id,eventID,path).
I need to get the images related to each event
I have tried the following statement in CakePHP:
<?php
App::uses('AppModel','Model');
class EventImages extends AppModel {
public $belongsTo = array('Event' => array('className' => 'Event','foreignKey' => 'eventID'));
}
but no data is retrieved in the controller any missing statement?
You have to define relation in Event model
public $hasMany = array('EventImages'=>array('className'=> 'EventImages', 'foreignKey'=>'eventID') //for multiple image
According to naming convention in cakephp Model name should be singular. Also you have to define public $primarykey = 'eventID' in Event model as cakephp by default use id field as primary key.
I have Users and I have Courses. I am trying to create a "Join" button for the users when they're viewing the course list in order to subscribe them to the Courses.
I was told to use
class Course extends AppModel
{
public $hasAndBelongsToMany = array('User');
}
and
class User extends AppModel
{
public $hasAndBelongsToMany = array('Course');
}
But I don't know how to implement the actual button and the posting of the info to a table called courses_users
Where do I implement this?
Thanks in advance!
If you are this new I would suggest using the cake bake utility which will examine your tables , ask some questions about the relations and build the model, controller and views for all the basic create, update and delete operations in your database. You can then modify them for your needs. That's how I still do it to save lots of time.
You want to sent the student ID and the course ID to your saveAll() method. You could do this through your courses controller as follows:
<?php
class CoursesController extends AppController {
public function join($courseId) {
$data = array(
'Course' => array(
'id' => $courseId
),
'Student' => array(
'id' => $this->Auth->user('id') // ID of logged in user
)
);
if ($this->Course->saveAll($data)) {
$this->Session->setFlash( __('Successfully joined course.'));
}
else {
$this->Session->setFlash( __('Error joining course.'));
}
$this->redirect('/');
}
}
This is just a simple example. You’ll need to tweak it to your app, and add any validation etc.
In model:
public function getOptionsGender()
{
array(0=>'Any', 1=>Male', 2=>'Female');
}
In view (edit):
echo $form->dropDownList($model, 'gender', $model->optionsGender);
but I have a CDetailView with "raw" attributes, and it displays numbers instead of genders.
$attributes = array(
...
'gender',
)
What is appropriate way to convert these numbers back to genders? Should I do it in a model, replacing fields such as $this->gender = getOptionsGender($this->gender)? Any github examples will be very appreciated.
I had to choose gender, age, city, country etc. in a few views that are not related to this one. Where should I place my getOptionsGender function definitions?
Thank for your help, the problem is solved.
In model:
public function getGenderOptions() { ... }
public function genderText($key)
{
$options = $this->getGenderOptions();
return $options[$key];
}
In view:
$attributes = array(
array (
'name'=>'gender',
'type'=>'raw',
'value'=>$model->genderText($model->gender), //or $this->genderText(...)
),
);
$this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>$attributes,
));
The working example can be found here:
https://github.com/cdcchen/e23passport/blob/c64f50f9395185001d8dd60285b0798098049720/protected/controllers/UserController.php
In Jeffery Winsett's book "Agile Web Application Development with Yii 1.1", he deals with the issue using class constants in the model you are using. In your case:
class Model extends CActiveRecord
{
const GENDER_ANY=0;
const GENDER_MALE=1;
const GENDER_FEMALE=2;
public function getGenderOptions(){
return array(
self::GENDER_ANY=>'Any',
self::GENDER_MALE=>'Male',
self::GENDER_FEMALE=>'Female',
);
}
public function getGenderText(){
$genderOptions=$this->genderOptions();
return isset($genderOptions[$this->gender]) ? $genderOptions[$this->gender] : "unkown gender({$this->gender})";
}
}
Then in your CDetailView you would have to alter it from gender to:
array(
'name'=>'gender',
'value'=>CHtml::encode($model->genderText()),
),
If several models have the same data, you may want to create a base model that extends CActiveRecord and then extend the new model instead of CActiveRecord. If this model is the only one with that data (ie User model only has gender), but other views use that model to display data, then I would leave it just in the single model class. Also keep in mind that if you place getGenderOptions in the extended class, and you extend ALL your models, they will all have that option available, but may not have the attributes needed and will throw an error if you aren't checking for it.
All this being said, I still think it is a matter or preference. You can handle it however you want, wherever you want. This is just one example from a book I have specifically on Yii.
I'm using Associations to Link Models together in CakePHP.
I have a Player model that is linked to a Statistic model using a $hasMany relationship. So basically one player can have many statistics.
After I set up these relationships, I use cake bake to generate the controllers and views for both the Player and Statistic models.
Everything works fine and works as expected, but when I go to add a statistic using the add template, the player_id is used as the association.
My question is how do I set up the model to use the player_id as the association but use something like the player's first and last name as the drop down menu in the add template.
Currently if I go to add a new statistic, I get a drop down box that called "Player" that lists all of the player id's but what I want is for the player's first_name and last_name to be in that drop down box instead of the id. I realize that I can modify the controller or template to accomplish this, but I Want to know if I can do this while setting up the model so that cake bake can take care of it.
Player Model:
<?php
class Player extends AppModel {
public $name = 'Player';
public $belongsTo = array(
'School' => array(
'className' => 'School',
'foreignKey' => 'school_id'
)
);
public $hasMany = 'Statistic';
}
Statistic Model:
<?php
class Statistic extends AppModel {
public $name = 'Statistic';
public $belongsTo = array(
'Player' => array(
'className' => 'Player',
'foreignKey' => 'player_id'
)
);
}
Players Table
`id|school_id|first_name|last_name|number|position
Cake uses the model's displayField attribute when choosing the default columns for a list. If none is defined for the model it will look for name or title. So in your model you can use:
public $displayField = 'first_name';
This will display the player's first name in the list.
If you want the display field to be the concatenation of two fields, you can use a virtual field in the model like so:
public $virtualFields = array(
'name' => "TRIM(CONCAT(Player.first_name, ' ', Player.last_name))"
);
Note the above works for Mysql. For another kind of database you will need to adjust the syntax. For example, for Sqlite it would be:
TRIM(Player.first_name || ' ' || Player.last_name)
Then add in your model:
public $displayField = 'name';
I'm starting a cakephp app, I've never used it in real world so I'm a bit confused how HABTM works, even though I read the documentation I couldn't get even the $this->User->Subscription and didn't see any extra object dumped
What I want is to create a HATBM between users and subscriptions
so I created three tables (users,subscriptions,users_subscribers)
Then in my User.php model I did this
var $hasAndBelongsToMany =
array(
'Subscription' =>
array('className'=>'Subscription',
'joinTable' => 'users_subscribers',
'foreignKey' => 'user_id',
'associationForeignKey' => 'subscription_id',
'unique' => true,
)
);
SUbscription.php
var $hasAndBelongsToMany = array(
'User'=>array('className'=>'User',
'joinTable' => 'users_subscribers',
'foreignKey' => 'subscription_id',
'associationForeignKey' => 'user_id',
'unique' => true));
Even with the tags example and following it, I cannot get the relation set, I also added the line <?php echo $this->element('sql_dump'); ?> to see if its running which it isn't...
Could anyone guide me how exactly you get HATBM to work, what else do I need to verify?
Full code:
pages_controller.php
http://sao.pastebin.com/PWQMhE2z
User model:
http://sao.pastebin.com/PWqwAj1v
Subscription model:
http://sao.pastebin.com/MfVFR4Kw
subscriptions SCHEMA:
http://sao.pastebin.com/mLRcEp1c
User SCHEMA:
http://sao.pastebin.com/UeTRHh3u
users_subscriptions SCHEMA:
http://sao.pastebin.com/4UeSDZte
The simplest and fastest way to get this working is by following CakePHP's rule of configuration over customization.
This means following the CakePHP conventions unless you have a very good reason not to.
I'd strongly recommend starting with a basic setup that you know works, and then modifying that if you need to. Here's a quick and easy way to get up and running.
The Database Tables
Start with three database tables: users, subscriptions and subscriptions_users. The schemas you already have are ok, but I'd make a couple modifications to make sure things go smoothly:
Add a name or title column to the users table. Either that, or you'll have to add the $displayField property to your User model. If you don't do this you'll miss out on some of the "automagic" that CakePHP provides. More info on $displayField
Change the join table's name to subscriptions_users. This is the CakePHP convention and there's no reason not to save yourself the time and worry of following it. :-)
Use the following schema for the join table:
CREATE TABLE subscriptions_users (
subscription_id int(11) NOT NULL,
user_id int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Note that there aren't any keys defined. From the CakePHP manual: "To avoid any issues - don't define a combined primary key for these two fields, if your application requires it you can define a unique index."
The Models
Try to keep your code clean. There are a lot of sensible defaults implemented in CakePHP and there's no point in defining them when they're already defined.
The following models should work for you:
user.php
<?php
class User extends AppModel {
var $hasAndBelongsToMany = array('Subscription');
}
?>
subscription.php
<?php
class User extends AppModel {
var $hasAndBelongsToMany = array('User');
}
?>
Pretty simple. Just be sure your model files are named correctly: user.php and subscription.php, all lowercase.
Also, note that you don't have to set any of the relationship options (className, joinTable, etc.) unless they need to be something besides the default. Ninety percent of the time the defaults should serve you just fine.
You should be up and running now. You can make sure the model objects are being loaded and are accessible in your controllers like this:
users_controller.php
<?php
class UsersController extends AppController {
var $name = 'Users';
function index() {
$this->autoRender = false;
var_dump(is_object($this->User));
var_dump(is_object($this->User->Subscription));
}
}
?>
subscriptions_controller.php
<?php
class SubscriptionsController extends AppController {
var $name = 'Subscriptions';
function index() {
$this->autoRender = false;
var_dump(is_object($this->Subscription));
var_dump(is_object($this->Subscription->User));
}
}
?>
The output of /users and /subscriptions should both be bool(true) bool(true).
You can see the full models by doing pr($this->User);.
Deleting records
If you delete a single record using, for example, $this->User->delete($user_id), all the records in the join table with that user ID will automatically be deleted as well.
If you want to delete a single record from a HABTM join table, without deleting the records that it links to, in effect, "unjoining" the two records, you can do it through the SubscriptionsUser model. This is a model that is created on the fly whenever there's a HABTM relationship.
See here for an example: CakePHP hasAndBelongsToMany (HABTM) Delete Joining Record
I did a test app with a basic schema and I get all the relations right. I suspect your woes have to do with the fact that you did $uses = array('User', 'Subscription');Why don't you try with $uses = $uses = array('User'); and then try
$this->User->find('all');
$this->User->Subscription->find('all');
You also need to define the same HABTM relation in your Subscription.php model. If I recall correctly, CakePHP internally fetches some of the required information from the other side's HABTM configuration.
I always use two "hasMany" relations and one "belongsTo" relation to get the HABTM effect in CakePHP with more control.
Try this:
User model (user.php)
class User extends AppModel {
public $name = 'User';
public $actsAs = array('Containable');
public $hasMany = array('UserSubscription');
}
Subscription model (subscription.php)
class Subscription extends AppModel {
public $name = 'Subscription';
public $actsAs = array('Containable');
public $hasMany = array('UserSubscription');
}
UserSubscription model (user_subscription.php)
class UserSubscription extends AppModel {
public $name = 'UserSubscription';
public $belongsTo = array('User','Subscription');
}
pages/home action (pages_controller.php)
public function home() {
$data = array(
'User' => array(
'id' => 1, 'user_email' => 'allenskd#gmail.com', 'user_password' => 'fdfdkert', 'user_salt' => 'haha', 'user_displayname' => 'David'
),
'UserSubscription' => array(
'user_id' => '1', 'subscription_id' => '1'
),
'Subscription' => array(
'id' => 1, 'title' => 'My first plan', 'price' => '30.00', 'subscriber_count' => '1'
),
);
$this->Subscription->save($data);
$this->User->saveAll($data);
$test = $this->User->find('all', array('contain' => array('UserSubscription' => array('Subscription'))));
pr($test);
}