PHP Slim - using anonymous functions with a simple rest api - php

I have created a simple rest api which handles some POST data. I would like to add some functions to sanitize the data before sending a response.
I am new to Slim and PHP so unsure if this is possible / i am solving the problem using the "correct" approach.
Here is my attempt so far (which does not work!) The middleware is called, but the process function always returns NULL
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require __DIR__ . '/../vendor/autoload.php';
$app = new \Slim\App();
// add function to $app
$app->process = function ($request, $response, $next) use($app) {
return 'process';
};
$process = $app->process;
// middleware
$mw = function ($request, $response, $next) {
$response = $next($request, $response);
// should return string from above function
$variable = $process
$data = array('name' => $name, 'process' => $variable);
$newResp = $response->withJson($data);
return $newResp;
};
$app->post('/api/name', function (Request $request, Response $response, array $args) {
$parsed= $request->getParsedBody();
$response = $response->withStatus(200);
})->add($mw);
$app->run();

There were several issues:
Added function to $app which results in a BadMethodCallException
$appalready has a method called process
Missed ; after $variable = $process
This code gives your desired result:
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require __DIR__ . '/../vendor/autoload.php';
// turn error logging on!
$app = new \Slim\App(['settings' => ['displayErrorDetails' => true]]);
// your function
$sanitize = function(){
return 'process';
};
// middleware + pass function
$mw = function ($request, $response, $next) use($sanitize) {
$response = $next($request, $response);
$variable = $sanitize(); // execute function
$data = array('name' => $name, 'process' => $variable);
$newResp = $response->withJson($data);
return $newResp;
};
$app->get('/api/name', function (Request $request, Response $response, array $args) {
$parsed= $request->getParsedBody();
$response = $response->withStatus(200);
})->add($mw);
$app->run();
When you don't need to use the functions in other middleware, you could simply define the functions in your middleware, like this:
// middleware
$mw = function ($request, $response, $next) use($sanitize) {
$response = $next($request, $response);
// your function
function sanitize(){
return 'process';
}
$data = array('name' => $name, 'process' => sanitize());
$newResp = $response->withJson($data);
return $newResp;
};

Related

Slim 4: Is it possible to call a route middleware with argument passed for it?

I would like to call a route middleware with a parameter passed from the route when added. How is it possible?
$app->get('/path', function($request, $response, $lvlreq = 1) {
$oViewParams = new \lib\ViewParams("referencia", "", "", "", "");
$params = array('viewp' => $oViewParams->getMassParams());
return $this->get('view')->render($response, 'some.html', $params);
})->add($authenticate)
->add($tmhasaccess);
First middleware doesn't need params, thats going well.
$authenticate = function (Request $request, RequestHandler $handler) {
if (!isset($_SESSION['param'])) {
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
$redirect = $route->getPattern();
$_SESSION['urlRedirect'] = $redirect;
$this->get('flash')->addMessage('error', 'error');
$response = $handler->handle($request);
return $response->withStatus(302)->withHeader('Location', '/login');
} else {
$response = $handler->handle($request);
return $response;
}
};
$tmhasaccess = function (Request $request, RequestHandler $handler) {
###I need $lvlreq value inside here to work with it. This won't work:
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
$lvlreq = $route->getArgument('lvlreq');
};
Middleware changed to class:
class TMHasAccessMiddleware
{
protected $lvlreq;
private $container;
function __construct($container, $lvlreq = 0) {
$this->lvlreq = $lvlreq;
$this->container = $container;
}
public function __invoke(Request $request, RequestHandler $handler): Response
{
##$this->lvlreq now accessible.
}
}
Can be called from route:
->add(new TMHasAccessMiddleware($container, 1));

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.

Variable is null in PHP closure

