Zend – Using custom error handlers in each module

Why does a project need a custom error handler

Quite often it is important to use custom error handlers in each module in order to provide better user experience. For example if there is an admin module in a project for managing data and an Exception is thrown somewhere within that module the automatic error handler located in the default module will kick in and display the exception in the default module rendering the default layout. Another example is if a project has an “api” module of some sort outputting JSON or XML as a service, and the situation here is a bit worse, because when an exception is razed, the default module will render the exception with the default HTML layout and the remote client may be accepting only JSON or XML. Please note that this approach only works in Zend Framework version 1.x.

To overcome this problem you can create a corresponding ErrorController in the controllers directory of each module, but this will not be enough since Zend Framework will not automatically detect the presence of the error controller by itself.

Here is a step by step guide on how to fully set up error handling

step 1: Create ErrorController.php file in the corresponding module “controllers” directory and don’t forget to prefix the controller name with the module name. Here is an example error controller for a module named “admin”:

<?php
class Admin_ErrorController extends Zend_Controller_Action
{

    public function errorAction()
    {
        try
        {
            //set different layout file
            Zend_Layout::getMvcInstance()->setLayout("admin");
        }
        catch (Exception $e) {}

        $errors = $this->_getParam('error_handler');

        if (!$errors || !$errors instanceof ArrayObject)
        {
            $this->view->message = 'You have reached the error page';
            return;
        }

        switch ($errors->type)
        {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                // 404 error -- controller or action not found
                $this->getResponse()->setHttpResponseCode(404);
                $priority = Zend_Log::NOTICE;
                $this->view->message = 'Page not found';
                break;
            default:
                // application error
                $this->getResponse()->setHttpResponseCode(500);
                $priority = Zend_Log::CRIT;
                $this->view->message = 'Application error';
                break;
        }

        // Log exception, if logger available
        if ($log = $this->getLog())
        {
	    $log->log('Error messange: '.$errors->exception->getMessage(), $priority);
	    $log->log('Request Parameters: '.print_r($errors->request->getParams(), true), $priority);
	    $log->log('Stack Trace: '.print_r($errors->exception->getTraceAsString(), true), $priority);
        }

        // conditionally display exceptions
        if ($this->getInvokeArg('displayExceptions') == true)
        {
            $this->view->exception = $errors->exception;
        }

        $this->view->request = $errors->request;
    }

    public function getLog()
    {
        $bootstrap = $this->getInvokeArg('bootstrap');
        if (!$bootstrap->hasResource('Log')) {
            return false;
        }
        $log = $bootstrap->getResource('Log');
        return $log;
    }
}

step 2: Add the following code in the init() method of each controller in the module:

public function init()
{
	parent::init();

	$error = Zend_Controller_Front::getInstance()->getPlugin('Zend_Controller_Plugin_ErrorHandler');
	$error->setErrorHandlerModule('admin');
}

Explanation:
Zend Framework 1.0 exception handling works by using a integrated plugin called “ErrorHandler”. This plugin works by checking the isException() method of the response object witch will indicate if an exception has been thrown during the dispatch process. After that if an exception was caught the plugin forwards the request to the pre-configured ErrorController and sets an error object in the request parameters. After that in the ErrorController the error is available via $this->getRequest()->getParam(“error_handler”);

Android VelocityTracker example VelocityDecelerator in SurfaceView with Canvas

If you are trying to make your own fling/swipe/scroll implementation in a Canvas driven SurfaceView, you will notice that there is a key feature missing – mechanism for smooth velocity deceleration. In this article we will give an android VelocityTracker example using a custom VelocityDecelerator class.

You may find that android includes VelocityTracker, which is a helper class for tracking velocity of touch events. This class is pretty helpful for determining the fling velocity produced by series of touch events. However, android lacks any mechanism for handling the velocity measured by VelocityTracker. The idea behind this is pretty simple, just implement the physics law of inertial movement or equally decelerating movement. The law says that:

S = V0*t - (a*t^2)/2

and also:

Vd = a*t

where:
– “S” is the overall movement distance
– “V0″ is the initial velocity (like the one provided by VelocityTracker)
– “t” is the overall movement time
– “a” is the acceleration, which in our case is less than zero, and that turns it into deceleration (in the law of inertia the deceleration is in fact the friction between the moving object and the supporting surface)
– “Vd” is the delta velocity, which means the velocity in a specified moment.

So basically, we need to start moving with “V0″ speed for “t” seconds until “Vd” becomes 0. Applying this on both X and Y axis we can achieve a smooth fling effect in a custom SurfaceView.

To do so, we are going to use this class implementation:

package eu.iostream.android.util;

public class VelocityDecelerator {
	
	public static final float FRICTIONAL_DECELERATION = 0.01f; //px/ms^2
	
	private int mDirectionX = 1;
	private int mDirectionY = 1;
	
	private float mVelocityX = 0;
	private float mVelocityY = 0;
	
	private float mPreviousVelocityX = 0;
	private float mPreviousVelocityY = 0;
	
