![]() |
|
Snippets |
|
Extend the myUser.class.php in any /lib folder with the following function:
public function isInGroups(array $groups, $strict = false) { if ($strict) { return (array_intersect($groups, $this->getGroupNames()) == $groups); } else { foreach ($groups as $g) { if (in_array($g, $this->getGroupNames())) return true; } } return false; }
Now you can check the groups of the user as following:
if ($sf_user->isInGroups(array('admin', 'editor'))) { // do stuff here... }
You can also check if the user is in all the groups specified. Just set the second parameter to true:
if ($sf_user->isInGroups(array('admin', 'editor'), true)) { // this is executed only if the user is in the groups admin AND editor // please note: he might still be a member of other groups }
This snippet will allow the user of your application to a. Change the fontsize of a webpage dynamically and b. print a properly formatted part of the webpage or let the browser handle the printing.
The snippet will become available as a symfony plugin as soons as 1.1 is stable. Why? symfony 1.1 contains the RemoveStylesheet function, which will make things easier.
The interface exists of three buttons (Increase) (Decrease) (Default), will immediately change the fontsize in the main content area. That includes h1, h2 etc.
The new fontsize is stored in a cookie, you'll have to do some coding if you want to store it in a database. The new fontsize is always retrieved on loadtime of a page.
Some changes in your CSS, and also probably in the CSS in this snippet, are necessary. You will have to set a default fontsize in the main content area CSS-rule. You will have to remove fontsize from all rules inside the main content area.
Note: If you want to use a fixed size for a certain part of the screen, then simply leave in the fontsize, it will not be resized then.
The interface exists of a checkbox User friendly printing, Enable the checkbox option to print only the main content area. Disable the option to allow the browser to handle full page printing.
Create file components.class.php in apps/frontend/modules/UserFriendly/actions with the following content
<?php class UserFriendlyComponents extends sfComponents { public function executeDefault() { } }
Create file _default.php in apps/frontend/modules/UserFriendly/templates with the following content
<?php use_helper('Javascript', 'I18N') ?> <div id="fn_userfriendly_container"> <h2><?php echo __('User options') ?></h2> <p><?php echo __('Change font size ')?><?php echo link_to_function( '(Help)', visual_effect('toggle_blind', 'help_font_div', array('duration' => 0.1)) ) ?> </p> <div id="help_font_div" style="display:none"> <?php echo __('With the three buttons below you can change the font size of the main content area.') ?><br /><?php echo __('From left to right: Increase, Decrease and back to Default font size.') ?> </div> <ul class="fn_userfriendly_actions"> <?php use_helper('Javascript') ?> <li> <?php echo button_to_function("", "changeFontSize('td','plus')", array('href' => '#Size+','class' => 'fn_userfriendly_action_fontplus')) ?> </li> <li> <?php echo button_to_function("", "changeFontSize('td','min')", array('href' => '#Size-','class' => 'fn_userfriendly_action_fontmin')) ?> </li> <li> <?php echo button_to_function("", "changeFontSize('td','std')", array('href' => '#DefaultSize','class' => 'fn_userfriendly_action_fontstd')) ?> </li> </ul> <br /> <p><?php echo __('User friendly printing ')?><?php echo link_to_function( '(Help)', visual_effect('toggle_blind', 'help_print_div', array('duration' => 0.1)) ) ?><br /> </p> <div id="help_print_div" style="display:none"> <?php echo __('Enable the option below to print only the main content area.') ?><br /><?php echo __('Disable the option to allow the browser to handle full page printing.') ?> </div> <?php $cookiename = 'userfriendly_print' ?> <?php $cookie = sfContext::getInstance()->getRequest()->getCookie($cookiename) ?> <?php if ($cookie == '') : ?> <?php $cookie = 1 ?> <?php endif; ?> <?php echo checkbox_tag('userfriendlyprint', 1, $cookie,array('onclick' => "setPrintMethod(); return false;")) ?> <label for="userfriendlyprint" class="small"><?php echo __('Print user friendly') ?></label> </div>
Create file UserFriendlyHelper.php in directory apps/frontend/lib/helper with the following content
<?php /** * User Friendly Helper * * @author Frank van Noorden <fnoorden@gmail.com> * @license will be released under the same LICENSE as symfony * @version 0.0.1 */ /** * addition of js-files and stylesheet */ function userfriendly_init() { $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('/js/UserFriendly'); $request = sfContext::getInstance()->getRequest(); // name of print cookie $print_cookie = 'userfriendly_print'; // Retrieve print cookie, the cookie always overrides the default $cookie = $request->getCookie($print_cookie); if (isset($cookie) && $cookie <> '') { $print = $cookie; } else { $print = 1; // default is 1-friendly printing, 0-browser printing $expire = time() + 31536000; // one year $response->setCookie($print_cookie, $print, $expire, '/'); } // Add print stylesheet if ($print == 1) { $response->addStylesheet('/css/userfriendlyprint','last', array('media' => 'print')); } return ''; }
Create UserFriendly.js in the js directory with the following content
/** * User Friendly js * @author Frank van Noorden <fnoorden@gmail.com> * @license will be released under the same LICENSE as symfony * @version 0.0.1 */ var prefsLoaded = false; var defaultFontSize = 100; var currentFontSize = defaultFontSize; /** * addLoadEvent: Add event handler to body when window loads */ // Multiple onload function created by: Simon Willison // http://simon.incutio.com/archive/2004/05/26/addLoadEvent function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != "function") { window.onload = func; } else { window.onload = function () { oldonload(); func(); } } } /** * changeFontSize: Change font size */ function changeFontSize(rulename, newSize){ if(newSize == 'plus') currentFontSize = parseInt(currentFontSize) + 10; if(newSize == 'min') currentFontSize = parseInt(currentFontSize) - 10; if(newSize == 'std') currentFontSize = 100; if(currentFontSize > 150){ currentFontSize = 150; }else if(currentFontSize < 50){ currentFontSize = 50; } setFontSize(rulename, currentFontSize); createCookie("fontSize", currentFontSize, 365); } /** * setFontSize: Set font size */ function setFontSize(ruleName, newFontSize){ var rule = getCSSRule(ruleName); rule.style.fontSize= newFontSize + '%'; } /** * setUserOptions: Get cookie and set stored font size */ function setUserOptions(rulename){ if(!prefsLoaded){ cookie = readCookie("fontSize"); currentFontSize = cookie ? cookie : defaultFontSize; setFontSize(rulename, currentFontSize); prefsLoaded = true; } } /** * createCookie: Create cookie, takes number of days as input */ function createCookie(name,value,days) { if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } /** * readCookie: Read cookie */ function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } /** * getCSSRule: Get the CSS rule */ function getCSSRule(ruleName) { ruleName=ruleName.toLowerCase(); if (document.styleSheets) { for (var i=0; i<document.styleSheets.length; i++) { var styleSheet=document.styleSheets[i]; var ii=0; var cssRule=false; do { // For each rule in the stylesheet if (styleSheet.cssRules) { cssRule = styleSheet.cssRules[ii]; // Mozilla } else { cssRule = styleSheet.rules[ii]; // IE style } if (cssRule) { // Rule found if (cssRule.selectorText.toLowerCase()==ruleName) { return cssRule; // Return the style object } // End found rule name } // end found cssRule ii++; } while (cssRule) // end Do While loop } // end For loop } // end styleSheet ability check return false; // Nothing found } // end getCSSRule /** * setPrintMethod: Set print method */ function setPrintMethod() { // Set print method var x = readCookie("userfriendly_print") if (x == 0) { x =1; } else { x=0; } createCookie("userfriendly_print",x,365,"/"); window.location = document.location.href; return false; }
The file userfriendlyprint.css has to be matched with your own CSS. Create userfriendlyprint.css in the css directory with the following content
/* Remove unwanted elements, probably different for you */ #content_main_navtop, #content_main_navbottom, #content_bar, .noprint, .last { display: none; } /* Ensure the content spans the full width */ #header, #content_main { width: 100%; margin: 0; float: none; } /* Change text colour to black (useful for light text on a dark background) */ .lighttext { color: #000 } /* Improve colour contrast of links */ a:link, a:visited { color: #781351 } /* Set color of image links to white (make them to disappear on print) */ a img, *:link img, *:visited img { border:medium none; color: #fff }
Change the view.yml and add the following:
components:
UserFriendly: [UserFriendly, default]
Change your layout.php Initialize the print environment, place this before </head> tag:
<?php use_helper('UserFriendly') ?> <?php userfriendly_init() ?>
The saved font size will be restored at load time of the page. Add after the <body> tag:
<?php use_helper('Javascript') ?> <?php echo javascript_tag(' addLoadEvent(function() { setUserOptions("td"); }); ') ?>
Note: the TD tag used in setUserOptions is the place where the font size is set in my case.
Include the component:
<?php include_component_slot('UserFriendly') ?>
Change your i18n file, if you use i18n
Demo at www.noorden.com
Sometimes if you use sfGuardUser and sfGuardUserProfile you need to create an empty profile just after adding the new user (automating is such a great thing). This snippet will help out.
UPDATE: Will Killian pointed me to the solution of using this without touching the plugin files, this way it will still work after upgrading the plugin. Thanks!
Edit apps/backend/modules/sfGuardUser/actions/actions.class.php
(create directories and files as needed, just for the record I use this with admin generator on "backend" app)
Mine looks like this.
<?php require_once(sfConfig::get('sf_plugins_dir').'/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php'); class sfGuardUserActions extends BasesfGuardUserActions { protected function savesfGuardUser($sf_guard_user) { parent::savesfGuardUser($sf_guard_user); $user_id = $sf_guard_user->getId(); $c = new Criteria(); $c->add(sfGuardUserProfilePeer::USER_ID,$user_id); $profile = sfGuardUserProfilePeer::doSelectOne($c); if(!$profile) { $profile = new sfGuardUserProfile(); $profile->setUserId($user_id); $profile->save(); } } }
if you won´t to add a foreignkey to sf_guard_user put this on top off you schema.yml file ;)
propel: _attributes : { package: "plugins.sfGuardPlugin.lib.model" } sf_guard_user: _attributes: { phpName: sfGuardUser } id:
now you can simple add a foreignkey
propel:
tbl_user_profile:
user_id: { type: integer, primaryKey: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade }
or
propel:
tbl_user_profile:
sf_guard_user_id:
Recently I needed to copy data that comes from a webform into the current session. Here is my solution ...
class myUser extends sfBasicSecurityUser { /** * Copy request data into the users session object * * @param array $exclude Fieldnames to exclude from copy */ public function copyRequestData ($exclude = array ()) { /// Get the request instance and its currently posted fieldnames $req = sfContext::getInstance ()->getRequest (); $fieldNames = $req->getParameterHolder ()->getNames (); /// Always exclude "posted" module and action $exclude[] = 'module'; $exclude[] = 'action'; /// Evaluate each fieldname and do a "lookup" if it can /// be copied foreach ($fieldNames as $fieldName) { if (!in_array ($fieldName, $exclude)) { $this->setAttribute ($fieldName, $req->getParameter ($fieldName, null)); } // end if } // end foreach } }
I don't know about you, but I often farm out action logic--like building a datastructure to pass to a template--to static functions in a class in my application or module lib/ directory.
However, these functions don't typically have access to the shortcut methods for setting/getting flash and request parameters (etc.). Like:
$foo = $this->getRequestParameter('foo');
Unless I've missed something, the code to do something similar outside of an action is just a little messy, and quite repetitive if used more than once. So I add a few things to my project to make the job simpler.
/** * This class adds a few more useful functions to the sfUser instance */ class myBasicUser extends sfBasicSecurityUser { const FLASH_NAMESPACE = 'symfony/flash'; /** User flash parameters (stored in the session until the next request) */ public function setFlash($name, $value) { $this->setAttribute($name, $value, self::FLASH_NAMESPACE); } public function getFlash($name, $default = null) { return $this->getAttribute($name, $default, self::FLASH_NAMESPACE); } public function hasFlash($name) { return $this->hasAttribute($name, self::FLASH_NAMESPACE); } /** User attribute parameters (stored in the session until removed) */ public function removeAttribute($name, $ns = null) { $this->getAttributeHolder()->remove($name, $ns); } public function getAttributes($ns = null) { return $this->getAttributeHolder()->getAll($ns); } public function removeAttributes($ns = null) { $this->getAttributeHolder()->removeNamespace($ns); } /** User parameter parameters (erased after every request) */ public function removeParameter($name, $ns = null) { $this->getParameterHolder()->remove($name, $ns); } public function getParameters($ns = null) { return $this->getParameterHolder()->getAll($ns); } public function removeParameters($ns = null) { $this->getParameterHolder()->removeNamespace($ns); } } class myUser extends myBasicUser { //... }
*Note: add those files to your lib/ director as myBasicUser.class.php and myUser.class.php respectively.
That gives me an easy way to do some things with the user object, but now I need an easy way to get the user outside of an action and an easier way to get/set request parameters/attributes, etc. I defined a class in my application lib/ directory like this:
/** * Shortcuts to all request and user attribute setting/getting/has functions * This class simply makes repetitive tasks a few characters (and in some cases, lines) shorter to accomplish */ class myTools { /** Get context singleton */ public static function getContext() { return sfContext::getInstance(); } /** Get request singleton */ public static function getRequest() { return sfContext::getInstance()->getRequest(); } /** Request parameter holder */ public static function getRequestParameterHolder() { return sfContext::getInstance()->getRequest()->getParameterHolder(); } /** Request attribute holder */ public static function getRequestAttributeHolder() { return sfContext::getInstance()->getRequest()->getAttributeHolder(); } /** Request parameters (read-only) */ public static function getRequestParameter($name, $default = null) { return sfContext::getInstance()->getRequest()->getParameter($name, $default); } public static function hasRequestParameter($name) { return sfContext::getInstance()->getRequest()->hasParameter($name); } /** Request attributes (read/write - erased after every request) */ public static function getRequestAttribute($name, $default = null) { return sfContext::getInstance()->getRequest()->getAttribute($name, $default); } public static function setRequestAttribute($name, $value) { sfContext::getInstance()->getRequest()->setAttribute($name, $value); } public static function hasRequestAttribute($name) { return sfContext::getInstance()->getRequest()->hasAttribute($name); } /** Get user singleton */ public static function getUser() { return sfContext::getInstance()->getUser(); } /** User attribute holder */ public static function getAttributeHolder() { return sfContext::getInstance()->getUser()->getAttributeHolder(); } /** User parameter holder */ public static function getParameterHolder() { return sfContext::getInstance()->getUser()->getParameterHolder(); } /** User flash parameters (stored in the session until the next request) */ public static function setFlash($name, $value) { sfContext::getInstance()->getUser()->setFlash($name, $value); } public static function getFlash($name) { return sfContext::getInstance()->getUser()->getFlash($name); } public static function hasFlash($name) { return sfContext::getInstance()->getUser()->hasFlash($name); } /** User attribute parameters (stored in the session until removed) */ public static function getAttribute($name, $default = null, $ns = null) { return sfContext::getInstance()->getUser()->getAttribute($name, $default, $ns); } public static function setAttribute($name, $value, $ns = null) { sfContext::getInstance()->getUser()->setAttribute($name, $value, $ns); } public static function removeAttribute($name, $ns = null) { sfContext::getInstance()->getUser()->removeAttribute($name, $ns); } public static function getAttributes($ns = null) { return sfContext::getInstance()->getUser()->getAttributes($ns); } public static function removeAttributes($ns = null) { sfContext::getInstance()->getUser()->removeAttributes($ns); } /** User parameter parameters (erased after every request) */ public static function getParameter($name, $default = null, $ns = null) { return sfContext::getInstance()->getUser()->getParameter($name, $default, $ns); } public static function setParameter($name, $value, $ns = null) { sfContext::getInstance()->getUser()->setParameter($name, $value, $ns); } public static function removeParameter($name, $ns = null) { sfContext::getInstance()->getUser()->removeParameter($name, $ns); } public static function getParameters($ns = null) { return sfContext::getInstance()->getUser()->getParameters($ns); } public static function removeParameters($ns = null) { sfContext::getInstance()->getUser()->removeParameters($ns); } /** User credentials */ public static function clearCredentials() { sfContext::getInstance()->getUser()->clearCredentials(); } public static function listCredentials() { return sfContext::getInstance()->getUser()->listCredentials(); } public static function removeCredential($credential) { sfContext::getInstance()->getUser()->removeCredential($credential); } public static function addCredential($credential) { sfContext::getInstance()->getUser()->addCredential($credential); } public static function addCredentials() { sfContext::getInstance()->getUser()->addCredentials(func_get_args()); } public static function hasCredential($credential) { return sfContext::getInstance()->getUser()->hasCredential($credential); } /** User authentication */ public static function isAuthenticated() { return sfContext::getInstance()->getUser()->isAuthenticated(); } public static function setAuthenticated($authenticated) { sfContext::getInstance()->getUser()->setAuthenticated($authenticated); } /** User culture */ public static function setCulture($culture) { sfContext::getInstance()->getUser()->setCulture($culture); } public static function getCulture() { return sfContext::getInstance()->getUser()->getCulture(); } }
There you have it. Now it's as simple as...
class myModuleLib { public static function myFunc() { ... $foo = myTools::getRequestParameter('foo', 'default_value'); myTools::setFlash($foo); ... } }
Overkill...? Maybe. You may use any of these functions that are useful, and simply omit those you think are unnecessary. The goal here is to standardize (even more) the methods used to access attributes of the request and user, etc. I'm guessing this will be beneficial for beginners (if nothing else, as an example), and also for people (like me) who like ridiculously consistent code.
Any comments, including comments on naming conventions of the functions are appreciated.
Here is the schema you need to set up database session storage.
CREATE TABLE `session` ( `sess_id` varchar(32) NOT NULL, `sess_data` text NOT NULL, `sess_time` int(11) NOT NULL );
Here is a little hack to use http auth when credentials or auth is insufficient:
public function executeSecure() { if (!$this->getUser()->hasAttribute("secure_referer")) $this->getUser()->setAttribute("secure_referer", $this->getRequest()->getReferer()); if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="Member Area"'); header('HTTP/1.0 401 Unauthorized'); return sfView::NONE; } else { if ($this->getUser()->tryLogin($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])) { return $this->redirect($this->getUser()->getAttribute("secure_referer")); } else { header('WWW-Authenticate: Basic realm="Member Area"'); header('HTTP/1.0 401 Unauthorized'); return sfView::NONE; } } }
No template is needed, as everytime you access it will redirect to the referer. Then change in app/yourapp/config/settings.yml the secure_module and secure_action to match this module.
You will need a myUser::tryLogin function that returns a boolean saying "auth is ok" or "bad auth"
And then you're done :p
[from my Wiki Post ab out that]