Cakephp - Two tables in one page - cakephp

I'm trying to understand Cakephp. I follow the manual from the official page http://book.cakephp.org/2.0/en/tutorials-and-examples/blog/blog.html and now i can display a few posts on my page. For some reasons all files and functions has to have the name "Posts" but when you want to search for a database table you have to write "post" [$this->set('posts', $this->Post->find('all'));]. WHY? I read about CakePHP Conventions and it doesn't make sense. What if i have a hello.ctp page and a "goodmorning" table name? I spent 2 days on this and i ALWAYS end up to this: Error: Call to a member function find() on a non-object. I want to display my posts and my "goodmorning" table on the same page.
Just to make it clear, I have two tables:
CREATE TABLE `Posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50),
`body` TEXT,
`created` DATETIME DEFAULT NULL,
`modified` DATETIME DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `Comments` (
`id` int(11) DEFAULT NULL,
`name` VARCHAR(50),
`comment` TEXT,
`created` DATETIME DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
PostController.php
<?php
class PostsController extends AppController {
public function index() {
$posts = $this->Post->find('all');
$this -> set ('posts',$posts);
$comments = $this->comment->find('all');
$this -> set ('comments',$comments);
}
}
?>
PostsModel.php
<?php
class Posts extends AppModel {
}
?>
CommentsModel.php
<?php
class Comments extends AppModel {
}
?>
If i remove those lines from PostController:
$comments = $this->comment->find('all');
$this -> set ('comments',$comments);
the "Posts" table will show up (localhost/cake/Posts). In pure php i can build this in a few minutes but in cakephp i really feel hopeless

The line $this->set('posts', $this->Post->find('all')); is going to your Posts model, executing the find() function, and then setting that data to the view variable $posts. You could change the variable name to 'Posts' in the first argument of $this->set() and the view variable the data would be set to would be $Posts.
CakePHP's naming conventions don't apply to variable names. You should define a style that you like for them and stick to it. The help documents typically use all lower case names with words separated by underscores, but that has no bearing on anything unless you're referencing one of CakePHP's pre-defined values.
The issue with your goodmorning table name is that table names by CakePHP convention should be lower case, plural, and the words should be separated by underscores. If you want the "Cake Magic" to connect all of your names together invisibly by convention, what you want to create is a database table named good_mornings, a Model named GoodMorning and a Controller named GoodMorningsController.

In Cakephp
For using table with custom names
<?php
class Post extends AppModel {
public $useTable = 'goodmorning';
}
?>
For using view with custom names
public function index() {
$this->autoRender = false;
$this->render('hello');
}

table name must be lowercase and plurals (e.g. posts)
model name must be lower case except for the first letter, and singular (e.g. Post)
controller name must be plural and attached to the word "Controller" (e.g. PostsController)
table id must be named "id" (but could be named with other names, you must specify the different name inside the Model class. e.g. $this->Post->id = $newId)

Related

How to create a many to many self-referencing relationship cakephp

The cakephp docs state the following:
You can even create self-associated tables to create parent-child relationships:
class CategoriesTable extends Table
{
public function initialize(array $config)
{
$this->hasMany('SubCategories', [
'className' => 'Categories'
]);
$this->belongsTo('ParentCategories', [
'className' => 'Categories'
]);
}
}
Which sounds good, but the code above doesn't actually do anything by itself. Like the code above looks like it should describe a self-referencing many to many relationship but if you take an existing Table class and just add that to the initialize function, nothing happens. There has to be some associated schema presumably which isn't shown.
So it's not clear how to actually set up a self-referencing relationship.
I've tried this:
CREATE TABLE `categories` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `categories_categories` (
`parent_id` int(11) NOT NULL,
`child_id` int(11) NOT NULL,
PRIMARY KEY (`parent_id`,`child_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And then baked that... but it's not clear to me how to get that to actually work with models and which models to create and what associations to put in them nor how to get those to be represented by a form element.

How To Force Insert In CakePHP?

I have a MySQL archive table with the following structure:
`histories`
`uid` int(10) unsigned NOT NULL,
`type` varchar(255) NOT NULL,
`param` int(11) NOT NULL,
`param2` varchar(255) NOT NULL,
`time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
I do not want to add an auto-incrementing `id' column. This table's engine is archive and it does exactly what I need it to, with this structure.
I wish to save like this:
$this->History->create();
$this->History->save(['uid' => uid, 'type' => 'deleted_entry', 'param' => $thing_id]);
But CakePHP forces an update, which I don't want and the ARCHIVE engine doesn't support. Cake seems to be looking for a primary key of uid, finding it and deciding that it should update and there seems to be no flag available to force an insert. I do not want to resort to $this->Model->query().
UPDATE:
Set $primaryKey = null in AppModel. $this->create(); will then insert.
class History extends AppModel {
public $primaryKey = null;
}
If you want to do an update after, simply:
$this->History->primaryKey = 'uid'; before the save()
You can tell Cake 2 that you have no primary key by setting the model's $primaryKey property to null:
$this->History->primaryKey = null;
$this->History->create();
$this->History->save(['uid' => uid, 'type' => 'deleted_entry', 'param' => $thing_id]);

delete function not working cakephp

