Archive for the ‘Tips’ Category

Tip: use CakePHP Route::url() for your URLs

Routing is one of the amazing features of CakePHP because it makes the urls beautiful. We use this most of the time and last time, I blogged about the helper to shortcut ones typing when using the HTML helper. Overtime, I realize how helpful it can be. Read on.

Always use array when passing parameters when creating a link or using Router::url(), it will save you time in the future. Why? Consider this scenario:

You created a controller /users/register and in your code and you added this

<?php echo $html->link('User Registration', '/users/register')?>

Then your group or your boss decided to use a better name /register. Your initial thought would be to replace all those texts to those new ones, isn’t it? There is a better approach. Try the ffg:

In /config/router.php

<?php Router::connect('/register',	array('controller'=>'users','action'=>'register'));  ?>

In your view:

<?php echo $html->link('Registration', array('controller'=>'users','action'=>'register'))?>

the HTML helper uses Router::url() in its link function and the Router class magically converts array parameters to what you stated in your config. In writing urls, we have to be consistent because it can be bad for SEO when you have too many urls pointing to the same location.

Although the above works beautifully but it can be a tedious job. I wrote not long ago about the html helper that could make this approach easier so you could write the ffg in your view.

<?php echo $html->link('Registration', url( 'users', 'register', null, 'teacher' ))?>

It saves a few characters!

From the last post, I refactored it and placed it in the bootstrap so I can call it anywhere (got that idea from the google groups).

Here it is:

    function url() {
        $args = func_get_args();
        $count = func_num_args();
 
        if ( $count == 1 ) {
            if ( is_array( $args[0] ) ) {
                $args = $args[0];
                $count = count($args);
            } else {
                return $args[0];
            }
        }
 
        $short_keys = array(
            0 => 'controller',
            1 => 'action',
            2 => 'plugin',
            'c' => 'controller',
            'a' => 'action',
            'p' => 'plugin',            
        );
 
        foreach ( $short_keys as $short_name => $long_name ) {
 
            if ( isset( $args[$short_name] ) ) {
                $args[$long_name] = $args[$short_name];
                unset( $args[$short_name] );
            }
 
        }
 
        // Need to explicitly assign plugin key
        if ( !isset( $args['plugin'] ) ) $args['plugin'] = null;
        if ( !isset( $args['action'] ) ) $args['action'] = 'index';
        if ( !isset( $args['admin'] ) ) $args['admin'] = false;
 
        $routing = Configure::read('Routing.admin');
        if ( preg_match( "/^{$routing}_/", $args['action'] ) && $routing ) {
            $args['admin'] = true;
            $args['action'] = substr( $args['action'], strlen($routing) + 1 );
        }
 
        return $args;
    }

The function above could take an array OR any number of string parameters.

url ( 'controller', 'action', 'plugin_name', ...[more params here] )
url ( array( 'c' => 'controller', 'a' => 'action', 'p' => 'plugin' ) )

The first one is strict for the first 3 parameters. The latter can be written in any order as you like. I also added support for prefix routing such as admin_*. So you can write:

url ( 'controller', 'admin_action', 'plugin_name', ...[more params here] )
url ( array( 'c' => 'controller', 'a' => 'admin_action', 'p' => 'plugin' ) )

Router::parse() can also be used instead of url() function but the latter is faster.

That’s it. Happy Baking!

Tags: ,

What is compact() in controller?

I don’t know how much functions in php I do not know but everyday I am finding new ones specially when I started tinkering CakePHP 1.2 last week. And my latest discovery is …. compact function. After using the console script, I found this code in the controllers

$users = $this->User->Teacher->find('list');
$this->set(compact('users'));

compact is a native PHP function that creates an array containing variables and their values. Chris Hartjes explains it well in his blog. It’s quite neat because it will save me a few lines and spaces.

There you go, our new gem today: compact()

Tags: , , ,

Handling SQL injection in CakePHP

One benefit of using a framework is that some of the most common problems we will encounter when building web applications from scratch is already taken cared of, that is if properly used. Today, we will discuss one of the most common problem we have experienced specially for beginners – SQL Injection.

