Commits

Anonymous committed 8121a5b

first initial

  • Participants

Comments (0)

Files changed (116)

+# cache directories
+Thumbs.db
+*.DS_Store
+*.empty
+
+#phpstorm project files
+.idea
+
+#netbeans project files
+nbproject
+
+#eclipse, zend studio, aptana or other eclipse like project files
+.buildpath
+.project
+.settings
+
+# sass cache files
+*.sass-cache
+
+# mac deployment helpers
+switch
+index
+
+# runtime and cache directories
+/app/runtime
+/www/assets
+
+# yiinitializr env.lock
+/app/lib/Yiinitializr/config/env.lock
+
+# env files and testdrive database
+/app/config/env.php
+/app/data/testdrive.db
+
+# composer
+/app/lib/vendor
+composer.lock
+YIInitializr-basic
+=======
+The following is a proposed project structure for basic applications that works in conjunction with YIInitializr components. 
+
+YIInitializr vanilla projects make extensive use of Composer. We found at [2amigos.us](http://2amigos.us) that is easier to your extensions bundle outside of your application scope - thanks to [Phundament](http://phundament.com) and Tobias Munk for his knowledge and shares. Composer is your dependency package best friend. 
+
+The package is cleaned from extensions, you choose what you wish to include in your composer.json files. The only ones included are Yii Framework (obviously), [YiiStrap](https://github.com/yii-twbs/yiistrap) and [YiiWheels](https://github.com/2amigos/yiiwheels), the rest is up to you. We do not want to confuse you 
+
+## Setup and first run
+
+  * Set up Git by following the instructions [here](https://help.github.com/articles/set-up-git).
+  * Update the configurations in `app/config/` to suit your needs. The `common/config/main.php` is configured to use **sqllite** by default. Change your `common/config/env/dev.php` to suit your database requirements.
+  * Composer is required The package includes already a `composer.phar` file.
+  * Browse through the `composer.json` and remove the dependencies you don't need also update the required versions of the extensions.
+  * If you have `composer` installed globally:
+	 * Run `composer self-update` to make sure you have the latest version of composer.
+	 * Run `composer install` to download all the dependencies.
+  * If you work the `composer.phar` library within the project boilerplate.
+    * Run `php composer.phar self-update` to make sure you have the latest version of composer.
+    * Run `php composer.phar install` to download all the dependencies.
+  * `Yiinitializr\Composer\Callback` will configure everything required on your application: `runtime` and `assets` folders and migrations.
+
+
+For more information about using Composer please see its [documentation](http://getcomposer.org/doc/).
+
+###How to configure the application
+
+We focused to release the pain of configuring your application and combine your configuration files. `Yiinitializr\Helpers\Initializr` is very easy to use, check for example the bootstrap `index.php` file:
+
+```
+require('./../app/lib/vendor/yiisoft/yii/framework/yii.php');
+
+Yii::setPathOfAlias('Yiinitializr', './../app/lib/Yiinitializr');
+
+use Yiinitializr\Helpers\Initializer;
+
+Initializer::create('./../app', 'main', array('common', 'env', 'local'))->run();
+```
+
+For more information about Yiinitializr please check it at [its github repo](https://github.com/2amigos/yiinitializr).
+
+## Overall Structure
+
+Bellow the directory structure used:
+
+```
+   |-app
+   |---cli
+   |-----commands
+   |-----migrations
+   |---config
+   |-----env
+   |---controllers
+   |---extensions
+   |-----behaviors
+   |-----components
+   |---helpers
+   |---lib #it will hold composer 'vendor' folder
+   |-----Yiinitializr
+   |-------Cli
+   |-------Composer
+   |-------Helpers
+   |-------config
+   |---messages
+   |---models
+   |---modules
+   |---views
+   |-----layouts
+   |-----site
+   |---widgets
+   |-www
+   |---css
+   |-----fonts
+   |---img
+   |---js
+   |-----libs
+```
+
+
+## Extensions
+
+The following extensions are part of YIInitializr-basic template:
+
+ * Yiistrap [https://github.com/yii-twbs/yiistrap](https://github.com/yii-twbs/yiistrap)
+ * Yiiwheels [https://github.com/2amigos/yiiwheels](https://github.com/2amigos/yiiwheels)
+ * Yiinitializr [https://github.com/2amigos/yiinitializr](https://github.com/2amigos/yiinitializr)
+
+> [![2amigOS!](http://www.gravatar.com/avatar/55363394d72945ff7ed312556ec041e0.png)](http://www.2amigos.us)    
+<i>web development has never been so fun</i>  
+[www.2amigos.us](http://www.2amigos.us) 
+deny from all

app/cli/commands/.gitkeep

Empty file added.

app/cli/migrations/.gitkeep

Empty file added.

app/config/common.php

+<?php
+/**
+ *
+ * common.php configuration file
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+return array(
+	'basePath' => realPath(__DIR__ . '/..'),
+    'preload' => array('log','bootstrap','chartjs'),
+	'aliases' => array(
+		'vendor' => 'application.vendor',
+
+	),
+	'import' => array(
+		'application.controllers.*',
+		'application.extensions.components.*',
+		'application.extensions.behaviors.*',
+		'application.helpers.*',
+		'application.models.*',
+
+	),
+    'modules' => array(
+    ),
+	'components' => array(
+        'db' => array(
+            'connectionString' => 'mysql:host=localhost;dbname=pres',
+            'username' => 'root',
+            'password' => 'root',
+            'enableProfiling' => true,
+            'enableParamLogging' => true,
+            'charset' => 'utf8',
+            'tablePrefix' => 'tbl_'
+        ),
+		'errorHandler' => array(
+			'errorAction' => 'site/error',
+		),
+
+        'log'=>array(
+            'class'=>'CLogRouter',
+            'routes'=>array(
+                array(
+                    'class'=>'CFileLogRoute',
+                    'levels'=>'error, warning, info',
+                ),
+                array(
+                    'class'=>'CWebLogRoute',
+                    'levels'=>'trace',
+                    'enabled'=>true,
+                ),
+            ),
+        ),
+
+	),
+	'params' => array(
+
+		// php configuration
+		'php.defaultCharset' => 'utf-8',
+		'php.timezone'       => 'UTC',
+        'yii.handleErrors'   => true,
+        'yii.debug' => true,
+        'yii.traceLevel' => 3,
+	)
+);

app/config/console.php

+<?php
+/**
+ *
+ * console.php configuration file
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+defined('APP_CONFIG_NAME') or define('APP_CONFIG_NAME', 'console');
+return array(
+	'commandMap' => array(
+		'migrate' => array(
+			'class' => 'system.cli.commands.MigrateCommand',
+			'migrationPath' => 'application.cli.migrations'
+		)
+	)
+);

app/config/env/dev.php

+<?php
+/**
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+return array(
+	'modules' => array(
+		'gii' => array(
+			'class' => 'system.gii.GiiModule',
+			'password' => 'yii',
+			'ipFilters' => array('127.0.0.1','::1'),
+		),
+	),
+	'components' => array(
+//		modify to suit your needs
+//		'db' => array(
+//			'connectionString' => '{CONNECTION_STRING}',
+//			'username' => '{USERNAME}',
+//			'password' => '{PASSWORD}',
+//			'enableProfiling' => true,
+//			'enableParamLogging' => true,
+//			'charset' => 'utf8',
+//		),
+	),
+	'params' => array(
+		'yii.handleErrors'   => true,
+		'yii.debug' => true,
+		'yii.traceLevel' => 3,
+	)
+);

app/config/main.php

+<?php
+/**
+ *
+ * main.php configuration file
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+defined('APP_CONFIG_NAME') or define('APP_CONFIG_NAME', 'main');
+
+use Yiinitializr\Helpers\ArrayX;
+
+// web application configuration
+return array(
+	'name' => '{APPLICATION NAME}',
+
+	// path aliases
+	'aliases' => array(
+        'bootstrap' => dirname(__FILE__) . '/../lib/vendor/drmabuse/yii-bootstrap-3-module',
+        'chartjs' => dirname(__FILE__) . '/../lib/vendor/drmabuse/yii-bootstrap-3-module/extensions/yii-chartjs-master',
+	),
+    'import' => array(
+        'bootstrap.*',
+        'bootstrap.components.*',
+        'bootstrap.models.*',
+        'bootstrap.controllers.*',
+        'bootstrap.helpers.*',
+        'bootstrap.widgets.*',
+        'bootstrap.extensions.*',
+        'chartjs.*',
+        'chartjs.widgets.*',
+        'chartjs.components.*',
+    ),
+	// application behaviors
+	'behaviors' => array(),
+
+	// controllers mappings
+	'controllerMap' => array(),
+
+	// application modules
+	'modules' => array(
+        'bootstrap' => array(
+            'class' => 'bootstrap.BootStrapModule'
+        ),
+    ),
+
+	// application components
+	'components' => array(
+
+        'bsHtml' => array(
+            'class' => 'bootstrap.components.BSHtml'
+        ),
+        'chartjs'=>array(
+            'class' => 'chartjs.components.ChartJs'
+        ),
+		'urlManager' => array(
+			// uncomment the following if you have enabled Apache's Rewrite module.
+			'urlFormat' => 'path',
+			'showScriptName' => false,
+
+			'rules' => array(
+				// default rules
+				'<controller:\w+>/<id:\d+>' => '<controller>/view',
+				'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
+				'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
+			),
+		),
+		'user' => array(
+			'allowAutoLogin' => true,
+		),
+
+		'errorHandler' => array(
+			'errorAction' => 'site/error',
+		),
+	),
+	// application parameters
+	'params' => array(
+        'yii.handleErrors'   => true,
+        'yii.debug' => true,
+        'yii.traceLevel' => 3,
+    ),
+);

app/config/test.php

+<?php
+/**
+ *
+ * test.php configuration file
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+return array(
+	'params' => array(
+		'yii.handleErrors'   => false,
+	)
+);

app/controllers/SiteController.php

+<?php
+/**
+ *
+ * SiteController class
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+class SiteController extends EController
+{
+	public function actionIndex()
+	{
+		$this->render('index');
+	}
+
+	/**
+	 * This is the action to handle external exceptions.
+	 */
+	public function actionError()
+	{
+		if($error=Yii::app()->errorHandler->error)
+		{
+			if(Yii::app()->request->isAjaxRequest)
+				echo $error['message'];
+			else
+				$this->render('error', $error);
+		}
+	}
+}

app/data/.gitkeep

Empty file added.

app/extensions/behaviors/.gitkeep

Empty file added.

app/extensions/components/EActiveRecord.php

+<?php
+/**
+ * EActiveRecord class
+ *
+ * Some cool methods to share amount your models
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+class EActiveRecord extends CActiveRecord
+{
+	/**
+	 * default form ID for the current model. Defaults to get_class()+'-form'
+	 */
+	private $_formId;
+
+	public function setFormId($value)
+	{
+		$this->_formId = $value;
+	}
+
+	public function getFormId()
+	{
+		if (null !== $this->_formId)
+			return $this->_formId;
+		else
+		{
+			$this->_formId = strtolower(get_class($this)) . '-form';
+			return $this->_formId;
+		}
+	}
+
+	/**
+	 * default grid ID for the current model. Defaults to get_class()+'-grid'
+	 */
+	private $_gridId;
+
+	public function setGridId($value)
+	{
+		$this->_gridId = $value;
+	}
+
+	public function getGridId()
+	{
+		if (null !== $this->_gridId)
+			return $this->_gridId;
+		else
+		{
+			$this->_gridId = strtolower(get_class($this)) . '-grid';
+			return $this->_gridId;
+		}
+	}
+
+	/**
+	 * default list ID for the current model. Defaults to get_class()+'-list'
+	 */
+	private $_listId;
+
+	public function setListId($value)
+	{
+		$this->_listId = $value;
+	}
+
+	public function getListId()
+	{
+		if (null !== $this->_listId)
+			return $this->_listId;
+		else
+		{
+			$this->_listId = strtolower(get_class($this)) . '-list';
+			return $this->_listId;
+		}
+	}
+
+	/**
+	 * Logs the record update information.
+	 * Updates the four columns: create_user_id, create_date, last_update_user_id and last_update_date.
+	 */
+	protected function logUpdate()
+	{
+		$userId = php_sapi_name() === 'cli'
+			? -1
+			: Yii::app()->user->id;
+
+		foreach (array('create_user_id' => $userId, 'create_date' => time()) as $attribute => $value)
+			$this->updateLogAttribute($attribute, $value, (!($userId===-1 || Yii::app()->user->isGuest) && $this->isNewRecord));
+
+		foreach (array('last_update_user_id' => $userId, 'last_update_date' => time()) as $attribute => $value)
+			$this->updateLogAttribute($attribute, $value, (!($userId===-1 || Yii::app()->user->isGuest) && !$this->isNewRecord));
+	}
+
+	/**
+	 * Helper function to update attributes
+	 * @param $attribute
+	 * @param $value
+	 * @param $check
+	 */
+	protected function updateLogAttribute($attribute, $value, $check)
+	{
+
+		if ($this->hasAttribute($attribute) && $check)
+			$this->$attribute = $value;
+
+	}
+
+	/**
+	 * updates the log fields before saving
+	 * @return boolean
+	 */
+	public function beforeSave()
+	{
+		$this->logUpdate();
+		return parent::beforeSave();
+	}
+
+}

app/extensions/components/EController.php

+<?php
+/**
+ * EController class
+ *
+ * Has some useful methods for your Controllers
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+class EController extends CController
+{
+	public $meta_keywords = array();
+	public $meta_description = array();
+	public $breadcrumbs;
+    public $layout;
+    public $mainNavPartials = array();
+    public $secondNavPartials = array();
+    public $menu;
+
+	/**
+	 * Gets a param
+	 * @param $name
+	 * @param null $defaultValue
+	 * @return mixed
+	 */
+	public function getActionParam($name, $defaultValue = null)
+	{
+		return Yii::app()->request->getParam($name, $defaultValue );
+	}
+
+	/**
+	 * Loads the requested data model.
+	 * @param string the model class name
+	 * @param integer the model ID
+	 * @param array additional search criteria
+	 * @param boolean whether to throw exception if the model is not found. Defaults to true.
+	 * @return CActiveRecord the model instance.
+	 * @throws CHttpException if the model cannot be found
+	 */
+	protected function loadModel($class, $id, $criteria = array(), $exceptionOnNull = true)
+	{
+		if (empty($criteria))
+			$model = CActiveRecord::model($class)->findByPk($id);
+		else
+		{
+			$finder = CActiveRecord::model($class);
+			$c = new CDbCriteria($criteria);
+			$c->mergeWith(array(
+				'condition' => $finder->tableSchema->primaryKey . '=:id',
+				'params' => array(':id' => $id),
+			));
+			$model = $finder->find($c);
+		}
+		if (isset($model))
+			return $model;
+		else if ($exceptionOnNull)
+			throw new CHttpException(404, 'Unable to find the requested object.');
+	}
+
+	/**
+	 * Performs the AJAX validation.
+	 * @param CModel the model to be validated
+	 */
+	protected function performAjaxValidation($model)
+	{
+		if (isset($_POST['ajax']) && $_POST['ajax'] === $model->formId)
+		{
+			echo CActiveForm::validate($model);
+			Yii::app()->end();
+		}
+	}
+
+	/**
+	 * Outputs (echo) json representation of $data, prints html on debug mode.
+	 * NOTE: json_encode exists in PHP > 5.2, so it's safe to use it directly without checking
+	 * @param array $data the data (PHP array) to be encoded into json array
+	 * @param int $opts Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_FORCE_OBJECT.
+	 */
+	public function renderJson($data, $opts=null)
+	{
+		if(YII_DEBUG && isset($_GET['debug']) && is_array($data))
+		{
+			foreach($data as $type => $v)
+				printf('<h1>%s</h1>%s', $type, is_array($v) ? json_encode($v, $opts) : $v);
+		}
+		else
+		{
+			header('Content-Type: application/json; charset=UTF-8');
+			echo json_encode($data, $opts);
+		}
+	}
+
+	/**
+	 * Utility function to ensure the base url.
+	 * @param $url
+	 * @return string
+	 */
+	public function baseUrl( $url = '' )
+	{
+		static $baseUrl;
+		if ($baseUrl === null)
+			$baseUrl = Yii::app()->request->baseUrl;
+		return $baseUrl . '/' . ltrim($url, '/');
+	}
+
+}

app/extensions/components/EWebApplication.php

+<?php
+/**
+ *
+ * EWebApplication class
+ * 
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+class EWebApplication extends CWebApplication {
+
+	/**
+	 * This function is here because we aren't creating a locale file for every client.
+	 * Thus we provide a fallback to "en".
+	 */
+	public function getLocale($localeID = null) {
+		try {
+			return parent::getLocale($localeID);
+		} catch (Exception $e) {
+			return CLocale::getInstance('en');
+		}
+	}
+
+	/**
+	 * We were getting tons of errors in the logs from OPTIONS requests for the URI "*"
+	 * As it turns out, the requests were from localhost (::1) and are apparently a way
+	 * that Apache polls its processes to see if they're alive. This function causes
+	 * Yii to respond without logging errors.
+	 */
+	public function runController($route) {
+		try {
+			parent::runController($route);
+		} catch (CHttpException $e) {
+			if (@$_SERVER['REQUEST_METHOD'] == 'OPTIONS' && @$_SERVER['REQUEST_URI'] == '*') {
+				Yii::app()->end('Hello, amigo!');
+			} else
+				throw $e;
+		}
+	}
+
+}

app/helpers/.gitkeep

Empty file added.

app/lib/Yiinitializr/CHANGELOG

+                   Yiinitializr Change Log
+                   ========================
+
+Thursday 28-March-2013
+----------------------------
+Initial release

app/lib/Yiinitializr/Cli/Console.php

+<?php
+/**
+ * Console class file.
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @author Nofriandi Ramenta <nramenta@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @link https://github.com/nramenta/clio
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+namespace Yiinitializr\Cli;
+/**
+ * Console provides a set of useful functions to work on the terminal
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @package Yiinitializr.Cli
+ * @since 1.0
+ */
+class Console
+{
+	/**
+	 * Text foreground colors.
+	 */
+	protected static $FGCOLOR = array(
+		'black'  => 30,
+		'red'    => 31,
+		'green'  => 32,
+		'brown'  => 33,
+		'blue'   => 34,
+		'purple' => 35,
+		'cyan'   => 36,
+		'grey'   => 37,
+		'yellow' => 33,
+	);
+
+	/**
+	 * Text styling.
+	 */
+	protected static $STYLE = array(
+		'normal'     => 0,
+		'bold'       => 1,
+		'light'      => 1,
+		'underscore' => 4,
+		'underline'  => 4,
+		'blink'      => 5,
+		'inverse'    => 6,
+		'hidden'     => 8,
+		'concealed'  => 8,
+	);
+
+	/**
+	 * Text background color.
+	 */
+	protected static $BGCOLOR = array(
+		'black'  => 40,
+		'red'    => 41,
+		'green'  => 42,
+		'brown'  => 43,
+		'yellow' => 43,
+		'blue'   => 44,
+		'purple' => 45,
+		'cyan'   => 46,
+		'grey'   => 47,
+	);
+
+	/**
+	 * Color specifier conversion table. Taken from PEAR's Console_Color.
+	 */
+	protected static $CONVERSIONS = array(
+		'%y' => array('yellow', null, null),
+		'%g' => array('green', null, null),
+		'%b' => array('blue', null, null),
+		'%r' => array('red', null, null),
+		'%p' => array('purple', null, null),
+		'%m' => array('purple', null, null),
+		'%c' => array('cyan', null, null),
+		'%w' => array('grey', null, null),
+		'%k' => array('black', null, null),
+		'%n' => array('reset', null, null),
+		'%Y' => array('yellow', 'light', null),
+		'%G' => array('green', 'light', null),
+		'%B' => array('blue', 'light', null),
+		'%R' => array('red', 'light', null),
+		'%P' => array('purple', 'light', null),
+		'%M' => array('purple', 'light', null),
+		'%C' => array('cyan', 'light', null),
+		'%W' => array('grey', 'light', null),
+		'%K' => array('black', 'light', null),
+		'%N' => array('reset', 'light', null),
+		'%3' => array(null, null, 'yellow'),
+		'%2' => array(null, null, 'green'),
+		'%4' => array(null, null, 'blue'),
+		'%1' => array(null, null, 'red'),
+		'%5' => array(null, null, 'purple'),
+		'%6' => array(null, null, 'cyan'),
+		'%7' => array(null, null, 'grey'),
+		'%0' => array(null, null, 'black'),
+		'%F' => array(null, 'blink', null),
+		'%U' => array(null, 'underline', null),
+		'%8' => array(null, 'inverse', null),
+		'%9' => array(null, 'bold', null),
+		'%_' => array(null, 'bold', null),
+	);
+
+	/**
+	 * Create ANSI-control codes for text foreground and background colors, and
+	 * styling.
+	 *
+	 * @param string $fgcolor Text foreground color
+	 * @param string $style   Text style
+	 * @param string $bgcolor Text background color
+	 *
+	 * @return string ANSI-control code
+	 */
+	public static function color($fgcolor, $style, $bgcolor)
+	{
+		$code = array();
+		if ($fgcolor == 'reset') {
+			return "\033[0m";
+		}
+		if (isset(static::$FGCOLOR[$fgcolor])) {
+			$code[] = static::$FGCOLOR[$fgcolor];
+		}
+		if (isset(static::$STYLE[$style])) {
+			$code[] = static::$STYLE[$style];
+		}
+		if (isset(static::$BGCOLOR[$bgcolor])) {
+			$code[] = static::$BGCOLOR[$bgcolor];
+		}
+		if (empty($code)) {
+			$code[] = 0;
+		}
+		return "\033[" . implode(';', $code) . 'm';
+	}
+
+	/**
+	 * aken from PEAR's Console_Color:
+	 *
+	 * Converts colorcodes in the format %y (for yellow) into ansi-control
+	 * codes. The conversion table is: ('bold' meaning 'light' on some
+	 * terminals). It's almost the same conversion table irssi uses.
+	 * <pre>
+	 *                  text      text            background
+	 *      ------------------------------------------------
+	 *      %k %K %0    black     dark grey       black
+	 *      %r %R %1    red       bold red        red
+	 *      %g %G %2    green     bold green      green
+	 *      %y %Y %3    yellow    bold yellow     yellow
+	 *      %b %B %4    blue      bold blue       blue
+	 *      %m %M %5    magenta   bold magenta    magenta
+	 *      %p %P       magenta (think: purple)
+	 *      %c %C %6    cyan      bold cyan       cyan
+	 *      %w %W %7    white     bold white      white
+	 *
+	 *      %F     Blinking, Flashing
+	 *      %U     Underline
+	 *      %8     Reverse
+	 *      %_,%9  Bold
+	 *
+	 *      %n     Resets the color
+	 *      %%     A single %
+	 * </pre>
+	 * First param is the string to convert, second is an optional flag if
+	 * colors should be used. It defaults to true, if set to false, the
+	 * colorcodes will just be removed (And %% will be transformed into %)
+	 *
+	 * @param $text
+	 * @param bool $color
+	 * @return mixed
+	 */
+	public static function colorize($text, $color = true)
+	{
+		$text = str_replace('%%', '% ', $text);
+		foreach (static::$CONVERSIONS as $key => $value) {
+			list($fgcolor, $style, $bgcolor) = $value;
+			$text = str_replace(
+				$key,
+				$color ? static::color($fgcolor, $style, $bgcolor) : '',
+				$text
+			);
+		}
+		return str_replace('% ', '%', $text);
+	}
+
+	/**
+	 * Strips a string from color specifiers.
+	 *
+	 * @param string $text String to strip
+	 *
+	 * @return string
+	 */
+	public static function decolorize($text)
+	{
+		return static::colorize($text, false);
+	}
+
+	/**
+	 * Strips a string of ansi-control codes.
+	 *
+	 * @param string $text String to strip
+	 *
+	 * @return string
+	 */
+	public static function strip($text)
+	{
+		return preg_replace('/\033\[(\d+)(;\d+)*m/', '', $text);
+	}
+
+	/**
+	 * Gets input from STDIN and returns a string right-trimmed for EOLs.
+	 *
+	 * @param bool $raw If set to true, returns the raw string without trimming
+	 *
+	 * @return string
+	 */
+	public static function stdin($raw = false)
+	{
+		return $raw ? fgets(STDIN) : rtrim(fgets(STDIN), PHP_EOL);
+	}
+
+	/**
+	 * Prints text to STDOUT.
+	 *
+	 * @param string $text
+	 * @param bool   $raw
+	 *
+	 * @return int|false Number of bytes printed or false on error
+	 */
+	public static function stdout($text, $raw = false)
+	{
+		if ($raw) {
+			return fwrite(STDOUT, $text);
+		} elseif (extension_loaded('posix') && posix_isatty(STDOUT)) {
+			return fwrite(STDOUT, static::colorize($text));
+		} else {
+			return fwrite(STDOUT, static::decolorize($text));
+		}
+	}
+
+	/**
+	 * Prints text to STDERR.
+	 *
+	 * @param string $text
+	 * @param bool   $raw
+	 *
+	 * @return int|false Number of bytes printed or false on error
+	 */
+	public static function stderr($text, $raw = false)
+	{
+		if ($raw) {
+			return fwrite(STDERR, $text);
+		} elseif (extension_loaded('posix') && posix_isatty(STDERR)) {
+			return fwrite(STDERR, static::colorize($text));
+		} else {
+			return fwrite(STDERR, static::decolorize($text));
+		}
+	}
+
+	/**
+	 * Prints text to STDERR appended with a PHP_EOL.
+	 *
+	 * @param string $text
+	 * @param bool   $raw
+	 *
+	 * @return int|false Number of bytes printed or false on error
+	 */
+	public static function error($text = null, $raw = false)
+	{
+		return static::stderr($text . PHP_EOL, $raw);
+	}
+
+	/**
+	 * Asks the user for input. Ends when the user types a PHP_EOL. Optionally
+	 * provide a prompt.
+	 *
+	 * @param string $prompt String prompt (optional)
+	 *
+	 * @return string User input
+	 */
+	public static function input($prompt = null)
+	{
+		if (isset($prompt)) {
+			static::stdout($prompt);
+		}
+		return static::stdin();
+	}
+
+	/**
+	 * Prints text to STDOUT appended with a PHP_EOL.
+	 *
+	 * @param string $text
+	 * @param bool   $raw
+	 *
+	 * @return int|false Number of bytes printed or false on error
+	 */
+	public static function output($text = null, $raw = false)
+	{
+		return static::stdout($text . PHP_EOL, $raw);
+	}
+
+	/**
+	 * Prompts the user for input
+	 *
+	 * @param string $text    Prompt string
+	 * @param array  $options Set of options
+	 *
+	 * @return string
+	 */
+	public static function prompt($text, $options = array())
+	{
+		$options = $options + array(
+			'required'  => false,
+			'default'   => null,
+			'pattern'   => null,
+			'validator' => null,
+			'error'     => 'Input unacceptable.',
+		);
+
+		top:
+		if ($options['default']) {
+			$input = static::input("$text [" . $options['default'] . ']: ');
+		} else {
+			$input = static::input("$text: ");
+		}
+
+		if (!strlen($input)) {
+			if (isset($options['default'])) {
+				$input = $options['default'];
+			} elseif ($options['required']) {
+				static::output($options['error']);
+				goto top;
+			}
+		} elseif ($options['pattern'] && !preg_match($options['pattern'], $input)) {
+			static::output($options['error']);
+			goto top;
+		} elseif ($options['validator'] &&
+			!call_user_func_array($options['validator'], array($input, &$error))) {
+			static::output(isset($error) ? $error : $options['error']);
+			goto top;
+		}
+
+		return $input;
+	}
+
+	/**
+	 * Asks the user for a simple yes/no confirmation.
+	 *
+	 * @param string $text    Prompt string
+	 *
+	 * @return bool Either true or false
+	 */
+	public static function confirm($text)
+	{
+		top:
+		$input = strtolower(static::input("$text [y/n]: "));
+		if (!in_array($input, array('y', 'n'))) goto top;
+		return $input === 'y' ? true : false;
+	}
+
+	/**
+	 * Gives the user an option to choose from. Giving '?' as an input will show
+	 * a list of options to choose from and their explanations.
+	 *
+	 * @param string $text    Prompt string
+	 * @param array  $options Key-value array of options to choose from
+	 *
+	 * @return string An option character the user chose
+	 */
+	public static function select($text, $options = array())
+	{
+		top:
+		static::stdout("$text [" . implode(',', array_keys($options)) . ",?]: ");
+		$input = static::stdin();
+		if ($input === '?') {
+			foreach ($options as $key => $value) {
+				echo " $key - $value\n";
+			}
+			echo " ? - Show help\n";
+			goto top;
+		} elseif (!in_array($input, array_keys($options))) goto top;
+		return $input;
+	}
+
+	/**
+	 * Execute a Closure as another process in the background while showing a
+	 * status update. The status update can be an indefinite spinner or a string
+	 * periodically sent from the background process, depending on whether the
+	 * provided Closure object has a $socket parameter or not. Messaging to the
+	 * main process is done by socket_* functions. The return value is either
+	 * the return value of the background process, or false if the process fork
+	 * failed.
+	 *
+	 * @param callable $callable Closure object
+	 * @return bool|int
+	 * @throws \Exception
+	 */
+	public static function work(\Closure $callable)
+	{
+		if (!extension_loaded('pcntl')) {
+			throw new \Exception('pcntl extension required');
+		}
+
+		if (!extension_loaded('sockets')) {
+			throw new \Exception('sockets extension required');
+		}
+
+		$spinner = array('|', '/', '-', '\\');
+		$i = 0; $l = count($spinner);
+		$delay = 100000;
+
+		$func = new \ReflectionFunction($callable);
+
+		$socket = (bool)$func->getNumberOfParameters();
+
+		if ($socket) {
+			$sockets = array();
+			if (socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets) === false) {
+				return false;
+			}
+		}
+
+		$pid = pcntl_fork();
+
+		if ($pid > 0) {
+			$done   = false;
+			$retval = 0;
+			pcntl_signal(SIGCHLD, function() use ($pid, &$done, &$retval) {
+				$child_pid = pcntl_waitpid($pid, $status);
+				if (pcntl_wifexited($status)) {
+					$retval = pcntl_wexitstatus($status);
+				}
+				$done = true;
+			});
+
+			if ($socket) {
+				$text = '';
+				while (!$done) {
+					$r = array($sockets[1]);
+					$w = null;
+					$e = null;
+					if ($status = socket_select($r, $w, $e, 0)) {
+						$data = socket_read($sockets[1], 4096, PHP_NORMAL_READ);
+						if ($data === false) {
+							throw new \Exception(
+								sprintf(
+									'socket write error %s',
+									socket_strerror(socket_last_error($sockets[1]))
+								)
+							);
+						}
+						echo str_repeat(chr(8), strlen($text));
+						$text = rtrim($data, "\n");
+						Console::stdout($text);
+					} else {
+						pcntl_signal_dispatch();
+					}
+					usleep($delay);
+				}
+				echo str_repeat(chr(8), strlen($text));
+				socket_close($sockets[0]);
+				socket_close($sockets[1]);
+			} else {
+				while (!$done) {
+					pcntl_signal_dispatch();
+					echo $spinner[$i];
+					usleep($delay);
+					echo chr(8);
+					$i = $i === $l - 1 ? 0 : $i + 1;
+				}
+			}
+
+			return $retval;
+		} elseif ($pid === 0) {
+			if ($socket) {
+				call_user_func($callable, $sockets[0]);
+			} else {
+				call_user_func($callable);
+			}
+			exit;
+		} else {
+			// Unable to fork process.
+			return false;
+		}
+	}
+}

app/lib/Yiinitializr/Cli/Daemon.php

+<?php
+/**
+ * Daemon class file.
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @author Nofriandi Ramenta <nramenta@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @link https://github.com/nramenta/clio
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+namespace Yiinitializr\Cli;
+/**
+ * Daemon  provides helpers for starting and killing daemonized processes
+ *
+ * @author Antonio Ramirez <ramirez.cobos@gmail.com>
+ * @package Yiinitializr.Cli
+ * @since 1.0
+ */
+class Daemon
+{
+	/**
+	 * Daemonize a Closure object.
+	 * @param array $options Set of options
+	 * @param callable $callable Closure object to daemonize
+	 * @return bool True on success
+	 * @throws \Exception
+	 */
+	public static function work(array $options, \Closure $callable)
+	{
+		if (!extension_loaded('pcntl')) {
+			throw new \Exception('pcntl extension required');
+		}
+
+		if (!extension_loaded('posix')) {
+			throw new \Exception('posix extension required');
+		}
+
+		if (!isset($options['pid'])) {
+			throw new \Exception('pid not specified');
+		}
+
+		$options = $options + array(
+			'stdin'  => '/dev/null',
+			'stdout' => '/dev/null',
+			'stderr' => 'php://stdout',
+		);
+
+		if (($lock = @fopen($options['pid'], 'c+')) === false) {
+			throw new \Exception('unable to open pid file ' . $options['pid']);
+		}
+
+		if (!flock($lock, LOCK_EX | LOCK_NB)) {
+			throw new \Exception('could not acquire lock for ' . $options['pid']);
+		}
+
+		switch ($pid = pcntl_fork()) {
+			case -1:
+				throw new \Exception('unable to fork');
+			case 0:
+				break;
+			default:
+				fseek($lock, 0);
+				ftruncate($lock, 0);
+				fwrite($lock ,$pid);
+				fflush($lock);
+				return true;
+		}
+
+		if (posix_setsid() === -1) {
+			throw new \Exception('failed to setsid');
+		}
+
+		fclose(STDIN);
+		fclose(STDOUT);
+		fclose(STDERR);
+
+		if (!($stdin  = fopen($options['stdin'], 'r'))) {
+			throw new \Exception('failed to open STDIN ' . $options['stdin']);
+		}
+
+		if (!($stdout = fopen($options['stdout'], 'w'))) {
+			throw new \Exception('failed to open STDOUT ' . $options['stdout']);
+		}
+
+		if (!($stderr = fopen($options['stderr'], 'w'))) {
+			throw new \Exception('failed to open STDERR ' . $options['stderr']);
+		}
+
+		pcntl_signal(SIGTSTP, SIG_IGN);
+		pcntl_signal(SIGTTOU, SIG_IGN);
+		pcntl_signal(SIGTTIN, SIG_IGN);
+		pcntl_signal(SIGHUP,  SIG_IGN);
+
+		call_user_func($callable, $stdin, $stdout, $stderr);
+	}
+
+	/**
+	 * Whether a process is running or not
+	 * @param $file
+	 * @return bool
+	 * @throws \Exception
+	 */
+	public static function isRunning($file)
+	{
+		if (!extension_loaded('posix')) {
+			throw new \Exception('posix extension required');
+		}
+
+		if (!is_readable($file)) {
+			return false;
+		}
+
+		if (($lock = @fopen($file, 'c+')) === false) {
+			throw new \Exception('unable to open pid file ' . $file);
+		}
+
+		if (flock($lock, LOCK_EX | LOCK_NB)) {
+			return false;
+		} else {
+			flock($lock, LOCK_UN);
+			return true;
+		}
+	}
+
+	/**
+	 * Kills a daemon process specified by its PID file.
+	 *
+	 * @param $file  Daemon PID file
+	 * @param bool $delete Flag to delete PID file after killing
+	 * @return bool  True on success, false otherwise
+	 * @throws \Exception
+	 */
+	public static function kill($file, $delete = false)
+	{
+		if (!extension_loaded('posix')) {
+			throw new \Exception('posix extension required');
+		}
+
+		if (!is_readable($file)) {
+			throw new \Exception('unreadable pid file ' . $file);
+		}
+
+		if (($lock = @fopen($file, 'c+')) === false) {
+			throw new \Exception('unable to open pid file ' . $file);
+		}
+
+		if (flock($lock, LOCK_EX | LOCK_NB)) {
+			flock($lock, LOCK_UN);
+			throw new \Exception('process not running');
+		}
+
+		$pid = fgets($lock);
+
+		if (posix_kill($pid, SIGTERM)) {
+			if ($delete) unlink($file);
+			return true;
+		} else {
+			return false;
+		}
+	}
+}

app/lib/Yiinitializr/Composer/Callback.php

+<?php
+/**
+ * Yiinitialzr\Composer\Callback provides composer hooks
+ *
+ * Totally inspired by the ComposerCallback of Phundament3 and adapted for its use with Yiinitialzr
+ *
+ * This setup class triggers `./yiic migrate` at post-install and post-update.
+ * For a package the class triggers `./yiic <vendor/<packageName>-<action>` at post-package-install and
+ * post-package-update.
+ *
+ * You can also create new commands to be called within your boilerplate configuration.
+ *
+ * See composer manual (http://getcomposer.org/doc/articles/scripts.md)
+ *
+ * Usage example
+ *
+ * config.php
+ *     'params' => array(
+ *            'composer.callbacks' => array(
+ *            'post-update' => array('yiic', 'migrate'),
+ *            'post-install' => array('yiic', 'migrate'),
+ *            'yiisoft/yii-install' => array('yiic', 'webapp', realpath(dirname(__FILE__))),
+ *        ),
+ * ))
+ *
+ * composer.json
+ *   "scripts": {
+ *            "pre-install-cmd": "Yiinitialzr\\Composer\\Callback::preInstall",
+ *            "post-install-cmd": "Yiinitialzr\\Composer\\Callback::postInstall",
+ *            "pre-update-cmd": "Yiinitialzr\\Composer\\Callback::preUpdate",
+ *            "post-update-cmd": "Yiinitialzr\\Composer\\Callback::postUpdate",
+ *            "post-package-install": [
+ *                "Yiinitialzr\\Composer\\Callback::postPackageInstall"
+ *            ],
+ *            "post-package-update": [
+ *            "Yiinitialzr\\Composer\\Callback::postPackageUpdate"
+ *            ]
+ * }
+ *
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://2amigos.us
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ *
+ * Credits to Phundament... Tobias, thanks for introducing me the wonders of composer
+ *
+ * @author Tobias Munk <schmunk@usrbin.de>
+ * @link http://www.phundament.com/
+ * @copyright Copyright &copy; 2012 diemeisterei GmbH
+ * @license http://www.phundament.com/license
+ */
+namespace Yiinitializr\Composer;
+
+use Composer\Script\Event;
+use Yiinitializr\Helpers\Initializer;
+use Yiinitializr\Helpers\Config;
+use Yiinitializr\Cli\Console;
+
+class Callback
+{
+	/**
+	 * Displays welcome message
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function preInstall(Event $event)
+	{
+		Console::output("\n%BYiinitialzr 1.0.1%n\n");
+		Console::output("* download packages specified in composer.json");
+		Console::output("* configures your runtime folders");
+		Console::output("* triggers composer callbacks (yiic commands)\n");
+
+		if (Console::confirm("Start Installation?"))
+			self::runHook('pre-install');
+		else
+			exit("\n%RInstallation aborted%n.\n");
+	}
+
+	/**
+	 * Executes a post-install callback
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function postInstall(Event $event)
+	{
+		self::runHook('post-install');
+		Console::output("\n%GInstallation completed!%n\n");
+	}
+
+	/**
+	 * Displays updating message
+	 *
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function preUpdate(Event $event)
+	{
+		Console::output("Updating your application to the latest available packages...");
+		self::runHook('pre-update');
+	}
+
+	/**
+	 * Executes post-update message
+	 *
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function postUpdate(Event $event)
+	{
+		self::runHook('post-update');
+		Console::output("%GUpdate completed.%n");
+	}
+
+	/**
+	 * Executes ./yiic <vendor/<packageName>-<action>
+	 *
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function postPackageInstall(Event $event)
+	{
+		$installedPackage = $event->getOperation()->getPackage();
+		$hookName = $installedPackage->getPrettyName() . '-install';
+		self::runHook($hookName);
+	}
+
+	/**
+	 * Executes ./yiic <vendor/<packageName>-<action>
+	 *
+	 * @static
+	 * @param \Composer\Script\Event $event
+	 */
+	public static function postPackageUpdate(Event $event)
+	{
+		$installedPackage = $event->getOperation()->getTargetPackage();
+		$commandName = $installedPackage->getPrettyName() . '-update';
+		self::runHook($commandName);
+	}
+
+	/**
+	 * Runs Yii command, if available (defined in config.php)
+	 */
+	private static function runHook($name)
+	{
+		$app = self::getYiiApplication();
+		if ($app === null) return;
+
+		if (isset($app->params['composer.callbacks'][$name]))
+		{
+			$args = $app->params['composer.callbacks'][$name];
+			$app->commandRunner->addCommands(\Yii::getPathOfAlias('system.cli.commands'));
+			$app->commandRunner->run($args);
+		}
+	}
+
+	/**
+	 * Creates console application, if Yii is available
+	 */
+	private static function getYiiApplication()
+	{
+		if (!is_file(Config::value('yii.path') . '/yii.php'))
+		{
+			// nothing yet installed, return
+			return null;
+		}
+
+		require_once(Config::value('yii.path') . '/yii.php');
+
+		spl_autoload_register(array('YiiBase', 'autoload'));
+
+		if (\Yii::app() === null)
+		{
+
+			if (!Config::value('envlock'))
+			{
+				$env = Console::prompt('Please, enter your environment -ie. "dev | prod | stage": ', array('default' => 'dev'));
+				Initializer::buildEnvironmentFiles($env);
+			} else
+			{
+				Console::output("\n%Benv.lock%n file found. No environment request required.\n");
+				Console::output("Note: if you wish to re-do enviroment setting merging, please remove the %Benv.lock%n file " .
+					"from the Yiinitializr %Bconfig%n folder.");
+			}
+
+			Initializer::createRuntimeFolders();
+
+			Initializer::createRuntimeFolders('assets');
+
+			if (is_file(Config::value('yiinitializr.config.console')))
+				$app = \Yii::createConsoleApplication(Config::value('yiinitializr.config.console'));
+			else
+				throw new \Exception("'yiinitializr.config.console' setting not found");
+
+		} else
+		{
+			$app = \Yii::app();
+		}
+		return $app;
+	}
+}

app/lib/Yiinitializr/Helpers/ArrayX.php

+<?php
+/**
+ * ArrayX class file.
+ *
+ * @author Antonio Ramirez <amigo.cobos@gmail.com>
+ * @link http://www.ramirezcobos.com/
+ * @link http://www.2amigos.us/
+ * @copyright 2013 2amigOS! Consultation Group LLC
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+namespace Yiinitializr\Helpers;
+
+/**
+ * ArrayX provides a set of useful functions
+ *
+ * @author Antonio Ramirez <ramirez.cobos@gmail.com>
+ * @package Yiinitializr.helpers
+ * @since 1.0
+ */
+class ArrayX
+{
+	/**
+	 * Get an item from an array using "dot" notation.
+	 *
+	 * <code>
+	 *        // Get the $array['user']['name'] value from the array
+	 *        $name = ArrayX::get($array, 'user.name');
+	 *
+	 *        // Return a default from if the specified item doesn't exist
+	 *        $name = ArrayX::get($array, 'user.name', 'Taylor');
+	 * </code>
+	 *
+	 * @param  array $array
+	 * @param  string $key
+	 * @param  mixed $default
+	 * @return mixed
+	 */
+	public static function get($array, $key, $default = null)
+	{
+		if (is_null($key)) return $array;
+
+		// To retrieve the array item using dot syntax, we'll iterate through
+		// each segment in the key and look for that value. If it exists, we
+		// will return it, otherwise we will set the depth of the array and
+		// look for the next segment.
+		foreach (explode('.', $key) as $segment)
+		{
+			if (!is_array($array) || !array_key_exists($segment, $array))
+			{
+				return self::value($default);
+			}
+
+			$array = $array[$segment];
+		}
+
+		return $array;
+	}
+
+	/**
+	 * Removes an item from the given options and returns the value.
+	 *
+	 * If no key is found, then default value will be returned.
+	 *
+	 * @param $array
+	 * @param $key
+	 * @param null $default
+	 * @return mixed|null
+	 */
+	public static function pop(&$array, $key, $default = null)
+	{
+		if (is_array($array))
+		{
+			$value = self::get($array, $key, $default);
+			unset($array[$key]);
+			return $value;
+		} else
+			return $default;
+	}
+
+	/**
+	 * Set an array item to a given value using "dot" notation.
+	 *
+	 * If no key is given to the method, the entire array will be replaced.
+	 *
+	 * <code>
+	 *        // Set the $array['user']['name'] value on the array
+	 *        ArrayX::set($array, 'user.name', 'Taylor');
+	 *
+	 *        // Set the $array['user']['name']['first'] value on the array
+	 *        ArrayX::set($array, 'user.name.first', 'Michael');
+	 * </code>
+	 *
+	 * @param  array $array
+	 * @param  string $key
+	 * @param  mixed $value
+	 * @return void
+	 */
+	public static function set(&$array, $key, $value)
+	{
+		if (is_null($key)) return $array = $value;
+
+		$keys = explode('.', $key);
+
+		// This loop allows us to dig down into the array to a dynamic depth by
+		// setting the array value for each level that we dig into. Once there
+		// is one key left, we can fall out of the loop and set the value as
+		// we should be at the proper depth.
+		while (count($keys) > 1)
+		{
+			$key = array_shift($keys);
+
+			// If the key doesn't exist at this depth, we will just create an
+			// empty array to hold the next value, allowing us to create the
+			// arrays to hold the final value.
+			if (!isset($array[$key]) || !is_array($array[$key]))
+				$array[$key] = array();
+
+			$array =& $array[$key];
+		}
+
+		$array[array_shift($keys)] = $value;
+	}
+
+	/**
+	 * Remove an array item from a given array using "dot" notation.
+	 *
+	 * <code>
+	 *        // Remove the $array['user']['name'] item from the array
+	 *        ArrayX::forget($array, 'user.name');
+	 *
+	 *        // Remove the $array['user']['name']['first'] item from the array
+	 *        ArrayX::forget($array, 'user.name.first');
+	 * </code>
+	 *
+	 * @param  array $array
+	 * @param  string $key
+	 * @return void
+	 */
+	public static function forget(&$array, $key)
+	{
+		$keys = explode('.', $key);
+
+		// This loop functions very similarly to the loop in the "set" method.
+		// We will iterate over the keys, setting the array value to the new
+		// depth at each iteration. Once there is only one key left, we will
+		// be at the proper depth in the array.
+		while (count($keys) > 1)
+		{
+			$key = array_shift($keys);
+
+			// Since this method is supposed to remove a value from the array,
+			// if a value higher up in the chain doesn't exist, there is no
+			// need to keep digging into the array, since it is impossible
+			// for the final value to even exist.
+			if (!isset($array[$key]) || !is_array($array[$key]))
+				return;
+
+			$array =& $array[$key];
+		}
+
+		unset($array[array_shift($keys)]);
+	}
+
+	/**
+	 * Return the first element in an array which passes a given truth test.
+	 *
+	 * <code>
+	 *        // Return the first array element that equals "Taylor"
+	 *        $value = ArrayX::first($array, function($k, $v) {return $v == 'Taylor';});
+	 *
+	 *        // Return a default value if no matching element is found
+	 *        $value = ArrayX::first($array, function($k, $v) {return $v == 'Taylor'}, 'Default');
+	 * </code>
+	 *
+	 * @param  array $array
+	 * @param  Closure $callback
+	 * @param  mixed $default
+	 * @return mixed
+	 */
+	public static function first($array, $callback, $default = null)
+	{
+		foreach ($array as $key => $value)
+		{
+			if (call_user_func($callback, $key, $value)) return $value;
+		}
+
+		return value($default);
+	}
+
+	/**
+	 * Recursively remove slashes from array keys and values.
+	 *
+	 * @param  array $array
+	 * @return array
+	 */
+	public static function stripSlashes($array)
+	{
+		$result = array();
+
+		foreach ($array as $key => $value)
+		{
+			$key = stripslashes($key);
+
+			// If the value is an array, we will just recurse back into the
+			// function to keep stripping the slashes out of the array,
+			// otherwise we will set the stripped value.
+			if (is_array($value))
+			{
+				$result[$key] = array_strip_slashes($value);
+			} else
+			{
+				$result[$key] = stripslashes($value);
+			}
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Divide an array into two arrays. One with keys and the other with values.
+	 *
+	 * @param  array $array
+	 * @return array
+	 */
+	public static function divide($array)
+	{
+		return array(array_keys($array), array_values($array));
+	}
+
+	/**
+	 * Pluck an array of values from an array.
+	 *
+	 * @param  array $array
+	 * @param  string $key
+	 * @return array
+	 */
+	public static function pluck($array, $key)
+	{
+		return array_map(function ($v) use ($key)
+		{
+			return is_object($v) ? $v->$key : $v[$key];
+
+		}, $array);
+	}
+
+	/**
+	 * Get a subset of the items from the given array.
+	 *
+	 * @param  array $array
+	 * @param  array $keys
+	 * @return array
+	 */
+	public static function only($array, $keys)
+	{
+		return array_intersect_key($array, array_flip((array)$keys));
+	}
+
+	/**
+	 * Get all of the given array except for a specified array of items.
+	 *
+	 * @param  array $array
+	 * @param  array $keys
+	 * @return array
+	 */
+	public static function except($array, $keys)
+	{
+		return array_diff_key($array, array_flip((array)$keys));
+	}
+
+
+	/**
+	 * Return the first element of an array.
+	 *
+	 * This is simply a convenient wrapper around the "reset" method.
+	 *
+	 * @param  array $array
+	 * @return mixed
+	 */
+	public static function head($array)
+	{
+		return reset($array);
+	}
+
+	/**
+	 * Merges two or more arrays into one recursively.
+	 * If each array has an element with the same string key value, the latter
+	 * will overwrite the former (different from array_merge_recursive).
+	 * Recursive merging will be conducted if both arrays have an element of array
+	 * type and are having the same key.
+	 * For integer-keyed elements, the elements from the latter array will
+	 * be appended to the former array.
+	 * @param array $a array to be merged to
+	 * @param array $b array to be merged from. You can specifiy additional
+	 * arrays via third argument, fourth argument etc.
+	 * @return array the merged array (the original arrays are not changed.)
+	 */
+	public static function merge($a, $b)
+	{
+		$args = func_get_args();
+		$res = array_shift($args);
+		while (!empty($args))
+		{
+			$next = array_shift($args);
+			foreach ($next as $k => $v)
+			{
+				if (is_integer($k))
+					isset($res[$k]) ? $res[] = $v : $res[$k] = $v;
+				elseif (is_array($v) && isset($res[$k]) && is_array($res[$k]))
+					$res[$k] = self::merge($res[$k], $v); else
+					$res[$k] = $v;
+			}
+		}
+		return $res;
+	}
+
+	/**
+	 * Searches for a given value in an array of arrays, objects and scalar
+	 * values. You can optionally specify a field of the nested arrays and
+	 * objects to search in.
+	 *
+	 * Credits to Util.php
+	 *
+	 * @param array $array  The array to search
+	 * @param string $search The value to search for
+	 * @param bool $field The field to search in, if not specified all fields will be searched
+	 * @return bool|mixed|string False on failure or the array key on
+	 * @link https://github.com/brandonwamboldt/utilphp/blob/master/util.php
+	 */
+	public static function deepSearch(array $array, $search, $field = FALSE)
+	{
+		// *grumbles* stupid PHP type system
+		$search = (string)$search;
+
+		foreach ($array as $key => $elem)
+		{