Archive

Archive for the ‘Labs’ Category

CakePHP ajaxed pagination and sort

May 16th, 2009

Here I will describe how I did an Ajaxed pagination for one of my projects using jQuery and Livequery Plugin. Currently I am working on a huge project which, hopefully, will feed me with some ideas for blog posts and this is one of them :) . So:

1. Loading the javascript libs

Loading the jQuery and Livequery was done by Autoloader helper, but if you don’t use it just include jQuery and Livequery in your layout with following code

<?php
echo $javascript->link('jquery.min');
echo $javascript->link('plugins/jquery.livequery');
?>

Read more…

CakePHP, Development, General, JavaScript, Labs , , ,

Passing variables to all Models from the Controller – strict MVC way

April 21st, 2009

It’s really easy to find inspiration when you developing on CakePHP. For the current project I need to create global (for all models) behavior which stores creator and modifier as well as deleter and deleted (for soft-delete).

What are the requirements

1. For every table (or at least the most of them) there are fields 6 fields:

  • creator (int) – user who create the the record
  • created (datetime) – date when the record was created
  • modifier (int) – user who modified the the record
  • modified (datetime) – date when the record was modified
  • deleter (int) – user who delete the the record
  • deleted (datetime) – date when the record was modified

2. Some tables doesn’t have such fields (like aros, acos, settings etc), so it should update tables which has such fields.

I’ve seen Soft Deletable Behavior as well as recently added WhoDidIt behavior, but I don’t like the approach of using _SESSION. I’ve also decided to use datetime field to determine if the record is active (field deleted is NULL) or deleted (if the field is set with date).

So the result was – I’ve write my own behavior who serves this.
Read more…

CakePHP, Development, Frameworks, Labs, PHP , ,

Autoload your javascript and css in CakePHP

December 20th, 2008

Have you ever wanted to have all your css or javascripts files loaded automatically once they are on place under /webroot/js and webroot/css folders? Well this is the solution.

What is all about

I’ve build a quick helper which will include all files under the js/ and css/ directories. So once the javascripts and css are there, they will be loaded automatically.

How to use it?

Using it is really easy. It’s like a normal helper:
1. add the file autoload.php under your /app/views/helpers
2. add it in the $helpers var in the controller
3. add the following snippet in your layout file. It should be under /app/views/layouts:

<?php echo $autoload->javascript();?>

This will include all files under /webroot/js

<?php echo $autoload->css();?>

This will include all files under /webroot/css

<?php echo $autoload->all();?>

This will include all files under /webroot/js and /webroot/css

Key features:

1. The helper includes all files recursively.
2. The helper includes also files under /root/vendors/js and /root/app/vendors/js too (same apply to css). Vendors are loaded first. (Thanks to suggestion from Juan Basso)
3. The order of the files in one directory is based on the name, so now you can control the order as well. (Thanks to suggestion from Juan Basso)
4. Files starting with . (dot) are not included, files under directories starting with . are not included as well, so you can exclude some files
5. if you want to load some files after other use directories. For example if you want to include plugins after the main lib (jQuery), place them in plugins directory like:
js/plugins/plugin_one.js
js/plugins/plugin_another.js
js/.hidden/plugin_third.js
js/jquery.js
the result will be:

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/plugins/plugin_one.js"></script>
<script type="text/javascript" src="js/plugins/plugin_another.js"></script>

(same apply to css as well)

Warning: I’ve noticed that this helper doesn’t work properly with scriptaculous, because the script tries to load the additional plugins and they fail, but for jQuery there is not a problem at all.

Finally here is the code of the helper:
Read more…

CakePHP, Development, Labs, PHP , , ,

Careful with JavaScript includes

December 11th, 2008

Ok, this is not a code snippet article. It’s just an experience which you probably already met, but it was nightmare to find and it took me 1/2 a day to fix this “stupid” bug.

So what is the case?

Working on a project including some advanced JavaScript and Ajax techniques my coworker Milen noticed that the Session is not behaving as expected. In a simple function like:

function test($id = false){
  if ($id != false) {
    echo $id;
    echo $k = $this->Session->read('some_var');
    $this->Session->write('some_var', $id);
  }
  $this->set('tests', $this->paginate());
 }

The result should be quite easy to be predicted: if you pass for example 5 on the second reload the $k should be with the same value as $id. Unfortunately instead of 5 the $k was ‘images’. Yep, quite strange, isn’t it?

if you put die() at the end of the function, the result is as expected.

What was the problem

In our current project we are using jQuery and some of it’s plugins. So the problems was in the ThickBox plugin. If you remove it from the header everything works.

Digging into unpacked version of the plugin we’ve noticed that the loading picture is not where it should be. there is an variable