	private long mStartTimeX = 0;
	private long mStartTimeY = 0;
	
	private long mPreviousTimeX = 0;
	private long mPreviousTimeY = 0;
	
	private long mCurrentTimeX = 0;
	private long mCurrentTimeY = 0;
	
	private float mTotalTimeX = 0;
	private float mTotalTimeY = 0;
	
	private long mCurrentTime;
	
	private float mDeltaTimeX;
	private float mDeltaTimeY;
	
	private float mTempDistance;
	
	public VelocityDecelerator(float velocityX, float velocityY) {
		start(velocityX, velocityY);
	}
	
	public void stop() {
		mVelocityX = mPreviousVelocityX = 0;
		mVelocityY = mPreviousVelocityY = 0;
		
		mTotalTimeX = 0;
		mTotalTimeY = 0;
		
		mStartTimeX = 0;
		mStartTimeY = 0;
	}
	
	public void start(float velocityX, float velocityY) {
		mDirectionX = (velocityX > 0 ? 1 : -1);
		mDirectionY = (velocityY > 0 ? 1 : -1);
		
		mVelocityX = mPreviousVelocityX = Math.abs(velocityX);
		mVelocityY = mPreviousVelocityY = Math.abs(velocityY);
		
		mCurrentTime = System.currentTimeMillis();
		
		mStartTimeX = mCurrentTime;
		mCurrentTimeX = mCurrentTime;
		mPreviousTimeX = mCurrentTime;
		mStartTimeY = mCurrentTime;
		mCurrentTimeY = mCurrentTime;
		mPreviousTimeY= mCurrentTime;
		
		mTotalTimeX = Math.abs((velocityX/FRICTIONAL_DECELERATION)); //ms
		mTotalTimeY = Math.abs((velocityY/FRICTIONAL_DECELERATION)); //ms
	}
	
	public int getDirectionX() {
		return mDirectionX;
	}
	
	public int getDirectionY() {
		return mDirectionY;
	}
	
	///
	
	public boolean isMoving() {
		return (getSpeedX() > 0 || getSpeedY() > 0);
	}
	
	///
	
	private void updateTimeX() {
		mCurrentTimeX = System.currentTimeMillis();
	}
	
	private void updateTimeY() {
		mCurrentTimeY = System.currentTimeMillis();
	}
	
	///
	
	public void calculateFreezeFrameData() {
		mPreviousTimeX = mCurrentTimeX;
		mPreviousTimeY = mCurrentTimeY;
		
		mPreviousVelocityX = getSpeedX();
		mPreviousVelocityY = getSpeedY();
		
		updateTimeX();
		updateTimeY();
	}
	
	///
	
	private float getSpeedX() {
		
		mDeltaTimeX = (mCurrentTimeX-mStartTimeX);
		
		if (mDeltaTimeX >= mTotalTimeX) return 0;
		
		return mVelocityX - FRICTIONAL_DECELERATION*mDeltaTimeX;
	}
	
	private float getSpeedY() {
		
		mDeltaTimeY = (mCurrentTimeY-mStartTimeY);
		
		if (mDeltaTimeY >= mTotalTimeY) return 0;
		
		return mVelocityY - FRICTIONAL_DECELERATION*mDeltaTimeY;
	}
	
	///
	
	public float getDeltaDistanceX() {
		
		mDeltaTimeX = (mCurrentTimeX - mPreviousTimeX);
		
		mTempDistance = mPreviousVelocityX*mDeltaTimeX - (FRICTIONAL_DECELERATION*mDeltaTimeX*mDeltaTimeX)/2;
		
		return (mTempDistance < 0 ? 0 : mTempDistance);
	}
	
	public float getDeltaDistanceY() {
		mDeltaTimeY = (mCurrentTimeY - mPreviousTimeY);
		
		mTempDistance = mPreviousVelocityY*mDeltaTimeY - (FRICTIONAL_DECELERATION*mDeltaTimeY*mDeltaTimeY)/2;
		
		return (mTempDistance < 0 ? 0 : mTempDistance);
	}
	
	///
	
	public float getCurrentDistanceX() {
		mDeltaTimeX = (mCurrentTimeX - mStartTimeX);
		
		mTempDistance = mVelocityX*mDeltaTimeX - (FRICTIONAL_DECELERATION*mDeltaTimeX*mDeltaTimeX)/2;
		
		return (mTempDistance < 0 ? 0 : mTempDistance);
	}
	
	public float getCurrentDistanceY() {
		mDeltaTimeY = (mCurrentTimeY - mStartTimeY);
		
		mTempDistance = mVelocityY*mDeltaTimeY - (FRICTIONAL_DECELERATION*mDeltaTimeY*mDeltaTimeY)/2;
		
		return (mTempDistance < 0 ? 0 : mTempDistance);
	}
	
	///
	
	public float getTotalDistanceX() {
		return mVelocityX*mTotalTimeX - (FRICTIONAL_DECELERATION*mTotalTimeX*mTotalTimeX)/2;
	}
	
