Phalcon ispatcher has detected a cyclic routing - php

I create a new project with Phalcon framework.
For begin, my environment is :
Phalcon 3.2.12
Windows 10
Xampp / PHP 7.2
At this time, I have created one login page in the index. When I launch my application, I have this message :
Fatal error: Uncaught Phalcon\Mvc\Dispatcher\Exception: Dispatcher has
detected a cyclic routing causing stability problems in
\public\index.php:32
Line 32 :
echo $application->handle()->getContent();
There is my dispatcher in services.php :
$di->setShared('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' => 'index',
'action' => 'show404'
));
return false;
}
});
$dispatcher = new PhDispatcher();
$dispatcher->setEventsManager($evManager);
return $dispatcher;
});
There is my IndexController :
class IndexController extends ControllerBase
{
public function indexAction()
{
$this->view->setLayout('login');
}
public function show404Action()
{
$this->view->setLayout('login');
$this->response->setStatusCode(404, "Not Found");
$this->view->pick('index/404');
}
}
There is my ControllerBase :
public function beforeExecuteRoute($dispatcher)
{
$isValid = true;
// check auth
if ($dispatcher->getControllerName() !== 'index') {
$isValid = false;
$this->view->disable();
$this->response->setStatusCode(401, 'Vous devez vous identifier pour accéder à votre environnement.');
if (!$this->request->isAjax()) {
$this->response->redirect('index');
}
}
return $isValid;
}
index.php
define('APP_PATH', realpath('..'));
/**
* Define APPLICATION_ENV (DEV,STAGING,PREPROD,PROD)
*
* #var APPLICATION_ENV string
*/
defined('APPLICATION_ENV') || define('APPLICATION_ENV', (isset($_SERVER['APPLICATION_ENV']) ? $_SERVER['APPLICATION_ENV'] : 'PROD'));
/**
* Read the configuration
*/
$config = include APP_PATH . "/app/config/" . strtolower(APPLICATION_ENV) . ".config.php";
/**
* Read auto-loader
*/
include APP_PATH . "/app/config/loader.php";
/**
* Read services
*/
include APP_PATH . "/app/config/services.php";
/**
* Handle the request
*/
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle()->getContent();
If I put a var_dump at the begin of method beforeExecuteRoute, I don't see the result of var_dump.
Have you an idea?
Thanks

probably you forward to something that can't be found. Try to rename show404 to showNotFound, you can inspect the $dispatcher->getControllerName() and getActionName() during the afterExecuteRoute event to see why your handler or action can never be found
public function showNotFoundAction()
{
$this->view->setLayout('login');
$this->response->setStatusCode(404, "Not Found");
$this->view->pick('index/404');
}
And
$dispatcher->forward(array(
'controller' => 'index',
'action' => 'showNotFound'
));

Related

Cake PHP 2 event listener not firing

