Kohana - display buffered views or custom view on shutdown - php

I am using Kohana View_Core derivative for my views. I would like to display buffered views or custom view on shutdown e.g.
If there were some errors/exceptions during the runtime => display error page
If executed with no errors => display the buffered output
The View
class View
{
private $file = '';
private $data = array();
private static $global_data = array();
public static $view = '';
private function __construct($file = FALSE, array $data = array())
{
if ($file !== FALSE)
{
$this->set_filename($file);
}
if (!empty($data))
{
$this->data = $data + $this->data;
}
}
/**
* Creates new view object and returns it.
*
* #param string filename
* #param array variables
* #return object View
*/
public static function factory($file = FALSE, array $data = array())
{
return new View($file, $data);
}
/**
* Captures the output that is generated when a view is included.
* The view data will be extracted to make local variables. This method
* is static to prevent object scope resolution.
*
* #param string filename
* #param array variables
* #return string
*/
public static function capture($view_filename, array $view_data)
{
extract($view_data, EXTR_SKIP);
ob_start();
try
{
require $view_filename;
}
catch (Exception $error)
{
$ob_handlers = ob_list_handlers();
if (!empty($ob_handlers))
{
ob_end_clean();
}
throw $error;
}
return ob_get_clean();
}
/**
* Load view file
*
* #param string filename
* #return boolean
* #return object View
*/
public function set_filename($file)
{
if (strpos($file, APP_DIR) === FALSE)
{
$extension = strrpos($file, '.') === FALSE ? '.php' : '';
$path = APP_DIR.DIR_SEP.'system'.DIR_SEP.'views'.DIR_SEP.$file.$extension;
}
else
{
$path = $file;
}
if (!file_exists($path))
{
Error::throw_throwable('Unable to find file '.$path);
}
$this->file = $path;
return $this;
}
/**
* Sets a global variable, similar to the set() method.
*
* #param string variable name
* #param mixed variable value
* #return object View
*/
public static function set_global($key, $value = FALSE)
{
self::$global_data[$key] = $value;
}
/**
* Assigns a variable by name.
*
* #param string variable name or an array of variables
* #param mixed variable value
* #return object View
*/
public function set($key, $value = FALSE)
{
if (is_array($key))
{
foreach ($key as $name => $value)
{
$this->data[$name] = $value;
}
}
else
{
$this->data[$key] = $value;
}
return $this;
}
/**
* Renders the view object to a string.
*
* #throws exception
* #param string filename
* #return string
*/
public function render($file = FALSE)
{
if ($file !== FALSE)
{
$this->set_filename($file);
}
if (empty($this->file))
{
Error::throw_throwable('Unable to find file '.$this->file);
}
$data = array_merge(View::$global_data, $this->data);
return View::capture($this->file, $data);
}
public function __toString()
{
try
{
$result = $this->render();
return $result;
}
catch (Exception $error)
{
Error::throw_throwable($error);
}
}
public function __set($key, $value)
{
$this->set($key, $value);
}
public function __get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : FALSE;
}
}
Usage
$content = View::factory('main/Main')
->set('order', !empty($_SESSION['order']) ? $_SESSION['order'] : FALSE)
->set('order_success', $order_success)
->set('items', $items)
->set('weights', $weights)
->set('ammounts', $ammounts)
->set('prices', $prices)
->set('total_price', $total_price)
->set('validator', FALSE)
;
$template = $this->get_template();
echo $template->set('content', $content);
What the previous lines do is echo a content view inside of template view. And this should be also the result that my shutdown handler is echoing if necessary. Is there a nice/easy way to do this?

