1
0

Initial Commit

This commit is contained in:
2014-05-06 12:16:20 +02:00
commit 0db46dd097
77 changed files with 23839 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
Yiinitializr Change Log
========================
Thursday 28-March-2013
----------------------------
Initial release

View File

@@ -0,0 +1,487 @@
<?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;
}
}
}

View File

@@ -0,0 +1,163 @@
<?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;
}
}
}

View File

@@ -0,0 +1,201 @@
<?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;
}
}

View File

@@ -0,0 +1,416 @@
<?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)
{
// *grumbles* stupid PHP type system
$key = (string)$key;
if ($field)
{
if (is_object($elem) && $elem->{$field} === $search)
{
return $key;
} else if (is_array($elem) && $elem[$field] === $search)
{
return $key;
} else if (is_scalar($elem) && $elem === $search)
{
return $key;
}
} else
{
if (is_object($elem))
{
$elem = (array)$elem;
if (in_array($search, $elem))
{
return $key;
}
} else if (is_array($elem) && in_array($search, $elem))
{
return array_search($search, $elem);
} else if (is_scalar($elem) && $elem === $search)
{
return $key;
}
}
}
return false;
}
/**
* Returns an array containing all the elements of arr1 after applying
* the callback function to each one.
*
* Credits to Util.php
*
* @param array $array an array to run through the callback function
* @param $callback Callback function to run for each element in each array
* @param bool $on_nonscalar whether or not to call the callback function on nonscalar values (objects, resr, etc)
* @return array
* @link https://github.com/brandonwamboldt/utilphp/blob/master/util.php
*/
public static function deepMap(array $array, $callback, $on_nonscalar = FALSE)
{
foreach ($array as $key => $value)
{
if (is_array($value))
{
$args = array($value, $callback, $on_nonscalar);
$array[$key] = call_user_func_array(array(__CLASS__, __FUNCTION__), $args);
} else if (is_scalar($value) || $on_nonscalar)
{
$array[$key] = call_user_func($callback, $value);
}
}
return $array;
}
/**
* Return the value of the given item.
*
* If the given item is a Closure the result of the Closure will be returned.
*
* @param mixed $value
* @return mixed
*/
public static function value($value)
{
return (is_callable($value) and !is_string($value)) ? call_user_func($value) : $value;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Config 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;
use Yiinitializr\Helpers\ArrayX;
/**
* Config provides easy access to Yiinitializr configuration file
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @package Yiinitializr.helpers
* @since 1.0
*/
class Config
{
/**
* @var array the configuration settings
*/
private static $_settings;
private static $_config_dir_path;
private static $_envlock_file_path;
/**
* Returns a value of the array
* @param $value
* @return mixed | null if no key is found
*/
public static function value($value)
{
return ArrayX::get(self::settings(), $value);
}
/**
* Reads the configuration settings from the file
* @return array|mixed
* @throws \Exception
*/
public static function settings()
{
if (null === self::$_settings)
{
self::$_settings = file_exists(self::getConfigurationDirectoryPath() . '/settings.php')
? require_once(self::getConfigurationDirectoryPath() . '/settings.php')
: array();
self::$_settings['envlock'] = file_exists(self::getEnvironmentLockFilePath());
}
if (empty(self::$_settings))
throw new \Exception('Unable to find Yiinitialzr settings file!');
return self::$_settings;
}
/**
* @param string $content
*/
public static function createEnvironmentLockFile($content = '')
{
umask(0);
file_put_contents(self::getEnvironmentLockFilePath(), $content);
@chmod(self::getEnvironmentLockFilePath(), 0644);
}
/**
* Returns the configuration directory path
* @return string
*/
public static function getConfigurationDirectoryPath()
{
if (null === self::$_config_dir_path)
self::$_config_dir_path = dirname(__FILE__) . '/../config';
return self::$_config_dir_path;
}
/**
* Returns the environment lock file path
* @return string
*/
public static function getEnvironmentLockFilePath()
{
if (null === self::$_envlock_file_path)
self::$_envlock_file_path = self::getConfigurationDirectoryPath() . '/env.lock';
return self::$_envlock_file_path;
}
}

View File

@@ -0,0 +1,251 @@
<?php
/**
* Initializer 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;
use Yiinitializr\Helpers\Config;
use Yiinitializr\Helpers\ArrayX;
use Yiinitializr\Cli\Console;
/**
* Initializer provides a set of useful functions to initialize a Yii Application development.
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @package Yiinitializr.helpers
* @since 1.0
*/
class Initializer
{
/**
* @param $root
* @param string $configName
* @param mixed $mergeWith
* @return mixed
* @throws Exception
*/
public static function create($root, $configName = 'main', $mergeWith = array('common', 'env'))
{
if (($root = realpath($root)) === false)
throw new Exception('could not initialize framework.');
$config = self::config($configName, $mergeWith);
if (php_sapi_name() !== 'cli') // aren't we in console?
$app = \Yii::createWebApplication($config); // create web
else
{
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
$app = \Yii::createConsoleApplication($config);
$app->commandRunner->addCommands($root . '/cli/commands');
$env = @getenv('YII_CONSOLE_COMMANDS');
if (!empty($env))
$app->commandRunner->addCommands($env);
}
// return an app
return $app;
}
/**
* @param string $configName config name to load (main, test, etc)
* @param null|string $mergeWith
* @return array
* @throws \Exception
*/
public static function config($configName = 'main', $mergeWith = null)
{
$files = array($configName);
$directory = Config::value('yiinitializr.app.directories.config.' . $configName);
if (null === $directory)
throw new \Exception("Unable to find 'yiinitializr.app.directories.config.'{$configName} on the settings.");
if (null !== $mergeWith)
{
if (is_array($mergeWith))
{
foreach($mergeWith as $file)
$files[] = $file;
}
else
$files[] = $mergeWith;
}
// do we have any other configuration files to merge with?
$mergedSettingFiles = Config::value('yiinitializr.app.files.config.' . $configName);
if (null !== $mergedSettingFiles)
{
if (is_array($mergedSettingFiles))
{
foreach($mergedSettingFiles as $file)
$files[] = $file;
}
else
$files[] = $mergedSettingFiles;
}
$config = self::build($directory, $files);
$params = isset($config['params'])
? $config['params']
: array();
self::setOptions($params);
return $config;
}
/**
* @param $directory
* @param $files array of configuration files to merge
* @return array
*/
public static function build($directory, $files)
{
$result = array();
if (!is_array($files))
$files = array($files);
foreach ($files as $file)
{
$config = file_exists($file) && is_file($file)
? require($file)
: (is_string($file) && file_exists($directory . '/' . $file . '.php')
? require($directory . '/' . $file . '.php')
: array());
if (is_array($config))
$result = ArrayX::merge($result, $config);
}
return $result;
}
/**
* Set php and yii options - some based on the loaded config params
* @param array $params The config params being used for the app
*/
protected static function setOptions(array $params)
{
// yii config
defined('YII_DEBUG') or define('YII_DEBUG', isset($params['yii.debug']) ? $params['yii.debug'] : false);
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', isset($params['yii.traceLevel']) ? $params['yii.traceLevel'] : 0);
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', isset($params['yii.handleErrors']) ? $params['yii.handleErrors'] : true);
defined('YII_ENABLE_EXCEPTION_HANDLER') or define('YII_ENABLE_EXCEPTION_HANDLER', YII_ENABLE_ERROR_HANDLER);
// php config
error_reporting(-1);
if(isset($params['php.defaultCharset']))
ini_set('default_charset', $params['php.defaultCharset']);
if(isset($params['php.timezone']))
date_default_timezone_set($params['php.timezone']);
date_default_timezone_set($params['php.timezone']);
if(!class_exists('YiiBase'))
require(Config::value('yii.path').'/yii.php');
}
/**
* Helper function to build environment files
* @param $environment
* @throws \Exception
*/
public static function buildEnvironmentFiles($environment = 'dev')
{
self::output("\n%gBuilding environment files.%n");
umask(0);
$directories = Config::value('yiinitializr.app.directories.config');
if (null === $directories)
throw new \Exception("Unable to find 'yiinitializr.app.directories.config' on the settings.");
if (!is_array($directories))
$directories = array($directories);
$environment = strlen($environment)
? $environment
: 'dev';
foreach ($directories as $directory)
{
if (file_exists($directory))
{
$environment_directory = $directory . '/env';
if (!file_exists($environment_directory))
{
mkdir($environment_directory);
self::output("Your environment directory has been created: %r{$environment_directory}%n.\n");
}
$environment_file = $environment_directory . '/' . $environment . '.php';
if (!file_exists($environment_file))
{
file_put_contents($environment_file, "<?php\n/**\n * {$environment}.php\n */\n\nreturn array(\n);");
@chmod($environment_file, 0644);
self::output("%gEnvironment configuration file has been created: %r{$environment_file}%n.\n");
}
if (!file_exists($directory . '/env.php'))
{
@copy($environment_file, $directory . '/env.php');
self::output("Your environment configuration file has been created on {$directory}.\n");
} else
self::output("'{$directory}/env.php'\n%pfile already exists. No action has been executed.%n");
}
}
Config::createEnvironmentLockFile($environment);
self::output("%gEnvironment files creation process finished.%n\n");
}
/**
* @param string $name the name of the runtime folder,
* @throws \Exception
*/
public static function createRuntimeFolders($name = 'runtime')
{
self::output("\n%gBuilding runtime '{$name}' folders.%n");
umask(0);
$directories = Config::value('yiinitializr.app.directories.' . $name);
if (null === $directories)
throw new \Exception("Unable to find 'yiinitializr.app.directories.{$name}' on the settings.");
if (!is_array($directories))
$directories = array($directories);
foreach ($directories as $directory)
{
$runtime = $directory . '/' . $name;
if (!file_exists($runtime))
{
@mkdir($runtime, 02777);
self::output("Your {$name} folder has been created on {$directory}.");
} else
self::output("'{$name}' %pfolder already exists. No action has been executed.%n");
}
self::output("%gRuntime '{$name}' folders creation process finished.%n");
}
/**
* Outputs text only to console
* @param $message
*/
protected static function output($message)
{
if (php_sapi_name() === 'cli')
Console::output($message);
}
}

View File

@@ -0,0 +1,31 @@
The Yiinitializr is free software. It is released under the terms of
the following BSD License.
Copyright (c) 2013 by 2amigOS! Consultation Group LLC (http://www.2amigos.us)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of 2amigOS! Consultation Group LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,128 @@
Yiinitializr
============
Library that will help boost your application installation with ease and also to run Yii applications from its
bootstrap files on a much cleaner way that the framework currently proposes. For example:
```
// yii has been installed via composer
require('./../app/lib/vendor/yiisoft/yii/framework/yii.php');
// set alias for namespacing
// make sure the path is correct as it can also be installed via composer (see above)
Yii::setPathOfAlias('Yiinitializr', './../app/lib/Yiinitializr');
// use its initializr
use Yiinitializr\Helpers\Initializer;
// tell the Initializer class providing the root, the application config name,
// and the files to merge -very useful when working with advanced boilerplates
// and different environments
Initializer::create('./../app', 'main', array('common', 'env', 'local'))->run();
```
INSTALLATION
------------
If you are going to use Yiinitializr to make use of `Yiinitializr\Helpers\Initializr` you can easily install it via
`composer`, but if you are going to use it within your application structure in order to configure your application
according to your custom needs, then the recommended use is that you [download](https://github.com/2amigos/yiinitializr/archive/master.zip)
its source files and place them on a top level folder.
###Configuration Settings
As with Yii, you need to go through a bit of configuration settings if you wish to handle your project structure setup
with `composer`. Don't worry, is not going to be too hard, the following is an example configuration file:
```
\\ where am i?
$dirname = dirname(__FILE__);
\\ where is the application folder?
$app = $dirname . '/../../..';
\\ where is the root?
$root = $app . '/..';
return array(
// yii configurations
'yii' => array(
// where is the path of the yii framework?
// On this example we have installed yii with composer
// and as it is used after composer installation, we
// can safely point to the vendor folder.
'path' => $app . '/lib/vendor/yiisoft/yii/framework'
),
// yiinitializr specific settings
'yiinitializr' => array(
// config folders
'config' => array(
// we just need the console settings
// On this example, and due that I used environments
// i created a custom console.php app for
// Yiinitializr\Composer\Callbak class (see below example)
'console' => $dirname . '/console.php'
),
// application structure settings
'app' => array(
// where is the root?
'root' => $root,
// directories setup
'directories' => array(
// where are the different configuration files settings?
'config' => array(
// 'key' is the configuration name (see above init example)
'main' => $app . '/config',
'console' => $app . '/config',
'test' => $app . '/config'
),
// where are my runtime folders?
'runtime' => array(
// heads up! only the folder location as "/config" will be
// appended
$app
),
'assets' => array(
// where to write the "assets folders"?
$root . '/www'
)
)
),
)
);
```
Here is an example of a custom `console.php` settings file when working with environments. As you saw on the previous
code, this file on the example was located on the same `Yiinitializr\config` folder:
```
require_once dirname(__FILE__) . '/../Helpers/Initializer.php';
require_once dirname(__FILE__) . '/../Helpers/ArrayX.php';
return Yiinitializr\Helpers\ArrayX::merge(
Yiinitializr\Helpers\Initializer::config('console', array('common', 'env', 'local')),
array(
'params' => array(
// here is where the composer magic start.
// Thanks! mr Tobias a.k.a Phundament man!
'composer.callbacks' => array(
'post-update' => array('yiic', 'migrate'),
'post-install' => array('yiic', 'migrate'),
)
),
)
);
```
REQUIREMENTS
------------
It works in conjunction with `composer` to install the boilerplate but
The minimum requirements by Yiinitializr that you have installed `composer` or have a `composer.phar` on your application
root in order to run and ** PHP 5.3+**
###Resources
- [Composer](http://getcomposer.org)
- [Phundament](http://phundament.com/)
- [Download latest ZIPball](https://github.com/2amigos/yiinitializr/archive/master.zip)
- [2amigOS Packagist Profile](https://packagist.org/packages/2amigos/)
> [![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)

View File

@@ -0,0 +1,30 @@
{
"name": "2amigos/yiinitializr",
"description": "Yii Web Programming Framework Application initializing library.",
"keywords": ["yii", "framework", "application", "boilerplate"],
"homepage": "http://yiinitializr.2amigos.us/",
"type": "library",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Antonio Ramirez",
"email": "amigo.cobos@gmail.com",
"homepage": "http://www.2amigos.us/",
"role": "Founder and development"
},
{
"name": "Matt Tabin",
"email": "amigo.tabin@gmail.com",
"homepage": "http://www.2amigos.us/",
"role": "Founder and development"
}
],
"support": {
"issues": "https://github.com/2amigos/yiinitializr/issues?state=open",
"wiki": "https://github.com/2amigos/yiinitializr",
"source": "https://github.com/2amigos/yiinitializr"
},
"require": {
"php": ">=5.3.0"
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Custom console.php config 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
*/
/**
* Include required classes
*/
require_once dirname(__FILE__) . '/../Helpers/Initializer.php';
require_once dirname(__FILE__) . '/../Helpers/ArrayX.php';
/**
* Return the configuration array appending composer callback methods
*/
return Yiinitializr\Helpers\ArrayX::merge(
Yiinitializr\Helpers\Initializer::config('console', array('common', 'env', 'local')),
array(
'params' => array(
'composer.callbacks' => array(
'post-update' => array('yiic', 'migrate'),
'post-install' => array('yiic', 'migrate'),
)
),
)
);

View File

@@ -0,0 +1,40 @@
<?php
/**
* Yiinitializr 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
*/
$dirname = dirname(__FILE__);
$app = $dirname . '/../../..';
$root = $app . '/..';
return array(
'yii' => array(
'path' => $app . '/lib/vendor/yiisoft/yii/framework'
),
'yiinitializr' => array(
'config' => array(
'console' => $dirname . '/console.php'
),
'app' => array(
'root' => $root,
'directories' => array(
'config' => array(
'main' => $app . '/config',
'console' => $app . '/config',
'test' => $app . '/config'
),
'runtime' => array(
$app
),
'assets' => array(
$root . '/www'
)
)
),
)
);