12/08/2018, 14:49

Laravel requests... DEADLY flexible

Request class is very flexible and gives a lot of ways to get the data. It extends Symfony Request class, so it does not only provide Laravel-specific methods. The class is highly flexible, but despite common opinion, very hard to use. And misuse of a single method may cause any kind of issues. ...

Request class is very flexible and gives a lot of ways to get the data. It extends Symfony Request class, so it does not only provide Laravel-specific methods.

The class is highly flexible, but despite common opinion, very hard to use. And misuse of a single method may cause any kind of issues.

Getter methods:

The most common operation is getting data from request parameters. There are 13 different ways to do this depending on data source, and controller flexibility. And there is no best way to implement in any code.

TL;DR: if you are lazy to read long text... here is a short recommendation.

  • $request->query($key) — for URL query parameters
  • $request->input($key) — for default POST requests (both form-data and JSON)
  • $request->json($key) — for JSON API
  • $request->file($key) — for multipart form-data requests with files.
  • Never: $request->$key.
  • Not recommended: $request->get($key), $request[$key].
  • And proceed to security section.

Strongly recommended to read all descriptions and remember their differences.

Methods list

1. Request method get()

/** @var string|array|null $value */
$value = $request->get($key, $default = null);

Uses data from 3 or 4 sources following the order below.

Not recommended to use according to Symfony docs except implicit need to have flexible request parsing. Much slower and less safe than using direct usage of bags.

Framework Data sources
Symfony * 1. Custom attributes
2. URL query parameters ($$_GET)
3. Request form data ($$_POST)
Laravel 4. JSON request body

* Hereafter "Symfony" assumes availability both in Symfony and Laravel.

2. Query parameter bag

/** @var string|array|null $value */
$value = $request->query->get($key, $default = null);

/** @var array $all */
$all = $request->query->all();

Returns one or all fields from URL query parameter bag.

Framework Data sources
Symfony URL query parameters

3. Request method query()

/** @var string|array|null $value */
$value = $request->query($key, $default = null);

/** @var array $all */
$all = $request->query();

Returns one or all fields from URL query parameter bag. Wrapper for query parameter bag as Laravel-style overloaded method.

Highly recommended to use with GET requests where no request body is provided.

Framework Data sources
Laravel URL query parameters

4. Request parameter bag

/** @var string|array|null $value */
$value = $request->request->get($key, $default = null);

/** @var array $all */
$all = $request->request->all();

Returns one or all fields from POST request sent with form data or from decoded JSON body (Laravel only).

Framework Data sources
Symfony 1. Request form data
Laravel 2. JSON request body

5. Files parameter bag

/** @var SymfonyComponentHttpFoundationFileUploadedFile|array|null $value */
$value = $request->files->get($key, $default = null);

/** @var array $all */
$all = $request->files->all();

Returns one or all files sent with multipart form-data request. This method returns instances of UploadedFile class provided with Symfony HTTP-Foundation package.

Note: works only with multipart/form-data content type.

Framework Data sources
Symfony Uploaded files

6. Request method file() and allFiles()

/** @var IlluminateHttpUploadedFile|array|null $value */
$value = $request->file($key, $default = null);

/** @var array $all */
$all = $request->allFiles();

Returns one or all files sent with multipart form-data request. The difference with previous method is that it returns instances of UploadedFile from Illuminate HTTP package, which has additional methods to work with Laravel file storage.

Framework Data sources
Laravel Uploaded files

7. JSON parameter bag

/** @var string|array|null $value */
$value = $request->json->get($key, $default = null);

/** @var array $all */
$all = $request->json->all();

Returns single or all fields from request JSON body. This bag is available only for valid JSON requests.

Framework Data sources
Laravel JSON request body

8. Request method json()

/** @var string|array|null $value */
$value = $request->json($key, $default = null);

/** @var array $all */
$all = $request->json();

Wrapper for json parameter bag in Laravel-style overloaded methods. Highly recommended to use with JSON API requests, which does not allow default form data.

Framework Data sources
Laravel JSON request body

9. Request method input()

/** @var string|array|null $value */
$value = $request->input($key, $default = null);

/** @var array $all */
$all = $request->input();

Generally works same as get($field) but the first priority of bag is defined by request type (JSON / Form data depending on method and content type) merged with URL query parameters.

This is the mostly recommended way if you need flexible controller (e. g. accepting both multipart and JSON requests).

