Tag Archives: cakePHP

Count the Number of Cakes – Finding complex results with CakePHP

CakePHP offers a good selection of tools to help you retrieve the data. Recently, I came into a situation where I needed to find and paginate results based on a single, distinct column in the table. Distinct data can be tricky, especially if the tools do not allow you to select the distinct based on a column. Distinct will check all columns returned, and coupling in time stamps, 99% of the time all rows will be distinct. So how do you grab the data? Well, first lets examine the sample data that is needed to be extracted first.

The sample data is in a MS SQL Server database. The table contains a record ID, title id, author id, genre, type, last check out date, and edit date. It is possible to have duplicate title, author IDs in the table. We need to extract all DISTINCT title IDs, along with the other information listed where the type is not a paperback, and provide a paginated list. I am sure this would be better architected if needed in the real world. Paginate will only get us so far, as this would only show all records.

class BooksController extends AppController {
    var $paginate = array(
        'order'        => array('Book.id' => 'desc'),
        'fields'    => array('Book.id', 'Book.title_id', 'Book.author_id', 'Book.genre_id', 'Book.type', 'Book.check_date', 'Book.edit_date'),
        'limit'        => 15,
    );
    . . . 
    function index(){
        $this->set('hardback_books', $this->paginate());
    }
}

We need to use more to build a conditional query so the paginate will query against this. We can use CakePHP’s data source to help in this. Now, we could also just write this query out ourselves, but this is helpful to know so when you have to build sub-queries for other items. All data is in MS SQL Server, and we can use normal SQL expressions, but we need to grab DISTINCT data, which goes by rows, not columns, which means we will need to do 2 sub-queries in addition to the main one. So we first need to grab a list of the TOP 1 items. This will be our inner query.

        SELECT TOP 1 * 
        FROM [books] AS [bk_inner] 
        WHERE 
            [bk_inner].[title_id] = [Book].[title_id] 
            AND 
            [bk_inner].[type] <> 'paperback' 

Next, we need to encapsulate that query with an outer one that will select all items which match up to the main query ID.

    SELECT * FROM 
    (
        SELECT TOP 1 * 
        FROM [books] AS [bk_inner] 
        WHERE 
            [bk_inner].[title_id] = [Book].[title_id] 
            AND 
            [bk_inner].[type] <> 'paperback' 
    ) AS [bk_outer] 
    WHERE bk_outer.[title_id] = Book.[title_id] 

So we have the queries, and it needs the main query needs to constrain the results that exists in the sub-queries.

SELECT TOP 15 
    [Book].[id],
    [Book].[title_id], 
    [Book].[author_id], 
    [Book].[genre_id], 
    [Book].[type],
    CONVERT(VARCHAR(20), [Book].[check_date], 20)
    CONVERT(VARCHAR(20), [Book].[edit_date], 20)
FROM [books] AS [Book] 
WHERE EXISTS 
(
    SELECT * FROM 
    (
        SELECT TOP 1 * 
        FROM [books] AS [bk_inner] 
        WHERE 
            [bk_inner].[title_id] = [Book].[title_id] 
            AND 
            [bk_inner].[type] <> 'paperback' 
    ) AS [bk_outer] 
    WHERE bk_outer.[title_id] = Book.[title_id] 
) 
ORDER BY [Book].[id] desc

We have the final full query. Now how do we get that? First, we need to invoke the getDataSource() method.

