Skip to content
/ param Public

Cool PHP library for processing input data from any source

Notifications You must be signed in to change notification settings

flsouto/param

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Param

Overview

This library allows you to extract, filter and validate individual fields from an associative array. It can be used, as an example, to validate request variables sent from a web browser. You give each parameter a "name", define the "context" and call "process"; the result will be the value extracted from the context or an error message in case of not conforming to one or more validation filters. Many predefined filters and validators are available from a "finger-friendly" API. You can also specify a fallback value to be returned in case of validation error.

Installation

Install via composer:

composer require flsouto/param

Usage

The example bellow creates a parameter and prints out its name

<?php
use FlSouto\Param;
require_once('vendor/autoload.php');

$param = new Param('test');

echo $param->name();
test

You can instantiate the parameter from the static get method which always returns the same instance for that name:

use FlSouto\Param;

$param1 = Param::get('country');
$param2 = Param::get('country');

var_dump($param1===$param2);

The output will be:

bool(true)

Processing Input

The process instance method receives a "context", which must be an associative array, and tries to extract the parameter value based on the parameter name.

use FlSouto\Param;

$param = Param::get('user_id');
$result = $param->process(['user_id'=>5]);

echo $result->output;

The output of the above will be:

5

Predefined Contexts

You can set the context on the parameter instance before calling the process method:

use FlSouto\Param;

$param = Param::get('language');
$param->context([
	'var1' => '...',
	'var2' => '...',
	'language' => 'en'
]);
$result = $param->process();

echo $result->output;
en

If you want to set the context and be able to modify it later, I recommend you provide an instance of ArrayObject like in the example bellow:

use FlSouto\Param;

$context = new ArrayObject;
$param = Param::get('lang_code');
$param->context($context);
// modify context later
$context['lang_code'] = 'en';
$result = $param->process();

echo $result->output;
en

Furthermore, you can work with the ParamContext class which allows you to factory parameters from a predefined context. Read more about it on the "ParamContext" section.

Namespaced Params

You can use square brackets for a fully qualified name. In the following example, the parameter 'email' is found inside the hierarchy user > contact:

use FlSouto\Param;

$param = Param::get('user[contact][email]');
$param->context([
	'user' => [
		'contact' => [
			'email' => 'user@domain.com'
		]
	]
]);
$result = $param->process();

echo $result->output;

The output of the above will be:

user@domain.com

Validation

The param object uses an instance of the Pipe class which allows you to bind a series of filters and/or validators to the data:

use FlSouto\Param;

$param = Param::get('user');
$param->pipe()->add('trim')->add(function($value){
	if(empty($value)){
		echo 'Cannot be empty';
	}
});
$result = $param->process(['user'=>'  ']);

echo $result->error;

Output:

Cannot be empty

The above snippet adds a filter that trims the parameter value, and also adds a validator that produces an error if the final value is empty. The printed error message is then captured inside the $result->error property.

Notice: the Param class actually provides a bunch of common filters and validatiors through the ParamFilters API. More on this subject in the "ParamFilters API" section.

Fallback values

You can specify a fallback value to be returned in the $result->output in case validation fails.

use FlSouto\Param;

$param = Param::get('lang');
$param->fallback('en');
$param->pipe()->add(function($value){
	if(empty($value)){
		echo 'No language selected';
	}
});
// pass an empty context
$result = $param->process([]);

echo $result->output;

The output will be:

en

Setting up defaults

The library provides the static setup method which allows you to intercept all param instances upon their creation. In the example bellow we define the default context for every parameter in our application to be the $_REQUEST superglobal, and we also set all parameters to be trimmed by default:

use FlSouto\Param;

// place this in a global bootstrap script
Param::setup(function(Param $param){
	$param->context($_REQUEST)->filters()->trim();
});

// Processing some request
$_REQUEST = ['name'=>'Fabio ','age'=>' 666 '];

$name = (new Param('name'))->process()->output;
$age = (new Param('age'))->process()->output;

echo "$name is $age years old";

The output from the above code will be:

Fabio is 666 years old

Method chaining

Last but not least, all setters of the Param class return the instance itself, so it is possible to use method chaining:

<?php
use FlSouto\Param;
require_once('vendor/autoload.php');

$_REQUEST['lang'] = 'pt';

Param::get('lang')
	->fallback('en')
	->context($_REQUEST)
	->pipe()
		->add('trim')
		->add(function($value){
			if(empty($value)) echo 'Cannot be empty';
		});

$result = Param::get('lang')->process();

ParamContext

The ParamContext allows you to create params out of a predefined context. It's actually a wrapper to the ArrayObject class that keeps track of added parameters:

<?php
require_once('vendor/autoload.php');
use FlSouto\ParamContext;

$context = new ParamContext();
$context->param('user_id');
$context->param('lang_code')->filters()->trim();

$context['user_id'] = 5;
$context['lang_code'] = 'en ';

$result = $context->process();

print_r($result->output);

The output will be an associative array with all the parameters extracted:

Array
(
    [user_id] => 5
    [lang_code] => en
)

You can still process an individual param and get its output:

require_once('vendor/autoload.php');
use FlSouto\ParamContext;

$context = new ParamContext();
$context->param('lang_code')->filters()->trim();

$context['lang_code'] = 'en ';
// process individual param:
$result = $context->param('lang_code')->process();

var_dump($result->output);

The output will be:

string(2) "en"

Validation

If there are any errors, these will be available as an associative array inside the ´$result->errors´ variable.

require_once('vendor/autoload.php');
use FlSouto\ParamContext;

$context = new ParamContext();
$required = function($value){
	if(empty($value)){
		echo "Cannot be empty";
	}
};

$context->param('user_id')->pipe()->add($required);
$context->param('user_name')->pipe()->add($required);

$result = $context->process();

print_r($result->errors);

Output:

Array
(
    [user_id] => Cannot be empty
    [user_name] => Cannot be empty
)

ParamFilters

The Param class has an instance method filters which returns an instance of ParamFilters. This class makes the process of filtering and validating data much easier.

The following sections are dedicated to showing the usage of each method in that object.

trim

Removes espaces from start and end of a string.

<?php
require_once('vendor/autoload.php');
use FlSouto\Param;

Param::get('name')
	->filters()
	->trim();

$result = Param::get('name')->process(['name'=>' maria ']);

var_dump($result->output);
string(5) "maria"

replace

The replace filter allows you to replace one string with another, similar to php's str_replace function:

use FlSouto\Param;

Param::get('money')
	->context(['money'=>'3,50'])
	->filters()
	->replace(',','.');

$output = Param::get('money')->process()->output;

var_dump($output);
string(4) "3.50"

replace using regex

If you wrap the search pattern between two slashes, a regular expression will be assumed.

use FlSouto\Param;

Param::get('file_name')
	->context(['file_name'=>'My  untitled document.pdf'])	
	->filters()
	->replace('/\s+/', '-');

$output = Param::get('file_name')->process()->output;

var_dump($output);
string(24) "My-untitled-document.pdf"

Another example using regex with the "i" modifier:

use FlSouto\Param;

Param::get('style')
	->context(['style'=>'CamelCase'])	
	->filters()
	->replace('/camelcase/i', 'under_scores');

$output = Param::get('style')->process()->output;

var_dump($output);
string(12) "under_scores"

strip

Matches a string or a regex pattern and remove it from the string:

use FlSouto\Param;

Param::get('name')->filters()->strip('/[^\d]/');

$result = Param::get('name')->process(['name'=>'f4b10']);

var_dump($result->output);
string(3) "410"

required

Makes sure the value is not empty. If empty, an error message is produced.

use FlSouto\Param;

Param::get('name')
	->context(['name'=>''])
	->filters()
		->required("Cannot be empty");

$error = Param::get('name')->process()->error;

var_dump($error);
string(15) "Cannot be empty"

All validators have default error messages that can be customized. Bellow is an example of redefining the default error message:

use FlSouto\Param;

FlSouto\ParamFilters::$errmsg_required = 'Cannot be empty';

Param::get('name')
	->context(['name'=>''])
	->filters()
		->required();

$error = Param::get('name')->process()->error;