	public float getTotalDistanceY() {
		return mVelocityY*mTotalTimeY - (FRICTIONAL_DECELERATION*mTotalTimeY*mTotalTimeY)/2;
	}
}

Now for example usage, lets assume that we have a class CustomSurface that extends SurfaceView. In our class CustomSurface we need to:
– declare both VelocityTracker and VelocityDecelerator

protected VelocityTracker mVelocity;
	
protected VelocityDecelerator mVelocityDecelerator;

– override the onTouchEvent method of SurfaceView, to capture all touch events, feed them to VelocityTracker and then initialize VelocityDecelerator with the measured velocity

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (event != null)
		{		
			if (!mScaling && event.getPointerCount() == 1) {
				
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					
					if (mVelocityDecelerator != null) mVelocityDecelerator.stop();
					
					mVelocity = VelocityTracker.obtain();
					
					mVelocity.addMovement(event);
				}
				
				if (event.getAction() == MotionEvent.ACTION_MOVE) {
					
					mVelocity.addMovement(event);
				}
				
				if (event.getAction() == MotionEvent.ACTION_UP) {
					
					mVelocity.addMovement(event);
					
					mVelocity.computeCurrentVelocity(1);
					
					if (mVelocityDecelerator == null) {
						mVelocityDecelerator = new VelocityDecelerator(mVelocity.getXVelocity(), mVelocity.getYVelocity());
					}
					else {
						mVelocityDecelerator.start(mVelocity.getXVelocity(), mVelocity.getYVelocity());
					}
					
					mVelocity.recycle();
				}

			}
			
			return true;
		}
		
		return super.onTouchEvent(event);
	}

– use VelocityDecelerator in your drawing thread

    public class AnimationThread extends Thread {
        protected boolean mRun;       
        protected SurfaceHolder mSurfaceHolder;        

        public AnimationThread(SurfaceHolder surfaceHolder) {
            mSurfaceHolder = surfaceHolder;
        }

        @Override
        public void run() {
            while (mRun) {
            	mCanvas = null;

                try {
                    mCanvas = mSurfaceHolder.lockCanvas();

                    synchronized (mSurfaceHolder) {  
                    	
                    	updatePosition();
                    	
                        doDraw(mCanvas);
                                       
                        sleep(mThreadDelay);
                    }
                } catch (Exception e) {                 
                    e.printStackTrace();
                    
                    setRunning(false);
                } finally {
                    if (mCanvas != null) {
                        mSurfaceHolder.unlockCanvasAndPost(mCanvas);
                    }
                }
            }
        }
        
        protected void doDraw(Canvas canvas) {
            
            if (!mLayers.isEmpty()) {
            	for (Renderable renderer: mLayers) {
            		renderer.render(canvas);
            	}
            }
            
            canvas.restore();
        }
        
        public void setRunning(boolean b) {
            mRun = b;
        }

        public void updatePosition() {
	        if (mVelocityDecelerator != null && mVelocityDecelerator.isMoving()) {
    		
                    mVelocityDecelerator.calculateFreezeFrameData();
    		
                    mDeltaX = Math.round(mVelocityDecelerator.getDeltaDistanceX())*mVelocityDecelerator.getDirectionX();
                    mDeltaY = Math.round(mVelocityDecelerator.getDeltaDistanceY())*mVelocityDecelerator.getDirectionY();
    		
                    //TODO use mDeltaX and mDeltaY to move your drawing objects around
            }
        }
    }

And that’s all. Good luck!

Search user agents php array

Here is a php array of all search user agents (Crawlerlist) listed on www.useragentstring.com

