Phalcon: why router's routes are not being called? - php

I have the following index.php:
<?php
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\DI\FactoryDefault;
use Phalcon\Mvc\Url as UrlProvider;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\Micro;
try {
// Register an autoloader
$loader = new Loader();
$loader->registerDirs(array(
__DIR__ . '/controllers/',
__DIR__ . '/models/'
))->register();
// Create a DI
$app = new Micro();
$di = new FactoryDefault();
$app->setDI($di);
// Setup the view component
$di->set('view', function () {
$view = new View();
$view->setViewsDir('/views/');
return $view;
});
// Setup a base URI so that all generated URIs include the "legacy" folder
$di->set('url', function () {
$url = new UrlProvider();
$url->setBaseUri('/legacy/api/v1/');
return $url;
});
$di->set('router', function() {
// require __DIR__.'/config/routes.php';
// return $router;
$router = new Phalcon\Mvc\Router(false);
$router->add('/', array(
"controller" => "site",
"action" => "index"
));
$router->notFound(
[
"controller" => "site",
"action" => "ping"
]
);
var_dump($router);
return $router;
});
$app->handle();
} catch (\Exception $e) {
// Do Something I guess, return Server Error message
$app->response->setStatusCode(500, "Server Error");
$app->response->setContent($e->getMessage());
$app->response->send();
}
and the following structure:
--api
----v1
------config
-------- routes.php
------controllers
--------SiteController.php
------models
------views
The problem is that I think my application ignores the router, because I'm getting the following error: if I navigate to "/" - Matched route doesn't have an associated handler. While if I go to some random location like "/12321" it returns Not-Found handler is not callable or is not defined.
Any idea what I'm doing wrong?

Remember that you're setting as base uri /legacy/api/v1/ so all your routes are intended to be appended to that.
$di->set('url', function () {
$url = new UrlProvider();
$url->setBaseUri('/legacy/api/v1/');
return $url;
});
You can't simply access: / but instead, you've to visit /legacy/api/v1/ or if you want to visit /user, you've to visit /legacy/api/v1/user.
Greetings!

I also had some problems with phalcon (1.3.x) routes too. Here's what I did to make them working the way I wanted. Took me a long time to figure that out:
/** #var \Phalcon\Mvc\Router $router */
$router = new Phalcon\Mvc\Router(FALSE); // does not create default routes
$router->removeExtraSlashes(TRUE);
$router->setDefaults(array(
'namespace' => 'Namespace\Controller',
'controller' => 'index',
'action' => 'index'
));
$router->notFound(array(
'controller' => 'index',
'action' => 'show404'
));
Hope it helps.

Related

When using the Slim Framework the get function is being output as plain text with an error message 'Page Not Found'