var_dump($error);
string(15) "Cannot be empty"

ifmatch

Produces an error when the string MATCHES A PATTERN:

use FlSouto\Param;

Param::get('name')
	->filters()
	->ifmatch('/\d/', 'Name cannot contain digits');

$error = Param::get('name')->process(['name'=>'M4ry'])->error;

var_dump($error);
string(26) "Name cannot contain digits"

Another example using regex modifiers:

use FlSouto\Param;

Param::get('phone')
	->filters()
	->ifmatch('/[a-z]/i', 'Phone cannot contain letters');

$error = Param::get('phone')->process(['phone'=>'9829574K'])->error;

var_dump($error);
string(28) "Phone cannot contain letters"

Notice: This validator is only applied when the value is not empty:

use FlSouto\Param;

Param::get('phone')
	->filters()
	->ifmatch('/[a-z]/i', 'Phone cannot contain letters');

$error = Param::get('phone')->process(['phone'=>''])->error;

var_dump($error);
NULL

If you want to make sure the value is not empty use the required filter before ifmatch.

ifnot

Produces an error when the string DOES NOT MATCH a pattern:

use FlSouto\Param;

Param::get('date')->filters()->ifnot('/^\d{4}-\d{2}-\d{2}$/','Date is expected to be in the format yyyy-mm-dd');
$error = Param::get('date')->process(['date'=>'10/12/1992'])->error;

var_dump($error);
string(47) "Date is expected to be in the format yyyy-mm-dd"

Notice: This validator is only applied when the value is not empty:

use FlSouto\Param;

Param::get('login')->filters()->ifnot('\w','Login must contain at least one letter');
$error = Param::get('login')->process([])->error;

var_dump($error);
NULL

maxlen

Makes sure the length of the string doesn't exceed a maximum:

use FlSouto\Param;

Param::get('description')->filters()->maxlen(30, "Description must be less than %d characters long!");
$error = Param::get('description')
	->process(['description'=>str_repeat('lorem ipsum', 10)])
	->error;


var_dump($error);
string(49) "Description must be less than 30 characters long!"

minlen

Makes sure the length of a string is at least certain characters long:

use FlSouto\Param;

Param::get('description')->filters()->minlen(10, "Description must be at least %d characters long!");

$error = Param::get('description')->process(['description'=>'Test'])->error;

var_dump($error);
string(48) "Description must be at least 10 characters long!"

Notice: This validator is only applied when the value is not empty:

use FlSouto\Param;

Param::get('description')->filters()->minlen(10, "Description must be at least %d characters long!");

$error = Param::get('description')->process(['description'=>''])->error;

var_dump($error);
NULL

maxval

Makes sure an integer is not more than certain value:

use FlSouto\Param;

Param::get('age')->filters()->maxval(150, "Age cannot be more than %d!");
$error = Param::get('age')->process(['age'=>200])->error;

var_dump($error);
string(28) "Age cannot be more than 150!"

minval

Makes sure the integer, if provided, is at least larger than X:

use FlSouto\Param;

Param::get('age')->filters()->minval(1, "Age cannot be less than %d!");
$error = Param::get('age')->process(['age'=>0])->error;

var_dump($error);
string(26) "Age cannot be less than 1!"

Notice: This validator is only applied when the value is not empty:

use FlSouto\Param;

Param::get('age')->filters()->minval(1, "Age cannot be less than %d!");
$error = Param::get('age')->process(['age'=>null])->error;

var_dump($error);
NULL

Chaining filters

Last but not least, you can use method chaning for adding multiple filters. The filters will be applied to the value in the same order they were added:

<?php
require_once('vendor/autoload.php');
use FlSouto\Param;

Param::get('number')
	->filters()
		->strip('/[^\d]/')
		->required()
		->minlen(5)
		->maxlen(10);

$result = Param::get('number')->process([
	'number' => '203-40-10/80'
]);

var_dump($result->output);

In the example above the data will be filtered before the validation constraints and the result will be:

string(9) "203401080"

About

Cool PHP library for processing input data from any source

Resources

Stars

Watchers

Forks

Packages

No packages published