I'm working on a Cake PHP 2 project that contains a custom module feature allowing for custom plugins. The functionality for this to work is loaded correctly, and the module I'm working on called QueueManager contains a controller linked to a button which dispatches an event, I'm then listening for this event in a file called app/modules/QueueManagerModule/Lib/Event/DispatchJobListener.php and it's here where I'm simply trying to write to a file to check if the listener is listening.
I'm not getting any errors logged to my error.log file, what am I missing?
My controller contains the following to dispatch the event:
<?php
App::uses('AppController', 'Controller');
App::uses('CakeEvent', 'Event');
class QueueController extends AppController
{
/**
* Define the name
*/
public $name = 'Queue';
/**
* Define the name
*/
public $layout = 'QueueManagerLayout';
/**
* Loaded models
*/
public $uses = array(
'QueueManagerJob',
'QueueManagerFailedJob'
);
/**
* View: Queue/dashboard
*/
public function dashboard()
{
if ($this->request->is('post')) {
$this->getEventManager()->dispatch(new CakeEvent(
'QueueManagerModule.QueueManagerJob.dispatch',
$this, array('payload' => ['name' => 'john'])
));
}
}
}
My Lib/Event/DispatchJobListener.php is listening for the event:
<?php
App::uses('CakeEventListener', 'Event');
class DispatchJobListener implements CakeEventListener {
public function implementedEvents() {
return array(
'QueueManagerModule.QueueManagerJob.dispatch' => 'test'
);
}
public function test($event) {
fopen("456465564.txt", "w");
}
}
And I've loaded the events in my module's Config/events.php file:
<?php
App::uses('CakeEventManager', 'Event');
App::uses('DispatchJobListener', 'Lib/Event');
CakeEventManager::instance()->attach(new DispatchJobListener());
Why don't I get any file created?
My custom module is loaded and contains an App::build section which loads the modules dircetories, and it's here where the Config is loaded, I've stubbed the events.php file in the project's main Config folder, and have loaded it through the bootstrap.php
<?php
App::uses('BaseModule', 'Modules');
App::uses('CakeEventManager', 'Event');
/**
* Helper class to load modules of a specific format from /app/modules directory,
* and create instances that can connect to system events, modify system behaviours etc.
*
* Usage:
*
* $_modules = new Modules();
$mods_arr = $_modules->initModules(ROOT.'/app/modules');
*
*/
class Modules
{
public function initModules($modules_base_dir)
{
$modules = array();
//loop over all directories in /app/modules/
foreach (new DirectoryIterator($modules_base_dir) as $dir)
{
if($dir->isDot()) continue;
if($dir->getFilename()=='.svn') continue;
if($dir->isFile()) {
continue;
}
//compile a list of all modules, and load each Module class
$classname = $dir->getFilename();
App::import('modules/'.$classname, $classname);
$module = new $classname();
array_push($modules, $module);
//enumerate all events from BaseModule so we know what we need to handle
$base_events_array = array();
$methods = get_class_methods('BaseModule');
foreach($methods as $method)
{
//strip out any method that starts with "handle_"
if(substr($method, 0, 7)=='handle_')
{
$base_events_array[] = substr($method, 7);
}
}
//IF this module is enabled
if($module->_enabled)
{
//register any EXISTING event handlers for this module
foreach($base_events_array as $event_name)
{
if(method_exists($module, 'handle_'.$event_name))
{
CakeEventManager::instance()->attach(array($module, 'handle_'.$event_name), $event_name);
}
}
//connect up any additional controllers,views, models, bootstraps from this module
App::build(array(
'Config' => array($modules_base_dir.'/'.$classname.'/Config/'),
'Console/Command' => array($modules_base_dir.'/'.$classname.'/Console/Command/'),
'Console/Command/Task' => array($modules_base_dir.'/'.$classname.'/Console/Command/Task/'),
'Lib' => array($modules_base_dir.'/'.$classname.'/Lib/'),
'Lib/Event' => array($modules_base_dir.'/'.$classname.'/Lib/Event/'),
'Controller' => array($modules_base_dir.'/'.$classname.'/Controller/'),
'View' => array($modules_base_dir.'/'.$classname.'/View/'),
'Model' => array($modules_base_dir.'/'.$classname.'/Model/'),
'Vendor' => array($modules_base_dir.'/'.$classname.'/Vendor/')
));
if(file_exists($modules_base_dir.'/'.$classname.'/bootstrap.php'))
{
include_once $modules_base_dir.'/'.$classname.'/bootstrap.php';
}
}
}
//die(var_dump(App::path('Controller')));
return $modules;
}
}

How to extend the class kartik\dynagrid\DynaGrid?