Let’s begin first by defining SQL Injection. According to wikipedia, SQL injection is a technique that exploits a security vulnerability occurring in the database layer of an application. The vulnerability is present when user input is either incorrectly filtered for string literal escape characters embedded in SQL statements or user input is not strongly typed and thereby unexpectedly executed. It is in fact an instance of a more general class of vulnerabilities that can occur whenever one programming or scripting language is embedded inside another.

To protect against SQL injection, user input must not directly be embedded in SQL statements. Instead, user input must be escaped, or parameterized statements must be used.

CakePHP handles this in its data abstraction layer by using mysql_real_escape_string(). To use effectively, programmers must comply to its rules. Why did I say comply? Some of model functions are very loose with what kind of parameter type to accept. This setting has caused some of the newcommers to not see the benefit of passing conditions by array. Let’s take for an example the findAll() function.

Model::findAll ( $conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null )
Parameters:
  mixed $conditions SQL conditions as a string or as an array(’field’=>’value’,…)
  mixed $fields Either a single string of a field name, or an array of field names

The $conditions accepts both string and array for its passed values. Logically, only the data passed as an array will be escaped. Using arrays allows CakePHP to generate the most efficient query possible, ensure proper SQL syntax, and properly escape each individual part of the query.

For complex find queries, we may opt for the string condition and do all the dirty work. As of this writing, CakePHP is now offering a solution to build complex conditions using arrays.

Cake can parse out any valid SQL comparison operator, including match expressions using LIKE, BETWEEN, or REGEX, as long as we leave a space between the operator and the expression or value.

array("Post.title" => "<> This is a post")

Below is the adaptation of the IN (…)-style matches

array("Post.title" => array("First post", "Second post", "Third post"))

By default, the framework joins multiple conditions with boolean AND. To accept other boolean conditions, we could do the ffg:

array
("or" =>
    array
    (
        "Post.title" => array("First post", "Second post", "Third post"),
        "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
    )
)

Or like this:

array 
("Author.name" => "Bob", "or" => array
    (
        "Post.title" => "LIKE %magic%",
        "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")
    )
)

More explanation of this can be found at the Manual: Complex Find Conditions (using arrays).

Model::save() is more strict so I did not see any problem following its rules. If you have questions for a certain model function syntax, the API can be a great resource.

With the benefit of these Model functions, we must still have to adapt to the framework’s environment which maybe of a disadvantage at first. It will just be your choice which manners will best suit you. At the end of the day, what will matter is that the code we produce is readable, maintanable and most of all secure.

Source:

Tags: ,

Using TinyMCE with CakePHP

It’s finally my deadline. Oh well, I am not really a blogger so I just hope you’ll stick with my article. Please bear with my “work of art”. Duh?!?

Ok, let’s get this started. As the title says, my article is all about TinyMCE + Cakephp. This may not be too challenging or may appear newly baked for others but for me, it’s something worth writing for. There’s just a few blocks of information that I need to discuss and everything we’ll be done in a short while.

TinyMCE is a WYSIWYG editor by Moxiecode which is downloadable for free. It has been integrated with some of the fast-rising CMS in the OS community nowadays. Such would be joomla and drupal. Here, integrating is so easy, so just follow these steps and good luck:

  1. Download tinyMCE.
  2. Once downloaded, unpack TinyMCE, and copy just the tinymce/jscripts/tiny_mce folder in /webroot/js.
  3. Then follows the configuration. To make this thing work on cakephp, simple do these:
    1. First, add the code below to the layout(s) that will be used on the page(s) that will have the editor.
      <script type="text/javascript"> 
        tinyMCE.init({ 
          theme : "simple",
          mode : "textareas",
          convert_urls : false
        }); 
      </script>
    2. Add the javascript helper to your $helpers array in your controller(s)
    3. Then, for each page that you would want the TinyMCE editor to show, just add to the top of the view file this code below:
      <script type="text/javascript"> 
        tinyMCE.init({ 
          theme : "simple",
          mode : "textareas",
          convert_urls : false
        }); 
      </script>

Source: Bakery

Tags:

CakePHP 1.2

The Beta version of CakePHP 1.2 has already been released. As always, newer versions are looked forward to because of the better functionality they are expected to offer with.