The variable $user is null in this closure function. I don't understand why.
Routes.php
require_once(__DIR__ . '/classes/user.php');
$user = User::getInstance(); // returns a $_SESSION user or a new User()
This does not work
$app->group('/user', function () use ($app, $user) {
$app->post('/activate', function(Request $request, Response $response) {
$parsedBody = $request->getParsedBody();
$result = $user->activate($parsedBody); // error user is null
return $response->withJson($result);
});
});
This does
$app->group('/user', function () use ($app) {
$app->post('/activate', function(Request $request, Response $response) {
$parsedBody = $request->getParsedBody();
$user = User::getInstance();
$result = $user->activate($parsedBody);
return $response->withJson($result);
});
});
You need to inherit that variable into your function.
http://php.net/manual/en/functions.anonymous.php - #3
$app->group('/user', function () use ($app, $user) {
$app->post('/activate', function(Request $request, Response $response) use ($user) {
$parsedBody = $request->getParsedBody();
$result = $user->activate($parsedBody); // now it shouldn't
return $response->withJson($result);
});
});

Accessing parameters in Slim v3 middleware

According to http://www.slimframework.com/docs/concepts/middleware.html, route middleware is added as follows.
<?php
$app = new \Slim\App();
$mw = function ($request, $response, $next) {
// How is $arg accessed?
$response->getBody()->write('BEFORE');
$response = $next($request, $response);
$response->getBody()->write('AFTER');
return $response;
};
$app->get('/ticket/{id}', function ($request, $response, $args) {
$response->getBody()->write(' Hello ');
// $arg will be ['id'=>123]
return $response;
})->add($mw);
$app->run();
$arg will be the parameters array. How can this be accessed in the middleware?
http://help.slimframework.com/discussions/questions/31-how-pass-route-pram-to-middleware shows an approach to do so, however, appears to be an earlier release of Slim, and errors Fatal error: Call to undefined method Slim\\Route::getParams().
Route Params can be accessed through the routeInfo Attribute on Request, as such
$app->get('/hello/{name}', \HelloWorld::class . ':execute')
->add(function ($request, $response, $next) {
var_dump($request->getAttribute('routeInfo')[2]['name']);exit();
return $next($request, $response);
});
This is noted in this Github issue

Error Handling in Slim Framework Custom Middleware

I am trying to handle errors in slim framework custom middle ware but dont know how to do this like in my code i am doing that if the request is not of four specific types then through an error that i want to handel in errorHandler with appropriate message and status but currently this code is just returning the status in postman with a blank screen in response body. I am not very much familiar with SLIM. Thanks in advance
<?php
require 'vendor/autoload.php';
use \Slim\App;
$c = new \Slim\Container();
$c['notAllowedHandler'] = function ($c) {
return function ($request, $response, $methods) use ($c) {
return $c['response']
->withStatus(405)
->withHeader('Allow', implode(', ', $methods))
->withHeader('Content-type', 'application/json')
->write(json_encode(array("c_status"=>"405","message"=>"Bad Request")));
};
};
$c['notFoundHandler'] = function ($c) {
return function ($request, $response) use ($c) {
return $c['response']
->withStatus(404)
->withHeader('Content-type', 'application/json')
->write(json_encode(array("c_status"=>"404","message"=>"Not Found")));
};
};
$c['errorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
$data = [
'c_status' => $response->getStatus(),
'message' => $exception->getMessage()
];
return $container->get('response')->withStatus($response->getStatus())
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
$app = new App($c);
$app->add(function ($request, $response, $next) {
if($request->isGet() || $request->isPost() || $request->isPut() || $request->isDelete()){
$response = $next($request, $response);
}else{
$response = $response->withStatus(403);
}
return $response;
});
require 'API/routes.php';
$app->run();
Throw an exception:
$app->add(function ($request, $response, $next) {
if($request->isGet() || $request->isPost() || $request->isPut() || $request->isDelete()){
$response = $next($request, $response);
}else{
throw new \Exception("Forbidden", 403);
}
return $response;
})

Categories