var tb_pathToImage = "images/loadingAnimation.gif"

and as you may notice the path is not compatible with Cake convention and obviously it’s not in the http://server/cakeapp/tests/test/images/.

In the example above we were writing id into the session. Yes but calling: http://server/cakeapp/tests/test/images/loadingAnimation.gif mean that $id take value of ‘images’.

It was quite tricky, because if you loading CSS or JavaScript and the file is not there, FireBug or even the html /if there is no correct CSS the styling will fail/ will warn the developer, but image loaded into the JS function is quite difficult to find.

Anyway, the conclusion is “Watch you JavaScript libs and what files they require”.

Ajax, CakePHP, Development, Frameworks, General, JavaScript, Labs, PHP , ,

My first Wordpress plugin

November 28th, 2008

Hey,

I am very proud to present you, my first plugin for Wordpress platform – Autocompleter.

The plugin adding autocomplete functionality for the search input field of your blog. The values are the tags and categories existing in the blog and this way you will help your visitors to find easily the proper information in your blog.

My first implementation was with Prototype and Script.aculo.us, but because I like very much jQuery library and I found a wonderful plugin for autocomplete, I build it with jQuery.

You can check the demo in this blog – top right – search box :)

Hope you will like it and you will vote for it :) Thanks

The official page is: wordpress.org/extend/plugins/autocompleter

Ajax, Development, General, JavaScript, Labs , , , ,

Fixing Dead Centre approach with jQuery

October 17th, 2008

I was worked on a centred project design of a website. When I met such requirement I’ve always used Dead Centre approach.

Unfortunately I’ve noticed that when the content is larger than the screen the top-left corner is not visible. In that current project the logo of the site was exactly on that place, so it’s really confusing.

I had to solve this issue in order to satisfy the clients requirements. So, I’ve used jQuery to sort this out.

You can see the difference in these 2 examples:

Resize your browser window in order to see the difference.
How it’s working?

First of all there are 2 javascript includes:

<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="jquery.dimensions.min.js"></script>

After this there is a function which track the size of the screen and the content.

<script type="text/javascript">
        /*Track height and width of the window and the content*/
        function resize(){
            if($(window).height() < $('#content').height()){
                $('#horizon').css('top', '0px');
                $('#content').css('top', '0px');
            } else {
                $('#horizon').css('top', '50%');
                $('#content').css('top', '-'+($('#content').height()/2)+'px');
            }
            if($(window).width() < $('#content').width()){
                $('#content').css('left', ($('#content').width()/2)+'px');
            } else {
                $('#content').css('left', '50%');
            }
        }
       
        //Bind events on resize
        $(document).ready(function(){
            resize();
        })
        $(window).bind("resize", function(){
            resize();
        });
    </script>

The explanation of the code:
I am using jQuery plugin named jQuery Dimensions Plugin 1.1 which extract the proper dimensions of the boxes.
The function checking if the content screen is bigger than the window size, if so it change the CSS in order to fit properly. I guess that you can see the logic easily. So, no more explanations here.

Hope this will help someone.

Development, Frameworks, JavaScript, Labs , , , , ,

Adding autocomplete field for search in Wordpress

October 10th, 2008

Added a nice Autocomplete field of the search box in that blog /top right/. It’s really nice to have and I really enjoyed doing it.

I followed that article: How to: Create an Ajax-based Auto-completing Search Field for your Wordpress Theme, but instead of using suggested js code, I’ve used Script.aculo.us Autocomplete way.

I really enjoyed and I hope you will like it too.

Update: I’ve wrote a plugin for this: nik.chankov.net/autocompleter/. Enjoy!

Ajax, General, JavaScript, Labs , , , ,

Working with nested data and find method with breadcrumbs in CakePHP

October 10th, 2008

Do you working with tree data in your projects?

Well, in CakePHP there is a Tree behavior which will help you to handle such structures. Let me show you how to use it in your projects. Hierarchical data structures are very well described here by Mike Hillyer and I would suggest you to take a look before you continue reading.

Let’s say we have following data structure:

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `parent_id` int(10) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `lft` int(10) DEFAULT NULL,
  `rght` int(10) DEFAULT NULL,
  PRIMARY KEY  (`id`)
)

Note, that in that table there are 3 special fields: parent_id, lft and rght.

The first one is very familiar to everyone who understanding the tree structures. The other 2 are to handle the MPTT logic (see the article mentioned above). The beautiful part of using Tree behavior is that you don’t need to worry about these 2 extra columns. The behavior will fill them automatically. :)

So, continue with the example. Attach the Tree behavior to your Model:

<?php
class Category extends AppModel {
    var $name = 'Category';
    var $useTable = 'categories';
    var $actsAs = array('Tree' => 'nested');
}
?>

That’s it. Now when you save (insert or update) your data into the table, the fields lft and rght will be automatically populated with the correct values. Of course your task is to have proper value set in parent_id :)

Why this is so important?
As you already know /if you read the article for MPTT/ using lft and rght values will give possibility to get very easy nested data in various ways.
In Model::find function there is already threaded option, but what about having breadcrumbs?

Here is a way to extend the Model::find function with this functionality. /inspired by Daniel Hofstetter’s post/

<?php
class Category extends AppModel {
    var $name = 'Category';
    var $useTable = 'categories';
    var $actsAs = array('Tree' => 'nested');

    public function find($type, $options = array()) {
        switch ($type) {
            case 'breadcrumbs':
                if(!isset($options['fields']))
                    $options['fields'] = null;
                if(!isset($options['recursive']))
                    $options['recursive'] = null;
                if(is_object($this->Behaviors->Tree) && $options['id']){
                    return $this->Behaviors->Tree->getpath($this, $options['id'], $options['fields'], $options['recursive']);
                } else {
                    return null;
                }
                break;
            default:
                return parent::find($type, $options);
        }
    }
}
?>

As you can see I am using the function TreeBehavior::getpath. There are a lot of handy functions in this behavior, but for breadcrumbs example this is just enough.

How to use it?

$this->Category->find('breadcrumbs', array('id'=>1));

so if you have data like this:

1 Root
2     Cat1
3         Cat1.1
4     Cat2

and use the function mentioned above with id=3 the result will be:

Array
(
    [0] => Array
        (
            [Category] => Array
                (
                    [id] => 1
                    [parent_id] =>
                    [name] => Root
                    [lft] => 1
                    [rght] => 8
                )
        )

    [1] => Array
        (
            [Category] => Array
                (
                    [id] => 2
                    [parent_id] => 1
                    [name] => Cat1
                    [lft] => 2
                    [rght] => 5
                )
        )

    [2] => Array
        (
            [Category] => Array
                (
                    [id] => 3
                    [parent_id] => 2
                    [name] => Cat1.1
                    [lft] => 3
                    [rght] => 4
                )
         )
)

After this with

$breadcrumbs = Set::extract('/Category/name', $result);
echo ' / '.implode(' / ', $breadcrumbs);

you will have the following result

/ Root / Cat1 / Cat1.1

I am leaving to you the styling of it as well as adding the links to the parent nodes.

CakePHP, Development, Frameworks, Labs, PHP , , , , , ,

Building cake application (Part VI)

October 4th, 2008

Saturday (Day 6)

Problem with validation messages while translating
Although my native language is Bulgarian and the requirement from the client was to have this site only in Bulgarian, I’ve preferred to have it in English and to make the translation with the i18n functions of CakePHP. There are 2 reasons to do this:

1. This will give me the possibility to show you the result of all these days of coding and
2. I can reuse some part of the codes the same as I’ve used in this project

So, up to my experience having application in English is never a bad idea. :)

You know, that the translating process is not very exciting process, but someone need to do it and because there is no one who can help me with this I’ve start the translation. Anyway. :(

While translating I noticed that the most of the validation messages are not appear of the translation file. I knew this from my past experience, but I needed to find an easy and elegant solution to translate these messages instead of putting them in all views. Putting in the view you need to do this at least 2 times.
Read more…

Ajax, CakePHP, Development, Frameworks, JavaScript, Labs, PHP , , , , ,

Building cake application (Part V)

October 3rd, 2008

Friday (day 5)

Constructing SQL statement for the search
Yep, today I need to finish the Profile search for the admin part. As I mentioned, the search is only by fields of experience, so there is no big and scary where clause /especially if you want to cover all cases, like splitting the words with AND, OR etc. will cause huge where with all possible combinations/.

There are 2 specific requirements here: The results need to be ordered by relevance and the report need to show fields of competence which are match to the search criteria next to each row /user/.

What does it means? Let’s say there are 2 users. First one has following skills like Java, PHP, MySQL, HTML and JavaScript, the second one knew only JavaScript and HTML, so when we search for users matching criterion PHP and HTML, the search results need to be ordered like this:

User1 – matching fields: PHP, HTML – relevance 2 criteria matched
User2 – matching fields: HTML – relevance: 1 criteria matched
and so on.

At first glance it look like I had to build huge SQL including few sub queries or functions for fetching the fields of relevance and matching fields and I was prepared for at least one day to accomplish this task, but in fact it was very fast.
Read more…

Ajax, CakePHP, Development, Frameworks, Labs, PHP , , , , , ,