It sounds like what you want is to show a custom error page when there is an error. What I typically do here is to extend Kohana_Kohana_Exception class (as Kohana_Exception) and override the public static function handler method.
This lets you put in some code that can check what the error is (HTTP_404_Exception or other) what the environment is (dev / production) and do whatever behavior you want.
In my case, something like this:
// If not production and not an HTTP exception
if ( ! ($e instanceof HTTP_Exception) && Kohana::$environment !== Kohana::PRODUCTION)
{
// Use built in error handler to show stace trace for developers
Kohana_Kohana_Exception::handler($e);
// ... exit(1);
}
// Otherwise
$injected_routes = array(Route::get('error'));
echo Request::factory('error-uri', NULL, FALSE, $injected_routes)
->headers(Request::$initial->headers())
->execute()
->send_headers(TRUE)
->body();
Here you need another route called error that matches error-uri and goes to another error controller/action/view that you can use to render your custom error page.
For this to work you need to have errors enabled by passing 'errors' => TRUE to your Kohana::init call in bootstrap.php.

Related

How do I pass the controller by other means than the url in PHP MVC

I realize this may be a dumb question, but I am struggling with a custom MVC project I started in order to learn PHP and I was not able to find what I was looking for anywhere else.
My question is, how do I pass the controller to my router, in a way that does not use the url. How would I make it so that the href in my link tags only provide the category and id and yet make it work. At the moment my urls look like this:
website/controller/method/args
ex: website/articles/post/13
I want the url to be like:
website/category/id-or-slug-from-title
I would really appreciate the help, since it's been bugging me for a week now.
Thanks in advance.
Well, it would be hard to describe possible steps in comment section, so I will add an answer.
The following steps will be exemplary and they do not describe the whole process. I will omit some details
Assuming that you're trying to implement MVC, you should have some kind of bootstrap.php (or something like that)
So, let's create our router class
/**
* Current method
* #var string
*/
protected $method;
/**
* Current args
* #var unknown
*/
protected $args = array();
private static $instance;
/**
* That's how we retrieve class instance
* #return app_router_http
*/
public static function getInstance()
{
if (!isset(static::$instance))
{
static::$instance = new self;
}
return static::$instance;
}
private function __clone() {}
/**
* #throws app_exception
*/
private function __construct()
{
/* парсим текущий урл */
$url = parse_url (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : "/", PHP_URL_PATH);
$url = preg_replace("/\\/{2,}/i", "/", $url);
/* Let's retrieve static route (for example - /category/id-or-slug-from-title) */
if ($_route = $this->getStaticRoute($url))
{
if ($_route->hasErrors())
{
throw new app_exception($_route->getErrors(";"));
}
$this
->setController($_route->getController())
->setMethod($_route->getMethod())
->setArgs($_route->getArgs() ? $_route->getArgs() : null)
;
return;
}
/* Let's retrive dynamic route, because we didn't fing static */
if ($_route = $this->getDynamicRoute($url))
{
if ($_route->hasErrors())
{
throw new app_exception($_route->getErrors(";"));
}
$this
->setController($_route->getController())
->setMethod($_route->getMethod())
->setArgs($_route->getArgs() ? $_route->getArgs() : null);
return;
}
throw new app_exception("Can't found any route objects", 503);
}
/**
* #param string $controller
* #return Router
*/
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
/**
* #return string
*/
public function getController()
{
return $this->controller;
}
/**
* #param string $method
* #return Router
*/
public function setMethod($method)
{
$this->method = $method;
return $this;
}
/**
* #return string
*/
public function getMethod()
{
return $this->method;
}
/**
* #param array $args
* #return Router
*/
public function setArgs(array $args = null)
{
if (isset($args))
{
$this->args = $args;
}
return $this;
}
/**
* #return mixed
*/
public function getArgs()
{
return $this->args;
}
/**
* #param string $route
* #param string $controller
* #param string $method
* #param string $objectId
* #return Route|NULL
*/
public function getStaticRoute($route = null, $controller = null, $method = null, $objectId = null)
{
$db = new DB(); //Some class for db connections
if (isset($route) && !isset($controller) && !isset($method) && !isset($objectId))
{
$selector = "SELECT * FROM `routes` WHERE `route` = '".$db->escape($route)."'";
}
if (!isset($route) && isset($controller) && isset($method) && isset($objectId))
{
$selector = "SELECT * FROM `routes` WHERE `controller` = '".$db->escape($controller)."' && `method` = '".$db->escape($method)."' && `objectId` = '".$db->escape($objectId)."'";
}
if (!isset($selector))
{
throw new app_exception(get_class($this)."::getStaticRoute incorrect params", 503);
}
if ($db->query($selector)->rows())
{
$row = $db->fetch();
$object = new Router();
$object->setAttributes($row);
if (!$object->hasErrors())
{
$object->setController("{$object->getController()}");//Here we are setting our awesome controller
if (!$this->isControllerExist($object->getController()))
{
return $object->addError("Controller {$object->getController()} missing (static route: #{$object->getId()})");
}
if (!$this->isMethodExist($object->getController(), $object->getMethod()))
{
return $object->addError("Method {$object->getMethod()} missing (controller: {$object->getController()}) (static route: #{$object->getId()})");
}
}
return $object;
}
return null;
}
/**
* #param string $path
* #return Router
*/
public function getDynamicRoute($path)
{
$object = new Router;
//Here we will assume that our url looks like this /controller/method/args
/* Url fragments */
$fragments = explode("/", substr($path, 1));
//Removing trailing slash
if (!$fragments[sizeof($fragments)-1])
{
unset($fragments[sizeof($fragments)-1]);
}
if (!isset($fragments[0]))
{
$fragments[0] = APP_ROUTE_DEFAULT_CONTROLLER; //Some kind of magic constant
}
$controller = $fragments[0];
if(!class_exists($controller)
{
throw new Exception("Ooops, controller not found", 404);
}
array_shift($fragments); //We don't need controller element anymore
for ($i = 0; $i <= 1; $i++)
{
if ($i == 0)
{
$method = APP_ROUTE_DEFAULT_METHOD;//We also need to handle urls like /news. For example, each controllers has default method index()
}
else
{
$method = $fragments[0];
}
if ($this->isControllerExist($controller) && $this->isMethodExist($controller, $method))
{
return
$object
->setController($controller)
->setMethod($method);
}
}
return $object->addError("Can't route to <strong>".implode("/", $fragments)."</strong> (dynamic route for module <strong>{$module}</strong>)");
}
/**
* #param string $controller
* #return boolean
*/
public function isControllerExist($controller = null)
{
if (!isset($controller))
{
$controller = $this->getController();
}
return class_exists($controller);
}
/**
* #param string $controller
* #param string $method
* #return boolean
*/
public function isMethodExist($controller = null, $method = null)
{
if (!isset($controller))
{
$controller = $this->getController();
}
if (!isset($method))
{
$method = $this->getMethod();
}
return method_exists($controller, $method);
}
public function run()
{
$_str = $this->getController();
$controller = new $_str;
$return = call_user_func_array(array($controller, $this->getMethod()), $this->getArgs());
return $return;
}
}
So, in bootstrap.php you just need to need to make a call Router::getInstance()->run()
Static route will try to pass your params
For dynamic routes, you always can read args from $_REQUEST
P.S. To be true, this is a cutted examaple made from my old project