public $botAgents = array(
	'008', 'ABACHOBot', 'Accoona-AI-Agent', 'AddSugarSpiderBot', 'AnyApexBot', 'Arachmo', 'B-l-i-t-z-B-O-T', 'Baiduspider', 'BecomeBot', 'BeslistBot', 'BillyBobBot', 'Bimbot', 'Bingbot',
	'BlitzBOT', 'boitho.com-dc', 'boitho.com-robot', 'btbot', 'CatchBot', 'Cerberian Drtrs', 'Charlotte', 'ConveraCrawler', 'cosmos', 'Covario IDS', 'DataparkSearch', 'DiamondBot', 'Discobot',
	'Dotbot', 'EARTHCOM.info', 'EmeraldShield.com WebBot', 'envolk[ITS]spider', 'EsperanzaBot', 'Exabot', 'FAST Enterprise Crawler', 'FAST-WebCrawler', 'FDSE robot', 'FindLinks',
	'FurlBot', 'FyberSpider', 'g2crawler', 'Gaisbot', 'GalaxyBot', 'genieBot', 'Gigabot', 'Girafabot', 'Googlebot', 'Googlebot-Image', 'GurujiBot', 'HappyFunBot', 'hl_ftien_spider', 'Holmes',
	'htdig', 'iaskspider', 'ia_archiver', 'iCCrawler', 'ichiro', 'igdeSpyder', 'IRLbot', 'IssueCrawler', 'Jaxified Bot', 'Jyxobot', 'KoepaBot', 'L.webis', 'LapozzBot', 'Larbin', 'LDSpider',
	'LexxeBot', 'Linguee Bot', 'LinkWalker', 'lmspider', 'lwp-trivial', 'mabontland', 'magpie-crawler', 'Mediapartners-Google', 'MJ12bot', 'MLBot', 'Mnogosearch', 'mogimogi', 'MojeekBot',
	'Moreoverbot', 'Morning Paper', 'msnbot', 'MSRBot', 'MVAClient', 'mxbot', 'NetResearchServer', 'NetSeer Crawler', 'NewsGator', 'NG-Search', 'nicebot', 'noxtrumbot', 'Nusearch Spider',
	'NutchCVS', 'Nymesis', 'obot', 'oegp', 'omgilibot', 'OmniExplorer_Bot', 'OOZBOT', 'Orbiter', 'PageBitesHyperBot', 'Peew', 'polybot', 'Pompos', 'PostPost', 'Psbot', 'PycURL', 'Qseero',
	'Radian6', 'RAMPyBot', 'RufusBot', 'SandCrawler', 'SBIder', 'ScoutJet', 'Scrubby', 'SearchSight', 'Seekbot', 'semanticdiscovery', 'Sensis Web Crawler', 'SEOChat::Bot', 'SeznamBot',
	'Shim-Crawler', 'ShopWiki', 'Shoula robot', 'silk', 'Sitebot', 'Snappy', 'sogou spider', 'Sosospider', 'Speedy Spider', 'Sqworm', 'StackRambler', 'suggybot', 'SurveyBot', 'SynooBot',
	'Teoma', 'TerrawizBot', 'TheSuBot', 'Thumbnail.CZ robot', 'TinEye', 'truwoGPS', 'TurnitinBot', 'TweetedTimes Bot', 'TwengaBot', 'updated', 'Urlfilebot', 'Vagabondo', 'VoilaBot', 'Vortex',
	'voyager', 'VYU2', 'webcollage', 'Websquash.com', 'wf84', 'WoFindeIch Robot', 'WomlpeFactory', 'Xaldon_WebSpider', 'yacy', 'Yahoo! Slurp', 'Yahoo! Slurp China', 'YahooSeeker',
	'YahooSeeker-Testing', 'YandexBot', 'YandexImages', 'YandexMetrika', 'Yasaklibot', 'Yeti', 'YodaoBot', 'yoogliFetchAgent', 'YoudaoBot', 'Zao', 'Zealbot', 'zspider', 'ZyBorg'
);

And this is one way to test if the current request is beeing made by a robot:

foreach($this->botAgents as $agent) {
	if (strstr($_SERVER['HTTP_USER_AGENT'], $agent )) {
		//We have a BOT
	}
}

How do I get javascript

Is the question “How do I get javascript?” the right one

Hello there, you are probably coming from Google. There are approximately two reasons for you to search about “How do I get javascript?”:

  • You want to enable javascript support in your browser.
  • You are curious about what javascript actually is.

Enabling javascript

First of all, make sure that you are using one of the mainstream browsers, and preferably – it’s latest version. If you are not sure how modern and good your browser is, make sure it is not Internet Explorer, but more likely Mozilla Firefox or Google Chrome.

Enabling Java Script in Mozilla Firefox:

  1. At the top of the Firefox window, click on the Edit menu and select Preferences
  2. In the Preferences window, select the Content panel.
  3. Enable JavaScript: Select this option to permit JavaScripts to execute on your computer.
  4. Click Close to close the window.

Edit - Preferences - Content - Enable JavaScript

Enabling Java Script in Google Chrome:

  1. On the web browser menu click on the Customize and control Google Chrome and select Settings.
  2. In the Settings section click on the Show advanced settings…
  3. Under the the Privacy click on the Content settings….
  4. When the dialog window opens, look for the JavaScript section and select Allow all sites to run JavaScript (recommended).
  5. Click on the OK button to close the window.

Customize - Settings - Show advanced - Privacy - Content - JavaScript - Allow

What is JavaScript

JavaScript is a popular scripting language, often built-in in modern browsers. It is being used to add interactive user experience to web sites. With javascript you can make all kinds of interactions, from effects and animations, to dynamically changing content and context switching. The most significant technology based on JavaScript is AJAX (Asynchronous JavaScript and XML) which is designed and dedicated to delivering dynamic content by making asynchronous web requests, without refreshing the current web page, or navigating the browser to a different web page. Take a look at other articles to learn more.

Zend_Service_Twitter and OAuth – How to use twitter API in Zend Framework

Zend_Service_Twitter, OAuth, Twitter API and how the f*ck to do it right..?

Using Zend Framework is a very pleasant thing, but sometimes you may.. sort of.. hit the wall. When you need to use Twitter Applications API in your web application, you may find some lack of information about the best practice and workflow of this subject. The flow is pretty simple actually, and I will explain it in short descriptions and code snippets as examples.

