Get param in Routing - Slim Framework 3 - php

How can I get the param in this case?
$this->get('/{id}', function($request, $response, $args) {
return $response->withJson($this->get('singleSelect'));
});
$this->appContainer['singleSelect'] = function ($id) {
return $this->singleSelect($id);
};
public function singleSelect($id) {
return $id;
}
Thanks in advance.
UPDATE
Solution in my case:
$app->group('/id', function () {
$this->get('/{id}', function($request, $response, $args) {
$this['container'] = $args; //work with $args inside the container
return $this->singleSelect($id);
});
});

If I right understand services have not access to routes parameters. All you can access is container itself but it could be tricky to get information about arguments from it (something like $container->getRoutes()['<routename>']->getArguments() where <routename> router could have subroutes, etc.)
IMHO your code should look like:
$container = new \Slim\Container;
$app = new \Slim\App($container);
class Example {
public function singleSelect($id) {
return $id;
}
}
$container['example'] = function () {
return new Example();
};
$app->group('/id', function () {
$this->get('/{id}', function($request, $response, $args) {
return $response->withJson($this->example->singleSelect($args['id']));
});
});
$app->run();

Related

PHP Router Parameters

I am looking for advice in passing parameters in my router's routes.
This is my router...
<?php namespace Framework;
class Router
{
private array $routes = [];
private Request $request;
public function __construct(Request $request, Response $response)
{
$this->request = $request;
$this->response = $response;
}
public function get(string $path, string|callable|array $callback): void
{
$this->routes['GET'][$path] = $callback;
}
public function post(string $path, string|callable|array $callback): void
{
$this->routes['POST'][$path] = $callback;
}
public function dispatch(): mixed
{
$method = $this->request->method();
$path = $this->request->path();
$callback = $this->routes[$method][$path];
if(is_null($callback))
{
throw new Exception\NotFoundException;
}
if(is_string($callback))
{
return new View($callback);
}
if(is_array($callback))
{
$callback[0] = new $callback[0];
}
return call_user_func($callback);
}
}
And my routes look like this...
return function (App $app)
{
$app->get('/', [Controllers\HomeController::class, 'index']);
$app->get('/about', [Controllers\HomeController::class, 'about']);
$app->get('/contact', function() {
var_dump(App::load()->request()->body());
});
$app->get('/blog', [Controllers\BlogController::class, 'index']);
$app->get('/blog/{id}', [Controllers\BlogController::class, 'index']);
};
I want to be able to pass a parameter (for example on the last blog route). And I am sort of at a loss about how to go about it.

Update/Put Route - Method not allowed

I'm using postman to test my API, but right now I have a problem with the put routes.
So this is a put route I wrote:
$app->put('/setting/{id}/settingvalue', function (ServerRequestInterface $request, Response
Interface $response, $args) {
try {
$user = new \Riecken\PBS\controller\SettingsValueController();
$result = $user->updateOneSettingsValueinDetail( $args['id'], $request->getParsedBody());
$response = $response->withJson($result);
$response = $response->withStatus(200);
return $response;
}catch(Exception $e) {
$response->getBody()->write($e->getMessage());
return $response->withStatus($e->getCode());
}
});
And this is the function which you see above (updateOneSettingsValueinDetail):
public function updateOneSettingsValueinDetail ($settingsvalueIdToUpdate, $body) {
try {
return $this->SettingsValueDao->update($settingsvalueIdToUpdate, $body);
}catch(DAOException $e) {
throw new \Exception($e->returnErrorMessage(), $e->returnHttpCode());
}catch(\Exception $e) {
throw new \Exception("System Error", 500);
}
}
The problem is that Postman tells me that the Method is not allowed, only POST and GET is allowed:
enter image description here
Does anybody know what type of problem that is and what the solution could be?
This response is come from Slim's NotAllowedHandler. And it is not only POST and GET as default. This response is not related to your mentioned above code.
Are you sure you don't customize "NotAllowedHandler" and you don't bind to app as middleware?
I wrote this code that containing that would create the same situation:
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\App;
require __DIR__ . '/../vendor/autoload.php';
$app = new App([]);
$container = $app->getContainer();
$app->add(function ($request, $response, $next) {
$allowed = ['GET', 'POST'];
if (!in_array($request->getMethod(), $allowed)) {
$notAllowed = new \Slim\Handlers\NotAllowed();
return $notAllowed($request, $response, $allowed);
}
$next($request, $response);
});
$app->put('/setting/{id}/settingvalue', function (ServerRequestInterface $request, ResponseInterface $response, $args) {
die("Expected Context via PUT");
});
$app->get('/setting/{id}/settingvalue', function (ServerRequestInterface $request, ResponseInterface $response, $args) {
die("Expected Other Context via GET");
});
$app->run();
I hope to it help you.

Laravel - Callable returning blank screen

I'm trying to create a callback to return my views based on data from my current logged-in user. If I do something basic like echoing 'hi' it works, is there any way accomplish this?
function checkUser($type,$callback){
if( is_callable($callback) ){
call_user_func($callback);
}
}
class FichaController extends Controller
{
public function contarFichas()
{
checkUser('particular',function(){
$currentUser = Auth::user();
$countFichas = Ficha::where('user_id',$currentUser->id)->count();
return view('particular.index', array('countFichas' => $countFichas));
});
}
}
Return the result from checkUser
if( is_callable($callback) ){
return $callback();
}
public function contarFichas()
{
return checkUser('particular',function(){
$currentUser = Auth::user();
$countFichas = Ficha::where('user_id',$currentUser->id)->count();
return view('particular.index', array('countFichas' => $countFichas));
});
}

Slim3 right way to set errors and check is user logged in