Installed the DynaGrid plugin and ran into the problem of expanding it. I created my own class DynaGridViewAdvanced, which is located on the path modules/appWidgets/widgets/grid and has namespace app\modules\appWidgets\widgets\grid.
The class code is as follows:
<?php
declare(strict_types=1);
namespace app\modules\appWidgets\widgets\grid;
use kartik\dynagrid\DynaGrid;
use Yii;
use yii\helpers\Url;
class DynaGridViewAdvanced extends DynaGrid {
/**
* #var bool активность функции перехода на просмотр при двойном клике
*/
public $transitionToView = false;
public function init() {
parent::init(); // TODO: Change the autogenerated stub
if ($this->transitionToView && empty($this->rowOptions)) {
$this->rowOptions = function($model, $key, $index, $grid) {
$viewLink = Url::toRoute(['/' . Yii::$app->controller->id . '/view']);
return ['ondblclick' => 'location.href="' . $viewLink . '?id="+(this.dataset.key);'];
};
}
}
public function run() {
parent::run(); // TODO: Change the autogenerated stub
}
}
Actually, the question is why the error is thrown out and how to fix it?
View not Found – yii\base\ViewNotFoundException
The view file does not exist: /var/www/urs/modules/appWidgets/widgets/grid/views/config.php
In DynaGrid itself there is a property _module, which stores in itself kartik\dynagrid\Module, in which there is a property configView. configView is used only in DynaGrid itself:
$dynagrid = $this->render(
$this->_module->configView,
[...]
)
As far as I understand the error, he is trying to find this configuration view file exactly with namespace.
See the full error page:

Symfony - Check if controller exists

My situation: I have a NavigatorController which is triggered by AJAX requests, and will
$this->forward("controllername")
the request. But how can I check if the controller exists based on controller name? Of course, BEFORE the actual forward happens and throws an error when the page controller does not exists.
You can actually use the
controller_resolver
service that Symfony uses in order to check if controller exists.
public function indexAction(Request $request)
{
$request->attributes->set('_controller', 'AppBundle\Controller\ExampleController::exampleAction');
try{
$this->get('debug.controller_resolver')->getController($request);
} catch (\Exception $e) {
$x = $e->getCode();
}
}
Hope it helps!
Also You can check by using Service:
namespace AppBundle\Service;
class ExampleService
{
/**
* #param string $controller
* #return bool
*/
public function has($controller)
{
list($class, $action) = explode('::', $controller, 2);
return class_exists($class);
}
}
In app/config/services.yml :
services:
app.controller.check:
class: AppBundle\Service\ExampleService
In Controller:
public function indexAction(Request $request)
{
$controller = 'AppBundle\Controller\DefaultController';
if($this->get('app.controller.check')->has($controller))
{
echo 'Exists';
}
else
{
echo "Doesn't exists";
}
}

Phalcon unittests not passing

