Calling a class method for a route - php

I've used Slim for several projects and I always was connecting routes to class methods, by doing $app->route('/', array('MyClass', 'method'));
However, after installing it with composer, this is the error I'm getting:
call_user_func_array() expects parameter 1 to be a valid callback, non-static method Pages::home() should not be called statically
Here's the code:
class Pages {
function home() {
print 'home';
}
}
$app = new \Slim\Slim();
$app->get('/', array('Pages', 'home'));
$app->run();
Did I miss something? Should I edit my class additionally?
Thanks!

Looks like your error reporting is turned up higher than it has been in the past, as I believe the error you're getting is an E_STRICT error. If you changed your function home() method to public static function home() you'd no longer get the error.
That said, a better solution might be to try the new(-ish) controller feature in Slim 2.4.0. Your new route would look like this:
$app->get('/', '\Pages:home');

The code is wrong, you are passing an array as a parameter instead of the callback. Try passing a function.
Documentation for GET Routes:
http://docs.slimframework.com/#GET-Routes
class Pages {
function home() {
print 'home';
}
}
$app = new \Slim\Slim();
$app->get('/',function() {
$page = new Pages();
$page->home();
});
$app->run();

Related

How can I use a Laravel closure to call a controller's __invoke() method?

In my Laravel application I have created a controller named InvokableController. It contains this function:
public function __invoke()
{
return view('home');
}
I'd like to be able to call the __invoke method, like this:
Route::get('/', function () {
$invokableObj = new InvokableController();
$invokableObj();
})->name('home');
While this works:
Route::get('/', 'InvokableController')->name('home');
It's not what I'm looking for. I'd like to call the invoke method in this manner:
$invokableObj = new InvokableController();
$invokableObj();
I tried with and without the parentheses after InvokableController, on the line that assigns $invokableObj, with no luck.
I don't get any error messages. I tried returning something else at the bottom of the closure, like the number 1, and it renders 1 in the browser, so I know we're getting through the previous lines of code.
APP_DEBUG is true. Other error messages are rendered where I mess up. Does that make this some type of logical error?
Its just a class, so $invokableObj->__invoke() should work just fine. Or you can use laravel DI:
app()->call(InvokableController::class . '#__invoke');
Route::get('/', function () {
return app()->call(InvokableController::class . '#__invoke');
// or
$invokableObj = new InvokableController();
return $invokableObj->__invoke();
})->name('home');

PHRoute can't route to controller 'Class not found '

Having never used a router before outside of a traditional framework I've become a little stuck with PHRoute and routing to a controller. My code is as follows, I have a index.php which includes config files and bootstrap/app.php which contents are as follows:
require_once('../application/controllers/home.php');
$router = $app['router'];
$router->any('/home', ['Home','Application/Controllers/Home']);
function processInput($uri){
$uri = implode('/',
array_slice(
explode('/', $_SERVER['REQUEST_URI']), 1));
return $uri;
}
use Phroute\Phroute\Dispatcher;
$dispatcher = new Dispatcher($router->getData());
$response = $dispatcher->dispatch($_SERVER['REQUEST_METHOD'], processInput($_SERVER['REQUEST_URI']));
echo $response;
The problem is it can't find my home controller when I hit the /home route
Uncaught Error: Class 'Home' not found in /application/vendor/phroute/phroute/src/Phroute/HandlerResolver.php:16
In the above code I have done a simple require so I know the class is defiantly loaded into the script. The class looks like the following:
<?php
namespace Application\Controllers;
class Home
{
public function __construct(){
echo 'home construct';
}
public function index(){
echo 'index';
}
}
Am I missing something?
The problem is your route definition. The phroute documentation says:
// Lazy load autoloaded route handling classes using strings for classnames
// Calls the Controllers\User::displayUser($id) method with {id} parameter as an argument
$router->any('/users/{id}', ['Controllers\User','displayUser']);
Your route definition should be the classname (including the namespace) followed by the method to be invoked:
$router->any('/home', ['Application\Controllers\Home', 'index']);

How can i create middleware on Slim Framework 3?

