Friday, October 16, 2009

AJAX in cakePhp, #cakephp, #php,

AJAX CakePHP
Using AJAX with CakePHP tutorial

CakePHP is a wonderful framework. Unfortunately, like a lot of software, documentation is severly lacking. The effort is definitely there, but with an API containing the occassional "Enter description here... unknown_type", it definitely makes things a bit more difficult. Especially for someone who adopted the RTFM mantra many years ago.

For this article, we're going to try and figure out how to get AJAX and cake to work together without having to comb cake's manual, wiki, the bakery, users' sites and tutorials and Google groups.

First things first - you'll need to have cake installed and running.

Next things second - you'll need to get the scriptaculous and prototype libraries. (I haven't tried any other AJAX libraries, but these seem to work just fine for now).

Note: there was an issue where the code crashed firefox that turned out to be caused by the prototype.js that's included in scriptaculous being the incorrect version. Therefore, I recommend downloading them separately.

You'll need to place the scriptaculous and prototype files in /app/webroot/js directory.

Now you need to add the following inside the tag of your layout file (/app/views/layout/default.thtml) to make them available:

print $html->charsetTag('UTF-8');
print $javascript->link('prototype');
print $javascript->link('scriptaculous.js?load=effects');
?>

At this point, you have 2 options - to use the RequestHandler component or not. If you're doing fancier AJAX things, you can check CakePHP's manual on RequestHandler, but to keep things simple, we won't use it.

In your controller's action, you want to add:

// controller file
var $helpers = array('Html', 'Javascript', 'Ajax');

function view() {
$this->render('layout file', 'ajax');
}

First we want to make sure we're using cake's built-in helpers, including the AJAX helper. In your action, you'll change the render action to include the ajax option, which tells cake to crunch the information and send the data somewhere rather than displaying a new page. We'll see where in a second.

What you want to do next is create a link, but not just any link. You want to enable an ajax link, and to do that you use the ajax helper that comes with cake.

// view file
echo $ajax->link('link text', '/controller/action',
array('update' => 'div id')
);

This will automatically generate a link with the appropriate attributes to output the ajax into the div you specify. Note: don't forget the forward slash - cake needs to be able to find your controller, otherwise nothing will appear to happen (no errors will be shown either).
Styling it

If you want to add a css class to the link, add the undocumented 'class' option as part of the options array.

// view file
echo $ajax->link('link text', '/controller/action',
array('update' => 'div id', 'class' => 'aclass'));

What about images?
To include an image to be linked rather than text, you simply include the html for the image in place of the first parameter, but be sure to add FALSE so the code doesn't get escaped.

echo $ajax->link('',
'/controller/action/',
array('update' => 'div id'),
null,
FALSE
);

Multiple divs
That's all fine and dandy, but what if you wanted to update more than one div at a time? To do that, you'll need to add an array of divs to update, and also use the $ajax helper to create the divs.

echo $ajax->link('link text', 'controller/action',
array('update' => array('div1', 'div2'))
);

// create the div code rather than hard-coding

echo $ajax->div('div1');
echo $ajax->divEnd('div1');

echo $ajax->div('div2');
echo $ajax->divEnd('div2');

So it updates. How do I make it look cool?
To add effects, you'll need to add the effect to the link:

$ajax->link('link text', 'controller/action',
array('update' => 'div id',
'loaded' => 'scriptaculous effect')
);

You can use loaded/loading or any of the other available options listed in the manual under helpers.
A complete example
We'll create a simple example here to demonstrate.

/**
* $Id: approot/controllers/things_controller.php
*/

class ThingsController extends AppController
{
var $name = 'Things';
var $helpers = array('Html', 'Javascript', 'Ajax');

// we're not going to use a model for this example, but
// it would be easy to use a database thanks to cake
var $uses = null;

/**
* initial page load
*/
function index() {

// preload dynamic data
$this->set('data1', 'content will update here');
$this->set('data2', 'here too');

$this->render('neat');

}//index()

/**
* display content action
*
* @param int id of content to display
*/
function view($id) {

// content could come from a database, xml, etc.
$content = array(
array('somebody is baking brownies',
'become a cake baker',),
array('knowledge is not enough',
'we must also apply - bruce lee')
);

$this->set('data1', $content[$id][0]);
$this->set('data2', $content[$id][1]);

// use ajax layout
$this->render('neat', 'ajax');

}//view()

}//ThingsController
?>




