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.
Related
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
I've been working (mostly for fun) on a custom router.
It's a work in progress, so any advice is always welcome!
But my main problem is that de css/js files are not loaded anymore.
It looks like the path to the files is attached to the current url, so users/(css path).
In Chrome and Firefox the assets just keep loading, no response/code is returned. If I deliberately cause an exception to be thrown, such as altering the file path, I do see the html of the exception being returned.
I've done a lot of debugging already, and cannot seem to figure it out.
/**
* #var
*/
private $routes;
/**
* #var string
* Todo: add this to an ini file or something
*/
private $base_route = "/index.php";
/**
* #param $route
* #param $callback
* #param string $method
*/
public function addRoute($route, $callback, $method = Route::GET)
{
$routes = $this->getRoutes();
if (empty($routes) || !in_array($route, $routes)) {
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], $method
);
return;
}
}
/**
* #param array $route
* #param $method
*/
public function setRoute(array $route, $method)
{
$this->routes[$method][] = $route;
}
/**
* #return mixed
*/
public function getRoutes()
{
return $this->routes;
}
/**
* #throws \Exception
*/
public function handle()
{
$route = $this->getURI();
$route = str_replace($this->base_route, "", $route);
$urlparts = explode("?", $route);
if (count($urlparts) > 1) {
$route = $urlparts[0];
$query = $urlparts[1];
}
if ($this->isAssetRoute($route)) {
$parts = explode("/", $route);
foreach ($parts as $part) {
if ($part !== "public") {
unset($parts[$part]);
} else {
continue;
}
}
$route = implode($parts);
return APP_PATH . "/" . $route;
}
if (empty($route)) {
$this->executeCallback("HomeController");
return;
}
$exists = false;
$routes = $this->getRoutes();
$requested_method = $this->getMethod();
if (!isset($routes[$requested_method])) {
throw new Exception("404: Route {$route} does not exist with method {$requested_method}");
}
$declared_routes = $routes[$requested_method];
$count_routes = count($declared_routes);
for ($i = 0; $i < $count_routes; $i++) {
if ($declared_routes[$i]["route"] === $route) {
$exists = true;
$data = $declared_routes[$i];
continue;
}
}
if (!$exists) {
throw new \Exception("404: route {$route} does not exist!");
}
//Todo: replace [var]
$route = $this->compileRoute($route);
$this->executeCallback($data["callback"]);
}
/**
* #return mixed
*/
private function getProtocol()
{
return $_SERVER["HTTPS"];
}
/**
* #return mixed
*/
public function getMethod()
{
return $_SERVER["REQUEST_METHOD"];
}
/**
* #return mixed
*/
public function getURI()
{
return $_SERVER["REQUEST_URI"];
}
/**
* #param $route
* #param $callback
*/
public function get($route, $callback)
{
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], Route::GET
);
}
/**
* #param $route
* #param $callback
*/
public function post($route, $callback)
{
$this->setRoute(
[
"route" => $route,
"callback" => $callback
], Route::POST
);
}
/**
* #param $route
* #return mixed
*/
public function compileRoute(&$route)
{
$uri = explode("/", $_SERVER["REQUEST_URI"]);
$formatted_route = "";
foreach ($uri as $key => $param) {
$formatted_route .= "/" . preg_replace(
"/\[(.*)\]/", "1", $param
);
}
return str_replace($this->base_route, "", $formatted_route);
}
/**
* #param $callback
* #throws \Exception
*/
public function executeCallback($callback)
{
$callback_data = explode("::", $callback);
$controller = $callback_data[0];
if (!isset($callback_data[1])) {
$method = "index";
} else {
$method = $callback_data[1];
}
if (!class_exists($controller)) {
throw new \Exception("Class {$controller} does not exist!");
}
if (!method_exists($controller, $method)) {
throw new \Exception("Method {$method} does not exist!");
}
$controller::$method();
}
/**
* #param $route
* #return bool
*/
private function isAssetRoute($route)
{
return (stripos($route, "/public/assets/") !== false);
}
Solved it by getting the correct header for it (text/css or application/javascript for those wondering), echoing the file contents and then returning;
I put the code for that in the if ($this->isAssetRoute($route)) statement, located in the handle() method.
All other code in that statement is removed.
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.
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.
Do anyone know why this occurs?
as far I can get, the child class method is declared in the same way as parent's.
Thanks!
here is my kernel code:
<?php
require_once __DIR__.'/../src/autoload.php';
use Symfony\Framework\Kernel;
use Symfony\Components\DependencyInjection\Loader\YamlFileLoader as ContainerLoader;
use Symfony\Components\Routing\Loader\YamlFileLoader as RoutingLoader;
use Symfony\Framework\KernelBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\ZendBundle\ZendBundle;
use Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle;
use Symfony\Bundle\DoctrineBundle\DoctrineBundle;
use Symfony\Bundle\DoctrineMigrationsBundle\DoctrineMigrationsBundle;
use Symfony\Bundle\DoctrineMongoDBBundle\DoctrineMongoDBBundle;
use Symfony\Bundle\PropelBundle\PropelBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Application\UfaraBundle\UfaraBundle;
class UfaraKernel extends Kernel {
public function registerRootDir() {
return __DIR__;
}
public function registerBundles() {
$bundles = array(
new KernelBundle(),
new FrameworkBundle(),
new ZendBundle(),
new SwiftmailerBundle(),
new DoctrineBundle(),
//new DoctrineMigrationsBundle(),
//new DoctrineMongoDBBundle(),
//new PropelBundle(),
//new TwigBundle(),
new UfaraBundle(),
);
if ($this->isDebug()) {
}
return $bundles;
}
public function registerBundleDirs() {
$bundles = array(
'Application' => __DIR__.'/../src/Application',
'Bundle' => __DIR__.'/../src/Bundle',
'Symfony\\Framework' => __DIR__.'/../src/vendor/symfony/src/Symfony/Framework',
'Symfony\\Bundle' => __DIR__.'/../src/vendor/symfony/src/Symfony/Bundle',
);
return $bundles;
}
public function registerContainerConfiguration(LoaderInterface $loader) {
return $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
public function registerRoutes() {
$loader = new RoutingLoader($this->getBundleDirs());
return $loader->load(__DIR__.'/config/routing.yml');
}
}
here is the parent class code:
<?php
namespace Symfony\Framework;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Resource\FileResource;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Loader\DelegatingLoader;
use Symfony\Component\DependencyInjection\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Framework\ClassCollectionLoader;
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier#symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* The Kernel is the heart of the Symfony system. It manages an environment
* that can host bundles.
*
* #author Fabien Potencier <fabien.potencier#symfony-project.org>
*/
abstract class Kernel implements HttpKernelInterface, \Serializable
{
protected $bundles;
protected $bundleDirs;
protected $container;
protected $rootDir;
protected $environment;
protected $debug;
protected $booted;
protected $name;
protected $startTime;
protected $request;
const VERSION = '2.0.0-DEV';
/**
* Constructor.
*
* #param string $environment The environment
* #param Boolean $debug Whether to enable debugging or not
*/
public function __construct($environment, $debug)
{
$this->environment = $environment;
$this->debug = (Boolean) $debug;
$this->booted = false;
$this->rootDir = realpath($this->registerRootDir());
$this->name = basename($this->rootDir);
if ($this->debug) {
ini_set('display_errors', 1);
error_reporting(-1);
$this->startTime = microtime(true);
} else {
ini_set('display_errors', 0);
}
}
public function __clone()
{
if ($this->debug) {
$this->startTime = microtime(true);
}
$this->booted = false;
$this->container = null;
$this->request = null;
}
abstract public function registerRootDir();
abstract public function registerBundles();
abstract public function registerBundleDirs();
abstract public function registerContainerConfiguration(LoaderInterface $loader);
/**
* Checks whether the current kernel has been booted or not.
*
* #return boolean $booted
*/
public function isBooted()
{
return $this->booted;
}
/**
* Boots the current kernel.
*
* This method boots the bundles, which MUST set
* the DI container.
*
* #throws \LogicException When the Kernel is already booted
*/
public function boot()
{
if (true === $this->booted) {
throw new \LogicException('The kernel is already booted.');
}
if (!$this->isDebug()) {
require_once __DIR__.'/bootstrap.php';
}
$this->bundles = $this->registerBundles();
$this->bundleDirs = $this->registerBundleDirs();
$this->container = $this->initializeContainer();
// load core classes
ClassCollectionLoader::load(
$this->container->getParameter('kernel.compiled_classes'),
$this->container->getParameter('kernel.cache_dir'),
'classes',
$this->container->getParameter('kernel.debug'),
true
);
foreach ($this->bundles as $bundle) {
$bundle->setContainer($this->container);
$bundle->boot();
}
$this->booted = true;
}
/**
* Shutdowns the kernel.
*
* This method is mainly useful when doing functional testing.
*/
public function shutdown()
{
$this->booted = false;
foreach ($this->bundles as $bundle) {
$bundle->shutdown();
$bundle->setContainer(null);
}
$this->container = null;
}
/**
* Reboots the kernel.
*
* This method is mainly useful when doing functional testing.
*
* It is a shortcut for the call to shutdown() and boot().
*/
public function reboot()
{
$this->shutdown();
$this->boot();
}
/**
* Gets the Request instance associated with the master request.
*
* #return Request A Request instance
*/
public function getRequest()
{
return $this->request;
}
/**
* Handles a request to convert it to a response by calling the HttpKernel service.
*
* #param Request $request A Request instance
* #param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
* #param Boolean $raw Whether to catch exceptions or not
*
* #return Response $response A Response instance
*/
public function handle(Request $request = null, $type = HttpKernelInterface::MASTER_REQUEST, $raw = false)
{
if (false === $this->booted) {
$this->boot();
}
if (null === $request) {
$request = $this->container->get('request');
} else {
$this->container->set('request', $request);
}
if (HttpKernelInterface::MASTER_REQUEST === $type) {
$this->request = $request;
}
$response = $this->container->getHttpKernelService()->handle($request, $type, $raw);
$this->container->set('request', $this->request);
return $response;
}
/**
* Gets the directories where bundles can be stored.
*
* #return array An array of directories where bundles can be stored
*/
public function getBundleDirs()
{
return $this->bundleDirs;
}
/**
* Gets the registered bundle names.
*
* #return array An array of registered bundle names
*/
public function getBundles()
{
return $this->bundles;
}
/**
* Checks if a given class name belongs to an active bundle.
*
* #param string $class A class name
*
* #return Boolean true if the class belongs to an active bundle, false otherwise
*/
public function isClassInActiveBundle($class)
{
foreach ($this->bundles as $bundle) {
$bundleClass = get_class($bundle);
if (0 === strpos($class, substr($bundleClass, 0, strrpos($bundleClass, '\\')))) {
return true;
}
}
return false;
}
/**
* Returns the Bundle name for a given class.
*
* #param string $class A class name
*
* #return string The Bundle name or null if the class does not belongs to a bundle
*/
public function getBundleForClass($class)
{
$namespace = substr($class, 0, strrpos($class, '\\'));
foreach (array_keys($this->getBundleDirs()) as $prefix) {
if (0 === $pos = strpos($namespace, $prefix)) {
return substr($namespace, strlen($prefix) + 1, strpos($class, 'Bundle\\') + 7);
}
}
}
public function getName()
{
return $this->name;
}
public function getSafeName()
{
return preg_replace('/[^a-zA-Z0-9_]+/', '', $this->name);
}
public function getEnvironment()
{
return $this->environment;
}
public function isDebug()
{
return $this->debug;
}
public function getRootDir()
{
return $this->rootDir;
}
public function getContainer()
{
return $this->container;
}
public function getStartTime()
{
return $this->debug ? $this->startTime : -INF;
}
public function getCacheDir()
{
return $this->rootDir.'/cache/'.$this->environment;
}
public function getLogDir()
{
return $this->rootDir.'/logs';
}
protected function initializeContainer()
{
$class = $this->getSafeName().ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer';
$location = $this->getCacheDir().'/'.$class;
$reload = $this->debug ? $this->needsReload($class, $location) : false;
if ($reload || !file_exists($location.'.php')) {
$this->buildContainer($class, $location.'.php');
}
require_once $location.'.php';
$container = new $class();
$container->set('kernel', $this);
return $container;
}
public function getKernelParameters()
{
$bundles = array();
foreach ($this->bundles as $bundle) {
$bundles[] = get_class($bundle);
}
return array_merge(
array(
'kernel.root_dir' => $this->rootDir,
'kernel.environment' => $this->environment,
'kernel.debug' => $this->debug,
'kernel.name' => $this->name,
'kernel.cache_dir' => $this->getCacheDir(),
'kernel.logs_dir' => $this->getLogDir(),
'kernel.bundle_dirs' => $this->bundleDirs,
'kernel.bundles' => $bundles,
'kernel.charset' => 'UTF-8',
'kernel.compiled_classes' => array(),
),
$this->getEnvParameters()
);
}
protected function getEnvParameters()
{
$parameters = array();
foreach ($_SERVER as $key => $value) {
if ('SYMFONY__' === substr($key, 0, 9)) {
$parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
}
}
return $parameters;
}
protected function needsReload($class, $location)
{
if (!file_exists($location.'.meta') || !file_exists($location.'.php')) {
return true;
}
$meta = unserialize(file_get_contents($location.'.meta'));
$time = filemtime($location.'.php');
foreach ($meta as $resource) {
if (!$resource->isUptodate($time)) {
return true;
}
}
return false;
}
protected function buildContainer($class, $file)
{
$parameterBag = new ParameterBag($this->getKernelParameters());
$container = new ContainerBuilder($parameterBag);
foreach ($this->bundles as $bundle) {
$bundle->registerExtensions($container);
if ($this->debug) {
$container->addObjectResource($bundle);
}
}
if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) {
$container->merge($cont);
}
$container->freeze();
foreach (array('cache', 'logs') as $name) {
$dir = $container->getParameter(sprintf('kernel.%s_dir', $name));
if (!is_dir($dir)) {
if (false === #mkdir($dir, 0777, true)) {
die(sprintf('Unable to create the %s directory (%s)', $name, dirname($dir)));
}
} elseif (!is_writable($dir)) {
die(sprintf('Unable to write in the %s directory (%s)', $name, $dir));
}
}
// cache the container
$dumper = new PhpDumper($container);
$content = $dumper->dump(array('class' => $class));
if (!$this->debug) {
$content = self::stripComments($content);
}
$this->writeCacheFile($file, $content);
if ($this->debug) {
$container->addObjectResource($this);
// save the resources
$this->writeCacheFile($this->getCacheDir().'/'.$class.'.meta', serialize($container->getResources()));
}
}
protected function getContainerLoader(ContainerInterface $container)
{
$resolver = new LoaderResolver(array(
new XmlFileLoader($container, $this->getBundleDirs()),
new YamlFileLoader($container, $this->getBundleDirs()),
new IniFileLoader($container, $this->getBundleDirs()),
new PhpFileLoader($container, $this->getBundleDirs()),
new ClosureLoader($container),
));
return new DelegatingLoader($resolver);
}
/**
* Removes comments from a PHP source string.
*
* We don't use the PHP php_strip_whitespace() function
* as we want the content to be readable and well-formatted.
*
* #param string $source A PHP string
*
* #return string The PHP string with the comments removed
*/
static public function stripComments($source)
{
if (!function_exists('token_get_all')) {
return $source;
}
$output = '';
foreach (token_get_all($source) as $token) {
if (is_string($token)) {
$output .= $token;
} elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
$output .= $token[1];
}
}
// replace multiple new lines with a single newline
$output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output);
// reformat {} "a la python"
$output = preg_replace(array('/\n\s*\{/', '/\n\s*\}/'), array(' {', ' }'), $output);
return $output;
}
protected function writeCacheFile($file, $content)
{
$tmpFile = tempnam(dirname($file), basename($file));
if (false !== #file_put_contents($tmpFile, $content) && #rename($tmpFile, $file)) {
chmod($file, 0644);
return;
}
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
}
public function serialize()
{
return serialize(array($this->environment, $this->debug));
}
public function unserialize($data)
{
list($environment, $debug) = unserialize($data);
$this->__construct($environment, $debug);
}
}
Your answer lies in the imported namespaces. In the Kernel's file, there's this use clause:
use Symfony\Component\DependencyInjection\Loader\LoaderInterface;
So that ties LoaderInterface to the fully namespaced class Symfony\Component\DependencyInjection\Loader\LoaderInterface.
Basically making the signature:
public function registerContainerConfiguration(Symfony\Component\DependencyInjection\Loader\LoaderInterface $loader);
In your class, you don't import that namespace. So PHP by default assumes the class is in your namespace (since none of the imported namespaces have that interface name).
So your signature is (since you don't declare a namespace):
public function registerContainerConfiguration(\LoaderInterface $loader);
So to get them to match, simply add the use line to the top of your file:
use Symfony\Component\DependencyInjection\Loader\LoaderInterface;