Access array using dynamic path

I have an issue in accessing the array in php.
$path = "['a']['b']['c']";
$value = $array.$path;
In the above piece of code I have an multidimensional array named $array.
$path is a dynamic value which I would get from database.
Now I want to retrieve the value from $array using $path but I am not able to.
$value = $array.$path
returns me
Array['a']['b']['c']
rather than the value.
I hope I have explained my question properly.
You have two options. First (evil) if to use eval() function - i.e. interpret your string as code.
Second is to parse your path. That will be:
//$path = "['a']['b']['c']";
preg_match_all("/\['(.*?)'\]/", $path, $rgMatches);
$rgResult = $array;
foreach($rgMatches[1] as $sPath)
{
$rgResult=$rgResult[$sPath];
}
The Kohana framework "Arr" class (API) has a method (Arr::path) that does something similar to what you are requesting. It simply takes an array and a path (with a . as delimiter) and returns the value if found. You could modify this method to suit your needs.
public static function path($array, $path, $default = NULL, $delimiter = NULL)
{
if ( ! Arr::is_array($array))
{
// This is not an array!
return $default;
}
if (is_array($path))
{
// The path has already been separated into keys
$keys = $path;
}
else
{
if (array_key_exists($path, $array))
{
// No need to do extra processing
return $array[$path];
}
if ($delimiter === NULL)
{
// Use the default delimiter
$delimiter = Arr::$delimiter;
}
// Remove starting delimiters and spaces
$path = ltrim($path, "{$delimiter} ");
// Remove ending delimiters, spaces, and wildcards
$path = rtrim($path, "{$delimiter} *");
// Split the keys by delimiter
$keys = explode($delimiter, $path);
}
do
{
$key = array_shift($keys);
if (ctype_digit($key))
{
// Make the key an integer
$key = (int) $key;
}
if (isset($array[$key]))
{
if ($keys)
{
if (Arr::is_array($array[$key]))
{
// Dig down into the next part of the path
$array = $array[$key];
}
else
{
// Unable to dig deeper
break;
}
}
else
{
// Found the path requested
return $array[$key];
}
}
elseif ($key === '*')
{
// Handle wildcards
$values = array();
foreach ($array as $arr)
{
if ($value = Arr::path($arr, implode('.', $keys)))
{
$values[] = $value;
}
}
if ($values)
{
// Found the values requested
return $values;
}
else
{
// Unable to dig deeper
break;
}
}
else
{
// Unable to dig deeper
break;
}
}
while ($keys);
// Unable to find the value requested
return $default;
}
I was hoping to find an elegant solution to nested array access without throwing undefined index errors, and this post hits high on google. I'm late to the party, but I wanted to weigh in for future visitors.
A simple isset($array['a']['b']['c'] can safely check nested values, but you need to know the elements to access ahead of time. I like the dot notation for accessing multidimensional arrays, so I wrote a class of my own. It does require PHP 5.6.
This class parses a string path written in dot-notation and safely accesses the nested values of the array or array-like object (implements ArrayAccess). It will return the value or NULL if not set.
use ArrayAccess;
class SafeArrayGetter implements \JsonSerializable {
/**
* #var array
*/
private $data;
/**
* SafeArrayGetter constructor.
*
* #param array $data
*/
public function __construct( array $data )
{
$this->data = $data;
}
/**
* #param array $target
* #param array ...$indices
*
* #return array|mixed|null
*/
protected function safeGet( array $target, ...$indices )
{
$movingTarget = $target;
foreach ( $indices as $index )
{
$isArray = is_array( $movingTarget ) || $movingTarget instanceof ArrayAccess;
if ( ! $isArray || ! isset( $movingTarget[ $index ] ) ) return NULL;
$movingTarget = $movingTarget[ $index ];
}
return $movingTarget;
}
/**
* #param array ...$keys
*
* #return array|mixed|null
*/
public function getKeys( ...$keys )
{
return static::safeGet( $this->data, ...$keys );
}
/**
* <p>Access nested array index values by providing a dot notation access string.</p>
* <p>Example: $safeArrayGetter->get('customer.paymentInfo.ccToken') ==
* $array['customer']['paymentInfo']['ccToken']</p>
*
* #param $accessString
*
* #return array|mixed|null
*/
public function get( $accessString )
{
$keys = $this->parseDotNotation( $accessString );
return $this->getKeys( ...$keys );
}
/**
* #param $string
*
* #return array
*/
protected function parseDotNotation( $string )
{
return explode( '.', strval( $string ) );
}
/**
* #return array
*/
public function toArray()
{
return $this->data;
}
/**
* #param int $options
* #param int $depth
*
* #return string
*/
public function toJson( $options = 0, $depth = 512 )
{
return json_encode( $this, $options, $depth );
}
/**
* #param array $data
*
* #return static
*/
public static function newFromArray( array $data )
{
return new static( $data );
}
/**
* #param \stdClass $data
*
* #return static
*/
public static function newFromObject( \stdClass $data )
{
return new static( json_decode( json_encode( $data ), TRUE ) );
}
/**
* Specify data which should be serialized to JSON
* #link http://php.net/manual/en/jsonserializable.jsonserialize.php
* #return array data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* #since 5.4.0
*/
function jsonSerialize()
{
return $this->toArray();
}
}

instanceof Closure returns false

In the routing part of my application I have classes Route and Router, Route just holds information about specific mapped route and also methods to set and get those information.
I am trying to pass Closure like this,
Router::map('/', function(){}, array());
i store the second parameter (Closure), like this
$route = new Route();
$route->setTarget($target);
*Second parameter is $target variable
when i try this
$target = $route->getTarget();
if($target instanceof Closure)
{
echo 1;
}else
{
echo 0;
}
it prints 0, but when i try print_r($target), i get
Closure Object ( )
class Route
class Route {
/**
* URL of this Route
* #var string
*/
private $url;
/**
* Accepted HTTP methods for this route
* #var array
*/
private $methods = array('GET','POST','PUT','DELETE');
/**
* Target for this route, can be anything.
* #var mixed
*/
private $target;
/**
* The name of this route, used for reversed routing
* #var string
*/
private $name;
/**
* Custom parameter filters for this route
* #var array
*/
private $filters = array();
/**
* Array containing parameters passed through request URL
* #var array
*/
private $params = array();
public function getUrl() {
return $this->url;
}
public function setUrl($url) {
$url = (string) $url;
// make sure that the URL is suffixed with a forward slash
if(substr($url,-1) !== '/') $url .= '/';
$this->url = $url;
}
public function getTarget() {
return $this->target;
}
public function setTarget($target) {
$this->target = $target;
}
public function getMethods() {
return $this->methods;
}
public function setMethods(array $methods) {
$this->methods = $methods;
}
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = (string) $name;
}
public function setFilters(array $filters) {
$this->filters = $filters;
}
public function getRegex() {
return preg_replace_callback("/:(\w+)/", array(&$this, 'substituteFilter'), $this->url);
}
private function substituteFilter($matches) {
if (isset($matches[1]) && isset($this->filters[$matches[1]])) {
return $this->filters[$matches[1]];
}
return "([\w-]+)";
}
public function getParameters() {
return $this->parameters;
}
public function setParameters(array $parameters) {
$this->parameters = $parameters;
}
}
class Router
class Router {
/**
* Array that holds all Route objects
* #var array
*/
private static $_routes = array();
/**
* Array to store named routes in, used for reverse routing.
* #var array
*/
private static $_namedRoutes = array();
/**
* The base REQUEST_URI. Gets prepended to all route url's.
* #var string
*/
private static $_basePath = '';
/**
* Set the base url - gets prepended to all route url's.
* #param string $base_url
*/
public function setBasePath($basePath) {
static::$_basePath = (string) $basePath;
}
/**
* Route factory method
*
* Maps the given URL to the given target.
* #param string $routeUrl string
* #param mixed $target The target of this route. Can be anything. You'll have to provide your own method to turn * this into a filename, controller / action pair, etc..
* #param array $args Array of optional arguments.
*/
public static function map($routeUrl, $target, array $args = array()) {
$route = new Route();
$route->setUrl(static::$_basePath . $routeUrl);
$route->setTarget($target);
if(isset($args['methods'])) {
$methods = explode(',', $args['methods']);
$route->setMethods($methods);
}
if(isset($args['filters'])) {
$route->setFilters($args['filters']);
}
if(isset($args['name'])) {
$route->setName($args['name']);
if (!isset(static::$_namedRoutes[$route->getName()])) {
static::$_namedRoutes[$route->getName()] = $route;
}
}
static::$_routes[] = $route;
}
/**
* Matches the current request against mapped routes
*/
public static function matchCurrentRequest() {
$requestMethod = (isset($_POST['_method']) && ($_method = strtoupper($_POST['_method'])) && in_array($_method,array('PUT','DELETE'))) ? $_method : $_SERVER['REQUEST_METHOD'];
$requestUrl = $_SERVER['REQUEST_URI'];
// strip GET variables from URL
if(($pos = strpos($requestUrl, '?')) !== false) {
$requestUrl = substr($requestUrl, 0, $pos);
}
return static::match($requestUrl, $requestMethod);
}
/**
* Match given request url and request method and see if a route has been defined for it
* If so, return route's target
* If called multiple times
*/
public static function match($requestUrl, $requestMethod = 'GET') {
foreach(static::$_routes as $route) {
// compare server request method with route's allowed http methods
if(!in_array($requestMethod, $route->getMethods())) continue;
// check if request url matches route regex. if not, return false.
if (!preg_match("#^".$route->getRegex()."*$#i", $requestUrl, $matches)) continue;
$params = array();
if (preg_match_all("/:([\w-]+)/", $route->getUrl(), $argument_keys)) {
// grab array with matches
$argument_keys = $argument_keys[1];
// loop trough parameter names, store matching value in $params array
foreach ($argument_keys as $key => $name) {
if (isset($matches[$key + 1]))
$params[$name] = $matches[$key + 1];
}
}
$route->setParameters($params);
if($route)
{
static::respond($route);
}
return $route;
}
return false;
}
/**
* Reverse route a named route
*
* #param string $route_name The name of the route to reverse route.
* #param array $params Optional array of parameters to use in URL
* #return string The url to the route
*/
public function generate($routeName, array $params = array()) {
// Check if route exists
if (!isset(static::$_namedRoutes[$routeName]))
throw new Exception("No route with the name $routeName has been found.");
$route = static::$_namedRoutes[$routeName];
$url = $route->getUrl();
// replace route url with given parameters
if ($params && preg_match_all("/:(\w+)/", $url, $param_keys)) {
// grab array with matches
$param_keys = $param_keys[1];
// loop trough parameter names, store matching value in $params array
foreach ($param_keys as $i => $key) {
if (isset($params[$key]))
$url = preg_replace("/:(\w+)/", $params[$key], $url, 1);
}
}
return $url;
}
private static function respond($route)
{
$target = $route->getTarget();
$path = null;
if($target instanceof Closure)
{
call_user_func($target);
}else
{
if(is_string($target))
{
$target = explode('#', $target);
$target[0] = explode(':', $target[0]);
$controller = $target[0][0];
$method = $target[0][1];
$application = $target[1];
$path = path('app') . $application . '/controllers/' . ucfirst($controller) . '.php';
}
if(is_array($target))
{
$controller = $target['controller'];
$method = $target['method'];
$application = $target['application'];
$path = path('app') . $application . '/controllers/' . ucfirst($controller) . '.php';
}
if(file_exists($path))
{
$obj = require($path);
$obj = new $controller();
$obj->$method();
}else
{
echo '404';
}
}
}
}
Are you using namespaces in your code?
If so you will need to specify the Closure class name as \Closure to escape to the global name space.

