I'm using Slim PHP as a framework for a RESTful API.
How do I grab GET params from the URL in Slim PHP?
For example, if I wanted to use the following:
http://api.example.com/dataset/schools?zip=99999&radius=5
You can do this very easily within the Slim framework, you can use:
$paramValue = $app->request()->params('paramName');
$app here is a Slim instance.
Or if you want to be more specific
//GET parameter
$paramValue = $app->request()->get('paramName');
//POST parameter
$paramValue = $app->request()->post('paramName');
You would use it like so in a specific route
$app->get('/route', function () use ($app) {
$paramValue = $app->request()->params('paramName');
});
You can read the documentation on the request object
http://docs.slimframework.com/request/variables/
As of Slim v3:
$app->get('/route', function ($request, $response, $args) {
$paramValue = $request->params(''); // equal to $_REQUEST
$paramValue = $request->post(''); // equal to $_POST
$paramValue = $request->get(''); // equal to $_GET
// ...
return $response;
});
For Slim 3/4 you need to use the method getQueryParams() on the PSR 7 Request object.
Citing Slim 3 / Slim 4 documentation:
You can get the query parameters as an associative array on the
Request object using getQueryParams().
I fixed my api to receive a json body OR url parameter like this.
$data = json_decode($request->getBody()) ?: $request->params();
This might not suit everyone but it worked for me.
Slim 3
$request->getQueryParam('page')
or
$app->request->getQueryParam('page')
IF YOU WANT TO GET PARAMS WITH PARAM NAME
$value = $app->request->params('key');
The params() method will first search PUT variables, then POST variables, then GET variables. If no variables are found, null is returned. If you only want to search for a specific type of variable, you can use these methods instead:
//--- GET variable
$paramValue = $app->request->get('paramName');
//--- POST variable
$paramValue = $app->request->post('paramName');
//--- PUT variable
$paramValue = $app->request->put('paramName');
IF YOU WANT TO GET ALL PARAMETERS FROM REQUEST WITHOUT SPECIFYING PARAM NAME,
YOU CAN GET ALL OF THEM INTO ARRAY IN FORMAT KEY => VALUE
$data = json_decode( $app->request->getBody() ) ?: $app->request->params();
$data will be an array that contains all fields from request as below
$data = array(
'key' => 'value',
'key' => 'value',
//...
);
Hope it helps you!
Use $id = $request->getAttribute('id'); //where id is the name of the param
In Slim 3.0 the following also works:
routes.php
require_once 'user.php';
$app->get('/user/create', '\UserController:create');
user.php
class UserController
{
public function create($request, $response, array $args)
{
$username = $request->getParam('username'));
$password = $request->getParam('password'));
// ...
}
}
Not sure much about Slim PHP, but if you want to access the parameters from a URL then you should use the:
$_SERVER['QUERY_STRING']
You'll find a bunch of blog posts on Google to solve this. You can also use the PHP function parse_url.
Inside your api controller function write the following code of line:
public function your_api_function_name(Request $request, Response $response)
{
$data = $request->getQueryParams();
$zip = $data['zip'];
$radius = $data['radius'];
}
The variable $data contains all the query parameters.
Probably obvious to most, but just in case, building on vip's answer concerning Slim 3, you can use something like the following to get the values for the parameters.
$logger = $this->getService('logger');
$params = $request->getQueryParams();
if ($params) {
foreach ($params as $key => $param) {
if (is_array($param)) {
foreach ($param as $value) {
$logger->info("param[" . $key . "] = " . $value);
}
}
else {
$logger->info("param[" . $key . "] = " . $param);
}
}
}
Related
I am building an API with laravel, so I am trying to pass Laravel's Eloquent functions as string and execute them in the controller, actually I am sending a JSON object but I am converting it to a string in backend, here is what I tried to do
API URL with parameters:
http://www.example.com/api/articles?parameters={"orderByDesc":"'created_at'", "limit":"2"}
Controller side:
$json = json_decode(request('parameters'), TRUE);
$query = '';
foreach ($json as $function => $value){
$query .= $function.'('.$value.')->';
}
$query = $query.'get();';
return $query;
Output:
orderByDesc('created_at')->limit(2)->get();
Now how can I execute this string as code on the model, example:
$articles = Article::orderByDesc('created_at')->limit(2)->get();
I couldn't concatenate like this: Article::.$query
And I can't use PHP's eval()
The idea is to use Laravel's Eloquent functions inside a JSON object and pass them in one URL parameter.
Thanks
Maybe you should try this.
$json = json_decode(request('parameters'), true);
$query = Article::query();
foreach($json as $function => $value){
$query->{$function}($value);
}
$query = $query->get();
return $query;
You can run function on object with ->{$func_name} syntax
Edit: You can pass multiple arguments too. But you can check if whether value is array or not:
foreach($json as $function => $value){
if(is_array($value)) {
$query->{$function}(...$value);
} else {
$query->{$function}($value);
}
}
In this case you can have: {"orderByDesc":"'created_at'", "limit":"2", "where": ["column_name", "LIKE", "%SOME_STRING"]} and it will generate query equivalent to: ->where('column_name', 'LIKE', '%SOME_STRING')
I am newly trying out TDD with laravel, and I want to assert if a redirect took a user to a url that has an integer param.
I wonder if I could use regex to catch all positive integers.
I'm running this app with the laravel 5.8 framework and I know that the url parameter is 1 because I refresh the database each for each test, so setting the redirect url as /projects/1 works but this sort of hardcoding feels weird.
I've attached a block of code I tried using regex for but this doesn't work
/** #test */
public function a_user_can_create_projects()
{
// $this->withoutExceptionHandling();
//If i am logged in
$this->signIn(); // A helper fxn in the model
//If i hit the create url, i get a page there
$this->get('/projects/create')->assertStatus(200);
// Assumming the form is ready, if i get the form data
$attributes = [
'title' => $this->faker->sentence,
'description' => $this->faker->paragraph
];
//If we submit the form data, check that we get redirected to the projects path
//$this->post('/projects', $attributes)->assertRedirect('/projects/1');// Currently working
$this->post('/projects', $attributes)->assertRedirect('/^projects/\d+');
// check that the database has the data we just submitted
$this->assertDatabaseHas('projects', $attributes);
// Check that we the title of the project gets rendered on the projects page
$this->get('/projects')->assertSee($attributes['title']);
}
I expected the test to treat the argument in assertRedirect('/^projects/\d+'); as regex and then pass for any url like /projects/1 so far it ends in a number, but it takes it as a raw string and expects a url of /^projects/\d+
I'd appreciate any help.
After watching a tutorial by Jeffery Way, he talked about handling this issue.
Here's how he solves the situation
//If we submit the form data,
$response = $this->post('/projects', $attributes);
//Get the project we just created
$project = \App\Project::where($attributes)->first();
// Check that we get redirected to the project's path
$response->assertRedirect('/projects/'.$project->id);
This is not possible by now. You need to test the Location header in the response with a regular expression.
This is a problem because you cann't use the current route name. That's why I did two functions that bring a little bit of readability to your test. You will use this function like this:
// This will redirect to some route with an numeric ID in the URL.
$response = $this->post(route('groups.create'), [...]);
$this->assertResponseRedirectTo(
$response,
$this->prepareRoute('group.detail', '[0-9]+'),
);
This is the implementation.
/**
* Assert whether the response is redirecting to a given URI that match the pattern.
*/
public function assertResponseRedirectTo(Illuminate\Testing\TestResponse\TestResponse $response, string $url): void
{
$lastOne = $this->oldURL ?: $url;
$this->oldURL = null;
$newLocation = $response->headers->get('Location');
$this->assertEquals(
1,
preg_match($url, $newLocation),
sprintf('Should redirect to %s, but got: %s', $lastOne, $newLocation),
);
}
/**
* Build the pattern that match the given URL.
*
* #param mixed $params
*/
public function prepareRoute(string $name, $params): string
{
if (! is_array($params)) {
$params = [$params];
}
$prefix = 'lovephp';
$rep = sprintf('%s$&%s', $prefix, $prefix);
$valuesToReplace = [];
foreach ($params as $index => $param) {
$valuesToReplace[$index] = str_replace('$&', $index . '', $rep);
}
$url = preg_quote(route($name, $valuesToReplace), '/');
$this->oldURL = route($name, $params);
foreach ($params as $index => $param) {
$url = str_replace(
sprintf('%s%s%s', $prefix, $index, $prefix),
$param,
$url,
);
}
return sprintf('/%s/', $url);
}
I've created a custom block like this:
class HelloBlock extends BlockBase implements BlockPluginInterface{
/**
* {#inheritdoc}
*/
public function build() {
$config = $this->getConfiguration();
$result = db_query('SELECT * FROM {test}');
return array(
'#theme' => 'world',
'#test' => $result
);
}
}
And I now want to programmatically get some parameter from the URL.
For example:
If the URL is http://localhost/drup/hello/5569 I want to get hold of the value 5569 inside my module.
I have tried arg(1) and drupal_get_query_parameters() but I got this error messages:
Call to undefined function `Drupal\hello\Plugin\Block\arg()`
and
Call to undefined function `Drupal\hello\Plugin\Block\drupal_get_query_parameters()`
How can I get the parameters?
Use \Drupal\Core\Routing;:
$parameters = \Drupal::routeMatch()->getParameters();
The named parameters are available as
$value = \Drupal::routeMatch()->getParameter('slug_name_from_route');
Where 'slug_name_from_router' comes from your routing.yml path property
path: '/your/path/{slug_name_from_route}'
If you want the raw parameter without any upcasting you can get
$value = \Drupal::routeMatch()->getRawParameter('slug_name_from_route');
I used to get the parameter value from URL (localhost/check/myform?mob=89886665)
$param = \Drupal::request()->query->all();
And applied in my select Query
$query = \Drupal::database()->select('profile_register', 'p1');
$query->fields('p1');
$query->condition('p1.mobileno', $edituseprof);
$query->condition('publishstatus', 'no');
$result = $query->execute()->fetchAll();
But on multiple parameter value, i am now successful(Ex: http://10.163.14.41/multisite/check/myform?mob=89886665&id=1)
$query = \Drupal::database()->select('profile_register', 'p1');
$query->fields('p1');
$query->condition('p1.mobileno', $edituseprof['mob']);
$query->condition('p1.ids', $edituseprof['id']);
$query->condition('publishstatus', 'no');
$result = $query->execute()->fetchAll();
arg() is deprecated in drupal 8, however we can get values like arg() function does in drupal 7 & 6
$path = \Drupal::request()->getpathInfo();
$arg = explode('/',$path);
print_r($arg); exit();
The output would be parameters in url except basepath or (baseurl),
Array
(
[0] =>
[1] => node
[2] => add
)
To get query parameter form the url, you can us the following.
If you have the url for example,
domainname.com/page?uid=123&num=452
To get "uid" from the url, use..
$uid = \Drupal::request()->query->get('uid');
To get "num" from the url, use..
$num = \Drupal::request()->query->get('num');
$route_match = \Drupal::service('current_route_match');
$abc = $route_match->getParameter('node'); //node is refrence to what you have written in you routing file i.e:
in something.routing.yml
entity.node.somepath:
path: '/some/{node}/path'
I have used {node} as arg(1). And I can access it by using *->getParameter('node');
Hope this will work.
If your url is like this below example
http://localhost/drupal/node/6666
Then you have to get the full url path by
$current_path = \Drupal::request()->getPathInfo();
then explode the path to get the arguments array.
$path_args = explode('/', $current_path);
Another example if value passed by a key in url like below where id contains the value
http://localhost/drupal?id=123
You can get the id by given drupal request
$id = \Drupal::request()->query->get('id');
Here's the example of accessing URL parameters and passing them to a TWIG template,
I am considering you have already created your module and required files and suppose "/test?fn=admin" is your URL
In Your .module file implement hook_theme and define variables and template name (Make sure you replace "_" with "-" when creating the template file)
function my_module_theme () {
return [
'your_template_name' => [
'variables' => [
'first_name' => NULL,
],
];
}
Now create your controller and put below code in it.
namespace Drupal\my_module\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
class MyModule extends ControllerBase {
public function content(Request $request) {
return [
'#theme' => 'my_template',
'#first_name' => $request->query->get('fn'), //This is because the parameters are in $_GET, if you are accessing from $_POST then use "request" instead "query"
];
}
}
Now in your TWIG file which should be "my-template.html.twig" you can access this parameter as,
<h3>First Name: {{ first_name }}</h3>
And its done.
Hope this helps.
The Drupal docs are great on this: https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes
define your path variable in yaml
example.name:
path: '/example/{name}'
...
Add the variable in your method and use it
<?php
class ExampleController {
// ...
public function content($name) {
// Name is a string value.
// Do something with $name.
}
}
?>
I'm trying to explain this as best as I can, please ask i'm im unclear about something.
I'm using a API where i get a bunch of information about a sensor.
This is a method in a class
public function getSensors()
{
$params = array();
return json_decode($this->consumer->sendRequest(constant('REQUEST_URI').'/sensors/list', $params, 'GET')->getBody());
And in my index.php
$params = array('id'=> XXXXXX);
$response = $consumer->sendRequest(constant('REQUEST_URI').'/sensor/info', $params,'GET');
echo json_decode($response->getBody());
This gives me a chunk of information like this:
{"id":"xxxxx","client":"xxxx","name":"xxxxx","lastUpdated": xxxx}
I only want to use some of this information.
This is the getBody() method-
public function getBody() {
if (self::METHOD_POST == $this->method && (!empty($this->postParams) || !empty($this->uploads))) {
if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
$body = http_build_query($this->postParams, '', '&');
if (!$this->getConfig('use_brackets')) {
$body = preg_replace('/%5B\d+%5D=/', '=', $body);
}
// support RFC 3986 by not encoding '~' symbol (request #15368)
return str_replace('%7E', '~', $body);
} elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
require_once 'HTTP/Request2/MultipartBody.php';
return new HTTP_Request2_MultipartBody(
$this->postParams, $this->uploads, $this->getConfig('use_brackets')
);
}
}
return $this->body;
}
If you're using an API you can't control what information you get unless the API defines a method to do so. If you're reading sensors then it's unlikely that will be an option.
Nevertheless, you can just ignore what you don't need.
For example:
$myArray = json_decode('{"id":"xxxxx","client":"xxxx","name":"xxxxx","lastUpdated": xxxx}');
$mySubset = array($myArray['id'], $myArray['lastUpdated']);
I just use json_decode to illustrate the point. From your comments it looks like getBody() is returning an array, but the error message you report points to an object.
For an array you can use
$myResp = $response->getBody();
$myId = $myResp['id'];
For an object you can use
$myResp = $response->getBody();
$myId = $myResp->id;
Apologies if I don't quite hit the mark - I'm firing a little blind here!
A comment on the PHP manual states:
If you are using this method, remember
that the array of arguments need to be
passed in with the ordering being the
same order that the SOAP endpoint
expects.
e.g
//server expects: Foo(string name, int age)
//won't work
$args = array(32, 'john');
$out = $client->__soapCall('Foo', $args);
//will work
$args = array('john', 32);
$out = $client->__soapCall('Foo', $args);
I'm building a SOAP client that dynamically assigns the argument values, which means that it happens that the arguments aren't always in the correct order. This then breaks the actual SOAP call.
Is there an easy solution to this, short of checking the order of the parameters for each call?
I had the same problem where I dynamically added the SOAP parameters and I had to get them in the correct order for my SOAP call to work.
So I had to write something that will get all the SOAP methods from the WSDL and then determine in which order to arrange the method arguments.
Luckily PHP makes it easy to get the SOAP functions using the '$client->__getFunctions()' method, so all you need to do is search for the service method you want to call which will contain the method arguments in the correct order and then do some array matching to get your request parameter array in the same order.
Here is the code...
<?php
// Instantiate the soap client
$client = new SoapClient("http://localhost/magento/api/v2_soap?wsdl", array('trace'=>1));
$wsdlFunctions = $client->__getFunctions();
$wsdlFunction = '';
$requestParams = NULL;
$serviceMethod = 'catalogProductInfo';
$params = array('product'=>'ch124-555U', 'sessionId'=>'eeb7e00da7c413ceae069485e319daf5', 'somethingElse'=>'xxx');
// Search for the service method in the wsdl functions
foreach ($wsdlFunctions as $func) {
if (stripos($func, "{$serviceMethod}(") !== FALSE) {
$wsdlFunction = $func;
break;
}
}
// Now we need to get the order in which the params should be called
foreach ($params as $k=>$v) {
$match = strpos($wsdlFunction, "\${$k}");
if ($match !== FALSE) {
$requestParams[$k] = $match;
}
}
// Sort the array so that our requestParams are in the correct order
if (is_array($requestParams)) {
asort($requestParams);
} else {
// Throw an error, the service method or param names was not found.
die('The requested service method or parameter names was not found on the web-service. Please check the method name and parameters.');
}
// The $requestParams array now contains the parameter names in the correct order, we just need to add the values now.
foreach ($requestParams as $k=>$paramName) {
$requestParams[$k] = $params[$k];
}
try {
$test = $client->__soapCall($serviceMethod, $requestParams);
print_r($test);
} catch (SoapFault $e) {
print_r('Error: ' . $e->getMessage());
}
An easy solution exists for named parameters:
function checkParams($call, $parameters) {
$param_template = array(
'Foo' => array('name', 'age'),
'Bar' => array('email', 'opt_out'),
);
//If there's no template, just return the parameters as is
if (!array_key_exists($call, $param_template)) {
return $parameters;
}
//Get the Template
$template = $param_template[$call];
//Use the parameter names as keys
$template = array_combine($template, range(1, count($template)));
//Use array_intersect_key to filter the elements
return array_intersect_key($parameters, $template);
}
$parameters = checkParams('Foo', array(
'age' => 32,
'name' => 'john',
'something' => 'else'
));
//$parameters is now array('name' => 'john', 'age' => 32)
$out = $client->__soapCall('Foo', $parameters);
Not only does it correctly order the parameters, it also filters the parameters in the array.
Another solution is to verify the xsd files from your wsdl.
PHP SOAP construct the request based on parameters order in xsd files.