I am relatively new to Slim so I am not sure if I am making an obvious mistake. I am trying to build the application in a secure way so the get function is not in the index file. The index requires a file that instantiates the slim app and requires the dependencies, settings, and routes files, the route file then requires the homepage which is where the error comes from.
When the code is run the page output is the get function from the homepage is displayed in plain text and then a error message underneath that reads:
"Page Not Found
The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.
Visit the Home Page"
I am sure php is installed properly as when I try the get function in the index page it run fine, I also tested it with phpinfo().
I am using xampp as my development environment.
/**
* Index.php
*/
ini_set('xdebug.trace_output_name', 'football_trivia_game');
ini_set('display_errors', 'On');
ini_set('html_errors', 'On');
ini_set('xdebug.trace_format', 1);
// Include bootstrap
include_once '../includes/bootstrap.php';
/**
* Bootstrap.php
*/
// Start the session
session_start();
// Require vendor
require 'vendor/autoload.php';
// Define app path
$app_path = __DIR__ . "/app/";
// Require settings
$settings = require $app_path . 'settings.php';
// Instantiate container
$container = new \Slim\Container($settings);
// Require the dependencies
require $app_path . 'dependencies.php';
// Instantiate app
$app = new \Slim\App($container);
// Require routes
require $app_path . 'routes.php';
// Execute app
$app->run();
session_regenerate_id(true);
/**
* Setttings.php
*/
// Display errors
ini_set('display_errors', 'On');
ini_set('html_errors', 'On');
// Get app url
$app_url = dirname($_SERVER['SCRIPT_NAME']);
// Get css path
$css_path = $app_url . '/css/app.css';
// Define css path
define('CSS_PATH', $css_path);
// Set settings
$settings = [
"settings" => [
'displayErrorDetails' => true,
'addContentLengthHeader' => false,
'mode' => 'development',
'debug' => true,
'view' => [
'template_path' => __DIR__ . '/templates/',
'twig' => [
'cache' => false,
'auto_reload' => true,
]],
'pdo_settings' => [
'rdbms' => 'mysql',
'host' => 'localhost',
'db_name' => 'fbta_db',
'port' => '3306',
'user_name' => 'username',
'user_password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
]
]
]
];
return $settings;
/**
* Dependencies
*/
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig(
$container['settings']['view']['template_path'],
$container['settings']['view']['twig'],
[
'debug' => true // This line should enable debug mode
]
);
// Instantiate and add Slim specific extension
$basePath = rtrim(str_ireplace('index.php', ''. $container['request']->getUri()->getBasePath()), '/');
$view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
return $view;
};
/**
* routes.php
*/
require 'routes/homepage.php';
/**
* Homepage Route
*/
// Get Request and Response
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
$app->get('/', function(Request $request, Response $response) {
$message = 'test';
$response->getBody()->write($message);
return $response;
});
I apologise if I have included too much code, I am just unsure where the problem stems from, any help would be appreciated.
Slim is very flexible. Your must to specify how you are include the route.php script.
My way
index.php:
declare(strict_types=1);
(require __DIR__ . '/../config/bootstrap.php')->run();
bootstrap.php
declare(strict_types=1);
use DI\ContainerBuilder;
use Slim\App;
require_once __DIR__.'/../vendor/autoload.php';
(Dotenv\Dotenv::createImmutable(dirname(__DIR__)))->load();
$containerBuilder = new ContainerBuilder();
// Set up settings
$containerBuilder->addDefinitions(__DIR__.'/container.php');
// Build PHP-DI Container instance
$container = $containerBuilder->build();
// Только для WEB
if ('cli' !== php_sapi_name()) {
// Create App instance
$app = $container->get(App::class);
// Register routes
(require __DIR__.'/routes.php')($app);
// Register middleware
(require __DIR__.'/middleware.php')($app);
} else {
$app = $container;
}
return $app;
In my way routes.php is a script wich MUST return a function:
return function (App $app) {...}
So, in my way, your routes.php returns nothing, because homepage.php returns nothing
So, in my way, your homepage.php muyst be looks like:
return function (App $app) {
$app->get('/', function(Request $request, Response $response) {
$message = 'test';
$response->getBody()->write($message);
return $response;
});
}
So, you must be pass road path from the index.php to route.php in slim. )

Slim Twig View return $view as null when used in render function

