<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>HirdWeb &#187; PHP</title>
	<atom:link href="http://www.hirdweb.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hirdweb.com</link>
	<description>Another Blog clogging up the already crowded internet</description>
	<lastBuildDate>Wed, 18 Jan 2012 20:54:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>SOAP Server and Client, now with WSDL part 2</title>
		<link>http://www.hirdweb.com/2011/05/25/soap-server-and-client-now-with-wsdl-part-2/</link>
		<comments>http://www.hirdweb.com/2011/05/25/soap-server-and-client-now-with-wsdl-part-2/#comments</comments>
		<pubDate>Wed, 25 May 2011 16:26:10 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[soap]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=720</guid>
		<description><![CDATA[Now here is the part where I give the example files. After we have planned the application functions, we need to figure out what we are going to return to the client. This is going to be a standard array with at least two levels: The Response array and the Data array. It will look [...]]]></description>
			<content:encoded><![CDATA[<p>Now here is the part where I give the example files. After we have planned the application functions, we need to figure out what we are going to return to the client. This is going to be a standard array with at least two levels: The Response array and the Data array. It will look similar to this:</p>
<pre>Array
(
    [responseMsg] => Array
        (
            [status] => ok
            [message] => Service call was successful
        )
    [allColors] => Array
        (
            [0] => blue
            [1] => green
            [2] => black
            [3] => white
            [4] => yellow
            [5] => red
            [6] => beige
        )
)</pre>
<p>Now that we have the basic idea, we need to create the WSDL file. Remember, it is very important to think of WSDL files as of reading from bottom to top. The final WSDl file is <a href='http://www.hirdweb.com/soap/hirdweb.wsdl' target='_blank'>located here</a>. Here is the basic idea of the WSDL file I created (going from the bottom to the top):</p>
<ol>
<li><b>Service</b>: This houses the binding, the location, the port, and the name. </li>
<li><b>Binding</b>: This houses the functions that will be exposed, the operation and the input and output encoding. Most of the time these will be similar with only the names being different.</li>
<li><b>Port Type</b>: Here is where I define the operations and the input/output definitions</li>
<li><b>Message</b>: These are individual nodes for the Request and Response messages for all functions. These will usually have two message nodes per function, and they will define the structure for each action</li>
<li><b>Types</b>: This defines each structure that has been mentioned in the Message and any subsequent structures that have to be defined. This is usually the area where most struggles occur.
<ul>
<li>This structure will be encompassed by schema target namespace</li>
<li>Import the XML namespaces to help build the structures in the reasponse</li>
<li>For each complex type, it should either mention a specific data type (xsd:), or a new defined structure (tns:)</li>
<li>Each structure that is an array should be defined as a SOAP-ENC:Array with a wsdl:arrayType parameter</li>
</ul>
</li>
</ol>
<p>So that is the WSDL. The one I have created defines the 2 functions, the input, the output, and the structure of each. Now we can move on to the Server code.<br />
<span id="more-720"></span><br />
Using PHP SOAP can be as easy as you make it or as hard as you make it. First off, we need to define the functions in the file. I called my server file, server.php. I want to set the cache to null, and then define those functions.</p>
<pre>&lt;?php
ini_set('soap.wsdl_cache_enabled', false);

function getColors($which = null){
. . .
}

function getNames($set = null){
. . .
}</pre>
<p>The next part it to get the server going. Hopefully, before doing this you have read the PHP manual online and read the parts about the SOAP server, and you will find this to be fairly easy. First we need to instantiate the new Server class, and pass to it the URL for the WSDL as a parameter. This is what I am doing for this example, but there are other ways and parameters that one could use. Next, we need to add the functions to the class, so that we can expose those out to the clients. Finally, we need to call the function to handle the calls from the client. Although this may sound a bit much, here is the code to get it done, with this example:</p>
<pre>// Set up the PHP SOAP server
$server = new SoapServer("http://www.hirdweb.com/soap/hirdweb.wsdl");
// Add the exposable functions
$server->addFunction("getColors");
$server->addFunction("getNames");
// Handle the request
$server->handle();</pre>
<p>And just like that, you have the server set up. What I am not showing here is the code for the functions. These are basic, and at the end of this post, will be the link to the code files. Basically each function takes the static array, and returns the data to the client. There is one extra function that I put in that build the Response header array. The getNames function just does a SWITCH statement to check to see which part of the static array to return. </p>
<p>Now to the client. Again, another easy implementation. First, we are not going to cache the WSDL. We are going to set up the client and point to the WSDL, setting trace to true in case we need the last response and request for debugging. I am also going to show which functions are available, so I will print that out. Next we need to call the functions, and set parameters if needed. So the code for this is again fairly easy. </p>
<pre>// Set to disable caching of the wsdl file
ini_set('soap.wsdl_cache_enabled', false);

// Create the SOAP client
$client = new SoapClient("hirdweb.wsdl", array('trace' => 1));

// Show all possible functions that can be used
show($client->__getFunctions()); 

// Make a call to the getColors method and print out the results
$info = $client->__soapCall("getColors", array());
show($info); 

// Make a call to the getNames method and print out the results
$names = $client->__soapCall("getNames", array("set" => "all"));
show($names); </pre>
<p>And the client is done. I created another function here called &#8220;show&#8221; which just wraps the array in &#8220;pre&#8221; tags. And now the client is complete. Make sure you test your WSDL file, and for complete compatibility, check the webservice in something like SoapUI and build a quick C# console app to make sure that can read from it. Once that happens, your webservice should be able to talk to any app, even if it does not use PHP on the back end. So have fun coding and building these webservices. </p>
<p><a href='http://www.hirdweb.com/soap/' target='blank'>All Code Files and Examples, WSDL, etc</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2011/05/25/soap-server-and-client-now-with-wsdl-part-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Count the Number of Cakes &#8211; Finding complex results with CakePHP</title>
		<link>http://www.hirdweb.com/2011/05/10/count-the-number-of-cakes-finding-complex-results-with-cakephp/</link>
		<comments>http://www.hirdweb.com/2011/05/10/count-the-number-of-cakes-finding-complex-results-with-cakephp/#comments</comments>
		<pubDate>Wed, 11 May 2011 03:23:27 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[custom queries]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=663</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<p>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. </p>
<pre>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());
    }
}</pre>
<p>We need to use more to build a conditional query so the paginate will query against this. We can use CakePHP&#8217;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. </p>
<pre>        SELECT TOP 1 *
        FROM [books] AS [bk_inner]
        WHERE
            [bk_inner].[title_id] = [Book].[title_id]
            AND
            [bk_inner].[type] <> 'paperback' </pre>
<p>Next, we need to encapsulate that query with an outer one that will select all items which match up to the main query ID. </p>
<pre>    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] </pre>
<p>So we have the queries, and it needs the main query needs to constrain the results that exists in the sub-queries. </p>
<pre>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</pre>
<p>We have the final full query. Now how do we get that? First, we need to invoke the getDataSource() method. </p>
<pre>class Book extends AppModel {
    . . .
    function getHardbackBooks(){
        $dbo = $this->getDataSource();
</pre>
<p>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 &#8220;table&#8221; for subquery2 will actually be subquery1, so we need to add that as a &#8220;table&#8221; in the array. </p>
<pre>$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
);</pre>
<p>Now, we need to make sure we add an EXISTS:</p>
<pre>$subQuery = ' EXISTS (' . $subQuery2 . ') ';
return $subQuery;</pre>
<p>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. </p>
<pre>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(){
        <b>$data = $this->Book->getHardbackBooks();
        // Set to the paginate object conditions
        $this->paginate['conditions'] = array($data);</b>
        $this->set('hardback_books', $this->paginate());
    }
}</pre>
<p>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. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2011/05/10/count-the-number-of-cakes-finding-complex-results-with-cakephp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Have Your Cake and Eat It Too</title>
		<link>http://www.hirdweb.com/2011/04/26/have-your-cake-and-eat-it-too/</link>
		<comments>http://www.hirdweb.com/2011/04/26/have-your-cake-and-eat-it-too/#comments</comments>
		<pubDate>Wed, 27 Apr 2011 00:15:23 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=573</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<div id="attachment_575" class="wp-caption alignleft" style="width: 160px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/04/new.png"><img src="http://www.hirdweb.com/wp-content/uploads/2011/04/new-150x150.png" alt="CakePHP" title="CakePHP" width="75" height="75" class="size-thumbnail wp-image-575" /></a><p class="wp-caption-text">CakePHP</p></div>
