![]() |
|
Snippets |
|
These two js functions do the job while using jQuery with admin double list
function double_list_move(src, dest) { var L = $(src).children(); $(L).each(function(i){ if(L[i].selected){ $(dest).append('<option value="'+$(L[i]).val()+'">'+ $(L[i]).text()+'</option>'); $(L[i]).remove(); } }); } function double_list_submit() { var sel = $("form").find("select.sf_admin_multiple-selected"); var C = $(sel).children(); $(C).each( function(i){ if(!C[i].selected) C[i].selected=true; } ); }
Enjoy it.
format a phone number with 7, 10, or 11 digits. also can convert phone number letters to numbers
lib/helpers/PhoneHelper.php
<?php function format_phone($phone = '', $convert = false, $trim = true) { // If we have not entered a phone number just return empty if (empty($phone)) { return ''; } // Strip out any extra characters that we do not need only keep letters and numbers $phone = preg_replace("/[^0-9A-Za-z]/", "", $phone); // Do we want to convert phone numbers with letters to their number equivalent? // Samples are: 1-800-TERMINIX, 1-800-FLOWERS, 1-800-Petmeds if ($convert == true) { $replace = array('2'=>array('a','b','c'), '3'=>array('d','e','f'), '4'=>array('g','h','i'), '5'=>array('j','k','l'), '6'=>array('m','n','o'), '7'=>array('p','q','r','s'), '8'=>array('t','u','v'), '9'=>array('w','x','y','z')); // Replace each letter with a number // Notice this is case insensitive with the str_ireplace instead of str_replace foreach($replace as $digit=>$letters) { $phone = str_ireplace($letters, $digit, $phone); } } // If we have a number longer than 11 digits cut the string down to only 11 // This is also only ran if we want to limit only to 11 characters if ($trim == true && strlen($phone)>11) { $phone = substr($phone, 0, 11); } // Perform phone number formatting here if (strlen($phone) == 7) { return preg_replace("/([0-9a-zA-Z]{3})([0-9a-zA-Z]{4})/", "$1-$2", $phone); } elseif (strlen($phone) == 10) { return preg_replace("/([0-9a-zA-Z]{3})([0-9a-zA-Z]{3})([0-9a-zA-Z]{4})/", "($1) $2-$3", $phone); } elseif (strlen($phone) == 11) { return preg_replace("/([0-9a-zA-Z]{1})([0-9a-zA-Z]{3})([0-9a-zA-Z]{3})([0-9a-zA-Z]{4})/", "$1($2) $3-$4", $phone); } // Return original phone if not 7, 10 or 11 digits long return $phone; }
A symfony helper for the stickman labs accordion http://www.stickmanlabs.com/accordion/
hopefully plugin oneday
<?php use_helper('Tag', 'Javascript'); function accordion($container, $options = array()){ $response = sfContext::getInstance()->getResponse(); $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/prototype'); $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/effects'); $response->addJavascript('accordion', 'last'); $options = _parse_attributes($options); $on_load = (isset($options['on_load']) && $options['on_load'] == false) ? false : true; if(isset($options['use_stylesheet']) && $options['use_stylesheet']==true) $response->addStylesheet('accordion'); $output= ''; //onLoad $output .= $on_load ? "Event.observe(window, 'load', function() {" : ''; //new accordion $output .= "var accordion_$container = new accordion ('$container', "; $accordion_options = array(); //speed if (isset($options['resize_speed'])) $accordion_options['resizeSpeed'] = $options['resize_speed']; //classes if(isset($options['toggle']) || isset($options['toggle_active']) || isset($options['content'])){ if(isset($options['toggle'])) $accordion_options['classNames']['toggle'] = "'{$options['toggle']}'"; if(isset($options['toggle_active'])) $accordion_options['classNames']['toggleActive'] = "'{$options['toggle_active']}'"; if(isset($options['content'])) $accordion_options['classNames']['content'] = "'{$options['content']}'"; $accordion_options['classNames'] = _options_for_javascript_no_sort($accordion_options['classNames']); } //size if(isset($options['height']) || isset($options['width'])){ if(isset($options['height'])) $accordion_options['defaultSize']['height'] = $options['height']; if(isset($options['width'])) $accordion_options['defaultSize']['width'] = $options['width']; $accordion_options['defaultSize'] = _options_for_javascript_no_sort($accordion_options['defaultSize']); } //direction if (isset($options['direction'])) $accordion_options['direction'] = "'{$options['direction']}'"; //event if (isset($options['on_event'])) $accordion_options['onEvent'] = "'{$options['on_event']}'"; $output .= _options_for_javascript_no_sort($accordion_options); //new accordion end $output .= ");"; if(isset($options['activate'])){ $number = $options['activate']; $output .= "accordion_$container.activate($$('#$container .{$options['toggle']}')[$number]);"; } //onLoad $output .= $on_load ? "});" : ''; return javascript_tag($output); } function _options_for_javascript_no_sort($options) { $opts = array(); foreach ($options as $key => $value) { $opts[] = "$key:$value"; } return '{'.join(', ', $opts).'}'; }
Hi, this is my first snippet (in my first Symfony project), so I hope this is useful and not boring for you. I show you my code to solve a problem: how to filter an admin_check_list using a criteria.
In my project I have in the schema also this tables:
role:
type: { primaryKey: true, type: char }
descritpion: { type: varchar(50), required: true }
user:
id:
username: { type: varchar(100), index: unique, required: true }
role_type: { type: char, foreignTable: role, foreignReference: type, required: true }
course:
id:
name: { type: varchar(255), required: true }
research_proposal: { type: longvarchar }
course_teacher:
course_id:
user_id:
Little explanation: Each user have a role. Each course can have more teacher; each teacher is an user with "T" role_type.
In the generator.yml I can write
edit:
fields:
course_teachers: { type: admin_check_list, params: through_class=CourseTeacher }
then in the course creation page I have a list of all users (and not a list of the teacher).
To reach my scope I need to override the ObjectAdminHelper. I create a file named ObjectAdminHelper.php and put it into the /lib/helper folder of my Symfony folder. To override successfully an helper it is necessary to overwrite (or write) all its method. So just copy all from the original ObjectAdminHelper.php file and paste it into this new file. The only method we need to override is "_get_object_list($object, $method, $options, $callback)": it use by default the method "_get_propel_object_list" to get the list to show... But if we would like to modify that list how can we do?
function _get_object_list($object, $method, $options, $callback){ $object = get_class($object) == 'sfOutputEscaperObjectDecorator' ? $object->getRawValue() : $object; // the default callback is the propel one if (!$callback) { $callback = _get_option($options, 'callback'); if (!$callback) { $callback = '_get_propel_object_list'; } } return call_user_func($callback, $object, $method, $options); }
This method get an option called "callback" to get the name of the callback method. If a callback method is not present it use the standard "_get_propel_object_list".
So if I would like to get only the teacher (role_type="T") i can write this function (very similar than _get_propel_object_list):
function _get_teacher_from_users($object, $method, $options){ $criteria = new Criteria(); $criteria->add(UserPeer::ROLE_TYPE, "T"); $through_class = _get_option($options, 'through_class'); $objects = sfPropelManyToMany::getAllObjects($object, $through_class, $criteria); $objects_associated = sfPropelManyToMany::getRelatedObjects($object, $through_class, $criteria); $ids = array_map(create_function('$o', 'return $o->getPrimaryKey();'), $objects_associated); return array($objects, $objects_associated, $ids); }
Now you can write all the function you need to filter the lists.
Last step: how can my generator.yml say to the helper which method it must use? Simply modify the course_teacher row:
edit:
fields:
course_teachers: { type: admin_check_list, params: through_class=CourseTeacher callback=_get_teacher_from_users }
I hope this is useful for you (and sorry for my english).
Pierpaolo Cira
There are two big open source rich text editors:
Some people prefer the first, some other the second, but there’s a problem for who likes to use TinyMCE: it lacks of a free file manager/uploader.
What we actually need is to have a TinyMCE installation with a free file manager/uploader, thus we take it from FCKEditor.
This is TinyFCK: a TinyMCE with the FCKEditor’s file manager/uploader, nothing less, nothing more.
Installation of TinyFCK rich text editing is described here. You need to download the editor from the project website (http://p4a.crealabsfoundation.org/tinyfck) and unpack it in a temporary folder. Copy the tiny_fck/ directory into your project web/js/ directory, and define the path to the library and new rich editor class in settings.yml.
all:
.settings:
rich_text_editor_class: TinyFCK
rich_text_js_dir: js/tiny_fck
After that create new text editor class file sfRichTextEditorTinyFCK.class.php in your project or application lib/ folder.
<?php /* * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> * (c) 2007 Eugene Krasichkov <megazlo@megazlo.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * sfRichTextEditorTinyFCK implements the TinyFCK rich text editor. * * <b>Options:</b> * - css - Path to the TinyFCK editor stylesheet * * <b>Css example:</b> * <code> * / * user: foo * / => without spaces. 'foo' is the name in the select box * .foobar * { * color: #f00; * } * </code> * */ class sfRichTextEditorTinyFCK extends sfRichTextEditor { /** * Returns the rich text editor as HTML. * * @return string Rich text editor HTML representation */ public function toHTML() { $options = $this->options; // we need to know the id for things the rich text editor // in advance of building the tag $id = _get_option($options, 'id', $this->name); // use tinymce's gzipped js? $tinymce_file = _get_option($options, 'tinymce_gzip') ? '/tiny_mce_gzip.php' : '/tiny_mce.js'; // tinymce installed? $js_path = sfConfig::get('sf_rich_text_js_dir') ? '/'.sfConfig::get('sf_rich_text_js_dir').$tinymce_file : '/sf/tinymce/js'.$tinymce_file; if (!is_readable(sfConfig::get('sf_web_dir').$js_path)) { throw new sfConfigurationException('You must install TinyFCK to use this helper (see rich_text_js_dir settings).'); } sfContext::getInstance()->getResponse()->addJavascript($js_path); use_helper('Javascript'); $tinymce_options = ''; $style_selector = ''; // custom CSS file? if ($css_file = _get_option($options, 'css')) { $css_path = stylesheet_path($css_file); sfContext::getInstance()->getResponse()->addStylesheet($css_path); $css = file_get_contents(sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.$css_path); $styles = array(); preg_match_all('#^/\*\s*user:\s*(.+?)\s*\*/\s*\015?\012\s*\.([^\s]+)#Smi', $css, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $styles[] = $match[1].'='.$match[2]; } $tinymce_options .= ' content_css: "'.$css_path.'",'."\n"; $tinymce_options .= ' theme_advanced_styles: "'.implode(';', $styles).'"'."\n"; $style_selector = 'styleselect,separator,'; } $culture = sfContext::getInstance()->getUser()->getCulture(); $tinymce_js = ' tinyMCE.init({ mode: "exact", language: "'.strtolower(substr($culture, 0, 2)).'", elements: "'.$id.'", plugins : "table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,zoom,flash,searchreplace,print,paste,directionality,fullscreen,noneditable,contextmenu", theme: "advanced", theme_advanced_buttons1_add_before : "save,newdocument,separator", theme_advanced_buttons1_add : "fontselect,fontsizeselect", theme_advanced_buttons2_add : "separator,insertdate,inserttime,preview,zoom,separator,forecolor,backcolor,liststyle", theme_advanced_buttons2_add_before: "cut,copy,paste,pastetext,pasteword,separator,search,replace,separator", theme_advanced_buttons3_add_before : "tablecontrols,separator", theme_advanced_buttons3_add : "emotions,iespell,flash,advhr,separator,print,separator,ltr,rtl,separator,fullscreen", theme_advanced_toolbar_location : "top", theme_advanced_toolbar_align : "left", theme_advanced_statusbar_location : "bottom", theme_advanced_resizing : true, theme_advanced_resize_horizontal : false, plugin_insertdate_dateFormat : "%Y-%m-%d", plugin_insertdate_timeFormat : "%H:%M:%S", file_browser_callback : "tinyFCKFileBrowserCallBack", paste_use_dialog : false, extended_valid_elements: "img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name]", apply_source_formatting : true, relative_urls: false, debug: false '.($tinymce_options ? ','.$tinymce_options : '').' '.(isset($options['tinymce_options']) ? ','.$options['tinymce_options'] : '').' }); function tinyFCKFileBrowserCallBack(field_name, url, type, win) { var connector = "../../filemanager/browser.html?Connector=connectors/php/connector.php"; var enableAutoTypeSelection = true; var cType; tinyfck_field = field_name; tinyfck = win; switch (type) { case "image": cType = "Image"; break; case "flash": cType = "Flash"; break; case "file": cType = "File"; break; } if (enableAutoTypeSelection && cType) { connector += "&Type=" + cType; } window.open(connector, "tinyfck", "modal,width=600,height=400"); }'; if (isset($options['tinymce_options'])) { unset($options['tinymce_options']); } return content_tag('script', javascript_cdata_section($tinymce_js), array('type' => 'text/javascript')). content_tag('textarea', $this->content, array_merge(array('name' => $this->name, 'id' => get_id_from_name($id, null)), _convert_options($options))); } }
Then clear cache:
symfony cc
Once this is done, toggle the use of rich text editing in text areas by adding the rich=true option. You can also specify custom options for the TinyFCK editor using the tinymce_options option.
<?php echo textarea_tag('name', 'default content', 'rich=true size=10x20')) ?> => a rich text edit zone powered by TinyFCK <?php echo textarea_tag('name', 'default content', 'rich=true size=10x20tinymce_options=language:"fr",theme_advanced_buttons2:"separator"')) ?> => a rich text edit zone powered by TinyFCK with custom parameters
A real client-side validation with some nice features, without Ajax tricks provided by sfYzAjaxValidationPlugin may be easily done using jsValidator (http://sourceforge.net/projects/jsformutils/) and little helper that follows.
<?php /** * Generates JavaScript code to validate a form using * jsValidator as client-side validation engine (see http://sourceforge.net/projects/jsformutils/) * * @param string $targetForm id attribute of the form to be validated * @param mixed $options associative array of options * @param string $action action to validated, defaults to current * * Options are: * stopOnFirstError: boolean, default: false * labelMessageDelimiter: string, default: ' : ', * messageSeparator: string, default: "\n", * messageHeader: string, default: 'These fields are invalid:\n---\n' + * highlightErrors: boolean, whether to mark erroneous fields * errorElementClass: string, CSS class name to be applied to wrong fields * highlightLabels: boolean, whether to mark fields or fields' labels */ function generate_validator($targetForm, $options, $action) { $NL = "\n"; $funcPrefix = 'validate_'; $labelsKey = 'labels'; $fieldsKey = 'fields'; $jsCode = ''; $paramHolder = sfContext::getInstance()->getRequest()->getParameterHolder(); $rulesFilePath = sfConfig::get('sf_app_module_dir').'/'.$paramHolder->get('module').'/'. sfConfig::get('sf_app_module_validate_dir_name').'/'; // Load rules from YAML file. if (file_exists($rulesFilePath.$paramHolder->get('action').'.yml')) $rules = sfYaml::load($rulesFilePath.$paramHolder->get('action').'.yml'); else $rules = sfYaml::load($rulesFilePath.$action.'.yml'); // Generate jsValidator compliant rules. $jsRules = array(); foreach ($rules['fields'] as $fieldId => $validationRule) { foreach ($validationRule as $validator=>$rule) { // Remove server-side sfCallbackValidator. if ($validator == 'sfCallbackValidator') { unset($validationRule[$validator]); continue; } // Map Symfony validators to jsValidator. $jsvalidator = preg_replace('/^sf(\w+Validator)$/', 'js\\1', $validator); if ($jsvalidator != $validator) { $validationRule[$jsvalidator] = $validationRule[$validator]; unset($validationRule[$validator]); } } $jsRules[] = array_merge ( array ('field' => $fieldId, 'label' => $rules['labels'][$fieldId]), $validationRule ); } // Generate final JavaScript code. $jsCode .= 'function '.$funcPrefix.$targetForm.'()'.$NL; $jsCode .= '{'.$NL. ' var options = '.json_encode($options).';'.$NL. ' var rules = '.json_encode($jsRules).';'.$NL. ' var jsv = new jsValidator();'.$NL. ' jsv.SetOptions(options);'.$NL.$NL. ' if (!jsv.Validate(rules))'.$NL. ' {'.$NL. ' alert(jsv.GetErrorMessage());'.$NL. ' return false;'.$NL. ' }'.$NL. ' return true;'.$NL. '}'.$NL; return javascript_tag($jsCode); } ?>
However, I need to clear this out. Besides placing this code into jsValidatorHelper.php either in modules' lib directory or symfony's one, we need to call it properly in the corresponding view.
First of all, include the helper (use JavaScript as well, jsValidator depends on it)
<?php use_helper('JavaScript', 'jsValidator') ?>
Validation is performed based on the same simple rule mechanism that Symfony provides. The only difference is that JavaScript validator needs these rules to be in JSON format and it needs some more options, that configure it's behavior.
<?php // Here we set validation options. // For more information please refer to documentation of jsValidator $options = array( 'stopOnFirstError' => false, 'labelMessageDelimiter' => ' : ', 'messageSeparator' => "\n", 'messageHeader' => "These fields are invalid:\n---\n", 'highlightErrors' => true, 'errorElementClass' => 'errClass', 'highlightLabels' => true ); // Output auto-generated JavaScript code. echo generate_validator('editComment', $options, 'update'); ?>
We also have to set up form to point to our validator before submitting. Note, that callback in onsubmit is named by concatenating "validate_" and form's id attribute.
<?php echo form_tag('comment/update', array('id'=>'editComment','onsubmit' => 'return validate_editComment()')) ?>
Each field must be somehow identified in the resulting error message. We achieve this by adding some extra information to <action>.yml configuration file.
# define labels for erroneous fields
labels:
<field_id>: <field_label_text>
There is a limitation to validation *.yml file structure. The syntax should be something like this:
# define labels for erroneous fields labels: author: Author email: E-mail body: Body fields: author: required: msg: The name field cannot be left blank email: sfEmailValidator: email_error: The email address is not valid. body: required: msg: The text field cannot be left blank fillin: enabled: on
And finally, don't forget to place jsValidator into /web/js folder, and include it in view.yml
<actionTemplate>: javascripts: [jsvalidator]
Feel free to modify the snippet code and validator to achieve best results!
Provide 4 functions which crypt e-mail address with javascript in order to not be captured by spammers robots.
antispam_email_tag($emailaddress, $content) : generate an e-mail link_tag (mailto) encrypted in javascript
antispam_js_encrypt($content) : encrypt in javascript some text
antispam_auto_link_email_addresses($text) : Turns all email addresses into clickable links. Email links are encrypted.
antispam_email_in_html($html) : Encrypt all e-mail link in HTML
[php]
function antispam_email_tag($emailaddress, $content=null, $options = array()) { $options = _parse_attributes($options); $options['href'] = 'mailto:'.$emailaddress; if($content===null) $content=$emailaddress; return antispam_js_encrypt(content_tag('a',$content,$options),rand(-8,5)); }
[php]
function antispam_js_encrypt($content,$chr_adjust=-1) { $encoded_content=''; for ($n = 0; $n < strlen($content); $n++) { $encoded_content .= dechex(ord(substr($content,$n,1))+ $chr_adjust) ; // + $chr_adjust } $rdm_function_name = ''; while(strlen($rdm_function_name)<8) { $tmp = rand ( 65, 122); if($tmp > 96 || $tmp < 91 ) $rdm_function_name .= chr($tmp); } $js_function='function '.$rdm_function_name."(e) { for (i = 0; i <= e.length; i+=2) { document.write(String.fromCharCode((parseInt((('0x') + e.substring(i,i+2)),16)) - (".$chr_adjust.")));}}"; return "<script>".$js_function."\n".$rdm_function_name."('" .$encoded_content. "');</script>"; }
[php]
function antispam_auto_link_email_addresses($text) { $found=true; $offset=0; while($found) { $found=preg_match('/[\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+/',$text,$matches, PREG_OFFSET_CAPTURE,$offset); if ($found) { $antispam_email_link=antispam_email_tag($matches[0][0]); $text=substr_replace ($text,$antispam_email_link,$matches[0][1],strlen($matches[0][0])); $offset=$matches[0][1]+strlen($antispam_email_link); } } return $text; }
[php]
function antispam_email_in_html($html) { $regex = '#<([aA])(\s)*(href|HREF)(\s)*=(\s)*[\"|\'](mailto:|MAILTO:)(.*?)[\"|\'](.*?)>(.*?)</\1>#is'; $found=true; $offset=0; while($found) { $found=preg_match($regex,$html,$matches, PREG_OFFSET_CAPTURE,$offset); if ($found) { $antispam_email_link=antispam_email_tag($matches[7][0],$matches[9][0]); $html=substr_replace ($html,$antispam_email_link,$matches[0][1],strlen($matches[0][0])); $offset=$matches[0][1]+strlen($antispam_email_link); } } return $html; }
In order to delay a page redirect with several seconds, I wrote this simple helper
<?php use_helper('Javascript'); /** * Adds javascript code to delay a page redirect * * @param string 'module/action' or '@rule' of the action (same argument as url_for()) * @param int time of delay in seconds. Default = 5 * @return JavaScript tag for delayed page redirect */ function delayed_redirect($internal_uri, $time = 5) { sfContext::getInstance()->getResponse()->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/prototype'); $code = 'new PeriodicalExecuter(function() { location.href=\''.url_for($internal_uri).'\';}, '.$time.')'; return javascript_tag($code); }
See http://www.symfony-project.com/book/1_0/07-Inside-the-View-Layer#Adding%20Your%20Own%20Helpers for information on how to add your own helper
This helper return path to a generate (and cached) thumbnail for an image and sizes given.
First it checks if the thumbnail as ever been created for the given size. If not, it created it and return the path to the thumbnail. Else, it will only return the path to the thumbnail.
Thumbnails are stored in a sub-directory of the original image named like [width]x[height].
examples : product/foobar.jpg which is 640x480 images - getThumbnail (320x320) will the first time generate the thumbnail "product/320x320/foobar.jpg", and return the path to this image.
parameters : - $image_path should be the path and filename of the image under uploads directory. ex: product/foobar.jpg - $width is the maximal thumbnail width - $height is the maximal thumbnail height
function getThumbnail($image,$width=null,$height=null, $scale = true, $inflate = true, $quality = 75) { $image_dir=dirname($image); $image_file=basename($image); $thumbnail_dir=''; if ($width>0) $thumbnail_dir.=$width; if ($height>0) $thumbnail_dir.='x'.$height; if ($width>0 || $height>0) $thumbnail_dir.='/'; if (!file_exists(sfConfig::get('sf_upload_dir').'/'.$image_dir.'/'.$thumbnail_dir.$image_file) && ($width!=null || $height!=null)) { if (!is_dir(sfConfig::get('sf_upload_dir').'/'.$image_dir.'/'.$thumbnail_dir)) { mkdir (sfConfig::get('sf_upload_dir').'/'.$image_dir.'/'.$thumbnail_dir,0777); } $thumbnail = new sfThumbnail($width, $height,$scale,$inflate,$quality); $thumbnail->loadFile(sfConfig::get('sf_upload_dir').'/'.$image_dir.'/'.$image_file); $thumbnail->save(sfConfig::get('sf_upload_dir').'/'.$image_dir.'/'.$thumbnail_dir.$image_file); } return '/uploads'.'/'.$image_dir.'/'.$thumbnail_dir.$image_file; }
This is very usefull to use it in model like this :
In model :
public function getThumbnail($width=null,$height=null) { sfLoader::loadHelpers('Thumbnail'); return getThumbnail('product/'.$this->getImage(),$width,$height); }
in template :
<?php foreach ($products as $product) { ?> <li><?php echo image_tag($product->getThumbnail(150,100)); ?></li> <?php } ?>
limitation : - work on images of upload directories only (other dir might have permission problem) - the check of thumbnail existance don't take care of scale and inflate values. It is easy to update the code to stored thumbnail in different subdirectory according to these parameters.
sometimes you may need to include a stylesheet only for IE, the best effort you give, this box-model gives you headaches and there is no other solution. Same issue for JS files (but it should not happen anymore thanks to prototype).
In these cases you can simply add this in your <head> section
<head>
<?php include_http_metas() ?>
<?php include_metas() ?>
<?php include_title() ?>
<link rel="shortcut icon" href="/favicon.ico" />
<?php include_javascripts() ?>
<?php include_stylesheets() ?>
<!--[if IE 7]>
<?php echo stylesheet_tag('my-css-for-IE7') ?>
<![endif]-->
<!--[if lte IE 6]>
<?php echo stylesheet_tag('my-css-for-IE6-or-lower') ?>
<![endif]-->
</head>
I made a helper for this, so your header will look more like this :
<?php use_helper('IE') ?>
<?php use_ie_stylesheet('my-css-for-IE7', 'version=7') ?>
<?php use_ie_stylesheet('my-css-for-IE6-or-lower', 'version=6 operator=lte') ?>
...
<head>
<?php include_http_metas() ?>
<?php include_metas() ?>
<?php include_title() ?>
<link rel="shortcut icon" href="/favicon.ico" />
<?php include_javascripts() ?>
<?php include_stylesheets() ?>
<?php include_ie_metas() ?>
</head>
Code is not shorter, but it's more "symfony-like" as you don't explicitly write yourself the strange-syntax comments and don't have to remember their (strange) syntax anymore.
The ideal way would be adding a filter inspired by "lib/symfony/sfCommonFilter.class.php" so we would not even have to call the include_* functions ;)
IMPORTANT :
If you do this (using IE helper or not) to OVERRIDE some CSS rules, don't forget that Symfony automagically adds your CSS and JS files just before </head>, so your CSS will be inserted BEFORE all the CSS included via "use_stylesheet()". So you have to call
<?php include_stylesheets() ?> <?php include_javascripts() ?>
before adding your conditional comments.
And the code of the helper, to be written in "lib/helper/IEHelper.php"
<?php function get_opening_ie_conditional_comments($version = null, $operator = null) { return '<!--[if ' . ($version ? $operator.' ' : '') . 'IE' . ($version ? ' '.$version : '') . ']>'; } function get_closing_ie_conditional_comments($version = null, $operator = 'lte') { return '<![endif]-->'; } function get_ie_conditional_comments($version = null, $operator = null) { return array( get_opening_ie_conditional_comments($version, $operator), get_closing_ie_conditional_comments($version, $operator) ); } function get_ie_metas($type = null) { if ($type == 'javascripts' || $type == 'stylesheets') { $metas = ''; $already_seen = array(); // Stylesheets $assets = sfContext::getInstance()->getResponse()->getParameter($type, array(), 'ie'); foreach ($assets as $asset_info) { list($asset, $options) = $asset_info; $file = $type == 'stylesheets' ? stylesheet_path($asset) : javascript_path($asset); if (isset($already_seen[$file])) { continue; } else { $already_seen[$file] = true; } // IE version (default : none) $version = isset($options['version']) ? $options['version'] : null; unset($options['version']); // IE version comparison operator (default : "le") $operator = isset($options['operator']) ? $options['operator'] : null; unset($options['operator']); // get corresponding comments list($start_comment, $end_comment) = get_ie_conditional_comments($version, $operator); $include = $type == 'stylesheets' ? stylesheet_tag($file, $options) : javascript_include_tag($file, $options); $metas .= $start_comment . "\n" . $include . $end_comment . "\n"; } return $metas; } elseif (is_null($type)) { return get_ie_metas('javascripts') . "\n" . get_ie_metas('stylesheets'); } } function include_ie_metas() { echo get_ie_metas(); } function use_ie_stylesheet($stylesheet, $options = array()) { $stylesheets = sfContext::getInstance()->getResponse()->getParameter('stylesheets', array(), 'ie'); if (!is_array($options)) $options = sfToolkit::stringToArray($options); $stylesheets[] = array($stylesheet, $options); sfContext::getInstance()->getResponse()->setParameter('stylesheets', $stylesheets, 'ie'); } function include_ie_stylesheets() { echo get_ie_stylesheets(); } function get_ie_stylesheets() { return get_ie_metas('stylesheets'); } function use_ie_javascript($js, $options = array()) { $javascripts = sfContext::getInstance()->getResponse()->getParameter('javascripts', array(), 'ie'); if (!is_array($options)) $options = sfToolkit::stringToArray($options); $javascripts[] = array($javascript, $options); sfContext::getInstance()->getResponse()->setParameter('javascripts', $javascripts, 'ie'); } function include_ie_javascripts() { echo get_ie_javascripts(); } function get_ie_javascripts() { return get_ie_metas('javascripts'); }
In an object_select_tag, the toString() method is automacally called to display the object in the list.
Sometimes, you can't use the same method for diffrent list on the same objects, so you have to specify wich method to call.
So this is the tip : 'text_method' => 'theMethodToCall'
object_select_tag($my_object, 'myMethod', array ( 'related_class' => 'MyObjectClass', 'text_method' => 'getCompleteDescription' ))
I've found this to be a pretty good solution for the dynamic page state v. bookmarking conflict that prevents users from bookmarking a specific state of your dynamic page. Typically, if a general user bookmarks your page after spending some time interacting with its dynamic features, she will be disappointed to find her bookmark doesn't reflect the state of the page when she bookmarked it.
If your Javascript is built in a way that you can hijack the window's onLoad handler to initialize a custom state, based what fragment might be in the URI, you just might find this helper function useful.
Save this to your project or application's /lib/helper folder.
<?php require_once(sfConfig::get('sf_symfony_lib_dir') . '/helper/JavascriptHelper.php'); /** * An alternative to the sf default link_to_function. * * Adds logic to onclick's concat'd "; return false;" so it only shows up if * the value of the href option doesn't include a #fragment. If no fragment is * embedded in the href it is set to "javascript:void(0)" a la Google. * * With the "; return false;" absent, the fragment will show up in the * browser's address bar, and will be included if the user copies the link or * bookmarks the current state of your dynamic page. You can then add a bit of * logic to your window initialization Javascript to detect any fragments in * the URL and adjust the onLoad state accordingly. * * @author Kris Wallsmith <kris [dot] wallsmith [at] gmail [dot] com> * @version tested on symfony 1.0.3 * @see link_to_function() * * @param string $name * @param string $function * @param mixed $options * * @return string */ function my_link_to_function($name, $function, $options = array()) { $options = _parse_attributes($options); $has_href = isset($options['href']); if(!isset($options['href'])) { $options['href'] = 'javascript:void(0)'; } $options['onclick'] = $function; if(!$has_href || strpos($options['href'], '#') === false) { $options['onclick'] .= '; return false;'; } return content_tag('a', $name, $options); }
Gravatar has moved as a plugin with local caching functions see : http://trac.symfony-project.com/trac/wiki/sfGravatarPlugin