I'm a new user of Slim framework, I've a simple Slim 3 application, with sign in and sign up validation. But I'm not really sure if this is the right/best way to set errors and check if user is logged in -In order to redirect it to his account if session user.id exists.
I used a middleware: AuthMiddleware which includes:
class AuthMiddleware
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function __invoke($request, $response, $next)
{
if (isset($_SESSION['user.id']) && !empty($_SESSION['user.id'])) {
return $response->withRedirect($this->container->router->pathFor('user.index'));
}
$twig = $this->container->view->getEnvironment();
if (isset($_SESSION['validation'])) {
$twig->addGlobal('errors', $_SESSION['validation']['errors']);
$twig->addGlobal('values', $_SESSION['validation']['values']);
unset($_SESSION['validation']);
}
if (isset($_SESSION['auth.signup.success'])) {
$twig->addGlobal('auth_signup_success', $_SESSION['auth.signup.success']);
unset($_SESSION['auth.signup.success']);
}
if (isset($_SESSION['auth.signin.failed'])) {
$twig->addGlobal('auth_signin_failed', $_SESSION['auth.signin.failed']);
unset($_SESSION['auth.signin.failed']);
}
$response = $next($request, $response);
return $response;
}
}
And I used Twig for my views.
Session validation assigned in the validator.php which includes:
class Validator
{
protected $errors = [];
protected $values = [];
public function validate($request, $rules)
{
foreach ($rules as $field => $rule) {
$this->values[$field] = $request->getParam($field);
try {
$rule->setName(ucfirst($field))->assert($request->getParam($field));
} catch (NestedValidationException $e) {
$this->errors[$field] = $e->getMessages()[0];
}
}
if ($this->failed()) {
$_SESSION['validation'] = [
'errors' => $this->errors,
'values' => $this->values,
];
}
return $this;
}
public function failed()
{
return !empty($this->errors);
}
}
Using Respect\Validation. Also, is this the right use of Middlewares?
Thanks in advance.
try creating a separate file for the methods, and calling it from the middleware:
<?php
class AuthMiddleware extends Middleware {
public function __invoke($request, $response, $next) {
if (!$this->container->auth->check()) {
$this->container->flash->addMessage('danger', 'Please sign in to continue.');
return $response->withRedirect($this->container->router->pathFor('auth.signin'));
}
$response = $next($request, $response);
return $response;
}
}
while the Auth class would have those methods to check:
<?php
public function check () {
return isset($_SESSION['user']);
}
public function user() {
if (isset($_SESSION['user'])) {
return User::find($_SESSION['user'])->first();
} else {
return false;
}
}
Don't forget to include the Auth Class within your $app:
<?php
$container['auth'] = function ($container) {
return new \App\Auth\Auth();
};

Slim 3 Implement Route Filtering

I am currently trying to implement route authentication filtering in Slim 3. What I would like to do is:
$app->get("/route", Filter::$guest(), function ($request, $response, $args) {
...
});
or maybe
$app->get("/route", function ($resquest, $response, $args) {
})->add(Filter::Admin);
and the Filter class would be:
class Filter
{
public static admin()
{
// Check if user is an admin.
// If not, throw an Error
}
...
In Slim 2, I could use someting like this
Filter.php
$authenticationCheck = function ($required) use ($app) {
return function () use ($required, $app) {
if ((!$app->auth && $required) || ($app->auth && !$required)) {
$app->redirect($app->urlFor("home"));
}
};
};
$authenticated = function () use ($authenticationCheck) {
return $authenticationCheck(true);
};
$guest = function () use ($authenticationCheck) {
return $authenticationCheck(false);
};
$admin = function () use ($app) {
return function () use ($app) {
if (!$app->auth || !$app->auth->isAdmin()) {
$app->notFound();
}
};
};
and in routes I could do:
$app->get("/route", $guest(), function () use ($app) {
//Route
});
I know that I can get the route through middleware, but I can't think of a good way to diffrenciate between a "admin" route and a normal route without having to build some sort of list.
You could create a basic middleware class Authorization:
<?php
class Authorization
{
/**
* Authorization middleware invokable class
*
* #param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* #param \Psr\Http\Message\ResponseInterface $response PSR7 response
* #param callable $next Next middleware
*
* #return \Psr\Http\Message\ResponseInterface
*/
public function __invoke($request, $response, $next)
{
$user = ""; //It should come from some place :)
if(!$this->isAuthorized($user)){
return $response->withRedirect('/notAuthorized');
}
return $next($request, $response);
}
/**
* Check if the given user is authorized.
*
* #param string $user The user to check.
*
* #return boolean True if the user is authorized, false otherwise.
*/
protected function isAuthorized($user){
return false;
}
}
Then you can extend it and create one middleware for guest authorization and another one for admin authorization:
<?php
class GuestAuthorization extends Authorization
{
protected function isAuthorized($user){
//Are you a guest?
$isGuest = true; //Your magic business here
return $isGuest;
}
}
class AdminAuthorization extends Authorization
{
protected function isAuthorized($user){
//Are you an admin?
$isAdmin = false; //Your magic business here
return $isAdmin;
}
}
Let's try with some routes and define the notAuthorized one:
<?php
$app->get("/guestRoute", function ($resquest, $response, $args) {
return $response->write("You're a guest");
})->add(new \GuestAuthorization());
$app->get("/adminRoute", function ($resquest, $response, $args) {
return $response->write("You're an admin");
})->add(new \AdminAuthorization());
$app->get("/notAuthorized", function ($resquest, $response, $args) {
return $response->write("You're not authorized for this, my son!");
});
PROs:
you can handle in different ways the authorization for every role;
you can add multiple middlewares for a single route.
CONs:
you can't handle in this way dynamic roles;
one middleware for each role.

Categories