The flow

The first step is to build a method to authorize your application and to request permissions from the user. This is done by using the Zend_Oauth_Consumer library’s mechanism to obtain the so called “request token”. The request token is used later by your application, to authenticate it’s self and to obtain the “access token” needed to initialize the Zend_Service_Twitter.
Here is an example of how to do this:

	protected function _authTwitter()
	{
		$config = array(
			'callbackUrl' => $this->view->serverUrl() . '/tweet/twitter-callback',
			'siteUrl' => 'http://twitter.com/oauth',
			'consumerKey' => "YOUR_APPLICATION_KEY",
			'consumerSecret' => "YOUR_APPLICATION_SECRET"
		);

		$consumer = new Zend_Oauth_Consumer($config);

		$token = $consumer->getRequestToken(); //this may throw an exception if something goes wrong, so don't hesitate to try/catch it

		$this->session->twitter_request_token = serialize($token); //$this->session is an Zend_Session_Namespace instance, we save the request token in the session for later usage in the callback

		$consumer->redirect();
	}

The code above will redirect your application to twitter.com/oauth to request permissions from the user. This requires a “callback” url to land after finishing the process of authentication and authorization.
You should call this method when you don’t have a access token stored and you need to request permissions to perform an API call.

The second step is to implement the callback action method, to do the following tasks:

  1. Check if there is a request token set in the session to continue the OAuth authentication flow
  2. Check if there is an OAuth response in the $_GET
  3. If both conditions are true, initialize the Zend_Oauth_Consumer again and obtain access token, based on the signed request and the request token.
  4. If access token is granted, save it for later usage, if not, handle the exception and fallback
	public function twitterCallbackAction()
	{
		$config = array(
			'callbackUrl' => $this->view->serverUrl() . '/tweet/twitter-callback',
			'siteUrl' => 'http://twitter.com/oauth',
			'consumerKey' => "YOUR_APPLICATION_KEY",
			'consumerSecret' => "YOUR_APPLICATION_SECRET"
		);

		$consumer = new Zend_Oauth_Consumer($config);

		//$this->session is an instance of Zend_Session_Namespace
		if (!empty($_GET) && isset($this->session->twitter_request_token))
		{
			try
			{
				$token = $consumer->getAccessToken(
						$_GET, unserialize($this->session->twitter_request_token)
				);
			}
			catch (Exception $e)
			{
				$this->log("TWITTER SUBMIT TWEET ERROR: ".$e->getMessage());
				//$this->log is an instance of Zend_Log

				$this->_redirect("/tweet");
				
				return;
			}

			//save the access token and clear the request token			

			$this->session->twitter_access_token = serialize($token);

			$this->session->twitter_request_token = null;

			//go back to application

			$this->_redirect("/tweet");
		}
		else
		{
			$this->session->errors = array("Invalid twitter connection...");

			$this->_redirect("/tweet");
		}
	}

If everything goes well you can now implement a form, that will post a message to your application, that will be tweeted in the user’s twitter account. You may do a lot of things actually. Take a look at the official Zend_Service_Twitter API.

Here is a Zend_Service_Twitter example of a twitter API call:

	protected function _sendMessage($message)
	{
		$twitter = new Zend_Service_Twitter(array(
					'accessToken' => unserialize($this->session->twitter_access_token)
				));//use access token from session

		$response = $twitter->status->update($message); //post tweet (less than 140 chars)

		$this->log("TWITTER SUBMIT TWEET RESPONSE: ".$response); //log, just in case of failures
	}

Good luck and happy coding!

LESS CSS tutorial – the beginners guide to a CSS preprocessor. Learn about LESS and save your time repeating CSS code.

LESS CSS tutorial – the beginners guide to a CSS preprocessor.

What is less ?

LESS is a CSS preprocessor. It can solve common code problems, such as code repetition. LESS is crossbrowser friendly. Very intuitive and agile tool.
This is a short tutorial of LESS CSS including some tips.
Before we start i want you to know that there are other CSS preprocessor like SASS, that will be covered in another post.

This tutorial will cover the following:

  • What is the DRY(Don’t repeat yourself) design pattern. How can be implement on CSS using LESS CSS
  • Short introduction to LESS
  • Editors and IDE
  • Getting started with LESS
  • LESS CSS nesting – LESS gives you the ability to use nesting in your CSS!
  • LESS parameters – Finally variables in your CSS
  • LESS functions and operations
  • LESS mixins
  • Final Tips

DRY ( don’t repeat yourself )

DRY is not just a design patter, but it is a way of thinking and a principle of software development. Simple steps to follow, so you can get the idea of DRY.

  1. Identify repetitive and reusable code.
  2. Instead if copy/paste huge blocks of CSS code, you can create a function (Mixin) with LESS to be called when you need those styles
  3. Make use of the Nested Rules – which will cut down some of your repetitive code.
  4. Use variables, color functions, operators and mixins to separate structural code from representational code