Which is the best way to display 'flash messages' in kohana v3?

I would like to know the best way to display flash messages in Kohana v3?
Some tutorials or examples would be helpful.
Do you mean like Kohana 2.x's flash session variables?
The latest Kohana supports get_once() which is pretty similar to the old flash session variables.
$session = Session::instance();
$session->set('test', 'Hello, World!');
// The session variable is returned and removed.
$test = $session->get_once('test');
I think the get_once is a great function, but what if you want to keep the data actually separate from the regular data, here's a basic class that overloads "Session" so that you can use "codeigniter" style flashdata calls with any data-store.
<?php defined('SYSPATH') or die('No direct script access.');
abstract class Session extends Kohana_Session {
/**
* This calls the parent Kohana_Session constructor and processes
* new flashdata to flashdata, and flashdata to old flashdata
*
* #param array configuration
* #param string session id
* #return void
* #uses Kohana_Session::__construct
*/
public function __construct(array $config = NULL, $id = NULL)
{
parent::__construct($config,$id);
if(array_key_exists('___of',$this->_data)){
//Remove old Flash data
unset($this->_data['___of']);
}
if(array_key_exists('___flash',$this->_data)){
//Move current last requests flash data to old flash data
$this->_data['___of'] = $this->_data['___flash'];
unset($this->_data['___flash']);
}
if(array_key_exists('___nf',$this->_data)){
//Move Last Requests added data to the flash data
$this->_data['___flash'] = $this->_data['___nf'];
unset($this->_data['___nf']);
}
}
/**
* keeps a variable set in the sessions flashdata array.
*
* $session->set_flashdata('foo', 'bar');
*
* #param string variable name
* #param ...
* #return $this
*/
public function keep_flashdata($k)
{
$args = func_get_args();
if(array_key_exists('___of',$this->_data)){
foreach($args as $key){
if(array_key_exists($key,$this->_data['___of'])){
//So we were going to trash it...
$this->set_flashdata($k,$this->_data['___of'][$key],true);
}
}
}
$this->_data['___nf'][$key] = $value;
return $this;
}
/**
* Set a variable in the sessions flashdata array.
*
* $session->set_flashdata('foo', 'bar');
*
* #param string variable name
* #param mixed value
* #return $this
*/
public function set_flashdata($key, $value, $current=false)
{
if(!array_key_exists('___nf',$this->_data)){
$this->_data['___nf'] = array();
}
$this->_data['___nf'][$key] = $value;
if($current){
if(!array_key_exists('___flash',$this->_data)){
$this->_data['___flash'] = array();
}
$this->_data['flash'][$key] = $value;
}
return $this;
}
/**
* Set a variable by reference in the sessions flashdata array.
*
* $session->bind_flashdata('foo', $foo);
*
* #param string variable name
* #param mixed referenced value
* #return $this
*/
public function bind_flashdata($key, & $value)
{
if(!array_key_exists('___nf',$this->_data)){
$this->_data['___nf'] = array();
}
$this->_data['___nf'][$key] =& $value;
return $this;
}
/**
* Removes a variable in the session array.
*
* $session->delete_flashdata('foo');
*
* #param string variable name
* #param ...
* #return $this
*/
public function delete_flashdata($key)
{
$args = func_get_args();
if(array_key_exists('___nf',$this->_data)){
foreach ($args as $key)
{
if(array_key_exists($key,$this->_data['___nf'])){
unset($this->_data['___nf'][$key]);
}
}
}
return $this;
}
/**
* Get a variable from the sessions flashdata array.
*
* $foo = $session->get_flashdata('foo');
*
* #param string variable name
* #param mixed default value to return
* #return mixed
*/
public function get_flashdata($key, $default = NULL)
{
if(array_key_exists('___flash',$this->_data) && array_key_exists($key,$this->_data['___flash'])){
return $this->_data['___flash'][$key];
} else if(array_key_exists('___nf',$this->_data) && array_key_exists($key,$this->_data['___nf'])){
return $this->_data['___nf'][$key];
}
return $default;
}
/**
* Get and delete a variable from the session array.
*
* $bar = $session->get_once('bar');
*
* #param string variable name
* #param mixed default value to return
* #return mixed
*/
public function get_flashdata_once($key, $default = NULL)
{
$value = $this->get_flashdata($key, $default);
if(array_key_exists($key, $this->_data['___flash'])){
unset($this->_data['___flash'][$key]);
}
if(array_key_exists($key, $this->_data['___nf'])){
unset($this->_data['___nf'][$key]);
}
return $value;
}
}
?>
I realize there was an answer to this, and like i stated before, the get_once method is great and all, but i enjoy auto garbage collection much more.
If you have any improvements on this code, let me know, its been great to me so far.
Have a look at this module, it might be what you are looking for https://github.com/daveWid/message
I've written a really simple class for this once. Check it out below. Usage examples below
class Notice {
private static $session;
private static $initialized = false;
// current notices
private static $notices = array();
function __construct() {
}
static function init() {
self::$session = Session::instance();
self::$notices['current'] = json_decode(self::$session->get_once('flash'));
if(!is_array(self::$notices['current'])) self::$notices['current'] = array();
self::$initialized = true;
}
static function add($notice, $key=null) {
if(!self::$initialized) self::init();
if(!is_null($key)) {
self::$notices['new'][$key] = $notice;
} else {
self::$notices['new'][] = $notice;
}
self::$session->set('flash', json_encode(self::$notices['new']));
return true;
}
static function get($item = null) {
if(!self::$initialized) self::init();
if($item == null) {
return self::$notices['current'];
}
if(!array_key_exists($item, self::$notices['current']))
return null;
return self::$notices['current'][$item];
}
}
Examples (provided this class is saved as APPPATH . 'classes/notice.php'):
Notice::add('Something great has happened!');
Notice::add('Exciting! I\'ve got something to tell you!', 'message');
echo Notice::get('message'); // "Exciting! I've got ..."
foreach(Notice::get() as $message) {
echo $i++ . $message .'<br />';
}
EDIT: funny... for some reason this question popped up somewhere, didn't notice it was a really old one... sorry for that!
I am using https://github.com/synapsestudios/kohana-notices in my project and I am very happy with it.