print $html->charsetTag('UTF-8');
print $javascript->link('prototype');
print $javascript->link('scriptaculous.js?load=effects');
?>





Really neat stuff here


// update both divs
echo $ajax->link('update divs', '/things/view/0',
array('update' => array('dynamic1', 'dynamic2'))
);
echo ' | ';
// use an effect
echo $ajax->link('blinders', '/things/view/1',
array('update' => array('dynamic1', 'dynamic2'),
'loading' => 'Effect.BlindDown(\'dynamic1\')')
);
?>



div('dynamic1'); ?>


divEnd('dynamic1'); ?>

div('dynamic2'); ?>


divEnd('dynamic2'); ?>

Wednesday, October 14, 2009

Plugin creation in 10 mintue, #cakephp, #php, #openSource, #MVC

Do you want to create a blog, a web management module, or anything you want for an application? Make it a CakePHP plugin and you can also put it in other applications. The main tie between a plugin and the application it has been installed into is the application's configuration (database connection etc.). Otherwise, it operates in its own little space, behaving much like it would if it were an application on its own.

To start, place your plugin files

in /app/plugins folder. Choose wisely the name of the folder for the plugin files because it will be used in many places. For any normal application, you do not need to define AppController and AppModel; that's required for the plugins. You'll need to create them before your plugin works. These two special classes are named after the plugin, and extend the parent application's AppController and AppModel. For example, the AppController will be /app/plugins/softpedia_test_controller.php and the AppModel /app/plugins/softpedia_test_model.php. If you forgot to define these classes, CakePHP will show you "Missing Controllers" error until you solve the problem.

The controllers for the plugin will be stored in /app/plugins/name_of_plugin/controller. In order to avoid namespace conflict, you should give the controller a unique name. The models of the plugin are stored in /app/plugins/name_of_plugin/models. Next, you will specify the place where you will put the plugin views. Views for the plugin have the same functions as in normal applications. Place the views in /app/plugins/name_of_plugin/views folder.

Before starting to create your CakePHP application, you should consider the following conventions:
- model filenames are singular, capitalized for single-word models, and UpperCamelCased for multi-word models.Also model filenames use a lower-case underscored syntax: e.g: softpedia_test.php
- table names are plural and lowercased
- foreign keys should always be: table_name_in_singular_form_id: user_id (foreign key) �� users (table)
- controller filenames are plural and underscored with "controller" appended: controller_name_controller.php

You can find all the conventions in the manual.

Karry Lugar Bill: American Aid for Pakistan: # pakistan-news ,# news, #karry lugar bill

Monday, October 12, 2009

redirect(), Header(), #cakephp, #cake, #opensource