I'm trying to set up unittests, but I'm having no luck at all. I created TestHelper.php in a tests folder. This file looks like this:
<?php
use Phalcon\Di;
use Phalcon\Di\FactoryDefault;
ini_set('display_errors',1);
error_reporting(E_ALL);
define('ROOT_PATH', __DIR__);
define('PATH_LIBRARY', __DIR__ . '/../app/library/');
define('PATH_SERVICES', __DIR__ . '/../app/services/');
define('PATH_RESOURCES', __DIR__ . '/../app/resources/');
define('BASE_DIR', dirname(__DIR__));
define('APP_DIR', BASE_DIR . '/app');
set_include_path(
ROOT_PATH . PATH_SEPARATOR . get_include_path()
);
// Required for phalcon/incubator
include __DIR__ . "/../vendor/autoload.php";
// Use the application autoloader to autoload the classes
// Autoload the dependencies found in composer
$loader = new \Phalcon\Loader();
$loader->registerDirs(
array(
ROOT_PATH
)
);
$config = include APP_DIR . '/config/config.php';
$loader->registerNamespaces(array(
'MyApp\Models' => $config->application->modelsDir,
'MyApp\Controllers' => $config->application->controllersDir,
'MyApp\Forms' => $config->application->formsDir,
'MyApp\Classes' => $config->application->classesDir,
'MyApp' => $config->application->libraryDir
));
$loader->register();
I also created UnitTestCase.php:
<?php
use Phalcon\Di;
use Phalcon\DI\FactoryDefault;
use Phalcon\Test\UnitTestCase as PhalconTestCase;
use Phalcon\Mvc\View;
use Phalcon\Crypt;
use Phalcon\Mvc\Dispatcher;
use \Phalcon\Mvc\Dispatcher as PhDispatcher;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\Model\Metadata\Files as MetaDataAdapter;
use Phalcon\Session\Adapter\Files as SessionAdapter;
use Phalcon\Flash\Direct as Flash;
use Phalcon\Logger;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Logger\Adapter\File as LoggerFile;
use MyApp\Auth\Auth;
use MyApp\AuthPublic\AuthPublic;
use MyApp\Acl\Acl;
use MyApp\CacheData\CacheData;
use MyApp\Mail\Mail;
use MyApp\PHPExcel\PHPExcel;
abstract class UnitTestCase extends PhalconTestCase
{
/**
* #var \Voice\Cache
*/
protected $_cache;
/**
* #var \Phalcon\Config
*/
protected $_config;
/**
* #var bool
*/
private $_loaded = false;
public function setUp(Phalcon\DiInterface $di = NULL, Phalcon\Config $config = NULL)
{
// Load any additional services that might be required during testing
$di = new FactoryDefault();
$config = include APP_DIR . '/config/config.php';
/**
* The URL component is used to generate all kind of urls in the application
*/
$di->set('url', function () use ($config) {
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
}, true);
/**
* Setting up the view component
*/
$di->set('view', function () use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(array(
'.volt' => function ($view, $di) use ($config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir . 'volt/',
'compiledSeparator' => '_'
));
return $volt;
}
));
return $view;
}, true);
/**
* Database connection is created based in the parameters defined in the configuration file
*/
$di->set('db', function () use ($config) {
$eventsManager = new EventsManager();
// Debug sql logging //
$is_debug_sql_logging = true;
if ( $is_debug_sql_logging )
{
$logger = new LoggerFile( $config->application->logsDir ."debug_sql.log" );
$logger->log( "\n------\n" );
// Listen all the database events //
$eventsManager->attach( 'db', function( $event, $connection ) use ($logger) {
if ( $event->getType() == 'beforeQuery' ) {
$log_message = $connection->getRealSQLStatement()."\n".print_r( $connection->getSQLVariables(), true );
$logger->log( $log_message, Logger::DEBUG );
}
if ($event->getType() == 'afterQuery') {
//...//
}
});
}
// Database connection //
$dbAdapter = new DbAdapter(array(
'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'database'
));
//Assign the eventsManager to the db adapter instance
$dbAdapter->setEventsManager( $eventsManager );
return $dbAdapter;
});
/**
* If the configuration specify the use of metadata adapter use it or use memory otherwise
*/
$di->set('modelsMetadata', function () use ($config) {
return new MetaDataAdapter(array(
'metaDataDir' => $config->application->cacheDir . 'metaData/'
));
});
$di->set('modelsManager', function() {
return new \Phalcon\Mvc\Model\Manager();
});
/**
* Start the session the first time some component request the session service
*/
$di->set('session', function () {
$session = new SessionAdapter();
$session->start();
return $session;
});
/**
* Cache of models
*/
$di->set('cache', function () {
$cacheData = new CacheData();
return $cacheData;
});
/**
* Crypt service
*/
$di->set('crypt', function () use ($config) {
$crypt = new Crypt();
$crypt->setKey($config->application->cryptSalt);
return $crypt;
});
/**
* Set a 404 redirect AND use a default namespace
*/
$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);
/* Dispatcher use a default namespace */
$dispatcher->setDefaultNamespace('MyApp\Controllers');
return $dispatcher;
},
true
);
/**
* Loading routes from the routes.php file
*/
$di->set('router', function () {
return require __DIR__ . '/routes.php';
});
/**
* Flash service with custom CSS classes
*/
$di->set('flash', function () {
return new Flash(array(
'error' => 'notification notification--error',
'success' => 'notification notification--success',
'notice' => 'notification notification--neutral',
'general' => 'notification notification--general',
'warning' => 'notification notification--warning'
));
});
/**
* Authentication component
*/
$di->set('auth', function () {
return new Auth();
});
/**
* Self test authentication component
*/
$di->set('authPublic', function () {
return new AuthPublic();
});
/**
* Mail service uses AmazonSES
*/
$di->set('mail', function () {
return new Mail();
});
/**
* Access Control List
*/
$di->set('acl', function () {
return new Acl();
});
/**
* PHPExcel
*/
$di->set('phpexcel', function () {
return new PHPExcel();
});
parent::setUp($di, $config);
$this->_loaded = true;
}
/**
* Check if the test case is setup properly
*
* #throws \PHPUnit_Framework_IncompleteTestError;
*/
public function __destruct()
{
if (!$this->_loaded) {
throw new \PHPUnit_Framework_IncompleteTestError('Please run parent::setUp().');
}
}
}
And also phpunit.xml:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="TestHelper.php"
backupGlobals="false"
backupStaticAttributes="false"
verbose="true"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true">
<testsuite name="Phalcon - Testsuite">
<directory>./</directory>
</testsuite>
</phpunit>
All this together, should make me able to run some unittests. However, when I go to the tests folder in terminal and run ../vendor/bin/phpunit it throws an error. The error is Phalcon\Di\Exception: Service 'modelsManager' wasn't found in the dependency injection container. I have been struggling for some hours with this and I hope someone will be able to help me. What am I doing wrong here?
Add DI::setDefault($di); before parent::setUp($di, $config); in UnitTestCase.php
This way you can access DI components globally, not only in local scope.
My setUp() function in UnitTestCase.php looks like this:
public function setUp()
{
parent::setUp();
$di = new FactoryDefault();
// load all services.
include APP_PATH . "/config/services.php";
DI::setDefault($di);
$this->setDi($di);
$this->_loaded = true;
}
This way I have access to DI via $this->di (eg: $this->di->get('config') and all other related libraries which need DI can get it globally.

Zend Framework current route in bootstrap

Ladies and gentlemen,
I am working hard on a new webapplication which is based on the Zend Framework.
Almost the whole webapplication will be secured with a login(username and password).
My idea is to check if the visitor can be authenticated and if not check if the user is requesting a login route. If he is not trying to login he will be redirected to the login page.
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
/**
* Bootstrap::_initRouterRewrites()
*
* #return void
*/
protected function _initRouterRewrites()
{
$frontController = Zend_Controller_Front::getInstance();
$this->router = $frontController->getRouter();
$this->router->addRoute(
'default',
new Zend_Controller_Router_Route('/',
array('controller' => 'index',
'action' => 'index'))
)
->addRoute(
'login',
new Zend_Controller_Router_Route('/inloggen.html',
array('controller' => 'auth',
'action' => 'login'))
);
}
/**
* Bootstrap::_initZendSession()
*
* #return void
*/
protected function _initZendSession()
{
// Ensure that both the session and the db resources are bootstrapped
$this->bootstrap(array('db', 'session'));
// Actually start the session
Zend_Session::start();
}
/**
* Bootstrap::_initAuthentication()
*
* #return void
*/
protected function _initAuthentication()
{
// Instantiate auth object
$auth = Zend_Auth::getInstance();
// Check if visitor has an identity
if (!$auth->hasIdentity())
{
}
}
}
When I use the method $this->router->getCurrrentRoute() inthe _initAuthentication method I get the following error: "Current route is not defined".
What can I do to check if the current route is login?
Thanks in advance!
At the time of bootstrapping routing has run yet. What you need here is a FrontController Plugin that hooks into the request lifecycle at the appropriate place . In your case that is probably going to be during routeShutdown after the routing has determined where to dispatch the request.
From http://devzone.zend.com/1692/zend-framework-mvc-request-lifecycle/:
Use plugins like this in bootstrap.php:
protected function _initPlugins() {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Plugin_Checkaccess());
}
and in plugins/Checkaccess.php
`
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$request = $this->getRequest();
$controllerName = strtolower($request->getControllerName());
$actionName = strtolower($request->getActionName());
if ('user' == $controllerName)
{
$session = new Zend_Session_Namespace('USER');
$notLogged = array('login','register');
if(!in_array($actionName, $notLogged) && !$session->user){
$request->setControllerName("index");
$request->setActionName("index");
$this->_response->setRedirect('/');
//$this->_response->setRedirect('/?redirectTo='.$this->_request->getRequestUri());
}elseif(in_array($actionName, $notLogged) && $session->user){
$request->setControllerName("user");
$request->setActionName("index");
$this->_response->setRedirect('/home');
}
return;
}
}
}`

Categories