Reading a value from application.ini

I have a value that's defined in application.ini
conditions.time= 50
How can I read it in an zend action the zend way?
You can use Zend_Config_Ini
$config = new Zend_Config_Ini('my/ini/file.ini');
echo $config->conditions->time; // 50
Here is my approach, which you can use anywhere in the application:
class My_Controller_Action_Helper_Options extends Zend_Controller_Action_Helper_Abstract
{
/**
* Options separator delimiterm e.g.
* option.subkey or
* option/subkey
*/
const DELIMITER = '.';
/**
* Retrieve application options from bootstrap
*
* #return array
*/
public function getOptions()
{
$front = $this->getFrontController();
$bootstrap = $front->getParam('bootstrap');
if (null === $bootstrap) {
throw new Exception('Unable to find bootstrap');
}
return $bootstrap->getOptions();
}
/**
* Get array key if exists, otherwise returns null
*
* #param array $values
* #param string $key
* #return mixed
*/
private static function _getValue($values, $key)
{
if (is_array($values) && isset($values[$key])) {
return $values[$key];
}
return null;
}
/**
* Get application option form bootstrap
*
* #example
* $options = Zend_Controller_Action_HelperBroker::getStaticHelper('options')
* ->get('conditions.time', 'defaultvalue');
*
* #param string $section
* #param mixed $default
* #return Zend_Config
*/
public function get($section = null, $default = null)
{
$value = $this->getOptions();
if (null !== $section && is_string($section)) {
if (false === strpos($section, self::DELIMITER)) {
$value = $this->_getValue($value, $section);
} else {
$sections = explode(self::DELIMITER, $section);
foreach ($sections as $section) {
$value = $this->_getValue($value, $section);
if (null === $value) {
break;
}
}
}
}
if (null === $value) {
return $default;
}
return $value;
}
/**
* #param string $section
* #param mixed $default
* #return Zend_Config
*/
public function direct($section = null, $default = null)
{
return $this->get($section, $default);
}
}
The Application's Bootstrap.php has access to the application.ini using $this->getOptions(), you could store the value you want in your registry something like this:
public function _initConditions()
{
$config = $this->getOptions();
if (isset($config['conditions']))
{
$registry = Zend_Registry::getInstance();
$registry->conditions = $config['conditions'];
}
}
You could then access your conditions using the registry, in much the same way that you set them here.
Here is an action helper for that :
class My_Controller_Action_Helper_Config
extends Zend_Controller_Action_Helper_Abstract
{
/**
* #return array
*/
public function direct()
{
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
$ns = strtolower(trim($bootstrap->getAppNamespace(), '_'));
return $bootstrap->getOption($ns);
}
}
You have to put your application namespace as a prefix :
; application.ini
My.conditions.time= 50
You can use it in a controller like this :
$config = $this->_helper->config();
$this->view->time = $config['conditions']['time'];
You might be able to use getenv('conditions.time')
http://www.php.net/manual/en/function.getenv.php
PHP has a parse_ini_file() function.

Categories