class Book extends AppModel {
    . . . 
    function getHardbackBooks(){
        $dbo = $this->getDataSource();

Next we need to use the buildStatement() to build each statement. Since CakePHP will build a sub query with this, we have to do this twice: once for the inner query, and once for the outer query. The “table” for subquery2 will actually be subquery1, so we need to add that as a “table” in the array.

$subquery1 = $dbo->buildStatement(
	array(
		'fields' => array('TOP 1 *'),
        'table' => $dbo->fullTableName($this),
        'alias' => 'bk_inner',
        'limit' => null,
        'offset' => null,
        'joins' => array(),
        'conditions' => 'bk_inner.title_id = Book.title_id AND bk_inner.type <> \'paperback\'',
        'order' => null,
        'group' => null
	
	),
	$this
);

$subQuery2 = $dbo->buildStatement(
    array(
        'fields' => array('*'),
        'table' => '(' . $subquery1 . ')',
        'alias' => 'bk_outer',
        'limit' => null,
        'offset' => null,
        'joins' => array(),
        'conditions' => 'bk_outer.[title_id] = Book.[title_id]',
        'order' => null,
        'group' => null
    ),
    $this
);

Now, we need to make sure we add an EXISTS:

$subQuery = ' EXISTS (' . $subQuery2 . ') ';
return $subQuery;

Return the data from the model to the controller. In the controller function we need to add a new condition to the paginate. In the conditions, we do not need to use a paired item value to set it, we can use the straight SQL returned from the model.

class BooksController extends AppController {
    var $paginate = array(
        'order'        => array('Book.id' => 'desc'),
        'fields'    => array('Book.id', 'Book.title_id', 'Book.author_id', 'Book.genre_id', 'Book.type', 'Book.check_date', 'Book.edit_date'),
        'limit'        => 15,
    );
    . . . 
    function index(){
        $data = $this->Book->getHardbackBooks(); 
        // Set to the paginate object conditions
        $this->paginate['conditions'] = array($data);
        $this->set('hardback_books', $this->paginate());
    }
}

And it returns the items based on the paginate parameters, ready to use in the view. It provides a DISTINCT list. And yes, I know I used more than 400 words in this one. It was closer to 500 without the code. Oh well, maybe tomorrow will be shorter.

Have Your Cake and Eat It Too

CakePHP is one of those frameworks where it is easy to set up and get an application running in a minimal amount of time. It provides different securities, helps, and functions in the framework so that your application can run smoothly and be safe. As with all applications, the level of security and functionality depends on the developer, not the code, not the language, not the database. An application is only as secure, functional and reliable as the person/team who is coding it. One of the reasons I do like Cake is that the built in security and helpers offer a developer a great way to secure data, validate it, and display it. And that can also be one of the more trickier parts of getting the application to work correctly, finding the data to do something with it.

CakePHP
CakePHP

CakePHP provides some functionality for finding the data, this is done using the “find” method. You can read more about this at the Cookbook. Using this, one can grab data from many different tables if needed, or just one table. For this exercise, I am going to use dummy data to show how to find data, using simplistic finds, and using joins, and sub-queries. So first lets examine the data tables. Not all of these are going to be connected. This is a very simplistic, quickly drawn up solution to a lending library

Sample Tables
Sample Tables

Continue reading Have Your Cake and Eat It Too

Data Model Relationships – CakePHP’s HABTM

For today, lets dive back into some code, well data modeling at least. When you set up an application that connects to a database, you need to understand the data that will be working in the application. This is the data that will be edited, added, read and even scrutinized int he application. When looking at the application data, one could easily put all data in a table and make it as flat as possible. We could normalize it until the cows come home as well. What is the best choice? My vote is always plan for what is best for the application, and the future of the application. When it comes to data, a more normalized data layout is always going to provide better performance and better ability to scale in the future. In our little example application, we are going to model the data for an online movie rental inventory. We will take an example film: Gran Torino to help the example model.

The data we need for this application includes some basic information: movie title, genre(s), stars, directors, writers, story information, rating, release year, rent price. We can include a lot more data if we really needed to, but for the purpose of this, we will keep it a little simple. A possible way of modeling this data is to create a table that stores all of this information, and have one table in the database. But now when we need to add something else, we have to add columns to the table. For example, in a few months the company decided to add related titles, sequels and sets, etc. It would require a refactor of the data in order to handle this, as well as refactor of the code. So lets split this out.

In the image below, I divided the content based on a few things: Title data, Talent Data, Genre Data, Rating Data

Starting the data model design
Starting the data model design

I now have the four main tables, but we need to figure out how these are related. First lets tackle the Rating Data, as that will be a simple design. I am linking to the IMDB so you can look at the data. The ratings available in the United States, at least the ones we will include, are: G (General Audiences), PG (Parental Guidance suggested), PG-13 (Parents strongly cautioned) and R (Restricted, no one under 17 allowed without a parent, or as I call it, PG-17). So each rating will be housed in this table. We will need an identifier, the rating, the explanation, and some data to track creation and modification. We do not need those last two, but it is just good practice to include those if there is ever going to modification on data. Using our example film, it is rated “R”. And since any film title object (Titles) will ever only have one rating (for the sake of this example) there is an easy relation of a hasOne relation to the Ratings table. We need to add a foreign key to the Titles table and connect these.

hasOne Relation to Ratings
Title hasOne Rating

Easy to connect those. Now, we need to tackle the Genres. This is a little more complicated, but we can get through this. The Genres table will house the genres we need to display. This list can be as big or small as needed. Our example movie is in the “Drama” genre according to IMDB. However, in our application, the business has decided the movie is classified as Drama and Action. So now a title is going to have many genres. And a genre can belong to many titles. The “Drama” genre may belong to multiple titles. So we can not just add a new column to the Titles table, as that will not satisfy the requirements. We need to add a connecting table, and according to the naming convention of CakePHP, the name of the connector table is the alphabetical order of the two tables it is connecting.

So we need to add a table titled “Genre_Titles”. It will have an ID, and foreign keys to both tables.

HABTM Genres
Connecting the Genre and Title tables

Now we are almost done with the HABTM set up. We made it through one of them, and that was a good thing. See it was not so difficult. Now, we need to finish this up, and connect the talent table to the title. Talent can be anything. Since the company wants to display the stars of the show, the directors and writers, we need to be able to connect these. And again, this will require a a HABTM relationship. An actor can be in many titles, just like Clint Eastwood, as he was not just in Gran Torino. So he may be listed in many titles. And, with this movie, he not only stars in it, he directed it. So now we not only need to match up this talent, we have to identify it correctly. So this adds a little complexity to this, but we can do this.

As you know from the previous example, we need to create a connecting table. The name would be “Talent_Titles”. But that still will not solve the issue of identifying Clint Eastwood as an actor and director in the title. We can add a new table “Talent_Types”. This will be a “lookup table” that houses Star, Director, Writer as values. We can then connect that to the connecting table. This relationship will be a hasMany to Talent_Titles, as a star may have many entries in the Talent_Title table.

HABTM Talent and Title
HABTM Talent and Title

And that is the HABTM design. Using the Bake method, you can now bake this up, and set up the model. The thing to remember about the HABTM, it is not something to fear. Usually, if a connecting table is needed, you have a HABTM design. Remember to think in human terms when examining the data model. What does this belong to, what does it have. In this, the Title will have many actors, directors, etc. And the actors, directors, etc will belong to many titles.

Thinking of the site

So as I am sitting here trying to get caught up on the StephenHird site, I am thinking a little more about it. It seems like it is just a huge issue right now and am not able to complete what I really want to complete on the site. So I may make an executive decision to abandon the code (not destroy it, but abandon it and store it safely if I want to use it again), start over from scratch, again using CakePHP, and the Facebook Graph API. This would be a little less intense, and would contain an easier example of how to get some data out there, and still include the Graph API in order to show examples of how to do this.

I still think the idea of the resume integrated with the API is a good one to show an example, but I am finding myself with less time to do a full blown app for it. And I figure, if I do a small example, that should be enough, and there is always the documentation available at Facebook for this. So if you have been following the Graph API integration, it still will happen, just in a different form.

Getting into the code

So it has been a couple of weeks since I have posted. But now we need to set up some base code before we can go forward with the details and then adding in the Facebook Graph API. In the last post, the Data model was set up. We have skills and certifications as standalone tables. Skills with the levels and areas tables connected together. We also have the main glue of resumes, connected to covers and tasks which itself is connected to jobs. A lot of tables to create the resume section, but will keep some of this information all together. We need to create some code so that we can get all this information.

If you Baked each object, and used the Bake methods to create the model, and associations, as well as the controllers an views, you will have some code ready to use and ready to go. After you have Baked these items, the sample code that is created is ok to begin with. However, we want to take advantage of a very important technique, and the is the centralization of code, and prevent code duplication. There is one other thing that gets to me, and this is more of an OCD thing for me in code, and that is the way that Cake does the edit check in the controller. In the base created code, it creates a section of code that checks for an ID. If it is not passed, then it redirects the page elsewhere. Like so:

function edit($id = null) {
    if (!$id && empty($this->data)) {
        $this->Session->setFlash(__('Invalid resume', true));
        $this->redirect(array('action' => 'index'));
    }
    . . . . 
}

So in this code segment, if one gets to the edit form, and an ID is passed, and the form is not filled in, then it will display the actual form. And if the ID is not passed in, then it redirects to the Index page. For examples, if the site name was test.com:
www.test.com/resume/edit/2 – will result in the form being shown
www.test.com/resume/edit – will result in a redirect and the error message

Now here is where my OCD kicks in a little. . . .
Continue reading Getting into the code

Adding Comments in your Site with the Facebook API

Now that I have jumped almost 2 weeks without a post, as I have been super busy, this should have been a real easy item to post, but I wanted to make sure that this is done correctly. This is probably one of the easiest methods to add some great Facebook functionality in your site. This revolves around comments to a page. In my example, I am posting topics to discuss. This is mainly just a small little blurb that I will enter via an admin form on the site, and then list the different topics for everyone to select one. Once they select it, they can view the details of the topic and then comment on it using the Facebook API/Social plugin. So as always, lets go through a basic plan for this idea.

1. The model is Topic, with a table in the DB labeled “topics”
2. Only the admin has access to add or edit the topics
3. All comments on this topic will be done through the Facebook API/Social Plugin Comments
4. Topics will have a title that will also double as the Unique ID (to be explained later)
5. Topic titles, or themes, will not be allowed to be edited, to be explained why later
6. Administration of the comments will be done by the Facebook Application admins, which differs from the site admins
7. Start Dates will determine if the topic is allowed to be visible yet
8. End dates are optional, and will be built upon later with more advanced FBML/FB JS libraries

And there it is, some basic ideas behind the whole idea. So now lets get into some of the items called out in Numbers 4 and 5
Continue reading Adding Comments in your Site with the Facebook API

Facebook Application on the Site

OK, I finally got my data models set up and working. I have the initial CakePHP set up on the site, it is using v1.3, and now I am ready to set it up for the Facebook integration, and start to add the integration. When we first set up the application on the Facebook side, I chose to do an “iframe” version of the application, as I want Facebook on my site, and be able to have integration with some of the great Facebook tools on the site, and be able to “promote me”. And remember this is just a way to show a possible real world example of how to integrate these things with your site. Actual applications may vary, but this is the base to integrate. At least, as of this posting it is the base, it may change in the future.

So lets go ahead and dive into it. If you do not have the application ID for your Facebook application, you can get it at the following:
http://www.facebook.com/developers/apps.php

The next thing is to grab the API and code from Facebook. This can be found at the following page:
http://developers.facebook.com/docs/

This is the main page, and you will need to scroll to the bottom of the page. This will list different APIs that are available. I am going to be using the PHP and JavaScript SDKs. This will provide the back end that I will want, and will also provide a positive user experience on the front end. So be sure to download both SDKs.

After that, now we need to start getting some stuff set up. In this post, I am just going to explain how to get this set up, and working right now. It is important that we get the correct items working, and so we will be working with the “pages” area for the JS SDK, and creating a very simple controller for the PHP SDK so we can get set up and running. I am just using, for right now, the base CakePHP CSS styles and layouts. All we need is a page to display some of the basic items to ensure that we have installed the SDKs in the proper locations. So lets go.
Continue reading Facebook Application on the Site

Facebook Integration Initial Steps

The next few posts will examine how I will integrate a Facebook application into one of my sites: stephenhird.com. If you have browsed to this site, you will see there is already a Facebook platform there. And while it does show some of the great things to do with the API, it is very basic and really does nothing. So In this post I will examine what I want to do with it, how to set up an initial application on Facebook, and then go from there. This will likely happen over the next few weeks/months and will be a little more drawn out depending on how much time I have to document this process. This is step one, and step one will always include planning.

First I need to figure out what I want to have on my site. Since it is my name that is on the URL, I will need to create a way that this site will be an online portfolio, biography and information repository. When doing this for any site, it is important to remember your brand. Even for individual sites like this, it is important for branding, because this is who I am, I do not want it to be a classic case of slop on the web. This site before was mainly just a testing ground and now will need to be more.

A side note here, my name is the same spelling as a famous photographer based in London. His site is well put together with good descriptive links and a great example of combining minimalist ideas with styled presentation. He keeps his brand on the pages and the site does not confuse or mislead with extra peripheral items, or overuse of Flash or other heavy web technologies loading down the page. His site is located at: http://www.stephenhird.co.uk/

OK, now on to the planning and setting up the Facebook Application.
Continue reading Facebook Integration Initial Steps

PEAR and CakePHP

This post is about my experience with loading in PEAR to a CakePHP 1.2.x application. This may be the right way or the wrong way, but I got it to work throughout the application. I had to do some changes, and if there is a better way of doing this, please let me know.

First off, here is the issue. I needed to be able to export a group of records from the database to an excel spreadsheet. I have tried to use the Excel Spreadsheet add in that is listed on the Bakery. It works nice, and I had to do some modification for 1.2, but it worked. But not the way I wanted it. I have used the PEAR library Spreadsheet_Excel_Writer before and I like the type of control that I wanted, over the cells, the formatting, the merging, etc etc etc. It provides the type of control that I wanted. So here is what I did to get this to work with the CakePHP framework.

First, I have to download the PEAR library and the Spreadsheet_Excel_Writer libraries to use. Since I use a local system to help develop, I could download these libraries to the local system and transport these over to the CakePHP application. So I went to PEAR site to get the libraries. To download these I ran the following commands:

pear install PEAR-1.8.1
pear install OLE-1.0.0RC1
pear install Spreadsheet_Excel_Writer-0.9.1

URL’s are listed below:
http://pear.php.net/package/PEAR/download
http://pear.php.net/package/Spreadsheet_Excel_Writer/download
http://pear.php.net/package/OLE/download
Continue reading PEAR and CakePHP

Regular Expressions

Here is a topic that has really flustered a lot of developers. Regular expressions is a concept that can be hard to get a real handle on. PHP has a couple of functions that can help do regular expressions. The one I focus on most is using the function:
preg_match()

This is a very useful tool, and if you look at the PHP manual for ereg(), it states that the function “preg_match” is a faster alternative to “ereg()”. Now while I am not going to get into the details of the speed and response times for both functions, as there will always be someone with a different opinion or case that shows how their way is better, and that is fine. What most people have a hard time dealing with is getting the actual match to do what is needed. There are times when It is just easier to do a Google search and get some code that someone else has already done and plug it in. But the real power is knowing what you are doing first, that way you can build your own.

For this example, we can take a look at CakePHP’s own little validation object. When you set up a model and add some validation to it, it calls this object. Based on the data that this going into the tables, it will call one of these functions. The way these functions work is by checking the input for a specific character list/set that should be contained in the text. If the entry does not match up, then it is not validated. The way CakePHp does this is by using the preg_match() function.
Continue reading Regular Expressions