<p>CakePHP provides some functionality for finding the data, this is done using the &#8220;find&#8221; method. You can read more about this at the <a href='http://book.cakephp.org/#!/view/1017/Retrieving-Your-Data' target='_blank'>Cookbook</a>. 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</p>
<div id="attachment_583" class="wp-caption aligncenter" style="width: 257px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/04/tables2.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2011/04/tables2-247x300.jpg" alt="Sample Tables" title="Sample Tables" width="247" height="300" class="size-medium wp-image-583" /></a><p class="wp-caption-text">Sample Tables</p></div>
<p><span id="more-573"></span></p>
<p>In the image above, shows some sample tables, and these are just made up, and contain sample rows that may exist in those tables. The BOOKS and AUTHORS tables are a HABTM relationship, with a connecting table. The PUBLISHERS has many BOOKS. And the INVEN_ITEMS contains a multiple list of books that show whether the book is available or not. So we can start grabbing the data. </p>
<p>First we need to get a count for all books. </p>
<pre>$total_books = $this->Book->find('count'); </pre>
<p>Now grab all authors, age, bio, book name, total pages, publish date for a single book with the ID of 212:</p>
<pre>$details = $this->Book->find('first',
    array(
        'conditions' => array(
            'Book.id' => '212',
        ),
        'fields' =>array(
            'Book.name',
            'Book.pages',
            'Book.publish_date',
            'Author.name',
            'Author.age',
            'Author.bio',
        ),
        'recursive' => 0,
    )
);</pre>
<p>This will create a query statement to grab the data for the set fields, and only for the book id that equals 212. Recursive is set to 0 so it will grab all related data. Remember that this is a HABTM item, so CakePHP will take that into account and grab all authors for the book. We can leave off the recursive, I just find it is best practice to put this in in order to make the query more readable by someone who did not develop the application. </p>
<p>Find all Publishers:</p>
<pre>$publishers = $this->Publisher->find('all'); </pre>
<p>Now three example of using the find technique in a basic way. More examples are available in the cookbook. Now what if we need to grab all the detailed information on the inventory items, and the tables are not connected in a CakePHP relationship? Without using a framework, the query statement would need to contain JOIN statements to get all the data we need. So the following is an example of this, again getting detailed info for the Book ID of 212:</p>
<pre>$details = $this->find('first',
    array(
        'joins' =>array(
            array(
                'table' => 'books',
                'alias' => 'Book',
                'type' => 'LEFT',
                'conditions' => array(
                    'Book.id = Inven_item.book_id',
                ),
                'recursive' => -1
            ),
            array(
                'table' => 'books_authors',
                'alias' => 'BookAuthor',
                'type' => 'LEFT',
                'conditions' => array(
                    'BookAuthor.book_id = Book.id',
                ),
                'recursive' => -1
            ),
            array(
                'table' => 'authors',
                'alias' => 'Author',
                'type' => 'LEFT',
                'conditions' => array(
                    'Author.id = BookAuthor.author_id',
                ),
                'recursive' => -1
            ),
            array(
                'table' => 'publishers',
                'alias' => 'Publisher',
                'type' => 'LEFT',
                'conditions' => array(
                    'Publisher.id = Book.publisher_id',
                ),
                'recursive' => -1
            ),
        ),
        'conditions' => array(
            'InvenItem.book_id' => '212',
        ),
        'fields' =>array(
            'Book.name',
            'Book.pages',
            'Book.publish_date',
            'Book.quick_overview',
            'Author.name',
            'Author.age',
            'Author.bio',
            'Author.country',
            'Publisher.name',
            'Publisher.location',
            'Publisher.state',
            'Publisher.country',
            'InvenItem.isbn',
            'InvenItem.available',
        ),
        'recursive' => -1
    )
);</pre>
<p>For whatever reason, the Inventory was not connected to the other tables, and so we force a join on the query. In the JOINS, we set this to a -1 recursive so it does not pull in all the other data. Now this is only one solution to put an example of a JOIN on a query. We have the tables, joined in tables, conditions, and recursive set. Once you get the data, then it will show all inventory items, details for the book, and whether or not the copy is available at the present time. </p>
<p>Now this may not be the best way to grab the data, and this is just for example purposes as well. Next week I will go further into detail about setting multiple conditions using &#8216;OR&#8217; instead of &#8216;AND&#8217;, creating a simple search on possible conditional search terms and areas, and I may even create a quick little app to demonstrate this in real life.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2011/04/26/have-your-cake-and-eat-it-too/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Data Model Relationships &#8211; CakePHP&#8217;s HABTM</title>
		<link>http://www.hirdweb.com/2011/03/15/data-model-relationships-cakephps-habtm/</link>
		<comments>http://www.hirdweb.com/2011/03/15/data-model-relationships-cakephps-habtm/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 15:04:59 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[data models]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=531</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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: <a href='http://www.imdb.com/title/tt1205489/' target='_blank'>Gran Torino</a> to help the example model.</p>
<p>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. </p>
<p>In the image below, I divided the content based on a few things: Title data, Talent Data, Genre Data, Rating Data<br />
<div id="attachment_535" class="wp-caption aligncenter" style="width: 529px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/03/table1a.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2011/03/table1a.jpg" alt="Starting the data model design" title="Table Set Up" width="519" height="235" class="size-full wp-image-535" /></a><p class="wp-caption-text">Starting the data model design</p></div></p>
<p>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 &#8220;R&#8221;. 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.<br />
<div id="attachment_538" class="wp-caption aligncenter" style="width: 356px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/03/table2.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2011/03/table2.jpg" alt="hasOne Relation to Ratings" title="hasOne Relation to Ratings" width="346" height="291" class="size-full wp-image-538" /></a><p class="wp-caption-text">Title hasOne Rating</p></div> </p>
<p>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 &#8220;Drama&#8221; 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 &#8220;Drama&#8221; 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. </p>
<p>So we need to add a table titled &#8220;Genre_Titles&#8221;. It will have an ID, and foreign keys to both tables.<br />
<div id="attachment_540" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/03/table3.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2011/03/table3-300x155.jpg" alt="HABTM Genres" title="HABTM Genres" width="300" height="155" class="size-medium wp-image-540" /></a><p class="wp-caption-text">Connecting the Genre and Title tables</p></div></p>
<p>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. </p>
<p>As you know from the previous example, we need to create a connecting table. The name would be &#8220;Talent_Titles&#8221;. 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 &#8220;Talent_Types&#8221;. This will be a &#8220;lookup table&#8221; 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.<br />
<div id="attachment_542" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.hirdweb.com/wp-content/uploads/2011/03/table4.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2011/03/table4-300x255.jpg" alt="HABTM Talent and Title" title="Final Data Model" width="300" height="255" class="size-medium wp-image-542" /></a><p class="wp-caption-text">HABTM Talent and Title</p></div></p>
<p>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. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2011/03/15/data-model-relationships-cakephps-habtm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting into the code</title>
		<link>http://www.hirdweb.com/2011/01/23/getting-into-the-code/</link>
		<comments>http://www.hirdweb.com/2011/01/23/getting-into-the-code/#comments</comments>
		<pubDate>Sun, 23 Jan 2011 19:04:34 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=472</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<p>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:</p>