By implementing DRY principles in your code you add also the KISS (Keep it simple, stupid!) design principle. When you need to change all the colors or fonts in your website – do it from one place via variables. When you need to change the behavior of all modal windows or popups – do it from one place using a mixin that generates those styles.
Q: Why you should bother with all of this?
A: The code repetion problem will expand in big and growing applications. At some point your code will become unmaintainable.

Short introduction to LESS

LESS expands the capabilities of CSS. It adds more features and agile solutions to common CSS problems. LESS is crossbrowser friendly.

Editors and IDE

A preferred LESS editor – sublime text 2.

LESS syntax is supported by many IDE’s like – VIM, Aptana Studio, Coda 2

Getting started with LESS

First you must download the latest less.js from github – https://github.com/cloudhead/less.js or the official site http://lesscss.org

You will need to create a file with .less extension to put your styles there. Preferred is styles.less

Add the less.js and styles.less to your HTML’s head section:

<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

Note the rel attribute of the link element must end with /less in order for LESS to work. You are also required to include the less.js script immediately after the link to the style sheet. If you’re using HTML5 syntax, you can omit the type=”text/css” and the type=”text/javascript”, but do not omit rel=”stylesheet/less”.

Server-side version of LESS – The easiest way to install LESS on the server is with Node Package Manager (NPM). Installations are available for Windows, OSX, UNIX

LESS CSS nesting

// Brand, links, text, and buttons
.navbar {
    text-align: center;
    // Hover and active states
    .brand:hover {
        text-decoration: none;
    }
    .btn-danger{
        float: right;
    }
    // Website or project name
    .brand {
        float: left;
        display: block;
        padding: 8px 20px 8px;
        color: @white;
    }
    // Plain text in topbar
    .navbar-text {
        margin-bottom: 0;
        line-height: 40px;
        color: @navbarText;

        a:hover {
          color: @white;
          background-color: transparent;
        }
    }
    // Buttons in navbar
    .btn,
    .btn-group {
        margin-top: 5px;
    }
    .btn-group .btn {
        margin-top: 0;
    }
}

LESS gives you the ability to use nesting in your CSS!
With the use of & combinator you can nest selector to concatenate the child to its parent selector, instead of acting as a descendant. This is very usefull for pseudo-classes like :hover, :visited and :focus.
With the ability to nest styles your code is more readable and consistent.

LESS parameters

// Accent colors
// -------------------------
@blue:                  #049cdb;
@blueDark:              #0064cd;
@green:                 #46a546;
@red:                   #9d261d;
@yellow:                #ffc40d;
@orange:                #f89406;
@pink:                  #c3325f;
@purple:                #7a43b6;

// Typography
// -------------------------
@sansFontFamily:        "Helvetica Neue", Helvetica, Arial, sans-serif;
@serifFontFamily:       Georgia, "Times New Roman", Times, serif;
@monoFontFamily:        Monaco, Menlo, Consolas, "Courier New", monospace;
@smallFonts:               Helvetica, Arial, sans-serif;

Finally variables!

Variables in LESS are defined via the keyword ‘@’
Variables can have value type of string or number. You can easy separate the presentational part of your layout like colors and fonts. Using variables will help you keep the consistency of your code. When you have all colors defined you don’t need any more to search and scroll for their hex values.

It’s a good practice to define all your variables in separated LESS file and include it on top of your main LESS file

LESS functions and operations

@linkColor:             @blueType;
@linkColorHover:        darken(@blueType, 15%);
@gridColumns1200:            12;      
@gridColumnWidth1200:     90px;
@gridGutterWidth1200:     10px;
@gridRowWidth1200:        (@gridColumns1200 * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns1200 + 1));

When using functions and arithmetical operations, the result will be a value
You can add, multiply or divide – pixel, em, %, hex values. Functions are mainly used to help you stick to a color scheme in your coding process. There is no need to go into photoshop and lighten a color with 10% for example.

LESS mixins

// Gradients
#gradient {
  .horizontal(@startColor: #555, @endColor: #333) {
    background-color: @endColor;
    background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+
    background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
    background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+
    background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10
    background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10
    background-repeat: repeat-x;
    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down
  }
}

Mixins are functions that let you implement OOCSS (Object Orientated CSS) principles in your styles. By separating identical styles from elements and using css class inheritance, you can decrease the number of repeated styles. That will help you reduce the CSS file size. This practice is the key foundation of DRY principles and design pattern. You can read more about OOCSS in the following links: http://www.slideshare.net/stubbornella/object-oriented-css, http://www.slideshare.net/stubbornella/what-is-object-oriented-css.

The execution of a mixin will return a block of CSS code. For example all your modal windows will include the .modal-behaviour() and .border-radius() mixins

If you were wondering, can be passed an argument to a mixin? Yes you can. That is another power full feature ot he mixins. You can set default values to your arguments, and pass other to override them. With passing a parameter to a mixin it becomes more flexible and reusable.