Calling this method without $key attribute will return all data from priority input source merged with additional sources.

Framework Data sources
Laravel 1. Main data source (Form data / JSON)
2. URL query parameters

10. Request method all() and helpers

/** @var array $all */
$all = $request->all();

/** @var array $filtered */
$filtered = $request->only($keys); // $keys is an array.
$filtered = $request->only($key1, $key2, ..., $keyN); // Each key is a string.

/** @var array $cleaned */
$cleaned = $request->except($keys); // $keys is an array.
$cleaned = $request->except($key1, $key2, ..., $keyN); // Each key is a string.

/** @var array $common */
$common = $request->intersect($keys); // $keys is an array.
$common = $request->intersect($key1, $key2, ..., $keyN); // Each key is a string.

Recursively merges data from input() and allFiles() together.

Helpers work same as Arr helper methods applied to results of all() method. Keys can be passed either as an array attribute or as multiple single attributes.

Be careful, because input source may override keys from files array.

Framework Data sources
Laravel 1. Main data source (Form data / JSON)
2. URL query parameters
3. Uploaded files

11. Request-as-array usage

/** @var string|array|null $value */
$value = $request[$key];
$value = $request->offsetGet($key);

Array-style getter applied to results of all() method.

Important: this method uses data_get() helper, which means that calling it with dot-separated key will work to get nested parameters.

$request['foo.bar'] == $request->all()['foo']['bar'];
Framework Data sources
Laravel 1. Main data source (Form data / JSON)
2. URL query parameters
3. Uploaded files

12. Request method route()

/** @var mixed|null $value */
$value = $request->route($key, $default = null);

/** @var array $all */
$all = $request->route();

Resolves single or all parameters from URL path matched by router.

Framework Data sources
Laravel Route path named parameters

13. "Magic" getter

/** @var string|array|null $value */
$value = $request->$key;
$value = $request->__get($key);

Resolves parameter BOTH from all() method and route() method.

Important: This might be a critical mistake to confuse behavior of this method with $request[$key]. It must be used very carefully to avoid misconfigured controllers. Also will not work with reserved keys like query or json

Framework Data sources
Laravel 1. Main data source (Form data / JSON)
2. URL query parameters
3. Uploaded files
4. Route path named parameters

If data exists... or not empty... or not null?

In many cases you need to check if there is data available in Request parameters or not. And here the mix of Symfony methods and Laravel methods might confuse you a lot. Let’s take a look at available methods.

The most important part here is that there is different logic for definitions of exists and not empty, which in general complies with default PHP rules, but must be paid special attention to avoid logic issues in controllers.

Methods list

1. Method has() of parameter bags

/** @var bool $inQuery */
$inQuery = $request->query->has($key);

/** @var bool $inRequest */
$inRequest = $request->request->has($key);

/** @var bool $inFiles */
$inFiles = $request->files->has($key);

/** @var bool $inJson */
$inJson = $request->json->has($key); // Laravel-only

Checks if the key exists in the parameter bag. Important: this is the only available way for default Symfony request.

2. Request method exists()

/** @var bool $in */
$in = $request->exists($keys); // $keys is an array.
$in = $request->exists($key1, $key2, ..., $keyN); // Each key is a string.

Checks if all of the keys exist in the result of all() method.

$keys may be passed both as an array attribute or as multiple single attributes.

3. Request method has()

/** @var bool $in */
$in = $request->has($keys); // $keys is an array.
$in = $request->has($key1, $key2, ..., $keyN); // Each key is a string.

On the opposite to previous method, it checks if all of the keys are not empty in the result of all() method.

4. Request method hasFile()

Checks if the file key exists and the file is valid (not empty and not broken).

Important strongly recommended to use this method to check the files for validity before using file() method.

5. Array key check

/** @var bool $in */
$in = isset($request[$key]);
$in = array_key_exists($key, $request);
$in = $request->offsetExists($key);

Checks if the key exists in the results of all() method.

6. "Magic" property check

/** @var bool $in */
$in = isset($request->$key);
$in = $request->__isset($key);

Checks if the key exists and value is not null in the results of all() method and route() method.

Before using any of these methods, you need to make sure what exactly you want to check — data existence or emptiness, input source and possible intersections of sources.

Is it hard already? Believe me, not yet             </div>
            
            <div class=

0