Complex Validation with classes or callback methods February 11, 2006
Posted by rossoft in CakePHP.6 comments
Complex Validation
——————–
There are several implementations of custom validation made by CakePHP users. I just show you another one. Some of the stuff is from CakeBaker and other cakers solution
My solution has these features:
* Each field can be validated for more than one validator. You can show a different message for know what validator has failed.
* A validator can be: a regular expression, a callback method of your model or a validator subclass. With validator subclasses you can share a custom validator between apps easily (simply put a file in the validators folder)
1. Edit the /app/app_model.php (if not exists, copy from /cake/app_model.php)
Edit and merge this with your file:
vendor('validator'. DS. 'validator');
class AppModel extends FixModel
{
function invalidFields($data)
{
return validator_invalidFields($this,$data);
}
}
2. Download this and uncompress into your /vendors folder. You will get a validator folder.
3. Copy to the file /app/helpers/error.php
<?php
class ErrorHelper extends Helper
{
function showMessage($target)
{
list($model, $field) = explode('/', $target);
if (isset($this->validationErrors[$model][$field]))
{
return sprintf('<div class="error_message">%s</div>',
$this->validationErrors[$model][$field]);
}
else
{
return null;
}
}
}
?>
4. Ready to go!! Example of usage:
var $validate=
array(
'empresa'=>array(array(VALID_NOT_EMPTY,'This is not optional'), array(VALID_UNIQUE,'This value is repeated')),
'responsable'=>array(array(VALID_NOT_EMPTY, 'This is not optional')),
'other'=>array(VALID_UNIQUE,'Error in this field',array(12,42))
);
In the example, the code field, needs to be a unique field not empty.
VALID_NOT_EMPTY is a CakePHP generic regexp. VALID_UNIQUE is a custom class validator (is the file /vendors/validator/validators/unique.php). Have a look at it for the syntax of custom classes. If you create the class MyownValidator, simply put the file myown.php in this folder, and the constant VALID_MYOWN will be automatically populated in all models for it’s use.
In the example, the other field, is validated with the validator VALID_BETWEEN. This class validator not exists (the file /vendors/validator/validators/between.php doesn’t exists). Then, you will get a notice because the constant VALID_BETWEEN is not defined. This is a custom callback function. In your model or app_model, define the constant like this:
define(’VALID_BETWEEN’,'VALID_BETWEEN’);
Then, in your model, create this function (is equivalent of a BetweenValidator class, the method has precedence)
function BetweenValidator($data,$field_name, $validator_params)
{
if (..) return true;
else return false;
}
Then in the example, this function will be called with the $data array, $field_name=’other’ and $validator_params=array(12,42).
(If you don’t want to define the VALID_BETWEEN constant, simply put the value ‘VALID_BETWEEN’ in the $validate array )
5. Show the error messages in the view
a) Include the error helper in your controller (var $helpers=array(’xxx’,'yyy’,'Error’)
b) Use this in your view:
<?=$error->showMessage($elementName)?>
$elementName is in the form Model/field
6. Test it !
Gzipping the html February 11, 2006
Posted by rossoft in CakePHP.8 comments
For improving the transfer of your page, you can compress it using gzip. Apache already supports that by a module, but php can do it for you by code if you don't have control of your web server.
Simply, put this somewhere before starting the output:
ob_start('ob_gzhandler');
Micro component (I love little components) that do this:
<?php
/*
* GzipOutput component.
* Facilitate sending gz-encoded data to web browsers that support compressed web pages.
* You can test gzip compression of your site in the url
* http://www.whatsmyip.org/mod_gzip_test/
*
* @author RosSoft
* @version 0.3
* @license MIT
*
*/
class GzipOutputComponent extends Object
{
function startup(&$controller)
{
static $once=true;
//only send gzip if browser supports it
$encodings=env('HTTP_ACCEPT_ENCODING');
$encodings = explode(',', strtolower(preg_replace('/s+/', '', $encodings)));
if ( $once && in_array('gzip', $encodings))
{
$once=false;
ob_start('ob_gzhandler');
}
}
}
?>
Problems under IIS February 11, 2006
Posted by rossoft in CakePHP.add a comment
I have IIS in my webhost provider… that sucks but that webhosting is cheap.
The IIS doesn’t have mod_rewrite, and I don’t have any configuration control.
Also, an url like this fails:
www.xxx.com/index.php/controller/action , so I have to hack the files a little to change the url to /index.php?url=/controller/action
This is a dirty copy-paste from the trac of cakephp
OK My modifications: This is for IIS without mod rewrite, and document root set to the root of the cake installation. In the wiki there is a tutorial for making it work installing a mod rewrite (My web provider doesn't permit installing mod's)
At the beginning of core.php, add the line:
define('SERVER_APACHE',false);
then replace the line define('BASE_URL',xxx) by:
if (SERVER_APACHE) {
define ('BASE_URL', env('SCRIPT_NAME') ); }
else {
define ('BASE_URL', env('SCRIPT_NAME') . '?url='); }
The file index.php of the root folder of the installation:
define ('APP_DIR', 'app'); define ('DS', DIRECTORY_SEPARATOR); define ('ROOT', dirname(FILE).DS);
require_once ROOT.'cake'.DS.'basics.php'; require_once ROOT.APP_DIR.DS.'config'.DS.'core.php'; require_once ROOT.'cake'.DS.'config'.DS.'paths.php';
$uri = setUri();
/**
* As mod_rewrite (or .htaccess files) is not working, we need to take
care
* of what would normally be rewritten, i.e. the static files in
/public
*/
if ($uri === '/' $uri === '/index.php') {
$_GET['url'] = '/'; require_once ROOT.APP_DIR.DS.WEBROOT_DIR.DS.'index.php'; }
else {
$elements = explode('/index.php', $uri); if(!empty($elements[1])) {
$path = $elements[1]; if (! SERVER_APACHE) {
$path=substr($path,5);
$path=split('&',$path); $path=$path[0];
}
} else {
$path = '/';
}
$_GET['url'] = $path;
require_once ROOT.APP_DIR.DS.WEBROOT_DIR.DS.'index.php'; }
Finally, in AppController?.php , add the functions:
function referer() {
if (env('HTTP_REFERER') && FULL_BASE_URL ) {
$base = FULL_BASE_URL . $this->webroot; if (strpos(env('HTTP_REFERER'), $base) == 0) {
$referer=substr(env('HTTP_REFERER'), strlen($base)-3); if (! SERVER_APACHE) {
if (strpos($referer,"?url=")===0) {
$referer=substr($referer,5);
} if (strpos($referer,"&")) {
$referer=explode("&",$referer); $referer=$referer[0];
}
} return $referer;
} else return '/';
} else return '/';
}
function redirect ($url) {
$this->autoRender = false; if(strpos($url, '/') !== 0) {
$url = '/'.$url;
} if (function_exists('session_write_close')) {
session_write_close();
} if (SERVER_APACHE) {
header ('Location: '.$this->base.$url);
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . $this->base . $url);
}
}
Creating pdf’s easy February 11, 2006
Posted by rossoft in CakePHP.5 comments
I have a mini-tutorial for creating pdf’s easy with cakephp.
Sending email through SMTP February 11, 2006
Posted by rossoft in CakePHP.3 comments
In my webhost provider, the function mail() doesn’t work. I have to send email through a SMTP, but PHP doesn’t support this directly (only in Windows, and you have to touch the php.ini)
1. Copy the following code to /app/controllers/components/email.php
<?php /* * EmailComponent for sending email through a SMTP server * * @author rossoft * @version 0.1 * @license MIT * */
//EDIT THIS PARAMS
define('CONFIG_SMTP_HOST','localhost');
define('CONFIG_SMTP_USER','rossoft');
define('CONFIG_SMTP_PASS','password');
define('CONFIG_SMTP_EMAIL','rossoft@myhost.com');
define('PHPMAILER_SUBDIR','phpmailer' . DS);vendor(PHPMAILER_SUBDIR. 'class.phpmailer');
class EmailComponent extends Object
{
var $thtml;
var $layout='email';
var $to = null;
var $controller;
var $from = CONFIG_SMTP_EMAIL;
var $subject = null;
var $cc = null;
var $bcc = null;
var $formatoHTML=false; //false ->texto, true->html
var $charset="utf-8";
function startup(&$controller)
{
$this->controller =& $controller;
}
function send()
{
return $this->_sendmail($this->to, $this->subject, $this->_message());
}
/**
* Envia el email
* @param array $to Destinatarios. Cada elemento puede ser un dirección o un array nombre-dirección
* @param string $subject Asunto del mensaje
* @param string $mensaje El mensaje
* @param string $from Remitente.
*/
function _sendmail($to,$subject,$mensaje,$from='')
{
$mail = new PHPMailer();
$mail->PluginDir = VENDORS .PHPMAILER_SUBDIR ;
$mail->SetLanguage('en',VENDORS .PHPMAILER_SUBDIR);
$mail->CharSet= $this->charset;
$mail->IsSMTP(); // send via SMTP
$mail->Host = CONFIG_SMTP_HOST; // SMTP servers
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Username = CONFIG_SMTP_USER; // SMTP username
$mail->Password = CONFIG_SMTP_PASS; // SMTP password
if ($from =='') $mail->From = CONFIG_SMTP_EMAIL;
else $mail->From = $from;
$mail->FromName = '';
foreach ($to as $address)
{
$mail->AddAddress($address);
}
//$mail->WordWrap = 50; // set word wrap
//$mail->AddAttachment("/var/tmp/file.tar.gz"); // attachment
//$mail->AddAttachment("/tmp/image.jpg", "new.jpg");
$mail->IsHTML($this->formatoHTML); // send as HTML
$mail->Subject = $subject;
$mail->Body = $mensaje;
//$mail->AltBody = "This is the text-only body";
return($mail->Send());
}
function _message()
{
ob_start();
$layout_backup=$this->controller->layout;
$this->controller->layout=$this->layout;
$this->controller->render($this->thtml);
$content= ob_get_clean();
$this->controller->layout=$layout_backup;
return $content;
}
}
?>
Don’t forget to edit the params at the top of the file
2. Download this class and put the files class.phpmailer.php class.smtp.php phpmailer.lang-en.php into /vendors/phpmailer
3. Include the email component
4. Example of usage.
In your action put:
<pre>
function myaction()
{
$this->set(’data’,$this->params['data']);//set $login variable
$this->email->controller=$this;
$this->email->thtml = ‘accept_email’;
$this->email->to = array($this->params['data']['Customer']['email']);
$this->email->subject = ‘hello !’;
return($this->email->send());
}
</pre>
Then create the file /app/views/mycontroller/accept_email.thtml , this is a normal view file and will be the body of your mail.
Mysql and UTF-8 February 11, 2006
Posted by rossoft in CakePHP.7 comments
After updating my mysql database to utf8, I had several problems with the encoding. Finally I discovered the solution: You must specify the encoding after the connection to the database through sql. Somewhere in your code you have to put the instruction:
mysql_query(”SET NAMES ‘utf8′”);
I have done a simple component for it (this is not a controller issue, but model issue, but a before filter in my AppModel dislikes me… and doesn’t exist any type of components in the model so…)
class MysqlComponent extends Object
{
function startup(&$controller)
{
//Changes the encoding of mysql to UTF-8
mysql_query("SET NAMES 'utf8'");
}
}
Cool flash effect February 11, 2006
Posted by rossoft in CakePHP.3 comments
I show the flash messages by setting the flash session variable, then in my layout I have to show that message.
I wanted to display that message with the highlight effect (Effect.Highlight) after the page is loaded.
1. create the file /webroot/js/highlight.js
function highlight_message()
{
var id="flash_message";
var elemento=document.getElementById(id);
if (elemento.innerHTML.length>0)
{
new Effect.Highlight(id);
}
Event.stopObserving(window, 'load', highlight_message);
}
Event.observe(window, 'load', highlight_message, false);
This registers a window.onLoad function for highlighting the message after the page is loaded.
2. We will overwrite the session component (it is a little hack)
Change the following code from the file session.php of /app/controllers/components/session.php (if this file doesn’t exists, copy it from /cake/controllers/components
function setFlashError($flashMessage)
{
$this->write('Message.flash_error', $flashMessage);
}
function flash()
{
if($this->check('Message.flash'))
{
echo '
<div>'.$this->read('Message.flash').'</div>
';
$this->del('Message.flash');
}
elseif($this->check('Message.flash_error'))
{
echo '
<div>'.$this->read('Message.flash_error').'</div>
';
$this->del('Message.flash_error');
}
else
{
echo '
<div></div>
';
return false;
}
}
There are 2 changes. First, flash function will return always a div with id=”flash_message”. It will be empty or not.
Second, a new function setFlashError($flashMessage) for setting a error message (this will change the style of the error in the view by changing the class atribute from Message.flash to Message.flashError)
3. Put this in your layout file (by default the file is /app/views/layouts/themes/default.thtml) where you want to place the error message.
<?php if (isset($this->controller->Session)) $this->controller->Session->flash(); else echo '<div id="flash_message"></div>'; ?>
4. Include the component ’session’ in your controller
5. Use these functions in your controller
$this->Session->setFlash($mensaje); //for a success message
$this->Session->setFlashError($mensaje); //for an error message
Calling a helper from a component or controller February 11, 2006
Posted by rossoft in CakePHP.3 comments
Someone asked me in the #cakephp on irc.freenode.net about calling a method of a helper from a component.
I think that this is a bad practice, but sometimes these hacks makes your life easier, and CakePHP wants it so…
I hacked the OutputComponent of rdBloggery (and updated to RC4 components model, making use of the startup method.
Put these code on /app/controllers/components/output.php (the other content not related to the helper-part is omitted…)
class OutputComponent extends Object {
var $view;
var $controller;
function startup(&$controller)
{
$this->controller=& $controller;
$this->view =& new View($controller);
}
function & returnHelper($helper)
{
$loaded=array();
$loadedHelpers=& $this->view->_loadHelpers($loaded, array($helper));
$helper=& $loadedHelpers[$helper];
if(isset($helper->helpers) && is_array($helper->helpers))
{
foreach($helper->helpers as $subHelper)
{
$helper->{$subHelper} =& $loadedHelpers[$subHelper];
}
}
return $helper;
}
}
Then, in your controller / component, include the component:
var $components=array('xxx','yyy','output');
Finally, use this in your controller / component:
$helper = $this->output->returnHelper('myhelper');
$helper->myfunc($param);
CakePHP February 11, 2006
Posted by rossoft in CakePHP.add a comment
Hi! this is my first blog. It is about CakePHP. Here you will find my solutions to the problems that I encounter.
I am happy to see you ![]()
Keep reading this blog!