I read the documentation here about creating middleware. But which folder or file i must be create it? Documentation is not contain this information.
Under the src folder i have middleware.php.
For example i want to get post information like this:
$app->post('/search/{keywords}', function ($request, $response, $args) {
$data = $request->getParsedBody();
//Here is some codes connecting db etc...
return json_encode($query_response);
});
i made this under the routes.php but i want to create class or middleware for this. How can i do? Which folder or file i must be use.
Slim3 does not tie you to a particular folder structure, but it does (rather) assume you use composer and use one of the PSR folder structures.
Personally, that's what I use (well, a simplified version):
in my index file /www/index.php:
include_once '../vendor/autoload.php';
$app = new \My\Slim\Application(include '../DI/services.php', '../config/slim-routes.php');
$app->run();
In /src/My/Slim/Application.php:
class Application extends \Slim\App
{
function __construct($container, $routePath)
{
parent::__construct($container);
include $routePath;
$this->add(new ExampleMiddleWareToBeUsedGlobally());
}
}
I define all the dependency injections in DI/services.php and all the route definitions in config/slim-routes.php. Note that since I include the routes inside the Application constructor, they will have $this refer to the application inside the include file.
Then in DI/services.php you can have something like
$container = new \Slim\Container();
$container['HomeController'] = function ($container) {
return new \My\Slim\Controller\HomeController();
};
return $container;
in config/slim-routes.php something like
$this->get('/', 'HomeController:showHome'); //note the use of $this here, it refers to the Application class as stated above
and finally your controller /src/My/Slim/Controller/HomeController.php
class HomeController extends \My\Slim\Controller\AbstractController
{
function showHome(ServerRequestInterface $request, ResponseInterface $response)
{
return $response->getBody()->write('hello world');
}
}
Also, the best way to return json is with return $response->withJson($toReturn)

Laravel 4.1 - Controller throw error when I try to load view with layout

I'm trying to load a blade view with layout, but I get this error:
"Attempt to assign property of non-object"
The structure is the following:
Route:
Route::pattern('controller', '\w+');
Route::get('{controller}', function($controller) {
$controllerClass = $controller.'Controller';
App::make($controllerClass)->index();
});
Controller:
class PricesController extends BaseController {
protected $layout = 'layouts.master';
public function index()
{
$this->layout->content = View::make('prices.index');
}
}
The debug says the issue is at line $this->layout->content = View::make('prices.index');
The views are fine... I have layouts folder with master.blade.php and I also have prices folder with index.blade.php.
The content section is exists as well with #stop and the #yield is there in the layout.
In the BaseController there is the setupLayout method:
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
What is the problem? Why I get that exception?
Thank you!
I know I helped you in the #laravel irc channel but there are 3 things here for any others with this problem.
This is not a good use of route files. Controller implicit routing is hard to maintain if your app gets larger. Consider using Route::resource instead if you're just trying to save a few lines of code. But I'll give you the benefit of the doubt.
You'll want to use the nest method for your layout, i.e. $this->layout->nest('content', 'prices.index');
The setupLayout() function is not being called because you are calling index() directly on the object. This is not how Laravel normally processes controllers.
I'm not going to walk through the entire routing process but if you look at vendors/laravel/framework/src/Illuminate/Routing/ControllerDisplatcher.php on line 89 you will see:
protected function call($instance, $route, $method)
{
$parameters = $route->parametersWithoutNulls();
return $instance->callAction($method, $parameters);
}
Let's look at vendors/laravel/framework/src/Illuminate/Routing/Controller.php on line 227 and you will see:
public function callAction($method, $parameters)
{
$this->setupLayout();
$response = call_user_func_array(array($this, $method), $parameters);
... irrelevant stuff omitted ...
}
These reason I show these things is show the magic Laravel is doing behind the scenes.
Basically you are skipping that magic and just calling PricesController->index() directly instead of going through the router. This is why setupLayout is never being called and you will get an exception because there is no $this->layout object yet created.

Slim pass class instance to $app

<?php
require 'vendor/autoload.php';
// Include all controllers
foreach(glob("controllers/*.php") as $controller)
{
include $controller;
}
// Instantiate a new Slip application
$app = new \Slim\Slim(array(
'debug' => true
));
// HOME CONTROLLER
$home = new Home;
$vr = $home->index();
// Register application routes
$app->get('/', function () {
echo $vr;
});
// Run application
$app->run();
This is my controller I want to use controllers and not keep everything in this single file. Anyhow I have a controllers map where I keep all my controllers. I automatically include them all at start however I can't seem to pass $home variable to get() method so I could call $vr indede it or $home->index()
You can pass it to your function like this:
..., function () use($home){
...
I think Slim also passes $app as the first argument to your function.
Edit: actually it doesn't according to its docs, so you'll have to pass that too inside the use statement (function arguments are URL parameters):
$app->get('/', function () use($home, $app) {
$vr = $home->index();
echo $vr;
// $app is accesible too...
});

Categories