Good morning,
I have been developing an application using Silex for the past couple of weeks and last night I either made a change to my code or something was updated as part of updating composer but it will not work.
I am using the 'Igorw\ConfigServiceProvider' to load up my routes which link to my configured controllers. But when I access the webpage I get the error message:
InvalidArgumentException: Unable to find controller "controllers.admin:index".
My files are as follows
composer.json
{
"require": {
"silex/silex": "1.2.*#dev",
"igorw/config-service-provider": "1.2.*#dev",
"symfony/yaml": "2.5.*#dev"
},
"autoload": {
"psr-4": {
"Turtle\\Controllers\\": "src/turtle/controllers"
}
}
}
config/routes.yml
config.routes:
admin:
pattern: /admin
defaults: { _controller: 'controllers.admin:index' }
method: GET
web/index.php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use \Igorw\Silex\ConfigServiceProvider;
use \Turtle\Controllers\AdminController;
$app = new Silex\Application;
$app["debug"] = true;
// load the routes
$app -> register (new ConfigServiceProvider(__DIR__ . "/../config/routes.yml"));
foreach ($app["config.routes"] as $name => $route) {
$app -> match($route["pattern"], $route["defaults"]["_controller"]) -> bind($name) -> method(isset($route["method"]) ? $route["method"] : "GET");
}
// register the classes
$app["controllers.admin"] = $app -> share(function($app) {
return new AdminController($app);
});
$app -> run();
src/turtle/controllers/AdminController.php
<?php
namespace Turtle\Controllers;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
class AdminController {
protected $app;
public function __construct(Application $app) {
$this -> app = $app;
}
public function index (Request $request) {
return "Hello World!";
}
}
I have checked the $app variable and it contains an instantiated AdminController class, but for some reason the system is picking up the controller properly. I really do not understand what has happened and can only put it down to an obscure mistake or an update.
Can anyone shed any light on this please?
Thanks, Russell
I cross posted this on the Silex GitHub issue site at https://github.com/silexphp/Silex/issues/919 and the problem has been pointed out. Kudos to Dave Marshall.
The web/index.php file is not registering the Silex ServerControllerServiceProvider. After adding this in the system now works. The updated file now looks like:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use \Igorw\Silex\ConfigServiceProvider;
use \Turtle\Controllers\AdminController;
$app = new Silex\Application;
$app["debug"] = true;
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
// load the routes
$app -> register (new ConfigServiceProvider(__DIR__ . "/../config/routes.yml"));
foreach ($app["config.routes"] as $name => $route) {
$app -> match($route["pattern"], $route["defaults"]["_controller"]) -> bind($name) -> method(isset($route["method"]) ? $route["method"] : "GET");
}
// register the classes
$app["controllers.admin"] = $app -> share(function($app) {
return new AdminController($app);
});
$app -> run();
I must have removed the line inadvertently when I was re-organising the files.
Related
I am trying to learn slim framework and I am following the tutorial. What I would like is a detailed explanation of what the be low snippet of code is doing within the slim environment.
$app->get('/client/{name}'
The reason that I am asking is because in keep getting route not found. But I have yet to figure out why. The base route works. But when I added the twig and tried to route to that. It fails.
Now comes the code:
This part is in my webroot/public/index.php
<?php
use DI\Container;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
use Twig\Error\LoaderError;
require __DIR__ . '/../vendor/autoload.php';
$container = new Container;
$settings = require __DIR__ . '/../app/settings.php';
$settings($container);
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);
// Create Twig
$twigPath = __DIR__ . "/../templates";
$twig = '';
try {
$twig = Twig::create($twigPath, ['cache' => false]);
} catch (LoaderError $e) {
echo "Error " . $e->getMessage();
}
// Add Twig-View Middleware
$app->add(TwigMiddleware::create($app, $twig));
$routes = require __DIR__ . '/../app/routes.php';
$routes($app);
$app->run();
This part is in the routes.php:
<?php
use Slim\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
return function (App $app) {
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write("Hello world! Really?");
return $response;
});
$app->get('/client/{name}', function (Request $request, Response $response, $args) {
$view = Twig::fromRequest($request);
return $view->render($response, 'client_profiles.html', [
'name' => $args['name']
]);
})->setName('profile');
};
The first route works fine the second does not. According to what I am reading. It should work. https://www.slimframework.com/docs/v4/features/templates.html
I feel that if I knew what get is looking to do. I may be able to fix it and build a proper route.
When I dig into the $app->get which connects with the RouterCollecorProxy.php. There is the $pattern variable and $callable. The callable is the anonymous function that comes after the common in the
$app->get('/client/{name}', function <- this is the callable, right?
I see the map class which takes me to the createRoute which returns the $methods, $pattern, callable and a few other things.
I think the pattern is where my problem is.
I have mvc php cms like this folder structure:
application
---admin
--------controller
--------model
--------view
--------language
---catalog
--------controller
------------------IndexController.php
--------model
--------view
--------language
core
--------controller.php
//...more
public
--------index.php
vendor
I install symfony/router component for help my route url using composer json:
{
"autoload": {
"psr-4": {"App\\": "application/"}
},
"require-dev":{
"symfony/routing" : "*"
}
}
Now with route documents I add this code for routing in index.php:
require '../vendor/autoload.php';
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
$route = new Route('/index', array('_controller' => 'App\Catalog\Controller\IndexController\index'));
$routes = new RouteCollection();
$routes->add('route_name', $route);
$context = new RequestContext('/');
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/index');
In My IndexController I have :
namespace App\Catalog\Controller;
class IndexController {
public function __construct()
{
echo 'Construct';
}
public function index(){
echo'Im here';
}
}
Now in Action I work in this url: localhost:8888/mvc/index and can't see result : Im here IndexController.
How do symfony routing url work and find controller in my mvc structure? thank for any practice And Help.
The request context should be populated with the actual URI that's hitting the application. Instead of trying to do this yourself you can use the HTTP Foundation package from symfony to populate this:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RequestContext;
$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());
It's also documented here: https://symfony.com/doc/current/components/routing.html#components-routing-http-foundation
After the matching ($parameters = $matcher->match('/index');) you can use the _controller key of the parameters to instantiate the controller and dispatch the action. My suggestion would be to replace the last \ with a different symbol for easy splitting, like App\Controller\Something::index.
You can then do the following:
list($controllerClassName, $action) = explode($parameters['_controller']);
$controller = new $controllerClassName();
$controller->{$action}();
Which should echo the response you have in your controller class.
I'm trying to load my custom classes for the model on Slim 3 (using the skeleton) so I made this:
In app/composer.json:
"autoload": {
"psr-4": {
"App\\Classes\\": "/src/classes"
}
},
In routes.php I have this setting:
<?php
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Container;
// Routes
$app->get('/sugiere', function (Request $request, Response $response, array $args) {
// Sample log message
$this->logger->info("Slim-Skeleton '/' route");
$cat_mapper = new \App\Classes\CategoryMapper($this->db);
$comuna_mapper = new \App\Classes\ComunaMapper($this->db);
$lang_mapper = new \App\Classes\LanguageMapper($this->db);
$netw_mapper = new \App\Classes\NetworkMapper($this->db);
$com_list = $com_mapper->getComunaList();
$cat_list = $cat_mapper->getCategoryList();
$lang_list = $lang_mapper->getLangList();
$netw_list = $netw_mapper->getNetworkList();
By the way I added to all classes a namespace App\Classes on top.
Your path /src/classes looks incorrect. It's unlikely your src directory is in the filesystem root.
Change your composer.json file to
"autoload": {
"psr-4": {
"App\\Classes\\": "src/classes/"
}
}
and run
composer dump-autoload
to re-generate the autoload.php file.
See https://getcomposer.org/doc/01-basic-usage.md#autoloading
I'm trying to create a custom middleware class and can't seem to call extend \Slim\Middleware because it's not found.
This is my index.php
<?php
require __DIR__ . '/../vendor/autoload.php';
session_start();
// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);
// Register middleware
require __DIR__ . '/../src/middleware.php';
// Run app
$app->run();
This is my middleware.php
<?php
require_once("tester_auth.php");
$app->add(new TestAuth());
This is my tester_auth.php which is the custom middleware file
<?php
use Slim\Middleware;
class TestAuth extends \Slim\Middleware {
public function __construct() {
//Define the urls that you want to exclude from Authentication, aka public urls
$this->whiteList = array('\/login');
}
public function deny_access() {
$res = $this->app->response();
$res->status(401);
}
public function isPublicUrl($url) {
$patterns_flattened = implode('|', $this->whiteList);
$matches = null;
preg_match('/' . $patterns_flattened . '/', $url, $matches);
return (count($matches) > 0);
}
public function call() {
//Get the token sent from jquery
$tokenAuth = $this->app->request->headers->get('Authorization');
//We can check if the url requested is public or protected
if ($this->isPublicUrl($this->app->request->getPathInfo())) {
//if public, then we just call the next middleware and continue execution normally
$this->next->call();
} else {
$this->deny_access();
}
}
}
It successfully gets to my TestAuth but gives me the error Class 'Slim\\Middleware' not found in /var/www/html/src/tester_auth.php on line 6 ...
Edit:
At first, I was having this issue because my composer.json didn't have middleware installed but I have since updated it and it's there now but still having the same issue..
"require": {
"php": ">=5.5.0",
"slim/slim": "^3.8",
"slim/php-view": "^2.0",
"slim/middleware": "*",
"monolog/monolog": "^1.17"
}
Try to restart your HTTP server (ngixn, PHP web server,..) in case it caches some PHP.
BTW, slim/middleware is for Slim 2., but you are using 3..
I try to use Monolog in my Silex application, according to the doc
http://silex.sensiolabs.org/doc/master/providers/monolog.html
I declare MonologServiceProvider in the app.php file as follow:
use Silex\Provider\MonologServiceProvider;
$app->register(new MonologServiceProvider(), array(
'monolog.logfile' => __DIR__ . '/../files/logs/log.log',
));
And I try to write in my log.log file on the controler:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// In a controler
$app['monolog']->info("test");
$app['monolog']->debug("test");
$app['monolog']->warning("test");
$app['monolog']->error("test");
I don't have any error, but it is not working at all.
I just wan't to put my "test" message in my log.log file, how can I do that ?
Thanks for help
I can't really answer your question based on the info you've given, but it's a slow-news day here, so strummed-up a working Silex site with working logging. All the files are on Github, but I'll repeat them here for ease of reading.
composer.json
{
"require" : {
"silex/silex" : "^2.0",
"monolog/monolog" : "^1.0"
},
"autoload" : {
"psr-4" : {
"community\\" : "src/"
}
}
}
public/index.php
<?php
use \community\app\Application;
require_once realpath(__DIR__ . '/../vendor/autoload.php');
$app = new Application();
$app["debug"] = true;
$app->run();
src/app/Application.php
<?php
namespace community\app;
use \Silex\Application as SilexApplication;
use Silex\Provider\MonologServiceProvider;
class Application extends SilexApplication {
function __construct() {
parent::__construct();
$this->registerServices();
$this->mountControllers();
}
function registerServices(){
$this->register(new MonologServiceProvider(), [
"monolog.logfile" => realpath(__DIR__ . "/../../log") . "/general.log"
]);
}
function mountControllers() {
$this->get('/testLog', 'community\controller\TestLogController::doGet');
}
}
src/controller/TestLogController.php
<?php
namespace community\controller;
use community\app\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class TestLogController {
public function doGet(Request $request, Application $app) {
$app["monolog"]->info("hi!");
return new Response("All good", Response::HTTP_OK);
}
}
That writes to log/general.log as follows:
[2016-12-28 13:58:05] app.INFO: hi! [] []
One thing I noticed is that if the path to the log file is bung, then Monolog just seems to swallow it (which is not exactly ideal). This could well be your issue.
Anyway, grab the code above and mess around with it. Hopefully you'll be able to work out the differences between yours and mine, and get yours working.