<pre>function edit($id = null) {
    if (!$id &#038;&#038; empty($this->data)) {
        $this->Session->setFlash(__('Invalid resume', true));
        $this->redirect(array('action' => 'index'));
    }
    . . . .
}</pre>
<p>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:<br />
www.test.com/resume/edit/2 &#8211; will result in the form being shown<br />
www.test.com/resume/edit &#8211; will result in a redirect and the error message</p>
<p>Now here is where my OCD kicks in a little. . . .<br />
<span id="more-472"></span><br />
If the table is housing 3 resumes, IDs of 1,2, and 3 and you go to the edit page for those resumes, it will display the resume content. But, for kicks and giggles, what if we passed in this as the URL:<br />
www.test.com/resume/edit/350</p>
<p>This will display a blank form and even allow one to input data, fill it out, and submit it. Now granted, the processing of it alone will provide a new resume. However, that is why we have an &#8220;Add&#8221; function. Why not create some logic to check to see if the ID is valid to begin with? This will help on both the edit, and view methods in the controller. (as the View function will behave the same way as the edit function on display). And it is not just for this controller, but it will likely be an issue in all controllers. What I did in this case, is provide a function in the App Model code so that it can check those. Here is one way to solve this. And there can be multiple ways to resolve this issue, this is just one method I have done.<br />
In the app/app_model.php code:</p>
<pre>function ifExists($model = null, $id){
    if ( ($model == null) || ($model == '') ||(is_null($id)) ||($id == '') ){
        return 0;
    }
    $check = $this->find('count', array('conditions' => array($model . "." . strtolower($model) . '_id' => $id)));

    return $check;
}</pre>
<p>The way I set up my models for the primary key is tableName_id. So for the resume table, the primary key is &#8220;resume_id&#8221;, and for the skills table it is &#8220;skill_id&#8221; and so forth. You can always modify this to use whatever naming convention you use. In this function, it checks to see if the model is passed. If it is not, returns a false. If a model is passed, then it runs a quick find query to see if that ID exists in the table. If it finds anything, then it returns a &#8220;1&#8243; (or true), if not, then a &#8220;0&#8243; (or false). By sticking this in the app_model.php file, it is now accessible by all models. To use this, in the edit function, for example, in the resume controller:</p>
<pre>function edit($id = null) {
    if ( ((!$id) || (!$this->Resume->ifExists('Resume', $id))) &#038;&#038; empty($this->data)) {
        $this->Session->setFlash(__('That Resume does not seem to exist, please try this again.', true));
        $this->redirect(array('action' => 'index'));
    }
    . . .
}</pre>
<p>This will check for an ID, checks to see if that resume exists, and that the form is not filled in yet. If the ID does not exist in the table, then it redirects to the Index page, with a customized message. I could also redirect to the add page with no message, and this is entirely up to you on how you want to do this. </p>
<p>For the View function, it is very similar:</p>
<pre>function view($id = null) {
    if ( (!$id) || (!$this->Resume->ifExists('Resume', $id)) ) {
        $this->Session->setFlash(__('That Resume ID does not seem to exist. Please try again', true));
        $this->redirect(array('action' => 'index'));
    }
    . . .
}</pre>
<p>Again, check for an ID, and then make sure it exists in the table. If not, then redirect. A small bit of code to help keep the application from having odd behavior and keep it clean. </p>
<p>Next is to process the forms. By using Bake, it creates two functions, add and edit. Both process the forms as needed. Which there is nothing we can do to clean that up. However, some basic pre-commit tasks are still to be done. One thing I am highly in favor of is sanitizing the data. If there is some basic checks we need to do on the data, then we must also do that as well. For this we, will use the jobs controller/model for the example. </p>
<p>In each row of the job, we have a start date and an end date. In the model, we will validate these fields to be a &#8220;date&#8221;. We also need to validate these dates in another way. The end date can not be earlier than the start date. It is quite impossible to end a job three months before you even start it. So we want to keep that in check as well. And let&#8217;s say we want to do that in the controller. So now we need to sanitize the data, and check the dates. This can be redundant in the code, as it will exist in the edit and add functions. And if we need to make a change to the logic, it will cause an issue in two places. So, we can take that and put this in its own function. First we start with the sanitation of the data. At the top of the file, place</p>
<pre>App::import('Sanitize');</pre>
<p>Then create a new function and place the sanitation in this function:</p>
<pre>function validateForm($data){
    $san = new Sanitize();
    // Clean the data
    $this->data = $san->clean($this->data);
    $this->data['Job']['company_name'] = $san->paranoid($this->data['Job']['company_name'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
    $this->data['Job']['via_company']  = $san->paranoid($this->data['Job']['via_company'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
    $this->data['Job']['location']     = $san->paranoid($this->data['Job']['location'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
     . . .
}</pre>
<p>In this, I am cleaning the Company Name, the Via Company (in case it was a contract job), and Location. The next thing we need to do is create the logic to test the dates.I am just going to create a simple number using the fields from the form. Then I will compare the 2 numbers, and if the end is less than the start, then it is an error. So the entire function is:</p>
<pre>function validateForm($data){
    $san = new Sanitize();
    // Clean the data
    $this->data = $san->clean($this->data);
    $this->data['Job']['company_name'] = $san->paranoid($this->data['Job']['company_name'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
    $this->data['Job']['via_company']  = $san->paranoid($this->data['Job']['via_company'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
    $this->data['Job']['location']     = $san->paranoid($this->data['Job']['location'], array(' ', '.', '/', '-', '*', '&#038;', '(', ')',','));
     . . .   

    $errors = array();

    // Set the dates in a usuable format
    $start = $data['Job']['start_date']['year'] . $data['Job']['start_date']['month'] . $data['Job']['start_date']['day'];
    $end   = $data['Job']['end_date']['year'] . $data['Job']['end_date']['month'] . $data['Job']['end_date']['day'];
    $today = date('Ymd'); 

    // Check to make sure the start date is not later than the end date
    if ( $start >= $end ){
        // $this->Job->invalidate('start_date', "The Start Date must be earlier than then End Date");
        $error['err']['field'] = 'start_date';
        $error['err']['messg'] = 'The Start Date must be earlier than then End Date';
    }

    // Check to see whether or not to include the end date as part of the insert
    if ( $end == $today ){
        $error['end'] = 0;
    } else {
        $error['end'] = 1;
    }
    $data[error] = $error;
    return $data;
}</pre>
<p>Now we need to be able to use that in the actual form. And we need to invoke an error in case there is an issue. If an error is found, we need to invalidate the field and provide the error message. That could be done in the following way:</p>
<pre>function edit($id = null) {
    . . .
    if (!empty($this->data)) {
        $check = $this->validateForm($this->data);
        // Check to make sure the start date is not later than the end date
        if ( isset($check['Error']['err']) ){
            $this->Job->invalidate($check['Error']['err']['field'], $check['Error']['err']['messg']);
        }

        // Set the data to the model now
        $this->Job->set( $check['Job'] );

        if ( $this->Job->validates() ) {
            // Do the normal process/save stuff
            . . .
        }
         . . .
    }
    . . .
}</pre>
<p>In this example, it shows how to find ways to cut down code repetition. Now I am sure we could even set this validation in the model as well. I am just giving an example of what we can do. Now using this, we can set up all the different functionality of the resume application. </p>
<p>In the next post, I will go through how to secure the Resume so only parts are seen by the world, and which parts you would have to log in for, and why. I will also go into a centralized query for all resume elements and be able to display.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2011/01/23/getting-into-the-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adding Comments in your Site with the Facebook API</title>
		<link>http://www.hirdweb.com/2010/10/30/adding-comments-in-your-site-with-the-facebook-api/</link>
		<comments>http://www.hirdweb.com/2010/10/30/adding-comments-in-your-site-with-the-facebook-api/#comments</comments>
		<pubDate>Sun, 31 Oct 2010 06:04:32 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Facebook]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=430</guid>
		<description><![CDATA[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. [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<p>1. The model is Topic, with a table in the DB labeled &#8220;topics&#8221;<br />
2. Only the admin has access to add or edit the topics<br />
3. All comments on this topic will be done through the Facebook API/Social Plugin Comments<br />
4. Topics will have a title that will also double as the Unique ID (to be explained later)<br />
5. Topic titles, or themes, will not be allowed to be edited, to be explained why later<br />
6. Administration of the comments will be done by the Facebook Application admins, which differs from the site admins<br />
7. Start Dates will determine if the topic is allowed to be visible yet<br />
8. End dates are optional, and will be built upon later with more advanced FBML/FB JS libraries</p>
<p>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<br />
<span id="more-430"></span><br />
With the Facebook Comments, you can get a base idea behind what this entails at the following location:<br />
<a href="http://developers.facebook.com/docs/reference/plugins/comments" target="_blank">http://developers.facebook.com/docs/reference/plugins/comments</a><br />
This will give you the basic comment box to add to the site. The important part of this comment box is the &#8220;Unique ID&#8221;. This will add all the comments to the basic page. However, it must be Unique and not change. In my requirements above, I am listing the topic title as the Unique ID. I could easily generate a number for this and add a couple of letters to it to make it truly unique and allow the title to change. In this example, I want to emphasize certain elements, so that is why I chose to do it this way. You can easily do this differently and still have it work. But this leads to Number 5. </p>
<p>The Unique ID should not change for the page, topic, area, etc. If the ID changes, all previous comments vanish and you basically are starting over. So it is important that the IDs are unique and do not change. This way the element of participation is intact. It will always stay in your site. </p>
<p>Another note. This example is showing how to include Facebook API in a CakePHP application. You can follow these same techniques for just about any site, no matter what framework. Just apply the same inclusion techniques in the proper location for the different framework/php site. </p>
<h3>Creating the base elements and DB table</h3>
<p>So, let&#8217;s get this thing going. First you should have a CakePHP site going and ready, connecting to a DB somewhere. Bake the Model, Controller and Views for this one. The SQL for the Topics that I am using is below:</p>
<pre>CREATE TABLE IF NOT EXISTS `topics` (
  `topic_id` int(11) NOT NULL auto_increment,
  `topic_slug` varchar(255) NOT NULL COMMENT 'Slug for use in the Facebook comments',
  `question` text NOT NULL COMMENT 'Question that is created for the different topics',
  `start_date` date NOT NULL COMMENT 'Start date for the question',
  `end_date` date default NULL COMMENT 'End date for the question',
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY  (`topic_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Topics for discussions and other items' AUTO_INCREMENT=1012 ;</pre>
<p>I baked this using the basic CRUD for the views and Controller, no Admin hooks, and the Model validation is as follows:</p>
<pre>class Topic extends AppModel {
    var $name = 'Topic';
    var $primaryKey = 'topic_id';
    var $displayField = 'topic_slug';
    var $validate = array(
        'topic_slug' => array(
            'minlength' => array(
                'rule' => array('minlength', 3),
                'message' => 'The Topic Identifier should be longer than 3 characters',
            ),
            'maxlength' => array(
                'rule' => array('maxlength', 50),
                'message' => 'The Topic Identifier should be no longer than 50 characters',
            ),
        ),
        'question' => array(
            'minlength' => array(
                'rule' => array('minlength', 3),
                'message' => 'You need to have a question at least 3 characters long',
            ),
        ),
        'start_date' => array(
            'date' => array(
                'rule' => array('date'),
                'message' => 'Please set a valid start date for this question',
            ),
        ),
    );
}</pre>
<h3>Controller work for the Index</h3>
<p>I removed all the links to Add, Edit and Delete from the views and kept those hidden except for the Admin. Now comes the controller. This is the important part of this, as we need to include the Facebook items, and based on the last post, we put those in the Vendors, so we need to include this. I am also using Sanitize, Auth and few others (Security and Email), along with the helpers of HTML and FORM.</p>
<pre>&lt;?php
App::import('Sanitize');
App::import('Vendor', 'facebook');
class TopicsController extends AppController {

    var $name = 'Topics';
    var $helpers = array('Html', 'Form');
    var $components = array('Security', 'Auth', 'Email');</pre>
<p>it is important to import the Facebook library. I will not go over the Auth in this example, or the beforeFilter or isAuthorized functions. The first action we need to deal with is the index() function. Originally, it looks like:
<pre>function index() {
        $this->Topic->recursive = 0;
        $this->set('topics', $this->paginate());
    }</pre>
<p>For our purposes, we want to limit the amount of posts shown to only those that have a start date that is equal to or less than today&#8217;s date. I have three examples in my DB, and you can create as many as you want for the example. Just make sure at least one is in the future. Right now when we look at the Index page, it is showing all topics. So we need to set different items in the call for paginate. To only grab those that are equal to or less than to today&#8217;s date, we will alter the call to paginate as follows:</p>
<pre>$today = date('Y-m-d');
$cond = array('Topic.start_date <=' => $today);
$this->set('topics', $this->paginate('Topic', $cond));</pre>
<p>This will limit all the posts to display to everyone to only those with a current (or past) start date. All those with a start date in the future will not be available until that date. But we also need to set a variable for the Admin to see all those topics waiting for the future. </p>
<pre>$future_topics = $this->Topic->find( 'all', array('conditions' => array('Topic.start_date >' => $today)) );
$this->set('futop', $future_topics);</pre>
<p>We now have 2 variables to work with in the view. You can do it a whole slew of different ways, and that is fine, this is just the method I prefer to do it. Now we need to get the view going. This is going to a little different, I have a few things to show Admin stuff just to admins, and show the future topics just to admins.</p>
<h3>The Add and Edit functions</h3>
<p>That does it for the view, now we need to do the Add and Edit functions. Remember we baked this, and let all the default take place. But, I need to get a valid Unique ID, and do not want any spaces in it. So we will alter the Add function to do this. And for the Edit function, we want to prevent any editing of the slug area. </p>
<pre>function add() {
        if (!empty($this->data)) {
            $san = new Sanitize();

            $this->data['Topic']['topic_slug'] = $san->paranoid($this->data['Topic']['topic_slug'], array(' '));

            $this->Topic->create();
            // Slug the topic title before saving
            $this->data['Topic']['topic_slug'] = preg_replace('/ /', '_', $this->data['Topic']['topic_slug']);
            if ($this->Topic->save($this->data)) {
                $this->Session->setFlash(__('The new Topic has been saved and will be put in queue', true));
                $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The Topic could not be saved. Please, try again.', true));
            }
        }
    }</pre>
<p>I am sanitizing the data for the slug, and trusting myself for the topic details. In real life, we would apply a sanitizing effect to this field as well. I then erase all non alphanumeric characters, and replace spaces with an underscore &#8220;_&#8221;. Then save it up. I am basically leaving the &#8220;add.ctp&#8221; alone with what was baked. I removed the fields that I really do not care about. </p>
<p>So now we move to the edit. We want to prevent any changes to the topic_slug, so in the form, we will remove this from the form and make sure we remove the underscores when showing it. The controller is:
<pre>function edit($id = null) {
        if ( ((!$id) || (!$this->Topic->ifExists('Topic', $id))) &#038;&#038; empty($this->data) ) {
            $this->Session->setFlash(__('The Topic you selected does not exist, please try again.', true));
            $this->redirect(array('action' => 'index'));
        }
        if (!empty($this->data)) {
            if ($this->Topic->save($this->data)) {
                $this->Session->setFlash(__('The topic has been saved', true));
                $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The topic could not be saved. Please, try again.', true));
            }
        }
        if (empty($this->data)) {
            $this->data = $this->Topic->read(null, $id);
        }
    }</pre>
<p>One quick thing to call out in this function. I added a new function to the parent app_model.php to make sure that the ID we are trying to edit exists and is valid. The basic baked function only checks for an ID, if one exists, it goes thru to the form, even if the ID does not exist in the DB. On the edit.ctp view, I removed the form element for the topic_slug and added this:</p>
<pre>$topic_title = preg_replace('/_/', ' ', $this->data['Topic']['topic_slug']);
echo "&lt;b&gt;Topic Title&lt;/b&gt;: &nbsp; &lt;h4&gt;" . ucwords($topic_title) . "&lt;/h4&gt;";</pre>
<p>And now the edit form works, keeps the underscore in and saves the form. Again, in the real world, you would want to do a little more on the back end to ensure there is no changes being made. But now we get to the view area and where the Facebook API/Social Plugin comes in. </p>
<h3>Creating the Detail View and adding in Facebook API/Social Plugin</h3>
<p>So here is where we get to the meat of the post. All other areas were in preparing to get here. Now, all you need to do is create a few different topics to work with. We want to alter the view in such a way it will display only the items we need, and will only display the topic to an admin if it is a future topic. Otherwise return the user to the index for topics with a message saying that the topic does not exist or is not yet available. So the view function is simple:
<pre>function view($id = null) {
        if ( (!$id) || (!$this->Topic->ifExists('Topic', $id)) ) {
            $this->Session->setFlash(__('The requested topic does not exist. Please try again.', true));
            $this->redirect(array('action' => 'index'));
        }
        // Make sure this is a valid ID as well
        $topic = $this->Topic->read(null, $id);
        $topic_title = $topic['Topic']['topic_slug'];
        // Set the title without the slug
        $topic_title = preg_replace('/_/', ' ', $topic['Topic']['topic_slug']);
        $topic['Topic']['topic_title'] = ucwords($topic_title);

        // make sure this topic is valid
        if ( ($topic['Topic']['start_date'] > date('Y-m-d')) &#038;&#038; (!$this->is_admin) ){
            $this->Session->setFlash(__('The requested topic does not seem to be available at the present moment. Try again later.', true));
            $this->redirect(array('action' => 'index'));
        }
        $this->set('topic', $topic);
    }</pre>
<p>Again, I used the app_model.php function to make sure the topic ID exists as well as being valid. If not, a message will be displayed to the end user. It sets the topic, and now we are ready for the view. </p>
<p>So what I did, was wipe all the data for the list, and added my own. I set the title to the H2 element. I set the question to a paragraph tag, and added the new FBML comment tag. The information for this tag can be found at:<br />
<a href='http://developers.facebook.com/docs/reference/fbml/comments_%28XFBML%29' target='_blank'>http://developers.facebook.com/docs/reference/fbml/comments_%28XFBML%29</a></p>
<p>Pay close attention to the different parameters you can set and how you can format this to fit your style on your site. I have set the following elements and values:<br />
xid = $topic['Topic']['topic_slug']<br />
width = 600<br />
title = $topic['Topic']['topic_title']<br />
publish_feed = false</p>
<p>And so the actual markup added to the page is the following, including the FBML script and div tag:</p>
<pre>&lt;div id="fb-root"&gt;&lt;/div&gt;
&lt;script src="http://connect.facebook.net/en_US/all.js#appId=APP_ID&amp;xfbml=1"&gt;&lt;/script&gt;
&lt;fb:comments xid="&lt;?php echo $topic['Topic']['topic_slug']; ?&gt;" width="600" title="&lt;?php echo $topic['Topic']['topic_title']; ?&gt;" publish_feed="false">&lt;/fb:comments&gt;</pre>
<p>And if you go to the page you will now see the comments section, but we are missing a very important item in the comments, and that is administration. The way to add this, we will need to add the correct element to the page. This consists of adding the correct JS API to the site. </p>
<p>According to the documentation, you have to be listed as a developer for the application to be able to administer comments. The way we have it set up right now, we can have comments, but there is no way we can administer those. The key to this is very simple and easily overlooked. In the FBML markup that we added to the view, you will notice a specific section:</p>
<pre>http://connect.facebook.net/en_US/all.js#<b>appId=APP_ID</b>&amp;xfbml=1</pre>
<p>You must input your application ID to this markup. Once you do that, and if you are listed as a developer, then you are able to now administer comments on your site. </p>
<p>See, that was easy. There is a lot of text on this post, and most of it has to do with setting up CakePHP to do this. Once we got to the Facebook API/Social Plugin section, it was very simple. With the next post, we will expand on the comments section a little further and see what else is possible. </p>
<p>You can see this all in action at the following:<br />
<a href='http://www.stephenhird.com' target='_blank'>www.stephenhird.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/10/30/adding-comments-in-your-site-with-the-facebook-api/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Facebook Application on the Site</title>
		<link>http://www.hirdweb.com/2010/10/17/facebook-application-on-the-site/</link>
		<comments>http://www.hirdweb.com/2010/10/17/facebook-application-on-the-site/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 15:21:08 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Facebook]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=390</guid>
		<description><![CDATA[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, [...]]]></description>
			<content:encoded><![CDATA[<p>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 &#8220;iframe&#8221; 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 &#8220;promote me&#8221;. 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.</p>
<p>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:</p>
<p>http://www.facebook.com/developers/apps.php</p>
<p>The next thing is to grab the API and code from Facebook. This can be found at the following page:</p>
<p>http://developers.facebook.com/docs/</p>
<p>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.</p>
<p>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 &#8220;pages&#8221; 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.<br />
<span id="more-390"></span><br />
<strong> Step 1: </strong><em>Download the SDK and move them to the following locations:</em><br />
A. PHP SDK (facebook.php)<br />
I put this at the following location:<br />
./app/vendors/facebook.php<br />
This will be used in the controllers and be imported by the controllers</p>
<p>B. JavaScript SDK<br />
I put the entire &#8220;src&#8221; directory in the following location:<br />
./app/webroot/js/src</p>
<p><strong>Step 2: </strong><em>Create a &#8220;test&#8221; page where we can see the Facebook JS SDK to make sure it works</em><br />
I just created a new file:<br />
./app/views/pages/facebook.ctp<br />
This will be visible at the following: http:///pages/facebook</p>
<p><strong>Step 3:</strong> <em>Copy the example in the jQuery folder, alter your default layout</em><br />
Reformat the example after you copy it to the ./app/views/pages/facebook.ctp to take out the header stuff. We only need the body, and make sure you put the header stuff in the default layout. Below is the code to add to the default layout:</p>
<pre>&lt;!doctype html&gt;
&lt;html xmlns:fb="http://www.facebook.com/2008/fbml" xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;
    &lt;?php echo $this-&gt;Html-&gt;charset(); ?&gt;
    &lt;title&gt;
        &lt;?php __('CakePHP: the rapid development php framework:'); ?&gt;
        &lt;?php echo $title_for_layout; ?&gt;
    &lt;/title&gt;
    &lt;?php echo $this-&gt;Html-&gt;css('cake.generic'); ?&gt;
    &lt;?php echo $scripts_for_layout; ?&gt;
    &lt;style&gt;
        body {
            font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
        }
        h1 a {
            text-decoration: none;
            color: #3b5998;
        }
        h1 a:hover {
            text-decoration: underline;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;</pre>
<p>Simple code to put in to test the JS API:</p>
<pre>&lt;h1&gt;Connect JavaScript - jQuery Login Example&lt;/h1&gt;
    &lt;div&gt;
      &lt;button id="login"&gt;Login&lt;/button&gt;
      &lt;button id="logout"&gt;Logout&lt;/button&gt;
      &lt;button id="disconnect"&gt;Disconnect&lt;/button&gt;
    &lt;/div&gt;
    &lt;div id="user-info" style="display: none;"&gt;&lt;/div&gt;

    &lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;

    &lt;div id="fb-root"&gt;&lt;/div&gt;
    &lt;script src="http://connect.facebook.net/en_US/all.js"&gt;&lt;/script&gt;
    &lt;script&gt;
      // initialize the library with the API key
      FB.init({ apiKey: 'YOUR API KEY WOULD GO HERE' });

      // fetch the status on load
      FB.getLoginStatus(handleSessionResponse);

      $('#login').bind('click', function() {
        FB.login(handleSessionResponse);
      });

      $('#logout').bind('click', function() {
        FB.logout(handleSessionResponse);
      });

      $('#disconnect').bind('click', function() {
        FB.api({ method: 'Auth.revokeAuthorization' }, function(response) {
          clearDisplay();
        });
      });

      // no user, clear display
      function clearDisplay() {
        $('#user-info').hide('fast');
      }

      // handle a session response from any of the auth related calls
      function handleSessionResponse(response) {
        // if we dont have a session, just hide the user info
        if (!response.session) {
          clearDisplay();
          return;
        }

        // if we have a session, query for the user's profile picture and name
        FB.api(
          {
            method: 'fql.query',
            query: 'SELECT name, pic FROM profile WHERE id=' + FB.getSession().uid
          },
          function(response) {
            var user = response[0];
            $('#user-info').html('&lt;img src="' + user.pic + '"&gt;&lt;br /&gt;' + user.name).show('fast');
          }
        );
      }
    &lt;/script&gt;</pre>
<p>Now, you should be able to go to your page and see a login button, a logout button, and disconnect. If you are already logged in to Facebook, you should see your own profile image (if you allowed it). If not, click the login button, and if you have the Facebook application set up correctly, and the API correct, you should be able to log in.</p>
<p><strong>Step 4:</strong> <em>Check the PHP API</em><br />
Now that we can see the JS API is working fine, we need to set up something so we can create a test for the PHP API. This is actually easier than it appears.</p>
<p>I first create a new layout just for the Facebook app, which I call facebook.ctp. It basically just erases all Cake icons, other special icons, and any kind of SQL output. Rename the title to &#8220;Facebook Testing:&#8221; (or whatever you want). Then create a new controller with no model. Use the <em>App::import</em>statement to include the facebook.php file. Now create an index function, and copy and paste the PHP area from the example included in the PHP SDK into the &#8220;index&#8221; function. It may be similar to this:</p>
<pre>&lt;?php
App::import('Vendor', 'facebook');
class FbsController extends AppController {
	var $name = 'Fbs';
	var $uses = null;	

	function index() {
	    // Set the layout
        $this-&gt;layout = 'facebook';        

        // Create our Application instance (replace this with your appId and secret).
        $facebook = new Facebook(array(
            'appId'  =&gt; 'YOUR APPLICATION ID WOULD GO HERE',
            'secret' =&gt; 'YOUR SECRET KEY HERE - DO NOT DISPLAY THIS TO ANYONE',
            'cookie' =&gt; true,
        ));

        $session = $facebook-&gt;getSession();
        $appID   = $facebook-&gt;getAppId();
        $uid     = '';
        $me = null;
        // Session based API call.
        if ( $session ) {
            try {
                $uid = $facebook-&gt;getUser();
                $me = $facebook-&gt;api('/me');
            } catch (FacebookApiException $e) {
                error_log($e);
            }
        }

        $logoutUrl = '';
        $loginUrl  = '';

        // login or logout url will be needed depending on current user state.
        if ( $me ) {
            $logoutUrl = $facebook-&gt;getLogoutUrl();
        } else {
            $loginUrl = $facebook-&gt;getLoginUrl();
        }
        // Set the variables to use in the view
        $this-&gt;set(array(
            'facebook'  =&gt; $facebook,
            'session'   =&gt; $session,
            'me'        =&gt; $me,
            'logoutUrl' =&gt; $logoutUrl,
            'loginUrl'  =&gt; $loginUrl,
            'appID'     =&gt; $appID,
            'uid'       =&gt; $uid,
        ));
	}
}
?&gt;</pre>
<p>In this controller, we are setting the basics we need for the application. Using the SDK to see if they are logged in, getting our app id, and setting the proper variables to be used later. We set the login or logout URLs to display the proper links. Finally, we are setting the variables to be used in the view.</p>
<p>Now we need to create a new directory in the views area named &#8220;fbs&#8221; and a file in that directory  named &#8220;index.ctp&#8221;. This view will house the base items for displaying the example. You can copy the HTML parts from the example.php and use them in this view. I modified it a little to alter what is shown.</p>
<pre>&lt;h2&gt;Test Facebook File&lt;/h2&gt;
&lt;div id="fb-root"&gt;&lt;/div&gt;
    &lt;script&gt;
      window.fbAsyncInit = function() {
        FB.init({
          appId   : '&lt;?php echo $appID ?&gt;',
          session : &lt;?php echo json_encode($session); ?&gt;, // don't refetch the session when PHP already has it
          status  : true, // check login status
          cookie  : true, // enable cookies to allow the server to access the session
          xfbml   : true // parse XFBML
        });

        // whenever the user logs in, we refresh the page
        FB.Event.subscribe('auth.login', function() {
          window.location.reload();
        });
      };

      (function() {
        var e = document.createElement('script');
        e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
        e.async = true;
        document.getElementById('fb-root').appendChild(e);
      }());
    &lt;/script&gt;

    &lt;?php if ($me): ?&gt;
        &lt;a href="&lt;?php echo $logoutUrl; ?&gt;"&gt;
          &lt;img src="http://static.ak.fbcdn.net/rsrc.php/z2Y31/hash/cxrz4k7j.gif"&gt;
        &lt;/a&gt;
    &lt;?php else: ?&gt;
        &lt;div&gt;
          Using JavaScript &amp; XFBML:
          &lt;br /&gt;
          &lt;fb:login-button&gt;&lt;/fb:login-button&gt;
          &lt;br /&gt;&lt;br /&gt;
        &lt;/div&gt;
        &lt;div&gt;
          Without using JavaScript &amp; XFBML:&lt;br /&gt;
          &lt;a href="&lt;?php echo $loginUrl; ?&gt;"&gt;
            &lt;img src="http://static.ak.fbcdn.net/rsrc.php/zB6N8/hash/4li2k73z.gif"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
    &lt;?php endif ?&gt;

    &lt;h3&gt;Session&lt;/h3&gt;
    &lt;?php if ($me): ?&gt;
        &lt;pre&gt;&lt;?php
        echo "session.base_domain - " .
            $session['base_domain'] . "&lt;br /&gt;session.expires - " .
            $session['expires'] . "&lt;br /&gt;";
        ?&gt;&lt;/pre&gt;

        &lt;h3&gt;You&lt;/h3&gt;
        &lt;img src="https://graph.facebook.com/&lt;?php echo $uid; ?&gt;/picture?type=large" /&gt;
        &lt;br /&gt;
        &lt;?php echo $me['name']; ?&gt;

        &lt;h3&gt;Your User Object&lt;/h3&gt;
        &lt;pre&gt;&lt;?php print_r($me); ?&gt;&lt;/pre&gt;
    &lt;?php else: ?&gt;
        &lt;strong&gt;&lt;em&gt;You are not Connected.&lt;/em&gt;&lt;/strong&gt;
    &lt;?php endif ?&gt;</pre>
<p>The login button examples will show two different ways to authenticate the user to the application. The JS example will open a new window and will log them in, post it back to the page and show the login. The non JS example will take the user to the page and give them the Facebook page to log in. Once they log in, it then redirects back to the calling page.</p>
<p>The information on the page shows the Session info, and below that, it shows a large profile image of the person logged in, and then an array of data of all public accessible information. If the person has set their profile to be private, then it will not show a lot of information.</p>
<p>These two examples can be seen at the following, with screenshots below:<br />
The JS SDK example<br />
<a href="http://www.stephenhird.com/pages/facebook">http://www.stephenhird.com/pages/facebook</a></p>
<div style="width:80%; margin-left:auto; margin-right:auto; display:inline-block;">
<div id="attachment_408" class="wp-caption alignleft" style="width: 160px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/10/js_sdk1.jpg"><img class="size-thumbnail wp-image-408" title="JavaScript SDK prelogin" src="http://www.hirdweb.com/wp-content/uploads/2010/10/js_sdk1-150x150.jpg" alt="JavaScript SDK prelogin" width="150" height="150" /></a><p class="wp-caption-text">JavaScript SDK prelogin</p></div>   <div id="attachment_409" class="wp-caption alignright" style="width: 160px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/10/js_sdk2.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2010/10/js_sdk2-150x150.jpg" alt="JavaScript SDK post-login" title="JavaScript SDK post-login" width="150" height="150" class="size-thumbnail wp-image-409" /></a><p class="wp-caption-text">JavaScript SDK post-login</p></div></div>
<p>The PHP SDK example<br />
<a href="http://www.stephenhird.com/fbs/">http://www.stephenhird.com/fbs/</a></p>
<div style="width:80%; margin-left:auto; margin-right:auto; display:inline-block;">
<div id="attachment_420" class="wp-caption alignleft" style="width: 160px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/10/php_sdk1.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2010/10/php_sdk1-150x150.jpg" alt="PHP SDK example pre login" title="PHP SDK example pre login" width="150" height="150" class="size-thumbnail wp-image-420" /></a><p class="wp-caption-text">PHP SDK example pre login</p></div>    <div id="attachment_421" class="wp-caption alignright" style="width: 160px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/10/php_sdk2.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2010/10/php_sdk2-150x150.jpg" alt="PHP SDK example post login" title="PHP SDK example post login" width="150" height="150" class="size-thumbnail wp-image-421" /></a><p class="wp-caption-text">PHP SDK example post login</p></div>
</div>
<p>In the next post, we will work on getting a good discussion going, which is really, really simple, we will tie it to a DB saved question that can be entered thru an admin form, and then we will examine the moderation of the Facebook comments on the discussion.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/10/17/facebook-application-on-the-site/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Its the Simple Things</title>
		<link>http://www.hirdweb.com/2010/10/08/its-the-simple-things/</link>
		<comments>http://www.hirdweb.com/2010/10/08/its-the-simple-things/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 13:54:28 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=387</guid>
		<description><![CDATA[I am still working forward on the Facebook integration and resume stuff. And will get that posted when I have completed the data model and the basic set up. I will also post about how to integrate Facebook into a CakePHP application. But in the mean time, there was something that happened, that I thought [...]]]></description>
			<content:encoded><![CDATA[<p>I am still working forward on the Facebook integration and resume stuff. And will get that posted when I have completed the data model and the basic set up. I will also post about how to integrate Facebook into a CakePHP application. But in the mean time, there was something that happened, that I thought may help me remember. </p>
<p>The other day I was working on an application with a simple login check and display of an error message. I would test the login function with a correct account and an incorrect account. It was driving me batty as when I logged in with wrong credentials, it would not give me the message that something was wrong. I was checking everything. I checked the controller, the model and the view. Could not pin point the issue. I could not find anything wrong. Here is what I had in the view:</p>
<pre>if ($sess->check(errors)) {
    $sess->errors);
}</pre>
<p>Basically, if the login is incorrect, it will set an error. The session object will read any errors, set the item in the session to display once, and then kill the error so it does not keep happening. And here is the problem, in another application using the same basic code it works fine. Could not pinpoint why this is a problem here. Until I took a brief walk away from the desk. Then I came back and understood what I needed to do. </p>
<p>The check function does not do any displaying of any kind. It is supposed to check the session for errors, and destroy the session element with the errors. Before it does that, it sets a variable for the errors. However, it does not display. I needed to alter it to this:</p>
<pre>if ($sess->check(errors)) {
    echo $sess->errors);
}</pre>
<p>And there it was! Wow, the littlest thing. I am reminded of a Simpsons episode in which Hank Scorpio tells Homer:<br />
&#8220;Well, you can&#8217;t argue with the little things. It&#8217;s the little things that make up life.&#8221;</p>
<p>Indeed it does. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/10/08/its-the-simple-things/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook Integration Initial Steps</title>
		<link>http://www.hirdweb.com/2010/09/22/facebook-integration-initial-steps/</link>
		<comments>http://www.hirdweb.com/2010/09/22/facebook-integration-initial-steps/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 13:39:46 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Facebook]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=377</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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. </p>
<p>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. </p>
<p>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: <a href='http://www.stephenhird.co.uk/' target='_blank'>http://www.stephenhird.co.uk/</a></p>
<p>OK, now on to the planning and setting up the Facebook Application.<br />
<span id="more-377"></span><br />
 First I will list out my goals with the site, and why put it in a Facebook application. I am choosing to do this myself, however, these may not really warrant a full blown Facebook application with every site/web application. </p>
<p>1. Describe who I am<br />
2. Display samples of my work, all work: code, art, etc<br />
3. Provide a theme/question for comments and research<br />
4. Provide contact information<br />
5. Online Resume with ability for download (never hurts to have a resume handy)<br />
6. Share my images from different travels and experiences<br />
7. A place where I can see where I have been, where I am going and how to get there</p>
<p>This is the base ideas behind my site. This is for a more personal reflection tying into the other interests in my life. </p>
<p>I am planning on building the base in CakePHP, and adding the Facebook API in to the application. Which means this will also generate more posts on CakePHP application development. The back end will be a DB driven application, with all frontend interaction via Facebook login. All Admin functionality of the site will be outside of the Facebook authentication. </p>
<p>Now since I already have the site up, I need to create the application side in Facebook.</p>
<p>1. Log in to Facebook, or go to this URL: <a href='http://www.facebook.com/developers/apps.php' target='_blank'>http://www.facebook.com/developers/apps.php</a><br />
2. New policies for Facebook insist that you either enter a mobile number or a credit card to validate you are a real person. The phone number is what I would suggest to use.<br />
3. After you enter the confirmation code, return to the main window to enter the name of the application and agree to terms<br />
4. Put in the security check code<br />
5. This will take you to the first part of the form</p>
<p>Now the form, it is a quick and easy form to fill out. There are four tabs and I will highlight each and a few items on each that I usually do:</p>
<ol>
<li>About
<ul>
<li>Enter the application name, upload images, icons, etc. </li>
<li>Enter the support email or page, and put in a privacy page, very important if you want to have this application take off.</li>
</ul>
</li>
<li>Web Site
<ul>
<li>Site url would be the site you are creating to work with the API</li>
<li>Domain is important if you want subdomains (for things like mobile domains, etc) to be authenticated using the same key</li>
</ul>
</li>
<li>Facebook Integration
<ul>
<li>Canvas will determine how you want the page top appear inside Facebook.</li>
<li>This is also where you decide to do a FBML (their markup) or an iFrame. I usually choose iFrame mainly because in my applications the bulk of interactivity is done on the domain and not Facebook. However, you can always do FBML to keep everything in Facebook. </li>
<li>Profile tabs will enable new tabs on the app page that can be added/used on individual profile pages</li>
</ul>
</li>
<li>Mobile and Devices
<ul>
<li>If you are developing for mobile users, enter the type of core markup to use, and the id for the iTunes app store. Important to <a href="http://developers.facebook.com/docs/guides/mobile/#itunes_app_store_id" target="_blank">read here</a> if you plan on making a mobile app</li>
</ul>
</li>
<li>Advanced>
<ul>
<li>Each section in this page holds a very important piece that may affect your application.</li>
<li>Authentication holds the sandbox keys, and where Facebook looks if a user takes your app off</li>
<li>Migrations holds the areas for callbacks, empty strings and OAuth</li>
<li>Security will allow you to enable only a few select IP addresses to access your application on the Facebook platform</li>
<li>Advertising and Advanced can do different things for ads, preloading, etc.</li>
</ul>
</ol>
<p>Above all else, read the side information if you get stuck, that is why it is there. </p>
<p>Once you are done, click the &#8220;Save Changes&#8221; button and it will save your data and create your application. </p>
<p>There, you have now just created a shell application on the Facebook platform and ready to enable the client side application. </p>
<p>In order to submit this application, Facebook posts this:<br />
&#8220;Your application must have at least 5 total users or 10 monthly active users before you can submit it to the Application Directory. We cannot showcase any applications that are under construction or do not utilize the Facebook Platform.&#8221;</p>
<p>So do not expect to create an application and then suddenly have it spread like wildfire. It has to provide useful or entertaining &#8220;stuff&#8221;, it has to work, and it has to be used. Once it is, then it can be submitted. So we have accomplished step one of the integration. Next up is to get the API on the site, and start developing the site. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/09/22/facebook-integration-initial-steps/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ORM Designs and Tools</title>
		<link>http://www.hirdweb.com/2010/09/04/orm-designs-and-tools/</link>
		<comments>http://www.hirdweb.com/2010/09/04/orm-designs-and-tools/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 14:07:22 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Ideas and Sorts]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ERD]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=346</guid>
		<description><![CDATA[ORM, that magical acronym that can send developers into a flurry of excitement, or the rolling eyes of grief. ORM stands for Object Relational Mapping. Used correctly, this can really help applications convert data into objects ready to use. While it does cause some overhead, the key thing to remember is that used properly, it [...]]]></description>
			<content:encoded><![CDATA[<p>ORM, that magical acronym that can send developers into a flurry of excitement, or the rolling eyes of grief. ORM stands for Object Relational Mapping. Used correctly, this can really help applications convert data into objects ready to use. While it does cause some overhead, the key thing to remember is that used properly, it can be really helpful. But that is also the way it is with anything related to code. Since I focus mainly on the open source areas, examining an ORM tool will be limited to the PHP view and aspect. </p>
<p>When designing the data objects, it is important to understand the data and how it relates to the application and other objects. Usually it is the planning sessions that get overlooked, or hurried, and create a problem for later on. This is why using a tool to help with this is always good. I specifically look for more of an ERD (Entity Relationship Diagram) type of tool that can help me visualize and document the data objects. Never underestimate the power of a visual diagram for data. This is worth everything when coming on a new project, or bringing in new resources to a major project. It can drastically decrease the learning curve. There are different tools out there that can help with ERD and ORM design, with the basic Visio diagrams (a Microsoft product), to more robust ERD tools that include different UML (Unified Modeling Language) tools integrated with it like MagicDraw. Each tool will have its pros and cons, no matter what the toolset is, no matter what the project is. I have found that there is not a single tool that is perfect for every project. But finding a good tool that can help in designing the database is a must. If it can even generate code, that is a lot better. One tool that is available that can help with ERD, and generate code, and help with ORM is <a href='http://www.orm-designer.com/' target="_orm">ORM Designer</a>. And I will examine this tool as it relates to Symfony, CakePHP and non framework applications.<br />
<span id="more-346"></span><br />
First off, lets answer a few questions:</p>
<ol>
<li />Why do I need to have an ORM designer if I am not using Propel or Doctrine?
<ul>
<li />You don&#8217;t, quite simply. The ORM Designer tool is not just for help with ORM items. It greatly helps in ORM, but is a great tool for ERD design. That may be selling it a little short, but it is very handy for that as well.</ul>
<li />I use CakePHP and need to help generate the code for the models, will this help?
<ul>
<li />Short answer yes, long answer no. This will help you design the data objects. But if you do not understand the data objects, and how they relate with each other and the actions acted upon the data, then it will not solve those problems.You need to understand the data in order to properly design it. </ul>
<li />I already have a Symfony app that I took on and am having a hard time visualizing the whole application. Will this help break down the data objects in the application if it is already written?
<ul>
<li />Yes, it will. In one of the examples below I examine this very thing using the Jobeet tutorial. And it is quite impressive in that vein</ul>
<li />Isn&#8217;t this just another tool that requires me learning more about how this tools works and wasting more time on this instead of doing actual coding?
<ul>
<li />Well, I will never tell anyone how to code, nor how to do things. But learning new tools is never a bad thing. Sure it takes time to learn, and it takes patience to learn how to use any new tool. I guess the follow up question to this one is: Do you really want to spend your time coding great projects, or fixing bugs the majority of time because you failed to plan?</ol>
<p>OK, I am sure there is more questions. However, let&#8217;s go through the actual product. One of the things I like about this product, is the ability to pull in Symfony (or non framework ORM) projects, and the application is deciphered. I used the standard Jobeet tutorial from Symfony, and imported the application. And it gave me the following.<br />
<div id="attachment_349" class="wp-caption alignleft" style="width: 308px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/09/orm1.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2010/09/orm1-298x300.jpg" alt="" title="User Object" width="298" height="300" class="size-medium wp-image-349" /></a><p class="wp-caption-text">User Object</p></div> <div id="attachment_350" class="wp-caption alignright" style="width: 190px"><a href="http://www.hirdweb.com/wp-content/uploads/2010/09/orm2.jpg"><img src="http://www.hirdweb.com/wp-content/uploads/2010/09/orm2-180x300.jpg" alt="" title="Job Object" width="180" height="300" class="size-medium wp-image-350" /></a><p class="wp-caption-text">Job Object</p></div></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>It was great. I could immediately see the relationships in the user object data, and the job object data. But now was the real test. I decided that I needed to add an object for the job object. This was for the benefits. So I added &#8220;jobeet_benefits&#8221; with an &#8220;id&#8221;, &#8220;benefits_title&#8221;, and &#8220;description&#8221;. I added the association over to the &#8220;jobeet_job&#8221; object. The user interface is done really well and was easy to add. So that passed. What about code generation. Would it update the code properly? And it was successful to write this over to the &lt;doc root&gt;/sym/config/schema.yml</p>
<p>Now all I need to do is run my propel scripts again, rebuild all the objects, build the DB, and the insert the fixtures and update any forms that were altered to include the new fields. And it works great. This is a great way to visually build, append, and maintain Symfony apps. It also works just as well with non framework Propel applications. I did not test this on Doctrine. </p>
<p>The downside to this though: no CakePHP import. I tried to do a few different ways to import a CakePHP application, and nothing worked. So that was a definite question mark when it comes to CakePHP applications. But since we can not open an existing one, let&#8217;s test the new project in CakePHP. </p>
<p>I just opened up the application and started to create a simple application that had a member class, that connected to a profile class. And each member can make a post. I created the objects based on the CakePHP naming convention. It created a good visual of how the entities relate to each other. and then I did an export to see what data would be created. This is the directory structure it created:</p>
<pre>
-app
 -models
  -base
     basemembers.php
     baseposts.php
     baseprofiles.php
   members.php
   posts.php
   profiles.php
  schema.module.xml
</pre>
<p>I was interested in why it created a base file set. And I am sure it is because if you put custom code in the model, and then need to update the ORM, it will not overwrite your custom code. So I decided I would test that. I put in a little function that did nothing in the posts.php file. I then went in to change the posts object to add a post title to the object. Then I exported the items again. And the custom function exists! This is a great thing for exporting the model changes. This is why the ORM Designer creates a Base file for the models, to keep custom code from being over-written. </p>
<p>Another good thing, and also a little bit of an area of opportunity, is the CakePHP validation. It makes validation of each field very easy. It provides a great way for each field to have a specific validation rule or rules. However, each validation rule has the same fields available which can be a little confusing to those who may not understand each validation rule. I understand why it is that way, it can just cause some issues for the more inexperienced CakePHP developer.</p>
<p>Now, a quick run down of what I liked about this and what I felt could be a little different:<br />
<b>Pros</b></p>
<ul>
<li />Cost: 99 Euros, approx 127 USD, not as expensive as other tools
<li />Ability to import Symfony and other Propel/Doctrine projects and be able to quickly get a feel for what the application holds
<li />In the Windows model it is easy to use, windows and sheets are good, and wizards are very simple to go through
<li />Very quickly learn time to use, design and export
<li />Can do a simple job, or get to more complex tasks
<li />Configuration of the application is easy, straightforward
<li />CakePHP validation made a little easier to understand
<li />Customization of associations, entities and fields
<li />Color coded models/modules makes it easier to distinguish separate modules, which is really good for the 3rd level normalized databases that grow in enterprise applications
<li />Does not require processor intensive and draining resources on a Windows machine
<li />Support is off the charts. The ORM Designer team really owns this product and really cares, so they provide some of the best support for the product.
</ul>
<p><b>Items that can be &#8220;areas of opportunity&#8221;</b></p>
<ul>
<li />There is no native support for Mac and Linux. Sure it works with Wine, but I just prefer my Mac apps to work natively with OSX instead of having to install more 3rd party software just to get some other 3rd party software running. Just my preference though
<li />The sheets to open projects, add projects, save, etc all seem to differ. I am more of a streamline type, if more than one &#8220;file&#8221; object sheet is needed, then make them all look the same
<li />Does not import existing CakePHP applications, which can cause some slow down if you start to use this tool after the application is already under way
<li />CakePHP validation seems to contain all options for every type of validation, and for someone who may not understand the details of all the different validation options, it can be a concern when it builds
</ul>
<p>Overall, this seems like a good tool. I am sure other people will find nuances as they start to use it more in the everyday world of developing. It seems like a good tool to use to help design databases. Even if the export is never done for the models/code in any framework/ORM, this is a great tool to use to help plan DBs out, view the relationships, associations. </p>
<p>To find out more information:<br />
<a href='http://www.orm-designer.com/' target='_orm'>ORM Designer Main page</a><br />
<a href='http://www.orm-designer.com/support/index' target='_orm'>Documentation and Tutorials</a><br />
<a href='http://twitter.com/ormdesigner' target='_orm'>ORM Designer on Twitter</a><br />
<a href='http://www.facebook.com/group.php?gid=188544547940&#038;ref=ts' target='_orm'>ORM Designer Facebook</a><br />
<a href='http://blog.orm-designer.com/' target='_orm'>Blog ORM Designer</a></p>
<p>************** EDIT 06 Sep 2010 **************<br />
<strong>From the ORM-Designer Team:</strong><br />
We‘re currently working on an automated import from database servers (MySQL, SQLServer and next major DB systems). This feature will enable users to easily import the model from their existing CakePHP (and other) projects.<br />
<em>(This is a huge one for the CakePHP community and one I am looking forward to)</em></p>
<p>Recently we added a new feature for CakePHP export, but this feature could be little hidden for new users and we want to propagate it more on our web in future. Besides the model files you can export also a DB structure to schema.php file which is useful for database migration.<br />
<a href='http://blog.orm-designer.com/2010/08/new-feature-for-cakephp-users-db-schema-export/' target='_blank'>More about this feature is on our blog</a>.<br />
<em>(This is another huge win for the CakePHP community)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2010/09/04/orm-designs-and-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