Below is a list of some of what’s new in 1.2.

1. .ctp file view extensions
2. FormHelper for form related functions
3. Support for themes
4. More advanced validations, caching
5. Support for i18n and l10n
6. Named arguments
7. New core helpers (Js, Paginator, RSS, XML)
8. New core classes (Set, Debugger, HttpSocket, Socket)

An overview of CakePHP 1.2 is presented in pdf that comes along with the beta version. Additionally, What’s New with CakePHP 1.2? lists the differences between 1.1 and 1.2.

Along with the new functionalities are the deprecated ones. Check out the Deprecated Stuff in CakePHP 1.2 for a list of the deprecated items. Although these stuffs still work, they are not recommended for use anymore. They will throw notice errors when debug level is greater than 0 and are more likely to be removed on future releases.

Binding your Models the Easy Way

Finally, I’ve posted my first cakephp blog which is already a week late. So late that I really had a hard time picking a nice topic to make it worth the wait. I don’t know if this one is but I hope it’ll be helpful especially to those who are new to cake. Ive been working on IsupportThisMessage.com for almost a year and still supporting it until now since they’re planning to add more functionalities to the system. This is where I learned the basics of cake.The manual is quite simple and I’ve read it over and over. But when I thought I already know a lot and started coding, I realized, I don’t even know a bit. So really, there’s no better way of learning than actually applying it. And for almost a year, I’ve learned a lot but I must admit, I still have a lot to learn.

One nice thing I like about cake is the use of MVC pattern which makes my codes more organized. And I like how the querying is done which is made more simple because you wouldn’t need to declare associated tables within your query if you have already specified the associations within your model. Fantastic! One of the most powerful features of CakePHP is the relational mapping provided by the model. At first, I didn’t want to touch anything in the models coz I was confused about associations. Besides I was scared I might break the code. But when I finally understood how, I declared the necessary associations within my models most especially “messages”, coz in isupport this is often being used and it has a lot of associated tables in it. But sometimes, when you query, your association settings in the model file are giving you too much (or not enough) information. What I mean to say is, sometimes you wouldn’t need some of the associated tables in your query result. So you have to think of a way how to minimize the result, and that is where unbindModel & bindModel model functions are used which allow you to change your association settings on the fly. But as quoted from the bakery section of cakephp.org by TommyO,

Changing the requirements of a bind done in this way means going through your controllers and changing the bindModel call, often in multiple places. Using unbindModel in a controller also means every time a new association is added you may need to go back into your controllers and unbind the new associations in order to optimize your code.

Silly, but true. Thanks to TommyO, he created a method to simplify this using the approach:

binding to other Models only when needed or unbinding existing relations to minimize the size of your result set.

But just an overview, you would just need to add a function within your appmodel. Then in your model class, just define your associations within an array called $assoc. You will see an example from the link. So easy huh?

So in your controller:

<?php
MessageController
extends AppController {
function index(
$id) {
// establish necessary associations
$this->Message->expects(array(‘Comments’, ‘User’));
$results = $this->Message->findAll();
}
}
?>

Now you have it. But that’s not all. Ive read another post in the bakery related to TommyO’s method for model associations. In TommyO’s approach, there’s a slight difference on the way you define your model association and the models get loaded *when* you call the expects() function. According to Mariano, the author of the post, he said he’s not a fan of changing how things are done in cakephp, neither do I. His approach is to use the Cakephp way of defining associations in the models and then specify which relations he’s interested in getting back when querying a model. This way, models behave the way models are supposed to. The main idea here is that you define your associations in the model the cakephp way. Then in your controller, if you want the standard result cakephp brings then you don’t need to call expects() (With TommyO’s approach, you will need to call expects() with all the necessary values). Use expects(), only when you want to limit the result of your query. And if you want to unbindAll just call expects() with no parameters. You will need to add three functions in your appmodel which you will find here. There are additional topics included here like “making multiple expects in one call“. And if I’m a little confusing in explaining, I think you can understand it better when you visit the links. hehehehe.

Good luck!

Tags: ,

Cakesheet Overview

http://cakephp.org/files/cakesheet.pdf
- gerold

Tags: