28 Jan

Joining powers of two great systems: Joomla and CakePHP

Articles, CakePHP, Latest Developments

The day I learned CakePHP, it started inspiring me for getting more and more out of it. Its custom hacks are pretty cool, and CakePHP is a complete framework in itself. However, like all other frameworks, it creates too much of work when we have to code some features again and again, like User-registration, a link manager, gallery and all.... Joomla does handle all this pretty well. So, after I saw Drake, I decided to write my same thing with Joomla as I like it as a CMS and it is used by us everyday.

I would like to thank Felix from ThinkingPHP the most, his research helped me a lot to do this.

Let's start with a nice fresh setup.

1) Download Fresh versions of Cake and Joomla
and install Cake first (for me its joomla_cake), Rename cakephp's /app/webroot/index.php to cakephp.php then install Joomla inside 'webroot' of Cake's directory.

So your directory structure will be like:

/app
---------/webroot
-----------------/joomla's index.php with other files
-----------------/cakephp.php (we will use this to triger Cake)
/cake
/vendors

Edit cakephp.php

PHP:
  1. if(isset($_GET['url']) && $_GET['url'] === 'favicon.ico')
  2. {
  3. }
  4. else
  5. {
  6. /*    $Dispatcher= new Dispatcher ();
  7.     $Dispatcher->dispatch($url);*/
  8. }

Now we have disabled page rendering if we include this 'cakephp.php' in any external application.

2) Lets Create Joomla Component which will trigger Cake. : Lets call it 'com_cake'. This will be our master component in Joomla which will be triggered in case of when any unidentified Joomla's component is called... Lets add this functionality first.. Edit Joomla's index.php:

PHP:
  1. //Before Joomla initialize its mainframe, lets play...
  2. // check missing component -- added before $mainframe is being initialized
  3. //##########################
  4. if (!file_exists( $mosConfig_absolute_path .'/components/'.$option ) )
  5.     $option='com_cake'//set component to com_cake if a controller is not found.
  6. //##########################
  7. $mainframe = new mosMainFrame( $database, $option, '.' );

Lets get back to create the component:


/app
---------/webroot
-----------------/components (Joomla's component dir)
------------------------/com_cake
----------------------------------/cake.html.php (trigger to cakephp)
----------------------------------/cake.php (calls trigger with required options)
/cake
/vendors

We have to follow Joomla conventions for this module...
Lets create these 2 files, cake.php and cake.html.php:

cake.html.php:

PHP:
  1. defined( '_VALID_MOS' ) or die( 'Restricted access' );
  2. class HTML_cake {
  3. function requestCakePHP($url)
  4. {
  5.     $_GET['url']=$url;
  6.     require_once 'cakephp.php';
  7.     ob_start();
  8.     $Dispatcher= new Dispatcher ();
  9.     $Dispatcher->dispatch($url);
  10. }
  11. }

cake.php: This file will judge which controller/action to pass in cakephp.

PHP:
  1. defined( '_VALID_MOS' ) or die( 'Restricted access' );
  2. require_once($mainframe->getPath('front_html'));
  3. $mainframe->setPageTitle("Check this out");
  4. global $database;
  5. $controller=mosGetParam( $_REQUEST ,'option'); //option passed is treated as a controller in cake
  6. $action=mosGetParam( $_REQUEST ,'task'); //task passed is treated as a controller in cake
  7. HTML_cake::requestCakePHP('/'.$controller.'/'.$action);

3) Time to check its functioning:

www.myserver.com/joomla/index.php?option=names&task=add

1. $_GET['option'] is passed to Joomla's index.php. There it concluded that component called 'names' is not found, so lets pass it to 'com_cake'

2. Now we are in cake.php (com_cake), we will check what controller and action it is requesting, and trigger the 'requestCakePHP' function.

This will make Joomla to assume that component being called is 'com_cake', and task is 'names/add'. This task will be then passed to Cake as $_GET['url'].

And we're done...

I see baked code of Cake's model 'name' inside Joomla.

Joomla and Cake together

Currently, I have not created it to handle the function arguments... but if I found this to be more useful... I will continue the project. The next updates will be:

1. Better handling of function arguments.
2. Customization of CakePHP's helpers to make use of right path and more.
3. Utilization of some plugins

Thanks
-- Max aka Abhimanyu Grover

22 Jan

Fixing Speed Issues in PHP/MySql

Articles, Best Practices

There are 70% of the cases with PHP/Mysql applications where speed is slow because of bad sql queries. To know if you're not doing anything wrong, here's the procedure.

You have to record the time before executing an SQL query.

< ?php
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$starttime = $time;
?>

Now, add this immediately after mysql_fetch_query function.

< ?php
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$endtime = $time;
$totaltime = ($endtime - $starttime);
echo 'SQL Query executed in ' .$totaltime. ' seconds.';
?>

To review this thing, if you are having a code like:

mysql_connect("localhost", "mysql_user", "mysql_password") or
die("Could not connect: " . mysql_error());
mysql_select_db("mydb");
$result = mysql_query("SELECT id, name FROM mytable");
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
printf("ID: %s Name: %s", $row[0], $row[1]);
}

mysql_free_result($result);
?>

Then, your final code must be:

mysql_connect("localhost", "mysql_user", "mysql_password") or
die("Could not connect: " . mysql_error());
mysql_select_db("mydb");
// code to initiate our time
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$starttime = $time;
$result = mysql_query("SELECT id, name FROM mytable");
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
printf("ID: %s Name: %s", $row[0], $row[1]);
}
// lets check the time gap
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$endtime = $time;
$totaltime = ($endtime - $starttime);
echo 'SQL Query executed in ' .$totaltime. ' seconds.';
mysql_free_result($result);
?>

This code is not complete in itself, but enchancing it more can help a lot in projects.

13 Jan

PNG issues with Internet Explorer

Latest Developments

While designing a layout which involved a lot of PNG files, I figured out that transparent PNG in IE appears with a light blue ugly background.

This is how it appears in IE:
PNG file in IE

Solution:
The Javascript code: pngfix.js as specified here.

Pros & Cons

Pros:

Ignored as a comment in other browsers - it's only run by Windows IE.
Works with (X)HTML Strict & Transitional Doctypes
Does not break W3C validation
Lightweight and very easily deployed
Works with existing in-line or external CSS rules based on class or ID selectors
Works with old-style img align="left" or align="right" attributes
Runs after any existing Body Onload code
Works with imagemaps and input images using a special version

Cons:

Doesn't work in IE versions earlier than 5.5 - the AlphaImageLoader filter wasn't introduced until version 5.5. There is no cure for earlier versions.
Requires JavaScript to be enabled - the estimations for how many people choose not to use JS vary wildly. See note [1]
CSS backround PNGs not supported - experimentation revealed I could traverse the Stylesheets collection and use the AlphaImageLoader trick to replace all background-image attributes containing PNGs, but then background-repeat would not work, and anchors placed over non-transparent parts of the image were not clickable :-( CSS rules for the PNG images based on the img selector are lost, but this is easily rectified by adding a class selector to your img rule such that img{..} becomes img,.png{..} - then add the attribute class="png" to each of your PNGs.

However, this issue is visible in IE 5.5 & 6 only but there are a lot of people who are still using them. So, I decided to post the solution here.

Credits:
Bob Osola

Hire us

Contact us to get a free quote on your project.