![]() |
|
Code snippets for symfony 1.x |
|
My alternative for sfFunctionCache, which can work with objects/classes. Useful for caching external data, like rss feeds etc.
class myFunctionCache extends sfFileCache { public function __construct($dir=null) { if (is_null($dir)) $dir = SF_ROOT_DIR.'/cache/'.SF_APP.'/function'; parent::__construct($dir); } public function call () { $arguments = func_get_args(); // check if first argument is array (object/class function call) if (is_array($arguments[0])) $id = md5(serialize(array_merge(array(0=>$arguments[0][1], 1=>(is_object($arguments[0][0]) ? get_class($arguments[0][0]) : $arguments[0][0]), array_slice($arguments_serialize=$arguments, 1))))); else $id = md5(serialize($arguments)); $data = $this->get($id); if ($data !== null) { $array = unserialize($data); $output = $array['output']; $result = $array['result']; } else { $target = array_shift($arguments); ob_start(); ob_implicit_flush(false); $result = call_user_func_array($target, $arguments); $output = ob_get_clean(); $this->set($id, '', serialize(array('output'=>$output, 'result'=>$result))); } if (!empty($output)) echo($output); return $result; } }
In action:
$cache = new myFunctionCache(); $rss_items = $cache->call(array(&$rss, 'getItems'), 'http://www.symfony-project.com/weblog/rss');
router eigrp 200 network 10.10.10.0 0.0.0.255 no auto-summary
You may disregard this snippet if you are working with a recent version of symfony. Installing symfony is now very straightforward, even from subversion.
I had to install symfony via subversion several times and it is a pain because the paths to several key files are to be manually changed in the files coming from the svn install. I prefer the subversion install over the pear beta install because i often have to fix bugs and patch things here and there in the symfony code.
1. svn checkout the symfony code somewhere on your server
2. Choose two distinct folder accessible from php where you will put the data and lib folders. Let us call those folders «DATA» and «LIB».
3. Make symbolic links of the data and lib directories inside those two folders. The following command is to be issued from the freshly checked out symfony folder:
ln -s data «DATA»/symfony ln -s lib «LIB»/symfony
4. Put the following file inside the bin folder:
#!/bin/sh PEAR_DIR= «PAKE» #put here the path to pake.php DATA_DIR= «DATA» # here is the path to the alias of the symfony data directory SYMFONY_DIR= «LIB» # here is the path to the alias of the symfony lib directory SVN_VERSION=svn # this does not matter sed -i '' -e "s#@PEAR-DIR@#${SYMFONY_DIR}/bin#g" symfony.sh #sed -i '' -e "s#@PEAR-DIR@#${PEAR_DIR}#g" symfony.bat sed -i '' -e "s#@PEAR-DIR@#${PEAR_DIR}#g" -e "s#@DATA-DIR@#${DATA_DIR}#g" -e "s#@SYMFONY-VERSION@#${SVN_VERSION}#g" symfony.php sed -i '' -e "s#@PEAR-DIR@#${PEAR_DIR}#g" -e "s#@DATA-DIR@#${DATA_DIR}#g" -e "s#@SYMFONY-VERSION@#${SVN_VERSION}#g" ../../lib/pear.php
5. Execute that file. You should be ready to use symfony
ln commands could be incorporated inside the script.bin directory was moved inside the data directory. The new version of the file above should work as well as before.Here is an example of obtaining a custom set of select columns using Propel Criteria, as opposed to using a custom SQL statement. The use of distinct is also demonstrated.
// Set up empty select $c = new Criteria(); $c->clearSelectColumns(); // Read distinct(owningdepot) from the load table... $c->addSelectColumn(TmsLoadPeer::OWNINGDEPOT); $c->addGroupByColumn(TmsLoadPeer::OWNINGDEPOT); $c->setDistinct(); // ...which are IN the provided list $c->add(TmsLoadPeer::LOAD_ID, $loadIds, Criteria::IN); $depots = TmsLoadPeer::doSelectRS($c); // Then return an array of depots $arrDep = array(); foreach ($depots as $depot) { $arrDep[] = $depot[0]; }
With this snippet we can implement the following functionalities from the global configuration file config/config.php:
Access control to the applications in certain environments. For example, disable access in the environment of development from production server.
IP access control to certain applications of the project. For example, to protect backend or administration zones of the project.
To have several global configuration files of config/config.php according to the environment in which we are. For example, to define different constants for each environment.
I developed a mini-library (config/config.lib.php) to include and use in the global config file config/config.php.
<?php /** * IP access control to an environment * * @param string $env environment name * @param array $ips IPs that has access * @param string $clientip client IP */ function envCorrecte ($env,$ips,$clientip) { if (SF_ENVIRONMENT==$env) { $acces=0; foreach($ips as $ip) { $ipclient=substr($clientip,0,strlen($ip)); if ($ipclient==$ip) { $acces=1; } } if ($acces==0) { echo "Keep away! this is not a public environment."; exit; } } } /** * IP access control to an application of the symfony project * * @param array $apps no public applications * @param array $ips IPs that has access * @param string $clientip client IP */ function appCorrecte ($apps,$ips,$clientip) { // solve problem with key '0' in array $apps_aux[0]=''; $apps = $apps_aux + $apps; // if (array_search(SF_APP,$apps)!=false) { $acces=0; foreach($ips as $ip) { $ADR=$HTTP_SERVER_VARS['REMOTE_ADDR']; $ipclient=substr($clientip,0,strlen($ip)); if ($ipclient==$ip) { $acces=1; } } if ($acces==0) { echo "Keep away! ".SF_APP." is not a public application."; exit; } } } ?>
Finally config/config.php file can be like this:
<?php include("config.lib.php"); /** * IP access control to 'env' and 'int' environments */ $ip_dev=array("10.138.0.","192.168."); $ip_int=array("10.138.0.","192.168."); envCorrecte('env',$ip_env,$HTTP_SERVER_VARS['REMOTE_ADDR']); envCorrecte('int',$ip_int,$HTTP_SERVER_VARS['REMOTE_ADDR']); /** * IP access control to backend applications */ $ip_apps=array("10.138.0.","192.168.","w.x.y.z"); $apps=array('myapp_1','myapp_2','myapp_n'); appCorrecte($apps,$ip_apps,$HTTP_SERVER_VARS['REMOTE_ADDR']); /** * Custom config.php file for each environment */ include("config.".SF_ENVIRONMENT.".php"); /** * Common config.php file for all environments */ define("example","content1"); ?>
select_date_tag is not available in 'rich' version. Waiting for a real enhancement, this is my workaround.
This is the RichDateHelper.php file:
<?php use_helper('Form'); function rich_select_date_tag($name, $value = null, $options = array(), $html_options = array()) { $context = sfContext::getInstance(); if (isset($options['culture'])) { $culture = $options['culture']; unset($options['culture']); } else { $culture = $context->getUser()->getCulture(); } // register our javascripts and stylesheets $langFile = '/sf/js/calendar/lang/calendar-'.strtolower(substr($culture, 0, 2)); $jss = array( '/sf/js/calendar/calendar', is_readable(sfConfig::get('sf_symfony_data_dir').'/web/'.$langFile.'.js') ? $langFile : '/sf/js/calendar/lang/calendar-en', '/sf/js/calendar/calendar-setup', ); foreach ($jss as $js) { $context->getResponse()->addJavascript($js); } $js = ' function updateSelect(cal) { var date = cal.date; var selectMonth = document.getElementById("'.get_id_from_name($name).'_month"); selectMonth.selectedIndex = date.getMonth(); var selectDay = document.getElementById("'.get_id_from_name($name).'_day"); selectDay.selectedIndex = (date.getDate() - 1); var selectYear = document.getElementById("'.get_id_from_name($name).'_year"); selectYear.selectedIndex = (date.getFullYear() - '.$options['year_start'].'); } document.getElementById("trigger_'.$name.'").disabled = false; Calendar.setup({ inputField : "'.$name.'_rich_sel_date", ifFormat : "%Y-%m-%d", button : "trigger_'.$name.'", singleClick : true, onUpdate : updateSelect, showsTime : false, range : ['.$options['year_start'].', '.$options['year_end'].'], showOthers : false, cache : 1, weekNumbers : false, firstDay : 1 }); '; $html = select_date_tag($name, $value, $options, $html_options); // calendar button $calendar_button = '...'; $calendar_button_type = 'txt'; if (isset($options['calendar_button_img'])) { $calendar_button = $options['calendar_button_img']; $calendar_button_type = 'img'; unset($options['calendar_button_img']); } else if (isset($options['calendar_button_txt'])) { $calendar_button = $options['calendar_button_txt']; $calendar_button_type = 'txt'; unset($options['calendar_button_txt']); } if ($calendar_button_type == 'img') { $html .= image_tag($calendar_button, array('id' => 'trigger_'.$name, 'style' => 'cursor: pointer')); } else { $html .= content_tag('button', $calendar_button, array('type' => 'button', 'disabled' => 'disabled', 'onclick' => 'return false', 'id' => 'trigger_'.$name)); } // add javascript $html .= content_tag('script', $js, array('type' => 'text/javascript')); $html .= '<div id="'.$name.'_rich_sel_date" style="display: inline;"></div>'; return $html; }
We wanted to use a 'propel-insert-sql' in our acceptance tests suite to clear DB before every test reducing interferences. We all learned here http://www.symfony-project.com/snippets/snippet/16 how to call a Pake task from our PHP code. To get a quiet 'propel-insert-sql' task letting 'test' task be verbose and reporting test results we must add a method to the pakeTask class in pakeTask.class.php file:
public function setVerbose() { $this->verbose = false; }
and edit sfPakePropel.php file to make 'propel-insert-sql' task quiet:
function run_propel_insert_sql($task, $args) { $task->setVerbose(); _call_phing($task, 'insert-sql'); }
This way we have a lot quiter acceptance test suite and a clean DB whenever we want.
A CNPJ and CPF validator for brazilian users...
Just add this in the module/lib/myCpfValidator.class.php path...
//Symfony integration as sfValidator of CPF and //CNPJ //Date - Jul 11, 2006 //Author - Lucas Peres (mysyfy@gmail.com) //CNPJ and CPF Validator //Author: Marcelo Bom Jardim //ABOUT //This PHP script will validate CNPJ and CPF //number by checking there length //and some other validations. class myCpfValidator extends sfValidator { private function validaCPF($cpf) { $soma = 0; if (strlen($cpf) <> 11) return false; // Verifica 1º digito for ($i = 0; $i < 9; $i++) { $soma += (($i+1) * $cpf[$i]); } $d1 = ($soma % 11); if ($d1 == 10) { $d1 = 0; } $soma = 0; // Verifica 2º digito for ($i = 9, $j = 0; $i > 0; $i--, $j++) { $soma += ($i * $cpf[$j]); } $d2 = ($soma % 11); if ($d2 == 10) { $d2 = 0; } if ($d1 == $cpf[9] && $d2 == $cpf[10]) { return true; } else { return false; } } private function validaCNPJ($cnpj) { if (strlen($cnpj) <> 14) return false; $soma = 0; $soma += ($cnpj[0] * 5); $soma += ($cnpj[1] * 4); $soma += ($cnpj[2] * 3); $soma += ($cnpj[3] * 2); $soma += ($cnpj[4] * 9); $soma += ($cnpj[5] * 8); $soma += ($cnpj[6] * 7); $soma += ($cnpj[7] * 6); $soma += ($cnpj[8] * 5); $soma += ($cnpj[9] * 4); $soma += ($cnpj[10] * 3); $soma += ($cnpj[11] * 2); $d1 = $soma % 11; $d1 = $d1 < 2 ? 0 : 11 - $d1; $soma = 0; $soma += ($cnpj[0] * 6); $soma += ($cnpj[1] * 5); $soma += ($cnpj[2] * 4); $soma += ($cnpj[3] * 3); $soma += ($cnpj[4] * 2); $soma += ($cnpj[5] * 9); $soma += ($cnpj[6] * 8); $soma += ($cnpj[7] * 7); $soma += ($cnpj[8] * 6); $soma += ($cnpj[9] * 5); $soma += ($cnpj[10] * 4); $soma += ($cnpj[11] * 3); $soma += ($cnpj[12] * 2); $d2 = $soma % 11; $d2 = $d2 < 2 ? 0 : 11 - $d2; if ($cnpj[12] == $d1 && $cnpj[13] == $d2) { return true; } else { return false; } } public function execute (&$value, &$error) { if($this->getParameter('tipo') == 'cpf') { if(!$this->validaCPF($value)) { $error = $this->getParameter('msg_error'); return false; } } else if($this->getParameter('tipo') == 'cnpj') { if(!$this->validaCNPJ($value)) { $error = $this->getParameter('msg_error'); return false; } } else { $error = $this->getParameter('msg_error'); return false; } return true; } public function initialize ($context, $parameters = null) { // initialize parent parent::initialize($context, $parameters); // set defaults $this->setParameter('msg_error', 'Invalid input'); $this->getParameterHolder()->add($parameters); return true; } }
Then at the module/validate.yml add:
names: [...] cpf: required: Yes required_msg: O campo CPF é requerido validators: cpfValidator cpfValidator: class: myCpfValidator param: tipo: cpf msg_error: CPF inválido
This one is a port of the Imagetext plugin for Smarty. So as I won't include the credit in this snippet please check them in the Smarty plugin itself here.
In order to make it work, this is what you need : - A 'fonts' folder in your projects' data directory, in which you copy the .ttf files you need - The following helper :
function imagetext($text,$styleName=null,$params=array()) { if(!$styleName){ $styleName='default'; } if (empty($text)) { return; } // Which style is in use $style=sfConfig::get('app_imagetext_styles'); $style=$style[$styleName]; // Param values overwrite style values foreach ($params as $key=>$value) $style[$key] = $value; // Error handling if (empty($style['font'])) { throw new sfViewException("imagetext: missing 'font' parameter"); return; } if (empty($style['size'])) { throw new sfViewException("imagetext: missing 'size' parameter"); return; } if (empty($style['bgcolor'])) { $style['bgcolor'] = 'FFFFFF'; } if (empty($style['fgcolor'])) { $style['fgcolor'] = '000000'; } ### Preferences $cacheDir=sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'imagetext'.DIRECTORY_SEPARATOR; $cacheUrl='imagetext/'; $fontDir=sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR; $text = preg_replace("=<br( /)?>=i", "\n", $text); // Which font is in use $font = $fontDir.$style['font']; // Hash of text and all parameters for the cache function $hash = md5(implode('',$style).$text); // The url of the created image $imgFile = $cacheDir.$styleName.'_'.$hash.'.'.$style['format']; $imgUrl = $cacheUrl.$styleName.'_'.$hash.'.'.$style['format']; ### Use cached image if available if (file_exists($imgFile) && @$style['dev'] != true && @$style['dynamic'] != true) if (@$style['urlonly'] == 'true') return $imgUrl; else return @$style['prehtml'].image_tag($imgUrl,array('style'=>'border: 0 px solid #00ff00','alt'=>preg_replace("=\r\n|\r|\n|\t=", ' ', htmlspecialchars($text)))).@$style['posthtml']; ### otherwise create it // Function to get a color handler of hex values if (!function_exists('fromhex')) { function fromhex($image,$string) { sscanf($string, "%2x%2x%2x", $red, $green, $blue); return ImageColorAllocate($image,$red,$green,$blue); } } ### create a four times larger image to improve kerning // The multiplier. The bigger the better the kerning and the typeface, but the slower the creation $multi = 4; // If "pixelfont" don´t use multiplier if ($style['pixelfont'] == 1) $multi = 1; // Calculate measures of image $bbox = imagettfbbox ($style['size']*$multi, 0, $font, $text); $xcorr = 0-$bbox[6]; // northwest X $ycorr = 0-$bbox[7]; // northwest Y $box['left'] = $bbox[6]+$xcorr+$style['x']*$multi; $box['height'] = abs($bbox[5])+abs($bbox[1]); $box['width'] = abs($bbox[2])+abs($bbox[0])+$style['x']*$multi; $box['top'] = abs($bbox[5]); // Create the big image $im = imagecreate ($box['width'], $box['height']); $bgcolor = fromhex($im,$style['bgcolor']); $fgcolor = fromhex($im,$style['fgcolor']); if ($style['pixelfont'] == 1) $fgcolor = -$fgcolor; imagettftext ($im, $style['size']*$multi, 0, $box['left'], $box['top'], $fgcolor, $font, $text); // Sample down the big image $width = $style['width']+$style['addx']; $height = $style['height']+$style['addy']; // Overwrite when height oder width is given if (empty($style['width'])) $width = $box['width']/$multi+$style['addx']+$style['x']; if (empty($style['height'])) $height = $box['height']/$multi+$style['addy']+$style['y']; $ds = imagecreatetruecolor ($width, $height); $bgcolor2 = fromhex($ds,$style['bgcolor']); imageFill($ds,0,0,$bgcolor2); imagecopyresampled($ds,$im,0,$style['y'],0,0,$box['width']/$multi, $box['height']/$multi,$box['width'], $box['height']); imagetruecolortopalette($ds,0,256); imagepalettecopy($ds,$im); ImageColorTransparent($ds,$bgcolor); // write whereto? if ($style['format'] == 'gif') ImageGIF ($ds,$imgFile); else ImagePNG ($ds,$imgFile); ImageDestroy ($im); ImageDestroy ($ds); // and display if ($style['dev']) $border = 1; else $border = 0; if ($style['urlonly'] == 'true') return $imgUrl; else return $style['prehtml'].image_tag($imgUrl,array('style'=>'border: '.$border.'px solid #00ff00','alt'=>preg_replace("=\r\n|\r|\n|\t=", ' ', htmlspecialchars($text)))).$style['posthtml']; }
As you can see in this code styles can (at least 'default' MUST be) be configured in app.yml. This is an example style config :
imagetext:
styles:
default:
font: hockey.ttf
size: 18
format: png
So now you can use the helper in your templates :
<?php use_helper('imageText') ?> <? echo imagetext('This is my title') ?> <p>Some blah blah</p> <? echo imagetext('This is another headline style','anotherstyle') ?>
This helper uses GD so depending on which version you have installed, you might or might not handle PNG or GIF.