Model Associations
There are basically 4 types of relationship that can take place between database tables:
Relationship | Association Type | Example |
one to one | hasOne | A user has one profile. |
one to many | hasMany | A user can have multiple recipes. |
many to one | belongsTo | Many recipes belong to a user. |
many to many | hasAndBelongsToMany | Recipes have, and belong to many tags. |
One-To-Many Relationship in Models
Think of a situation where we need to store information about some authors and their books and the relation between authors and books is one-to-many. This means an author can have multiple books but a book belongs to only one author (which is rather absurd, as in real life scenario a book can also have multiple authors). We are now going to define associations in models for this one-to-many relation, so that our models recognize their relations and can deal with them accordingly.
Create a new database and put a fresh copy of CakePHP inside the web root. Name the database whatever you like but rename the cake folder to relationship(your cake folder name). Configure the database in the new Cake installation.
1. Execute the following SQL statements in the database to create a table named authors,
2. Create a books table in our database by executing the following SQL commands:
3. Create the Author model using the following code (/app/models/authors.php):
4. Use the following code to create the Book model (/app/models/books.php):
5. Create a controller for the Author model with the following code: (/app/controllers/authors_controller.php):
6. Use the following code to create a controller for the Book model (/app/controllers/books_controller.php):
7. Now, go to the following URLs and add some test data:
http://localhost/relationship/authors/and
http://localhost/relationship/books/
A foreign-key named author_id is added to the books table to establish the one-to-many relation between authors and books. Through this foreign-key, an author is related to multiple books, as well as, a book is related to one single author.
By Cake convention, the name of a foreign-key should be underscored, singular name of target model, suffixed with _id.
Saving Related Model Data in One-To-Many Relation
Associations can also make saving related data pretty easy. We will now create a simple program that can save a book and can relate the book with an author at the time of saving. We will add some code to the previous code-base to put in the save functionality.
In the BooksController (/app/controllers/books_controller.php), add the FormHelperand write a new action add(),
[php]<?php
class BooksController extends AppController {
var $name = ‘Books’;
var $helpers = array(‘Form’ );
function index() {
$this->Book->recursive = 1;
$books = $this->Book->find(‘all’,
array(‘fields’ =>
array(‘Book.isbn’,’Book.title’,’Author.name’)
)
);
$this->set(‘books’, $books);
}
function add() {
if (!empty($this->data)) {
$this->Book->create();
$this->Book->save($this->data);
$this->redirect(array(‘action’=>’index’));
}
$authors = $this->Book->Author->generateList();
$this->set(‘authors’, $authors);
}
}
?>
[/php]
1.Create a view for the action ‘/books/add’ (/app/views/add.ctp)
[php]<?php echo $form->create(‘Book’);?>
<fieldset>
<legend>Add New Book</legend>
<?php
echo $form->input(‘isbn’);
echo $form->input(‘title’);
echo $form->input(‘description’);
echo $form->input(‘author_id’);
?>
[/php]
[php]
</fieldset>
<?php echo $form->end(‘Submit’);?>
[/php]
2.Point your browser to the following URL and add a book:
http://localhost/relationship/books/add
In previous examples, the only association that the Author model has is a hasMany association with the Book model. This association was created by the following line of code:
var $hasMany = ‘Book’;
Here, a string is used to define the hasMany association. It is also possible to do the same thing using an associative array like the following:
[sql]
var $hasMany=array(‘Book’=>array(‘className’=>’Book’,));
Likewise, for the Book model we can do the following:
var$belongsTo=array(‘Author’=>array(‘className’=>’author’,));
[/sql]
This alternative method is handy if we want to add more than one association of the same type or
we need to customize some of the relationship characteristics.
If we have another model Tutorial and our Author model also has a hasMany association with the Tutorial model, we can use the array approach to define these two associations in theAuthor model:
[sql]
var $hasMany = array(
‘Book’ => array(
‘className’ => ‘Book’,
),
‘Tutorial’ => array(
‘className’ => ‘Tutorial’,
)
);
[/sql]
3.7 Views
CakePHP view files are written in plain PHP and have a default extension of .ctp (CakePHP Template). View files are stored in /app/views/, in a folder named after the controller that uses the files, and named after the action it corresponds to. For example, the view file for the Products controller’s “view()” action, would normally be found in /app/views/products/view.ctp.
3.7.1 Layouts
A layout contains presentation code that wraps around a view.Layout files should be placed in /app/views/layouts. CakePHP’s default layout can be overridden by creating a new default layout at /app/views/layouts/default.ctp.
3.7.2 Elements
Many applications have small blocks of presentation code that need to be repeated from page to page, sometimes in different places in the layout. CakePHP can help you repeat parts of your website that need to be reused. These reusable parts are called Elements.Elements live in the /app/views/elements/ folder, and have the .ctp filename extension. They are output using the element method of the view.
[php]
<?php echo $this->element(‘helpbox’); ?>
[/php]
3.7.3.helpers: these classes encapsulate view logic that is needed in many places in the view layer. Among other things, helpers in CakePHP can help you build forms, build AJAX functionality, paginate model data, or serve RSS feeds
Steps To Create an Blog Application
Getting Cake
Download latest stable verson of CakePhp .One of the Link for downloading cakephp http://github.com/cakephp/cakephp/downloads.
After downloading the CakePHP package, extract its contents to the document root directory of your web server, or one of its subdirectories. For this example, I’ll assume that your CakePHP application is installed in the document root directory named as cake1 and that it’s accessible at http://localhost/testcake.
For Solving these warnings
1.Change the default seed and cipher value by editing /app/config/core.php. It doesn’t much matter what the new value is, as long as it’s not easily guessed.
2.Edit your database configuration file (/app/config/database.php.default) and save it as database.php
3.Provide Writting permission for the tmp directory
4.If you don’t want or can’t get mod_rewrite (or some other compatible module) up and running on your server, you’ll need to use Cake’s built in pretty URLs. In /app/config/core.php, uncomment the line that looks like:Configure::write(‘App.baseUrl’, env(‘SCRIPT_NAME’));
- Creating Database
[sql]
CREATE TABLE IF NOT EXISTS `blogs` ( `id` int(255) NOT NULL auto_increment PRIMARY KEY,`date` date NOT NULL
`title` varchar(255) NOT NULL ,`introtext` text NOT NULL, `maintext` text NOT NULL );
fill the database with some sample data.
INSERT INTO `blogs` (`id`, `date`, `title`, `introtext`, `maintext`)
VALUES(1, ‘2008-10-24’, ‘My first blog post’, ‘
<h1>Hello World!</h1>
r\n
This is my first article using the CakePHP framework. I hope you like it.
‘,
‘
<h2>This text will only be visible on the second page.</h2>
\<strong>r\n</strong>
<h3>It”sjust like how <a title="Joomla! CMS" href="http://joomla.org/">Joomla!</a> works!</h3>
‘),
(2, ‘2008-10-27’, ‘2nd article’, ‘
This is my second article, just totest the amazingly cool CakePHP framework.
‘,
‘
Even the <em>read more</em> works!
‘),(3, ‘2008-11-02’, ‘Last article’,
‘
Sorry guys, this will be my lastarticle. Make sure you check out
<a title="Marcofolio" href="http://www.marcofolio.net/">Marcofolio</a> for more interesting articles!
‘,
‘
And in the future: Making this blog bigger & better!
‘);
[/sql]
we can easily create a blog in the /blog/ section of the site (The URL will look like this: http://yourdomain.com/blog/).
You must remember the syntax of an URL for CakePHP: http://yourdomain.com/CONTROLLER/FUNCTION/ARG1/ARG2/ etc.
Anyway, when you now visit the/blog/ section of your site, you’ll see the following error (with the default download package).
It’s telling us that Cake is missing the BlogController, together with the filename it’s searching for and the default code. Let’s follow this error message by creating a “blog_controller.php” file in the app/controllers directory. This file will have the following code:
[php]
<?php
class BlogController extends AppController {
var $name = ‘Blog’;
// Used when indexing the page (http://yourdomain.com/blog/)
function index()
{
}
}
?>
[/php]
When done correctly, the following error should show up: The view is missing.
To fix this problem, go to your app/views folder. Create a new folder called blog inside of the views folder. Inside the/blog/folder, create a file called index.ctp (CTP = Cake Template). Leave the file empty for now.
The model in a MVC-pattern (Model-View-Controller) represents the storage type. In Cake, the model is the final place before data enteres the actual database (or the first when data is retrieved from the database). We want to create a Blog model to retrieve Blog data from the database.
To achieve this, create blog.php inside the app/models folder. This file will contain the following code:
[php]
<?php
class Blog extends AppModel
{
var $name = ‘Blog’;
var $primaryKey = ‘id’;
}
?>
[/php]
Now we’ll have to “tell” the controller to use the model. To do so, add the following line to yourblog_controller.php, right under the $name variable.
var $uses = array(‘Blog’);
To check if the controller is now connected to the model,
change your blog_controller.php and add the following inside the index() function:
$this->Blog->findAll();
This code will ask the Blog-model to do a “findAll()” (standard model function in CakePHP) to retrieve all the data the model can get from the database (in this case: Everything from the “blogs” table). The debug() function will give you a human readable output to check your output.
When you now visit your blog (http://yourdomain.com/blog/), you should be able to read all information from the “blogs” table in your database in several arrays. If so, we can move on!
The controller now has a connection with the correct model.
Now we’ll need to connect the controller information with the view.
To do so, add the following line to your index() function of blog_controller.php:
$this->set(‘articles’, $this->Blog->findAll());
Now the “articles” variable for the object “Blog” will contain all blog posts retrieved from the database.
Open the index.ctp file, located in views/blog. To test if it worked, add the following line to the file:
<?php print_r$articles) ?>
When you now view the page in your browser (http://yourdomain.com/blog/), you should once again see all articles in the form of an array. There is one difference from the previous version tough: You’re now getting the data from the view.This is how a view for the blog could look like.
[html]
<div id="blog">
<?php foreach ($articles as $article) : ?>
<div class="article">
<h1><a href="blog/index/<?= $article[‘Blog’][‘id’] ?>"
title="<?= $article[‘Blog’][‘title’] ?>"><?= $article[‘Blog’][‘title’] ?></a></h1>
<p class="date"><?= $article[‘Blog’][‘date’] ?></p>
<p><?= $article[‘Blog’][‘introtext’] ?>
<a href="blog/index/<?= $article[‘Blog’][‘id’] ?>" title="<?= $article[‘Blog’][‘title’] ?>"
<class="readon">Read more…</a></p>
</div>
</div>
[/html]
When you now look at your /blog/, you would now be able to really see your blog alive!
As you now can see, the title and the “read more…” are linked to the following URL:http://yourdomain.com/blog/ID, where ID is the ID of the article. This is the URL to show the full article.
To make this work, we’ll need to make changes to the controller and add a view. We’ll start with the controller, so open blog_controller.php. Make the following changes to your index() function:
function index($view = null)
[php]
// What to do if a view is set{
if (isset($view)){
$this->set(‘article’, $this->Blog->find("id = $view"));
$this->render(‘article’); }
else
{
$this->set(‘articles’, $this->Blog->findAll());
}
}}
[/php]
So far, we’ve been using the default layout that comes with CakePHP and no CSS styling was used. Let’s change that, making it our real own blog.We already know that our code is working, so we’ll not need to debug anymore or see the queries executed. Open core.php located in app/config. Search for Configure::write(‘debug’, 2); and change the “2” to a “0”.Create a new layout file called default.ctp in the app/views/layouts folder. Add the following code to that file.
[html]
<html>
<head>
<title>My first CakePHP blog</title>
<?= $html->css(‘default’); ?>
</head>
<body>
<?= $content_for_layout ?>
</body>
<html>
[/html]
For adding some CSS styles for pages create default.css inside the app/webroot/css folder.
For changing the home page, create: APP/views/pages/home.ctp.