Hello I am having an issue while rendering the page, i hope someone can help me with it.
I have tried changing the directory structure as well creating a new project with similar code , but nothing works for me .
routes.php
<?php
$app->get('/home' , function() {
return $this->view->render($response,'home.twig');
});
app.php
<?php
session_start();
require __DIR__ . '/../vendor/autoload.php';
$app = new \Slim\App([
'settings'=> [
'displayErrorDetails' => true,
]
]);
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig(__DIR__.'/../resources/views', [
'cache' => __DIR__.'../cache',
]);
// Instantiate and add Slim specific extension
$view->addExtension(new Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
require __DIR__ . '/../app/routes.php';
index.php
<?php
require __DIR__ . '/../bootstrap/app.php';
$app->run();
See Slim templates section.
The closure needs extra parameters in routes.php:
// Render Twig template in route
$app->get('/home', function ($request, $response) {
return $this->view->render($response, 'home.twig');
});

Phalcon Application sending "No data received" on production, but not localhost

I am writing a Phalcon PHP website on windows and on my local server everything works as specified. When the base url is reached, it forwards to my public folder with .htaccess and loads index.php. The contents of index.php are below.
It should be noted that almost all contents in index.php below are from the official Phalcon documentation page.
<?php
echo "TEST TEST DEST";
use \Phalcon\Mvc\Dispatcher;
try {
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerDirs(array(
'../app/controllers/',
'../app/models/'
))->register();
//Create a DI
$di = new Phalcon\DI\FactoryDefault();
//Setup the view component
$di->set('view', function(){
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../app/views/');
return $view;
});
$di->set(
'dispatcher',
function() use ($di) {
$eventsManager = $di->getShared('eventsManager');
$eventsManager->attach(
'dispatch:beforeException',
function($event, $dispatcher, $exception) {
switch ($exception->getCode()) {
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
$dispatcher->forward(
array(
'controller' => 'error',
'action' => 'error404',
)
);
return false;
break; // for checkstyle
default:
$dispatcher->forward(
array(
'controller' => 'error',
'action' => 'error404',
)
);
return false;
break; // for checkstyle
}
}
);
$dispatcher = new Dispatcher();
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
},
true
);
//Setup a base URI so that all generated URIs include the "tutorial" folder
$di->set('url', function(){
$url = new \Phalcon\Mvc\Url();
$url->setBaseUri('/');
return $url;
});
//Handle the request
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle()->getContent();
} catch(\Phalcon\Exception $e) {
echo "PhalconException: ", $e->getMessage();
}
This then redirects the page to the index controller and the indexAction as specified by the default Phalcon behavior. On localhost this displays my index.html page perfectly as specified.
The problem is that when I load it to my production server, that is CentOS, the index.php file instead returns No Data Received when the following line is run.
echo $application->handle()->getContent();
I have no idea what the problem could be and am fairly new to Phalcon and PHP in general so any advice would be greatly appreciated.

Using a RouteCollectionProvider in Silex

I have a custom Silex\RouteCollection which I want to register...
class RouteCollectionProvider extends RouteCollection
{
public function __construct() {
$this->add(
'Index',
new Route('/', array(
'method' => 'get',
'controller' => 'index',
'action' => 'index'
)
));
}
}
...during the bootstrapping:
$app = new Silex\Application();
/** here **/
$app->run();
I could use:
$app = new Silex\Application();
$routes = new RouteCollectionProvider();
foreach ($routes->getIterator() as $route) {
$defaults = $route->getDefaults();
$pattern = $route->getPath();
$callback = 'Controller\\'
. ucfirst($defaults['controller'])
. 'Controller::'
. $defaults['action']
. 'Action';
$app->get($pattern, $callback);
}
$app->run();
I don't like having the initialization of those routes right in there.
Do you know any spot in Silex, where this does fit better?
I cannot use $app->register() because it's getting called too late and the routes won't get active in there.
Maybe there is an event I can use with
$app->on('beforeCompileRoutesOrSomething', function() use ($app) {
// initialize routes
}
Or a hook in the Dispatcher?
My aim is to not have a big collection of $app->get() or $app->post() in there. I also know I can ->mount() a controller but then still I have all my get definitions in my bootstrap and not in a Provider.
This post solves the problem: Scaling Silex pt. 2.
$app = new Application;
$app->extend('routes', function (RouteCollection $routes, Application $app) {
$routes->addCollection(new MyCustomRouteCollection);
return $routes;
});
$app->run();

ZF2 - How to change the error/404 response page? Not just template but to set a new ViewModel

By default the page is set like this in the Application module.config array:
'template_map' => array(
'error/404' => __DIR__ . '/../view/error/404.phtml'
I want to change the page. I want new ViewModel for it full of variables. It means that simply to change the template is not enough:
'error/404' => __DIR__ . '/../view/error/my_new_404_template.phtml'
But I can't understand how to make it. I can't see the way the request comes to the 'error/404'.
How to create new ViewModel for it?
How to attach variables to it?
How the route comes to 'error/404' to catch it to change?
For example, I have such a method for 'error/404' page:
public function pageNotFoundAction() {
$view = new ViewModel();
$view->setTemplate('error/404'); // set my template
$sm = $this->getServiceLocator()->get('SessionManager');
$cont = new Container('SomeNamespace', $sm);
$view->var1 = $cont->offsetGet('someValue1'); // the "error/404" template
$view->var2 = $cont->offsetGet('someValue2'); // is full of variables
$view->var3 = $cont->offsetGet('someValue3');
$view->var4 = "One more view variable";
// And now I return it somewhere and want it to be called
// in case of "the page is not found"
return $view;
}
How to make such a change? I can't get the system they've created to deal with things like 'error/404'. Please help.
UPD 1
Even more complicated task. How to have several 'error/404' pages?
Would like to ask guys who created the framework whether they know that 'not_found_template' cannot have an array of 'error/404' pages. How it can be? If I set this option like this:
'template_map' => array(
'error/404' => __DIR__ . '/../view/error/404.phtml',
'my-page/one_more_error404' => __DIR__ . '/../view/my-page/my-page/one_more_error404.phtml',
'other_page/second_404' => __DIR__ . '/../view/other-page/one_more_error404.phtml',
'not_found_template' => array(
'error/404',
'my-page/one_more_error404',
'other-page/second_404',
);
it throws an error. 'not_found_template' force you to have only one 'error/404' template?
There is another way. To catch an EVENT_DISPATCH_ERROR and totally rebuild viewModel. Cavern is that layout – is a root viewModel, and content appended into layout by default is another viewModel (child). These points are not such clear described in official docs.
Here is how it can look like in your Module.php:
public function onBootstrap(MvcEvent $event)
{
$app = $event->getParam( 'application' );
$eventManager = $app->getEventManager();
/** attach Front layout for 404 errors */
$eventManager->attach( MvcEvent::EVENT_DISPATCH_ERROR, function( MvcEvent $event ){
/** here you can retrieve anything from your serviceManager */
$serviceManager = $event->getApplication()->getServiceManager();
$someVar = $serviceManager->get( 'Some\Factory' )->getSomeValue();
/** here you redefine layout used to publish an error */
$layout = $serviceManager->get( 'viewManager' )->getViewModel();
$layout->setTemplate( 'layout/start' );
/** here you redefine template used to the error exactly and pass custom variable into ViewModel */
$viewModel = $event->getViewModel();
$viewModel->setVariables( array( 'someVar' => $someVar ) )
->setTemplate( 'error/404' );
});
}
I used this to manage 404 error (I moved my website from spip to ZF2 based cms) :
In module onBootstrap function :
$eventManager->getSharedManager()->attach('*', MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), -100);
Then
public function onDispatchError(MvcEvent $event)
{
$response = $event->getResponse();
if ($response->getStatusCode() == 404) {
$url = $event->getRouter()->assemble(array(), array('name' => 'index'));
$requestUri = $event->getRequest()->getRequestUri();
$response->getHeaders()->addHeaderLine('Location', "$url?url=$requestUri");
$response->setStatusCode(200);
$response->sendHeaders();
$event->stopPropagation(true);
} elseif($response->getStatusCode() == 500){
//DO SOMETHING else?
return;
}
}
In this code we never return a 404 error, we just call the route (in my example index) with the requested url as param
I hope that help you.
I am not sure I follow what you are trying to achieve, can you give a clear example of what you are trying to do?
If you are simply trying to add variables to the view model passed you could even do this in your controller, check out AbstractActionController
/**
* Action called if matched action does not exist
*
* #return array
*/
public function notFoundAction()
{
$response = $this->response;
$event = $this->getEvent();
$routeMatch = $event->getRouteMatch();
$routeMatch->setParam('action', 'not-found');
if ($response instanceof HttpResponse) {
return $this->createHttpNotFoundModel($response);
}
return $this->createConsoleNotFoundModel($response);
}
/**
* Create an HTTP view model representing a "not found" page
*
* #param HttpResponse $response
* #return ViewModel
*/
protected function createHttpNotFoundModel(HttpResponse $response)
{
$response->setStatusCode(404);
// Add in extra stuff from your ServiceLocator here...
// $viewModel->setTemplate(..);
return new ViewModel(array(
'content' => 'Page not found',
));
}
The First thing is to create the views :
modules/Yourapplication/view/yourapplication/error/index.phtml
modules/Yourapplication/view/yourapplication/error/404.phtml
The second thing is to register the views in the module config:
In module.config.php of your application
'view_manager' => array(
//[...]
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
//[...]
'error/404' => __DIR__ . '/../view/yourapplication/error/404.phtml',
'error/index' => __DIR__ . '/../view/yourapplication/error/index.phtml',
),
// [...]
),
in module.php you can also change template and layout.
function onBootstrap(EventInterface $e) {
$app = $e->getApplication();
$evt = $app->getEventManager();
$evt->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this,'onDispatchError'), 100);
}
function onDispatchError(MvcEvent $e) {
$vm = $e->getViewModel();
$vm->setTemplate('layout/blank');
}
Or more simply (where you want) :
/* #var \Zend\Mvc\View\Http\RouteNotFoundStrategy $strategy */
$strategy = $this->getServiceLocator()->get('HttpRouteNotFoundStrategy');
$strategy->setNotFoundTemplate('application/other/404');
$view = new ViewModel();
//$view->setTemplate('application/other/404');
return $view;
You should first detach default notfoundstrategy and in your Module.php and in case of a 404, you should return a new viewmodel from the controller. Please see this post: http://www.cagataygurturk.com/zf2-controller-specific-not-found-page/

Categories