// Box sizing Mixin
.box-sizing(@boxmodel) {
  -webkit-box-sizing: @boxmodel;
     -moz-box-sizing: @boxmodel;
          box-sizing: @boxmodel;
}
// Block level inputs
.input-block-level {
  display: block;
  width: 100%;
  min-height: 30px; 
  .box-sizing(border-box); // using a mixin
}

Another good feature of Mixins is to store them in namespaces. For example you want all your font mixins to be stored in #fonts namespace:

// FONTS
// --------------------------------------------------

#font {
  #family {
    .serif() {
      font-family: @serifFontFamily;
    }
    .sans-serif() {
      font-family: @sansFontFamily;
    }
    .monospace() {
      font-family: @monoFontFamily;
    }
  }
  .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
    font-size: @size;
    font-weight: @weight;
    line-height: @lineHeight;
  }
  .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
    #font > #family > .serif;
    #font > .shorthand(@size, @weight, @lineHeight);
  }
  .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
    #font > #family > .sans-serif;
    #font > .shorthand(@size, @weight, @lineHeight);
  }
  .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
    #font > #family > .monospace;
    #font > .shorthand(@size, @weight, @lineHeight);
  }
} 

Final Tips

  • Keep your code simple and consistent
  • Use DRY principles where possible
  • For better understanding and implementation of OOCSS use a LESS framework like Bootstrap
  • There are many many more things that can be said about LESS. For example LESS preferred frameworks. Advanced techniques for rapid web development and prototyping. Fluid and fixed layouts. Grid system generator mixins. Best practices for development and production environments. Mobile and tablet development. Quick retina displays enhancements and support. All topics will be featured in a separated advanced LESS CSS tutorial. If you enjoy writing less code, please check out the next tutorial as soon it is available :)

    There are useful links available at the end of the presentation.

    In general – write LESS do more! This is the major feature of LESS.
    The LESS CSS tutorial is formatted as a presentation – LESS presentation

Zend twitter view helper for better user experience

Displaying tweets on a website in the same manner that twitter displays them is a nice user friendly feature to have. Shown bellow is the source for a zend twitter view helper. It should be placed in the “views/helpers” directory in your project in a file named Twitter.php.

<?php
class Zend_View_Helper_Twitter extends Zend_View_Helper_Abstract
{
	public function twitter()
	{
		return $this;
	}

	public function linkifyUsernames($tweet)
	{
		return preg_replace("/@(\w+)/i", "<a href=\"http://twitter.com/$1\" target=\"_blank\">$0</a>", $tweet);
	}

	public function linkifyHashTags($tweet)
	{
		return preg_replace("/#(\w+)/i", "<a href=\"http://twitter.com/#!/search/%23$1\" target=\"_blank\">$0</a>", $tweet);
	}

	public function linkify($tweet)
	{
		$tweet = $this->linkifyUsernames($tweet);
		$tweet = $this->linkifyHashTags($tweet);

		return $tweet;
	}
}

Usage

After you create the file this zend twitter view helper can be used from your view script by calling the twitter() method and then using either linkifyUsernames(), linkifyHashTags() or just linkify() to linkify both usernames and hashtags.

The regular expressions will convert #anystring to

<a href="http://twitter.com/#!/search/#anystring" target="blank">#anystring</a>

and @anyone to

<a href="http://twitter.com/@anyone" target="blank">@anyone</a>

Example

In a view script:

<?php echo $this->twitter()->linkify("Lorem @ipsum dolor #sit amet, consetetur sadipscing @elitr, sed diam nonumyeirmod #tempor invidunt ut #labore et dolore magna"); ?>

will output:
Lorem @ipsum dolor #sit amet, consetetur sadipscing @elitr, sed diam nonumyeirmod #tempor invidunt ut #labore et dolore magna

Numeric only inputs with jQuery

This little jQuery snippet will let you to quickly create a numeric only textbox (input). A nice feature to include for improved user experience.

$.fn.numericOnly = function(decimal, callback) {
	var $el = $(this);
	$el.keydown(function(event) {
		var allowedKeycodes = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8, 9,
					96, 97, 98, 99, 100, 101, 102, 103, 104, 105];

		if(decimal && $el.val().indexOf('.') == -1) {
			allowedKeycodes.push(190);
			allowedKeycodes.push(110);
		}

		if($.inArray(event.which, allowedKeycodes) == -1) {
			if(callback) callback.call($el);
			event.preventDefault();
		}

		return true;
	});
}

Click Here for the demo.

Making numeric only textbox

To setup the numeric only plugin with its default settings use:

$("#input_id").numericOnly();

And it will disallow entering non numeric characters.

To allow decimal numbers pass true as the first parameter:

$("#input_decimal").numericOnly(true);

And the plugin will allow the input of one “.” decimal point.

For giving a visual feedback effect when user tries to type a illegal character one can use the callback function. The bellow example will make the border of the input red for 300 miliseconds:

$("#numeric_only_callback").numericOnly(true, function(){
	var oldBorder = this.css('border-color');

	this.css('border-color', 'red');

	var el = this;
	setTimeout(function(){
		el.css('border-color', oldBorder);
	},300);
});