This is our PHP redirect() function, it has been tested with PHP versions >= 4.2.0. Seen a lot of requests for this on various mailing lists so we thought we'd share.
We've added support for different HTTP/1.1 3XX status codes. Each of the response codes tell the requesting User-Agent how to respond as described below.
In the W3C specification it's stated that the server should also give some content back for the User-Agent to render if it does not obey the redirect. This redirect function will output some pretty HTML if the headers have already been sent following the W3C intentions.
301 Moved Permanently - Forget the old page existed
302 Found - Use the same method (GET/POST) to request the specified page.
303 See Other - Use GET to request the specified page. Use this to redirct after a POST.
307 Temporary Redirect - Good for response to POST.
Usage example
// Do stuff here before sending headers
redirect('/')
redirect("/my/page")
redirect("http://www.foo.bar/page.htm",303)
redirect("./index.php",307)
?>
The redirect function itself
You may copy and paste this code freely where you need to, please give us credit it if you use it
// func: redirect($to,$code=307)
// spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
function redirect($to,$code=301)
{
$location = null;
$sn = $_SERVER['SCRIPT_NAME'];
$cp = dirname($sn);
if (substr($to,0,4)=='http') $location = $to; // Absolute URL
else
{
$schema = $_SERVER['SERVER_PORT']=='443'?'https':'http';
$host = strlen($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:$_SERVER['SERVER_NAME'];
if (substr($to,0,1)=='/') $location = "$schema://$host$to";
elseif (substr($to,0,1)=='.') // Relative Path
{
$location = "$schema://$host/";
$pu = parse_url($to);
$cd = dirname($_SERVER['SCRIPT_FILENAME']).'/';
$np = realpath($cd.$pu['path']);
$np = str_replace($_SERVER['DOCUMENT_ROOT'],'',$np);
$location.= $np;
if ((isset($pu['query'])) && (strlen($pu['query'])>0)) $location.= '?'.$pu['query'];
}
}

$hs = headers_sent();
if ($hs==false)
{
if ($code==301) header("301 Moved Permanently HTTP/1.1"); // Convert to GET
elseif ($code==302) header("302 Found HTTP/1.1"); // Conform re-POST
elseif ($code==303) header("303 See Other HTTP/1.1"); // dont cache, always use GET
elseif ($code==304) header("304 Not Modified HTTP/1.1"); // use cache
elseif ($code==305) header("305 Use Proxy HTTP/1.1");
elseif ($code==306) header("306 Not Used HTTP/1.1");
elseif ($code==307) header("307 Temporary Redirect HTTP/1.1");
else trigger_error("Unhandled redirect() HTTP Code: $code",E_USER_ERROR);
header("Location: $location");
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
}
elseif (($hs==true) || ($code==302) || ($code==303))
{
// todo: draw some javascript to redirect
$cover_div_style = 'background-color: #ccc; height: 100%; left: 0px; position: absolute; top: 0px; width: 100%;';
echo "
\n";
$link_div_style = 'background-color: #fff; border: 2px solid #f00; left: 0px; margin: 5px; padding: 3px; ';
$link_div_style.= 'position: absolute; text-align: center; top: 0px; width: 95%; z-index: 99;';
echo "
\n";
echo "

Please See: ".htmlspecialchars($location)."

\n";
echo "
\n
\n";
}
exit(0);
}

Friday, October 9, 2009

How send Email using Cakephp, #cakephp, #php, #codignitor, #opensource

I know the title of this post a little bit confusing but let me explain what I want to tell.

You are using CakePHP’s email component and you should set the same information in each time before you send your email like server address, username, password etc.

Just create a new file mailer.php with the following content and drop it into your CakePHP application components folder (I like convention over configuration! ).
App::import('Component', 'Email');
class MailerComponent extends EmailComponent
{
var $from = 'ME ';
var $replyTo = 'noreply@localhost';
var $sendAs = 'both';
var $delivery = 'smtp';
var $xMailer = 'Postman';
var $smtpOptions = array(
'port'=> 25,
'host' => 'serveradress',
'timeout' => 30,
'username' => 'username',
'password' => 'password'
);
}
?>
And right now you have a new component with the name “Mailer” and its server configuration is predefined. You can reuse it without being affected by any kind of mail server change.

You can define a new function inside your controller (_sendEmail() in our case) and make the email sending process more painless.

view sourceprint?
class AnyController extends AppController
{
function contact()
{
if ($this->_sendEmail('Name', 'blabla@fakeemail', 'Grate site!')) {
$this->Session->setFlash(__("Thank you", true));
} else {
$this->Session->setFlash('Damn it!');
}
}

function _sendEmail($name, $email, $message)
{
$this->Mailer->to = 'info@localhost';
$this->Mailer->subject = __("Site Contact", true);
$this->Mailer->template = 'contact';

$this->set('name', $name);
$this->set('email', $email);
$this->set('message', $message);
$this->Mailer->send();

$this->log( $this->Mailer->subject . ' -> Name:'. $name .' | E-posta: '. $email .' | Message: '. $message .' | smtp error: '. serialize($this->Mailer->smtpError) );

return $this->Mailer->smtpError ? false : true;
}
}