i am working on a Cakephp 2.x ...i want to delete a single record from the database
i have a table in my database called Image .. which contain following fields..
idImage,User_id,filename,filesize,filemime
I would like to delete the single record with idImage=imageid
delete * from posts where imageid = 3'
i am doing this ..image id now has a value 4
$this->Image->imageId = $imageId;
if($this->Image->delete()){
echo "successfull";
}else{
echo "not";
}
but the code is not working .not deleting the record from db
id, not imageId
Setting imageId on the Image model will have no effect at all. If the model's primary key is not id it's necessary to configure the model so that Cake is aware of this and will use your chosen primary key field instead of id.
<?php
class Image extends AppModel {
$primaryKey = 'imageId';
Irrespective of the value of the primary key, the property to set to use the syntax in the question is:
$this->Image->id = $imageId;
if($this->Image->delete()){
This will attempt to delete the image with the given $imageId.
Alternatively just pass it to the delete function:
if($this->Image->delete($imageId)){
Deleting without a primary key
If the objective is to delete by a value that isn't the primary key, either look for it first:
$id = $this->Image->field('id', array('imageId' => $imageId));
if ($id && $this->Image->delete($id)) {
...
Or use deleteAll:
// delete 1 or more records with a matching field value
$this->Image->deleteAll(array(
'imageId' => $imageId
));

Validating Multiple sets of POST data in Cakephp

I've got a Cakephp Project with an 'Addresses' table with the following structure:
CREATE TABLE `addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`name` varchar(50) NOT NULL,
`company` varchar(50) NOT NULL,
`address1` varchar(50) NOT NULL,
`address2` varchar(50) DEFAULT NULL,
`city` varchar(40) NOT NULL,
`state` varchar(2) NOT NULL,
`country` varchar(2) NOT NULL,
`zip` varchar(5) NOT NULL,
PRIMARY KEY (`id`)
)
There is a page in this project which asks the user for both a Shipping Address and a Billing Address, and im not certain how to structure the names of the form inputs to allow multiple instances of the same database fields on one page
In the View, I've attempted to use an alias to seperate the two instances of the Address fields
I.E.-
<?=$this->Form->input('Shipaddress.zip', array('label' => 'Zip Code'));?>
...
<?=$this->Form->input('Billaddress.zip', array('label' => 'Zip Code'));?>
then in the view, i tried to seperate the two instances, validate both, and set the appropriate $this->validationError values to properly display the errors to the correct field views
// place in arrays with proper model name ['Address']
$ship_array['Address'] = $this->request->data['Shipaddress'];
$bill_array['Address'] = $this->request->data['Billaddress'];
//Set Data to model, Validate Against model, change model name in validationErrors to match aliased fields, and remove validationErrors for ['Address']
$this->Address->set($ship_array);
$shipping_valid = $this->Address->validates(array('fieldList' => array('name', 'company', 'address1', 'address2', 'city', 'state', 'country', 'zip')));
$this->validationErrors['Shipaddress'] = $this->validationErrors['Address'];
$this->validationErrors['Address'] = array();
//Do it again for Billing Address fields
$this->Address->set($bill_array);
$billing_valid = $this->Address->validates(array('fieldList' => array('name', 'company', 'address1', 'address2', 'city', 'state', 'country', 'zip')));
$this->validationErrors['Billaddress'] = $this->validationErrors['Address'];
$this->validationErrors['Address'] = array();
unfortunately, this doesnt appear to work, and i'm afraid that I've gone too far trying to make this work...
can someone give my a kick in the right direction on how this can be done properly?
Figured out how to do it on my own...
in /app/Model i created 'ShippingAddress.php' and 'BillingAddress.php', Both Extend "Address"
//ShippingAddress.php
<?php
App::uses('Address', 'Model');
class ShippingAddress extends Address {
}
//BillingAddress.php
<?php
App::uses('Address', 'Model');
class BillingAddress extends Address {
}
To prevent the new models from using tables named after them, we edit the parent Address.php and set $useTable so that both extended models use Addresses Table
//Address.php
...
public $useTable = 'addresses';
...
then its just a matter of inserting the two instances of the input fields into the view... no renaming models, no modifying validationErrors, it just works :)

How do I use the TranslateBehavior in CakePHP?

There is no documentation on cakephp.org and I am unable to find one on google. Please link me some documentation or supply one!
The translate behavior is another of CakePHP's very useful but poorly documented features. I've implemented it a couple of times with reasonable success in multi-lingual websites along the following lines.
Firstly, the translate behavior will only internationalize the database content of your site. If you've any more static content, you'll want to look at Cake's __('string') wrapper function and gettext (there's some useful information about this here)
Assuming there's Contents that we want to translate with the following db table:
CREATE TABLE `contents` (
`id` int(11) unsigned NOT NULL auto_increment,
`title` varchar(255) default NULL,
`body` text,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The content.php model then has:
var $actsAs = array('Translate' => array('title' => 'titleTranslation',
'body' => 'bodyTranslation'
));
in its definition. You then need to add the i18n table to the database thusly:
CREATE TABLE `i18n` (
`id` int(10) NOT NULL auto_increment,
`locale` varchar(6) NOT NULL,
`model` varchar(255) NOT NULL,
`foreign_key` int(10) NOT NULL,
`field` varchar(255) NOT NULL,
`content` mediumtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Then when you're saving the data to the database in your controller, set the locale to the language you want (this example would be for Polish):
$this->Content->locale = 'pol';
$result = $this->Content->save($this->data);
This will create entries in the i18n table for the title and body fields for the pol locale. Finds will find based on the current locale set in the user's browser, returning an array like:
[Content]
[id]
[titleTranslation]
[bodyTranslation]
We use the excellent p28n component to implement a language switching solution that works pretty well with the gettext and translate behaviours.
It's not a perfect system - as it creates HABTM relationships on the fly, it can cause some issues with other relationships you may have created manually, but if you're careful, it can work well.
For anyone searching the same thing, cakephp updated their documentation. For Translate Behavior go here..

Resources