how to create 404 error page for manual bootstrap for example in this app ? http://album-o-rama.phalconphp.com/
i use this dispatcher :
$di->set(
'dispatcher',
function() use ($di) {
$evManager = $di->getShared('eventsManager');
$evManager->attach(
"dispatch:beforeException",
function($event, $dispatcher, $exception)
{
switch ($exception->getCode()) {
case PhDispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case PhDispatcher::EXCEPTION_ACTION_NOT_FOUND:
$dispatcher->forward(
array(
'controller' => 'error',
'action' => 'show404',
)
);
return false;
}
}
);
$dispatcher = new PhDispatcher();
$dispatcher->setEventsManager($evManager);
return $dispatcher;
},
true
);
Try this in your index.php:
$di->set('dispatcher', function() {
$eventsManager = new \Phalcon\Events\Manager();
$eventsManager->attach("dispatch:beforeException", function($event, $dispatcher, $exception) {
//Handle 404 exceptions
if ($exception instanceof \Phalcon\Mvc\Dispatcher\Exception) {
$dispatcher->forward(array(
'controller' => 'index',
'action' => 'show404'
));
return false;
}
//Handle other exceptions
$dispatcher->forward(array(
'controller' => 'index',
'action' => 'show503'
));
return false;
});
$dispatcher = new \Phalcon\Mvc\Dispatcher();
//Bind the EventsManager to the dispatcher
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
}, true);
The recommended functionality here is:
http://docs.phalconphp.com/en/latest/reference/routing.html#not-found-paths
and maybe
routing.html#dealing-with-extra-trailing-slashes
For manual bootstrap, instead of use dispatcher, you could set a router
/**
* Registering a router
*/
$di->set('router', require __DIR__.'/../common/config/routes.php');
Then add this route rule at 'common/config/routes.php'.
$router->notFound(array(
'module' => 'frontend',
'namespace' => 'AlbumOrama\Frontend\Controllers\\',
'controller' => 'index',
'action' => 'route404'
));
Finally define a controller and a view to capture this action.
And voilĂ : 404 error page!
Just for comment, I pull request this solution for the app you mentioned:
https://github.com/phalcon/album-o-rama/pull/5/files
For new version of Phalcon you can handle error using routes by adding this code to service.php
$di->set('router',function() use($Config){
$router = new \Phalcon\Mvc\Router();
$router->notFound(array(
"controller" => "error",
"action" => "error404"
));
return $router;
});
public function show404Action()
{
$this->response->setStatusCode(404, 'Not Found');
$this->view->pick('error/show404');
}
Related
I've implemented a router, securityplugin (for ACL) and notfoundplugin.
I want my site to be set up with a subcontroller structure: Link
The website is set up in the following main parts:
Index
Admin
Tickets
Account
The issues I have:
When calling: domain/admin/actionofadmin
Returns custom 404: "Page doesn't exist" instead of the normal action result
When calling: domain/admin/actionofadmin. (<-- mind the dot at the end)
Returns index action of index controller instead of the normal action result
Why does the router return theses results? How can they be fixed?
Extra questions:
How does Phalcon know where to find a view and link it to the correct controller? Example: A dashboardController resides in a folder "admin" inside the folder "controllers".
How does Phalcon know that in the SecurityPlugin ACL it needs to search for the correct controller while it doesn't get a namespace? Example: When I want to allow controller Tickets of namespace app\controllers\admin to be only viewed by admin users.
Extra information:
Phalcon 3.0.3
PHP 5.6
Let me know if you need any more information / files or if I should post it somewhere else for ease of reading.
Files:
/app/controllers/AdminController.php
<?php
namespace Ontrack\Controllers;
class AdminController extends ControllerBase
{
public function indexAction(){
}
public function testAction(){
echo "test";
}
}
/app/config/services.php Excerpt
//This makes sure the routes are correctly handled for authorized/unauthorized
/**
* MVC dispatcher
*/
$di->set("dispatcher", function () use ($di) {
// Create an events manager
$eventsManager = $di->getShared('eventsManager');
/**
*Check if the user is allowed to access certain action using the SecurityPlugin
*Listen for events produced in the dispatcher using the Security plugin
*/
$eventsManager->attach("dispatch:beforeDispatch", new SecurityPlugin());
// Handle exceptions and not-found exceptions using NotFoundPlugin
$eventsManager->attach("dispatch:beforeException", new NotFoundPlugin());
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('Ontrack\Controllers');
// Assign the events manager to the dispatcher
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
}
);
/app/config/loader.php
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
[
$config->application->controllersDir,
$config->application->modelsDir,
$config->application->pluginsDir
]
)->register();
$loader->registerNamespaces(
[
'Ontrack\Controllers' => APP_PATH . '/controllers/',
'Ontrack\Controllers\Admin' => APP_PATH . '/controllers/admin',
'Ontrack\Models' => APP_PATH . '/models/'
]
)->register();
/app/config/routes.php
<?php
$router = new Phalcon\Mvc\Router(false);
$router->setDefaults(
[
"controller" => "index",
"action" => "index",
]
);
$router->add('/:controller/:action/:params', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
'action' => 2,
'params' => 3,
]);
$router->add('/:controller/:action', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
'action' => 2,
]);
$router->add('/:controller', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
]);
$router->add('/admin/:controller/:action/:params', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
'action' => 2,
'params' => 3,
]);
$router->add('/admin/:controller/:action', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
'action' => 2,
]);
$router->add('/admin/:controller', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
]);
$router->removeExtraSlashes(true);
return $router;
/app/plugins/SecurityPlugin.php
<?php
use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Adapter\Memory as AclList;
use Phalcon\Acl\Resource;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
class SecurityPlugin extends Plugin
{
/**
* Returns an existing or new access control list
*
* #returns AclList
*/
public function getAcl()
{
if (!isset($this->persistent->acl)) {
$acl = new AclList();
$acl->setDefaultAction(Acl::DENY);
// Register roles
$roles = [
'admins' => new Role(
'admins',
'Website administrators'
),
'users' => new Role(
'users',
'Member privileges, granted after sign in.'
),
'guests' => new Role(
'guests',
'Anyone browsing the site who is not signed in is considered to be a "Guest".'
)
];
foreach ($roles as $role) {
$acl->addRole($role);
}
//Private area resources
$privateResources = array(
'account' => array('*')
);
$privateResourcesAdmin = array(
'admin' => array('*'),
'tickets' => array('*')
);
//Public area resources
$publicResources = array(
'index' => array('*'),
'register' => array('*'),
'errors' => array('show401', 'show404', 'show500'),
'register' => array('*'),
'login' => array('*'),
'logout' => array('*')
);
foreach ($privateResources as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
foreach ($privateResourcesAdmin as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
foreach ($publicResources as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
//Grant access to public areas to users, admins and guests
foreach ($roles as $role) {
foreach ($publicResources as $resource => $actions) {
foreach ($actions as $action){
$acl->allow($role->getName(), $resource, $action);
}
}
}
//Grant access to private area to role Users
foreach ($privateResources as $resource => $actions) {
foreach ($actions as $action){
$acl->allow('users', $resource, $action);
}
}
foreach ($privateResourcesAdmin as $resource => $actions) {
foreach ($actions as $action){
$acl->allow('admins', $resource, $action);
}
}
//The acl is stored in session, APC would be useful here too
$this->persistent->acl = $acl;
}
return $this->persistent->acl;
}
/**
* This action is executed before execute any action in the application
*
* #param Event $event
* #param Dispatcher $dispatcher
* #return bool
*/
public function beforeDispatch(Event $event, Dispatcher $dispatcher){
$auth = $this->session->has('auth');
if (!$auth){
$role = 'guests';
} else {
$authSession = $this->session->get("auth");
if($authSession['account_type'] == 99){
$role = 'admins';
} else {
$role = 'users';
}
}
$controller = $dispatcher->getControllerName();
$action = $dispatcher->getActionName();
$acl = $this->getAcl();
if (!$acl->isResource($controller)) {
$dispatcher->forward([
'controller' => 'errors',
'action' => 'show404'
]);
return false;
}
$allowed = $acl->isAllowed($role, $controller, $action);
if (!$allowed) {
if($controller === 'admin'){
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show404'
));
} else {
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show401'
));
}
return false;
}
}
}
/app/plugins/NotFoundPlugin.php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Dispatcher;
use Phalcon\Mvc\Dispatcher\Exception as DispatcherException;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
/**
* NotFoundPlugin
*
* Handles not-found controller/actions
*/
class NotFoundPlugin extends Plugin
{
/**
* This action is executed before execute any action in the application
*
* #param Event $event
* #param MvcDispatcher $dispatcher
* #param Exception $exception
* #return boolean
*/
public function beforeException(Event $event, MvcDispatcher $dispatcher, Exception $exception)
{
error_log($exception->getMessage() . PHP_EOL . $exception->getTraceAsString());
if ($exception instanceof DispatcherException) {
switch ($exception->getCode()) {
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show404'
));
return false;
}
}
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show500'
));
return false;
}
}
When calling: domain/admin/actionofadmin(as i understand domain is for example www.google.pl) phalcon is expecting ActionofadminController according to your routes. Are you sure there is such controller? Don't sure why with with dot it's hitting index controller and index action though.
How does Phalcon know where to find a view and link it to the correct controller? Example: A dashboardController resides in a folder "admin" inside the folder "controllers".
It's getting this info from dispatcher. Mvc application if you don't render view your self is implicit automatically rendering. Check this source: https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/application.zep#L348 And other view classes.
About Acl Plugin - it doesn't check for namespace at all. So if you have two controllers with same name but other namespace this wil cause obviously a problem. You just need to change security plugin to your needs.
I have set the Route:
$router->add('/:module/:controller/:action/:params', [
'module' => 1,
'controller' => 2,
'action' => 3,
'params' => 4
]);
When I enter URL to the browser, for example: auth/login/index and module under this URL does not exist, so it throws an exception:
Phalcon\Mvc\Application\Exception: Module 'auth' isn't registered in the application container
How can I catch this exception?
SOLUTION:
$router->add('/:module/:controller/:action/:params', [
'module' => 1,
'controller' => 2,
'action' => 3,
'params' => 4
])->beforeMatch(function($uri) use ($application) {
$modules = $application->getModules();
$moduleName = array_filter(explode('/', $uri))[1];
if(!isset($modules[$moduleName]))
return false;
return true;
});
In beforeMatch method I check If module exist.
For second param you can use closure and check via
if ($di->has('modulename'))
Update1
As I can see https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/application.zep#L232
you can use event manager and return false from beforeStartModule if module not found in DI
if typeof eventsManager == "object" {
if eventsManager->fire("application:beforeStartModule", this, moduleName) === false {
return false;
}
}
Update2
Also you can use dispatcher setting:
// Initialize the Dispatcher
$di->setShared('dispatcher', function() use ($eventsManager) {
$dispatcher = new \Phalcon\Mvc\Dispatcher;
// Attach a listener for type "dispatch:beforeException"
$eventsManager->attach('dispatch:beforeException', function($event, $dispatcher, $exception) {
/**
* #var \Phalcon\Mvc\Dispatcher\Exception $exception
* #var \Phalcon\Mvc\Dispatcher $dispatcher
*/
switch ($exception->getCode()) {
case \Phalcon\Mvc\Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case \Phalcon\Mvc\Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
case ANY OTHER CODE HERE:
$dispatcher->forward([
'controller' => 'error',
'action' => 'show404'
]);
return false;
}
});
// Setting up the Dispatcher component
$dispatcher->setDefaultNamespace('your_default_namespace_here');
// Obtain the Events Manager from the DI and bind the eventsManager to the module dispatcher
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
How to connect to the subdomains Phalcon:
city1.site.com
city2.site.com
city3.site.com
...
cityN.site.com
city - in the database
I am trying to do so
$router->add('{subdomain:\w+}.{domain:.+}', array(
'controller' => 'category',
'action' => 'categorySearch'
)
);
but does not work.
Phalcon's router doesn't match subdomains. You have to match $_SERVER['SERVER_NAME'] with a regular expression to create corresponding routers.
<?php
$di = new \Phalcon\Di\FactoryDefault();
$di->setShared('router', function() {
// Match subdomain with regular expression
if(preg_match("/^(\\w+)\\.site\\.com$/", $_SERVER['SERVER_NAME'], $matches) === 1) {
$subdomain = $matches[1];
}
// Create a router without default routes
$router = new \Phalcon\Mvc\Router(false);
if (isset($subdomain)) {
// Create routes for subdomains
$router->add('/category', array(
'controller' => 'category',
'action' => 'categorySearch'
));
} else {
// Create routes for main domain
}
return $router;
});
// Retrieve corresponding router at runtime
$di->getShared('router')->handle();
may be this can help you problem
$di['router'] = function()
{
$router = new Phalcon\Mvc\Router(false);
switch ($_SERVER['HTTP_HOST'])
{
case 'm.domain.com':
$router->add('/m/xxx/yyy', array(
'controller' => 'xxx',
'action' => 'yyy'
));
//...
break;
default:
$router->add('/xxx/yyy', array(
'controller' => 'xxx',
'action' => 'yyy'
));
break;
}
return $router;
};
How do I set default controller and default action in PhalconPHP?
I have used this code without success:
$di->set('router', function () {
$router = new \Phalcon\Mvc\Router();
$router->notFound(['controller' => 'Index', 'action'=> 'index']);
$router->setDefaultController('Bookmarks');
$router->setDefaultAction('index');
return $router;
});
It can fail because you did not set the default namespace for the controller. I also had some trouble with the case of the controller name when i switched from windows to linux. Using lower case name seemed to solve the issue.
$router = new Phalcon\Mvc\Router\Annotations(false);
$router->removeExtraSlashes(true);
$router->setDefaultNamespace('App\Controllers\\');
$router->setDefaultController('index');
$router->setDefaultAction('index');
/**
* Standard MVC routes
*/
$router->add('/', []);
$router->add(
'/:controller',
[
'controller' => 1
]
);
$router->add(
'/:controller/:action/:params',
[
'controller' => 1,
'action' => 2,
'params' => 3
]
);
return $router;
Also, notFound method did not work for me. So i attached a listener to the eventsManager to handle this issue.
$di->set('dispatcher', function () use ($di) {
// ERROR 404 - Page not found
$evManager = $di->getShared('eventsManager');
$evManager->attach(
"dispatch:beforeException",
function ($event, $dispatcher, $exception) {
switch ($exception->getCode()) {
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
$dispatcher->forward(
[
'controller' => 'error',
'action' => 'show404'
]
);
return false;
}
}
);
$dispatcher = new Dispatcher();
$dispatcher->setEventsManager($evManager);
return $dispatcher;
}, true);
Hi I'm trying to implement a Multi Module MVC for frontend and backend like what is in phalconphp documentations. But I can't make it work. it's about an hour but I really can not understand where is the problem.
Could anyone guide me how can I make a skeleton for a multi module mvc for frontend and backend.
what should I put in Moudle.php for frontend and backend
And also what should I put in bootstrap file located in public/index.php
And any extra file or information I need.
The code in the phalcon/mvc repository on GitHub will help. You can find it here:
https://github.com/phalcon/mvc/tree/master/multiple
More specifically, you'll be interested in:
https://github.com/phalcon/mvc/blob/master/multiple/public/index.php
https://github.com/phalcon/mvc/blob/master/multiple/apps/backend/Module.php
I tend to use this in my index.php:
$application = new \Phalcon\Mvc\Application($di);
// Register the installed modules
$application->registerModules(
array(
'web' => array(
'className' => 'Apps\Web\Module',
'path' => '../apps/web/Module.php',
)
)
);
echo $application->handle()->getContent();
And in my Module.php:
<?php
namespace Apps\Web;
use Phalcon\Loader;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\View;
use Phalcon\Mvc\ModuleDefinitionInterface;
class Module implements ModuleDefinitionInterface
{
/**
* Register a specific autoloader for the module
*/
public function registerAutoloaders()
{
$loader = new Loader();
$loader->registerNamespaces(
array(
'Apps\Web\Controllers' => '../apps/web/controllers/',
)
);
$loader->register();
}
/**
* Register specific services for the module
* #param \Phalcon\DI\FactoryDefault $di
*/
public function registerServices($di)
{
//Registering a dispatcher
$di->set(
'dispatcher',
function() use ($di) {
$eventsManager = $di->getShared('eventsManager');
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('Apps\Web\Controllers');
$eventsManager->attach(
'dispatch:beforeException',
function($event, $dispatcher, $exception) use ($di) {
/* #var $dispatcher \Phalcon\Mvc\Dispatcher */
switch ($exception->getCode()) {
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
$di->set('lastException', $exception);
$dispatcher->forward(
array(
'module' => 'web',
'controller' => 'error',
'action' => 'notFound',
)
);
return false;
default:
$di->set('lastException', $exception);
$dispatcher->forward(
array(
'module' => 'web',
'controller' => 'error',
'action' => 'uncaughtException',
)
);
return false;
}
}
);
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
}
);
}
}
Hopefully this helps!