This is not a replacement for the server-side validation. Just an easy way to enhance user experience.

Zend Framework Configure Console Tool

The tool

Zend Framework ships with a library folder and bin folder. The library folder contains all the good stuff and the bin folder contains the ZF console tool. This tool is often ignored and unused, which usually leads to statements like “what a stupid framework, I don’t like it”. The tool consists of a launcher (.bat/.sh) that initialized the zf.php file, which actually just facilitates access to the Zend_Tool package and your custom project providers and manifests. Manifests are used to import custom (non-standard) providers and providers are just classes with action methods. Each action method should be named as a verb, that indicates the action that will be taken over the project, in term of the provider name. For example “create controller” is a zf tool command that runs create() method in the controller provider. The main purpose of all this is to be able to add custom automated functionalities to your project, but could also be used for maintenance and scheduled tasks.

The setup

Setting up the ZF console tool is actually pretty easy. As long as you don’t make any preliminary mistakes.
Possible faults are:

  1. Make sure that there is NO .zf.ini inside your home directory (/home/username in linux and C:\Users\Username in.. you know)
  2. Make sure that there is no hardcoded include path that leads to the Zend folder:
      php -r "echo ini_get('include_path').PHP_EOL;"
      
  3. Make sure you have a valid .zfproject.xml file in your project directory. If not, running ./zf.sh create poject in the original bin folder extracted from the archive will create a new empty project with valid .zfproject.xml file. In addition, make sure that the <projectProviderFolder/> in the xml file is enabled.
  4. Make sure you have a copy of Zend Framework in the library folder of your project.
  5. Make sure your library folder is configured as an include path in your project’s application.ini
  6.   includePaths.library = APPLICATION_PATH "/../library"
      

After validating the points above just copy the original bin folder from the extracted archive in your project’s root directory.

Running

To launch the zf console tool simply type in your terminal from your project’s root directory:

./bin/zf.sh

If everything goes well you should see a list of all available providers and their actions. Now you can use the tool to create modules, controllers, actions, dummy dbtable models and etc. You can also write your own project providers to extend the functionalities of the zf console tool.

Zend Framework 1.11 and CRON jobs. Wait, wut?

Setup Zend Framework CRON jobs

Setup CRON jobs for Zend Framework applications? Yes it is possible and actually it’s pretty simple and elegant. Read below to see how to use create zend framework cron jobs.

CRON

Every serious web application demands large and/or heavy amounts of calculations to be made, or data to be prepared outside the client flow. Probably the best solution for this is to run CRON jobs. Running CRONs is sometimes pretty easy, just execute a .php file, it does what it does and that’s it, but when it comes to ZF, you may need to use more than just custom initialized PDO and files I/O. If you need to run Zend_Db, Zend_Db_Table models, Zend_Cache, or other Zend Framework libraries in your CRON, you will need to do it The Zend Way.

How

Just create a project provider in your project’s directory, using your ZF console tool. To do so, make sure you have a working ZF tool and run:

./bin/zf.sh create project-provider MyCron run

You can verify the results of this operation by taking a look inside your project’s “providers” directory and by running the ZF tool again to list the available providers and actions:

./bin/zf.sh

The next step is to open the provider file in the “providers” directory and add an init() method as a private or protected method, depending on whether you are going to extend this provider or not. Public methods are visible in ZF tool, so the init method should never be public.

    /**
     * @var Zend_Db_Adapter_Abstract
     */
    private $db;
    
    /**
     *
     * @var array 
     */
    private $config;

    private function init()
    {
	$this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); //load .zfproject.xml

	$bootstrapResource = $this->_loadedProfile->search('BootstrapFile'); //get application bootstrap

	/* @var $zendApp Zend_Application */
	$zendApp = $bootstrapResource->getApplicationInstance(); //initialize application instance

	try
	{
	    //bootstrap resource plugins for later usage
	    $zendApp->bootstrap('log');
	    $zendApp->bootstrap('cachemanager');
	    $zendApp->bootstrap('db');

            //new Zend_Session_Namespace(); //uncomment if you are going to use Facebook API, prevents from session_start bug
        }
	catch (Zend_Application_Exception $e)
	{
	    throw new Zend_Tool_Project_Provider_Exception($e->getMessage());
	}
        
	$this->db = $zendApp->getBootstrap()->getResource('db')->getConnection(); //get database instance for later usage

	$this->config = $zendApp->getOptions(); //get the contents of application.ini as array
    }

Now, you can use the init() method inside your action methods to configure the povider.

    public function run()
    {
	$this->init();

	//awsome stuff go here
    }


CRONTAB Setup

The final step is to setup your crontab to execute the ZF console tool and your project provider at predefined time intervals or events. To do this, edit the file, opened by “crontab -e” command

* * * * * cd /path/to/project && ./bin/zf.sh run my-cron

This for example will execute the project provider’s run() method each and every minute. For more information about CRONTAB settings, see here or run “man crontab