vendor and env first commit

This commit is contained in:
2025-03-28 08:52:46 +01:00
parent f8388bc81b
commit 8f26283832
10976 changed files with 1349952 additions and 2 deletions
@@ -0,0 +1,21 @@
<?php
namespace Proengsoft\JsValidation\Exceptions;
use Exception;
class PropertyNotFoundException extends Exception
{
/**
* Property Not Found Exception.
*
* @param string $property
* @param string $caller
* @param \Exception $previous
*/
public function __construct($property = '', $caller = '', Exception $previous = null)
{
$message = "'$property' not found in '$caller'' object";
parent::__construct($message, 0, $previous);
}
}
@@ -0,0 +1,18 @@
<?php
namespace Proengsoft\JsValidation\Facades;
use Illuminate\Support\Facades\Facade;
class JsValidatorFacade extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'jsvalidator';
}
}
@@ -0,0 +1,207 @@
<?php
namespace Proengsoft\JsValidation\Javascript;
trait JavascriptRulesTrait
{
/**
* Handles multidimensional attribute names.
*
* @param string $attribute
* @return string
*/
abstract protected function getAttributeName($attribute);
/**
* Parse named parameters to $key => $value items.
*
* @param array $parameters
* @return array
*/
abstract public function parseNamedParameters($parameters);
/**
* Confirmed rule is applied to confirmed attribute.
*
* @param $attribute
* @param array $parameters
* @return array
*/
protected function ruleConfirmed($attribute, array $parameters)
{
$parameters[0] = $this->getAttributeName($attribute);
$attribute = "{$attribute}_confirmation";
return [$attribute, $parameters];
}
/**
* Returns Javascript parameters for After rule.
*
* @param $attribute
* @param array $parameters
* @return array
*/
protected function ruleAfter($attribute, array $parameters)
{
if (! ($date = strtotime($parameters[0]))) {
$date = $this->getAttributeName($parameters[0]);
}
return [$attribute, [$date]];
}
/**
* Returns Javascript parameters for Before rule.
*
* @param $attribute
* @param array $parameters
* @return array
*/
protected function ruleBefore($attribute, array $parameters)
{
return $this->ruleAfter($attribute, $parameters);
}
/**
* Validate that two attributes match.
*
* @param string $attribute
* @param array $parameters
* @return array
*/
protected function ruleSame($attribute, array $parameters)
{
$other = $this->getAttributeName($parameters[0]);
return [$attribute, [$other]];
}
/**
* Validate that an attribute is different from another attribute.
*
* @param string $attribute
* @param array $parameters
* @return array
*/
protected function ruleDifferent($attribute, array $parameters)
{
return $this->ruleSame($attribute, $parameters);
}
/**
* Validate that an attribute exists when any other attribute exists.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredWith($attribute, array $parameters)
{
$parameters = array_map([$this, 'getAttributeName'], $parameters);
return [$attribute, $parameters];
}
/**
* Validate that an attribute exists when all other attributes exists.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredWithAll($attribute, array $parameters)
{
return $this->ruleRequiredWith($attribute, $parameters);
}
/**
* Validate that an attribute exists when another attribute does not.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredWithout($attribute, array $parameters)
{
return $this->ruleRequiredWith($attribute, $parameters);
}
/**
* Validate that an attribute exists when all other attributes do not.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredWithoutAll($attribute, array $parameters)
{
return $this->ruleRequiredWith($attribute, $parameters);
}
/**
* Validate that an attribute exists when another attribute has a given value.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredIf($attribute, array $parameters)
{
$parameters[0] = $this->getAttributeName($parameters[0]);
return [$attribute, $parameters];
}
/**
* Validate that an attribute exists when another attribute does not have a given value.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleRequiredUnless($attribute, array $parameters)
{
return $this->ruleRequiredIf($attribute, $parameters);
}
/**
* Validate that the values of an attribute is in another attribute.
*
* @param string $attribute
* @param mixed $parameters
* @return array
*/
protected function ruleInArray($attribute, array $parameters)
{
return $this->ruleRequiredIf($attribute, $parameters);
}
/**
* Validate the dimensions of an image matches the given values.
*
* @param string $attribute
* @param array $parameters
* @return array
*/
protected function ruleDimensions($attribute, $parameters)
{
$parameters = $this->parseNamedParameters($parameters);
return [$attribute, $parameters];
}
/**
* Validate an attribute is unique among other values.
*
* @param string $attribute
* @param array $parameters
* @return array
*/
protected function ruleDistinct($attribute, array $parameters)
{
$parameters[0] = $attribute;
return $this->ruleRequiredIf($attribute, $parameters);
}
}
@@ -0,0 +1,230 @@
<?php
namespace Proengsoft\JsValidation\Javascript;
use Exception;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\View;
use Proengsoft\JsValidation\Exceptions\PropertyNotFoundException;
class JavascriptValidator implements Arrayable
{
/**
* Registered validator instance.
*
* @var ValidatorHandler
*/
protected $validator;
/**
* Selector used in javascript generation.
*
* @var string
*/
protected $selector;
/**
* View that renders Javascript.
*
* @var
*/
protected $view;
/**
* Enable or disable remote validations.
*
* @var bool
*/
protected $remote;
/**
* 'ignore' option for jQuery Validation Plugin.
*
* @var string
*/
protected $ignore;
/**
* Constructor.
*
* @param ValidatorHandler $validator
* @param array $options
*/
public function __construct(ValidatorHandler $validator, $options = [])
{
$this->validator = $validator;
$this->setDefaults($options);
}
/**
* Set default parameters.
*
* @param $options
* @return void
*/
protected function setDefaults($options)
{
$this->selector = empty($options['selector']) ? 'form' : $options['selector'];
$this->view = empty($options['view']) ? 'jsvalidation::bootstrap' : $options['view'];
$this->remote = isset($options['remote']) ? $options['remote'] : true;
if (isset($options['ignore'])) {
$this->ignore = $options['ignore'];
}
}
/**
* Render the specified view with validator data.
*
* @param null|\Illuminate\Contracts\View\View|string $view
* @param null|string $selector
* @return string
*/
public function render($view = null, $selector = null)
{
$this->view($view);
$this->selector($selector);
return View::make($this->view, ['validator' => $this->getViewData()])
->render();
}
/**
* Get the view data as an array.
*
* @return array
*/
public function toArray()
{
return $this->getViewData();
}
/**
* Get the string resulting of render default view.
*
* @return string
*/
public function __toString()
{
try {
return $this->render();
} catch (Exception $exception) {
return trigger_error($exception->__toString(), E_USER_ERROR);
}
}
/**
* Gets value from view data.
*
* @param $name
* @return string
*
* @throws \Proengsoft\JsValidation\Exceptions\PropertyNotFoundException
*/
public function __get($name)
{
$data = $this->getViewData();
if (! array_key_exists($name, $data)) {
throw new PropertyNotFoundException($name, get_class());
}
return $data[$name];
}
/**
* Gets view data.
*
* @return array
*/
protected function getViewData()
{
$this->validator->setRemote($this->remote);
$data = $this->validator->validationData();
$data['selector'] = $this->selector;
if (! is_null($this->ignore)) {
$data['ignore'] = $this->ignore;
}
return $data;
}
/**
* Set the form selector to validate.
*
* @param string $selector
*
* @deprecated
*/
public function setSelector($selector)
{
$this->selector = $selector;
}
/**
* Set the form selector to validate.
*
* @param string $selector
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function selector($selector)
{
$this->selector = is_null($selector) ? $this->selector : $selector;
return $this;
}
/**
* Set the input selector to ignore for validation.
*
* @param string $ignore
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function ignore($ignore)
{
$this->ignore = $ignore;
return $this;
}
/**
* Set the view to render Javascript Validations.
*
* @param null|\Illuminate\Contracts\View\View|string $view
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function view($view)
{
$this->view = is_null($view) ? $this->view : $view;
return $this;
}
/**
* Enables or disables remote validations.
*
* @param null|bool $enabled
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function remote($enabled = true)
{
$this->remote = $enabled;
return $this;
}
/**
* Validate Conditional Validations using Ajax in specified fields.
*
* @param string $attribute
* @param string|array $rules
* @param null $callback Dummy attribute to make API seamless with Laravel sometimes()
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function sometimes($attribute, $rules, $callback = null)
{
$this->validator->sometimes($attribute, $rules);
return $this;
}
}
@@ -0,0 +1,120 @@
<?php
namespace Proengsoft\JsValidation\Javascript;
use Proengsoft\JsValidation\JsValidatorFactory;
use Proengsoft\JsValidation\Support\DelegatedValidator;
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class MessageParser
{
use UseDelegatedValidatorTrait;
/**
* Whether to escape messages using htmlentities.
*
* @var bool
*/
protected $escape;
/**
* Create a new JsValidation instance.
*
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
* @param bool $escape
*/
public function __construct(DelegatedValidator $validator, $escape = false)
{
$this->validator = $validator;
$this->escape = $escape;
}
/**
* Replace javascript error message place-holders with actual values.
*
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return mixed
*/
public function getMessage($attribute, $rule, $parameters)
{
$attribute = str_replace(JsValidatorFactory::ASTERISK, '*', $attribute);
$data = $this->fakeValidationData($attribute, $rule, $parameters);
$message = $this->validator->getMessage($attribute, $rule);
$message = $this->validator->makeReplacements($message, $attribute, $rule, $parameters);
$this->validator->setData($data);
return $this->escape ? e($message) : $message;
}
/**
* Creates fake data needed to parse messages
* Returns original data.
*
* @param string $attribute
* @param string $rule
* @param $parameters
* @return array
*/
protected function fakeValidationData($attribute, $rule, $parameters)
{
$data = $this->validator->getData();
$this->fakeFileData($data, $attribute);
$this->fakeRequiredIfData($data, $rule, $parameters);
return $data;
}
/**
* Generate fake data to get RequiredIf message.
*
* @param $data
* @param $rule
* @param $parameters
* @return void
*/
private function fakeRequiredIfData($data, $rule, $parameters)
{
if ($rule !== 'RequiredIf') {
return;
}
$newData = $data;
$newData[$parameters[0]] = $parameters[1];
$this->validator->setData($newData);
}
/**
* Generate fake data to get file type messages.
*
* @param $data
* @param $attribute
* @return void
*/
private function fakeFileData($data, $attribute)
{
if (! $this->validator->hasRule($attribute, ['Mimes', 'Image'])) {
return;
}
$newFiles = $data;
$newFiles[$attribute] = $this->createUploadedFile();
$this->validator->setData($newFiles);
}
/**
* Create fake UploadedFile to generate file messages.
*
* @return UploadedFile
*/
protected function createUploadedFile()
{
return new UploadedFile('fakefile', 'fakefile', null, UPLOAD_ERR_NO_FILE, true);
}
}
@@ -0,0 +1,201 @@
<?php
namespace Proengsoft\JsValidation\Javascript;
use Proengsoft\JsValidation\JsValidatorFactory;
use Proengsoft\JsValidation\Support\DelegatedValidator;
use Proengsoft\JsValidation\Support\RuleListTrait;
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
class RuleParser
{
use JavascriptRulesTrait;
use RuleListTrait;
use UseDelegatedValidatorTrait;
/**
* Dummy Laravel validation rule for form requests.
*/
const FORM_REQUEST_RULE_NAME = 'ProengsoftFormRequest';
/**
* Js validation rule used to validate form requests.
*/
const FORM_REQUEST_RULE = 'laravelValidationFormRequest';
/**
* Rule used to validate remote requests.
*/
const REMOTE_RULE = 'laravelValidationRemote';
/**
* Rule used to validate javascript fields.
*/
const JAVASCRIPT_RULE = 'laravelValidation';
/**
* Token used to secure romte validations.
*
* @var null|string
*/
protected $remoteToken;
/**
* Conditional Validations.
*
* @var array
*/
protected $conditional = [];
/**
* Create a new JsValidation instance.
*
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
* @param null|string $remoteToken
*/
public function __construct(DelegatedValidator $validator, $remoteToken = null)
{
$this->validator = $validator;
$this->remoteToken = $remoteToken;
}
/**
* Return parsed Javascript Rule.
*
* @param string $attribute
* @param string $rule
* @param $parameters
* @param $rawRule
* @return array
*/
public function getRule($attribute, $rule, $parameters, $rawRule)
{
$isConditional = $this->isConditionalRule($attribute, $rawRule);
$isRemote = $this->isRemoteRule($rule);
$isFormRequest = $this->isFormRequestRule($rule);
if ($isFormRequest || $isConditional || $isRemote) {
[$attribute, $parameters] = $this->remoteRule($attribute, $isConditional);
$jsRule = $isFormRequest ? static::FORM_REQUEST_RULE : static::REMOTE_RULE;
} else {
[$jsRule, $attribute, $parameters] = $this->clientRule($attribute, $rule, $parameters);
}
$attribute = $this->getAttributeName($attribute);
return [$attribute, $jsRule, $parameters];
}
/**
* Gets rules from Validator instance.
*
* @return array
*/
public function getValidatorRules()
{
return $this->validator->getRules();
}
/**
* Add conditional rules.
*
* @param mixed $attribute
* @param array $rules
* @return void
*/
public function addConditionalRules($attribute, $rules = [])
{
foreach ((array) $attribute as $key) {
$current = isset($this->conditional[$key]) ? $this->conditional[$key] : [];
$merge = head($this->validator->explodeRules((array) $rules));
$this->conditional[$key] = array_merge($current, $merge);
}
}
/**
* Determine if rule is passed with sometimes.
*
* @param mixed $attribute
* @param string $rule
* @return bool
*/
protected function isConditionalRule($attribute, $rule)
{
return isset($this->conditional[$attribute])
&& in_array($rule, $this->conditional[$attribute]);
}
/**
* Returns Javascript parameters for remote validated rules.
*
* @param string $attribute
* @param string $rule
* @param $parameters
* @return array
*/
protected function clientRule($attribute, $rule, $parameters)
{
$jsRule = self::JAVASCRIPT_RULE;
$method = "rule{$rule}";
if (method_exists($this, $method)) {
[$attribute, $parameters] = $this->$method($attribute, $parameters);
}
return [$jsRule, $attribute, $parameters];
}
/**
* Returns Javascript parameters for remote validated rules.
*
* @param string $attribute
* @param bool $forceRemote
* @return array
*/
protected function remoteRule($attribute, $forceRemote)
{
$attrHtmlName = $this->getAttributeName($attribute);
$params = [
$attrHtmlName,
$this->remoteToken,
$forceRemote,
];
return [$attribute, $params];
}
/**
* Handles multidimensional attribute names.
*
* @param mixed $attribute
* @return string
*/
protected function getAttributeName($attribute)
{
$attribute = str_replace(JsValidatorFactory::ASTERISK, '*', $attribute);
$attributeArray = explode('.', $attribute);
if (count($attributeArray) > 1) {
return $attributeArray[0].'['.implode('][', array_slice($attributeArray, 1)).']';
}
return $attribute;
}
/**
* Parse named parameters to $key => $value items.
*
* @param array $parameters
* @return array
*/
public function parseNamedParameters($parameters)
{
return array_reduce($parameters, function ($result, $item) {
[$key, $value] = array_pad(explode('=', $item, 2), 2, null);
$result[$key] = $value;
return $result;
});
}
}
@@ -0,0 +1,173 @@
<?php
namespace Proengsoft\JsValidation\Javascript;
use Proengsoft\JsValidation\Support\DelegatedValidator;
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
class ValidatorHandler
{
use UseDelegatedValidatorTrait;
/**
* Rule used to disable validations.
*
* @const string
*/
const JSVALIDATION_DISABLE = 'NoJsValidation';
/**
* @var RuleParser
*/
protected $rules;
/**
* @var MessageParser
*/
protected $messages;
/**
* @var bool
*/
protected $remote = true;
/**
* Create a new JsValidation instance.
*
* @param RuleParser $rules
* @param MessageParser $messages
*/
public function __construct(RuleParser $rules, MessageParser $messages)
{
$this->rules = $rules;
$this->messages = $messages;
$this->validator = $rules->getDelegatedValidator();
}
/**
* Sets delegated Validator instance.
*
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
* @return void
*/
public function setDelegatedValidator(DelegatedValidator $validator)
{
$this->validator = $validator;
$this->rules->setDelegatedValidator($validator);
$this->messages->setDelegatedValidator($validator);
}
/**
* Enable or disables remote validations.
*
* @param bool $enabled
* @return void
*/
public function setRemote($enabled)
{
$this->remote = $enabled;
}
/**
* Generate Javascript Validations.
*
* @return array
*/
protected function generateJavascriptValidations()
{
$jsValidations = [];
foreach ($this->validator->getRules() as $attribute => $rules) {
if (! $this->jsValidationEnabled($attribute)) {
continue;
}
$newRules = $this->jsConvertRules($attribute, $rules, $this->remote);
$jsValidations = array_merge($jsValidations, $newRules);
}
return $jsValidations;
}
/**
* Make Laravel Validations compatible with JQuery Validation Plugin.
*
* @param $attribute
* @param $rules
* @param bool $includeRemote
* @return array
*/
protected function jsConvertRules($attribute, $rules, $includeRemote)
{
$jsRules = [];
foreach ($rules as $rawRule) {
[$rule, $parameters] = $this->validator->parseRule($rawRule);
[$jsAttribute, $jsRule, $jsParams] = $this->rules->getRule($attribute, $rule, $parameters, $rawRule);
if ($this->isValidatable($jsRule, $includeRemote)) {
$jsRules[$jsAttribute][$jsRule][] = [
$rule,
$jsParams,
$this->messages->getMessage($attribute, $rule, $parameters),
$this->validator->isImplicit($rule),
$jsAttribute,
];
}
}
return $jsRules;
}
/**
* Check if rule should be validated with javascript.
*
* @param $jsRule
* @param bool $includeRemote
* @return bool
*/
protected function isValidatable($jsRule, $includeRemote)
{
return $jsRule && ($includeRemote || $jsRule !== RuleParser::REMOTE_RULE);
}
/**
* Check if JS Validation is disabled for attribute.
*
* @param $attribute
* @return bool
*/
public function jsValidationEnabled($attribute)
{
return ! $this->validator->hasRule($attribute, self::JSVALIDATION_DISABLE);
}
/**
* Returns view data to render javascript.
*
* @return array
*/
public function validationData()
{
$jsMessages = [];
$jsValidations = $this->generateJavascriptValidations();
return [
'rules' => $jsValidations,
'messages' => $jsMessages,
];
}
/**
* Validate Conditional Validations using Ajax in specified fields.
*
* @param string $attribute
* @param string|array $rules
* @return void
*/
public function sometimes($attribute, $rules = [])
{
$callback = function () {
return true;
};
$this->validator->sometimes($attribute, $rules, $callback);
$this->rules->addConditionalRules($attribute, (array) $rules);
}
}
@@ -0,0 +1,94 @@
<?php
namespace Proengsoft\JsValidation;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\ServiceProvider;
use Proengsoft\JsValidation\Javascript\ValidatorHandler;
class JsValidationServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->bootstrapConfigs();
$this->bootstrapViews();
$this->bootstrapValidator();
$this->publishAssets();
if ($this->app['config']->get('jsvalidation.disable_remote_validation') === false) {
$this->app[Kernel::class]->pushMiddleware(RemoteValidationMiddleware::class);
}
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton('jsvalidator', function ($app) {
$config = $app['config']->get('jsvalidation');
return new JsValidatorFactory($app, $config);
});
}
/**
* Configure and publish views.
*
* @return void
*/
protected function bootstrapViews()
{
$viewPath = realpath(__DIR__.'/../resources/views');
$this->loadViewsFrom($viewPath, 'jsvalidation');
$this->publishes([
$viewPath => $this->app['path.base'].'/resources/views/vendor/jsvalidation',
], 'views');
}
/**
* Configure Laravel Validator.
*
* @return void
*/
protected function bootstrapValidator()
{
$callback = function () {
return true;
};
$this->app['validator']->extend(ValidatorHandler::JSVALIDATION_DISABLE, $callback);
}
/**
* Load and publishes configs.
*
* @return void
*/
protected function bootstrapConfigs()
{
$configFile = realpath(__DIR__.'/../config/jsvalidation.php');
$this->mergeConfigFrom($configFile, 'jsvalidation');
$this->publishes([$configFile => $this->app['path.config'].'/jsvalidation.php'], 'config');
}
/**
* Publish public assets.
*
* @return void
*/
protected function publishAssets()
{
$this->publishes([
realpath(__DIR__.'/../public') => $this->app['path.public'].'/vendor/jsvalidation',
], 'public');
}
}
@@ -0,0 +1,288 @@
<?php
namespace Proengsoft\JsValidation;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Foundation\Http\FormRequest as IlluminateFormRequest;
use Illuminate\Support\Arr;
use Illuminate\Validation\Validator;
use Proengsoft\JsValidation\Javascript\JavascriptValidator;
use Proengsoft\JsValidation\Javascript\MessageParser;
use Proengsoft\JsValidation\Javascript\RuleParser;
use Proengsoft\JsValidation\Javascript\ValidatorHandler;
use Proengsoft\JsValidation\Remote\FormRequest;
use Proengsoft\JsValidation\Support\DelegatedValidator;
use Proengsoft\JsValidation\Support\ValidationRuleParserProxy;
class JsValidatorFactory
{
const ASTERISK = '__asterisk__';
/**
* The application instance.
*
* @var \Illuminate\Container\Container
*/
protected $app;
/**
* Configuration options.
*
* @var array
*/
protected $options;
/**
* Create a new Validator factory instance.
*
* @param \Illuminate\Container\Container $app
* @param array $options
*/
public function __construct($app, array $options = [])
{
$this->app = $app;
$this->setOptions($options);
}
/**
* @param $options
* @return void
*/
protected function setOptions($options)
{
$options['disable_remote_validation'] = empty($options['disable_remote_validation']) ? false : $options['disable_remote_validation'];
$options['view'] = empty($options['view']) ? 'jsvalidation:bootstrap' : $options['view'];
$options['form_selector'] = empty($options['form_selector']) ? 'form' : $options['form_selector'];
$this->options = $options;
}
/**
* Creates JsValidator instance based on rules and message arrays.
*
* @param array $rules
* @param array $messages
* @param array $customAttributes
* @param null|string $selector
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function make(array $rules, array $messages = [], array $customAttributes = [], $selector = null)
{
$validator = $this->getValidatorInstance($rules, $messages, $customAttributes);
return $this->validator($validator, $selector);
}
/**
* Get the validator instance for the request.
*
* @param array $rules
* @param array $messages
* @param array $customAttributes
* @return \Illuminate\Validation\Validator
*/
protected function getValidatorInstance(array $rules, array $messages = [], array $customAttributes = [])
{
$factory = $this->app->make(ValidationFactory::class);
$data = $this->getValidationData($rules, $customAttributes);
$validator = $factory->make($data, $rules, $messages, $customAttributes);
$validator->addCustomAttributes($customAttributes);
return $validator;
}
/**
* Gets fake data when validator has wildcard rules.
*
* @param array $rules
* @param array $customAttributes
* @return array
*/
protected function getValidationData(array $rules, array $customAttributes = [])
{
$attributes = array_filter(array_keys($rules), function ($attribute) {
return $attribute !== '' && mb_strpos($attribute, '*') !== false;
});
$attributes = array_merge(array_keys($customAttributes), $attributes);
$data = array_reduce($attributes, function ($data, $attribute) {
// Prevent wildcard rule being removed as an implicit attribute (not present in the data).
$attribute = str_replace('*', self::ASTERISK, $attribute);
Arr::set($data, $attribute, true);
return $data;
}, []);
return $data;
}
/**
* Creates JsValidator instance based on FormRequest.
*
* @param $formRequest
* @param null|string $selector
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function formRequest($formRequest, $selector = null)
{
if (! is_object($formRequest)) {
$formRequest = $this->createFormRequest($formRequest);
}
if ($formRequest instanceof FormRequest) {
return $this->newFormRequestValidator($formRequest, $selector);
}
return $this->oldFormRequestValidator($formRequest, $selector);
}
/**
* Create form request validator.
*
* @param FormRequest $formRequest
* @param string $selector
* @return JavascriptValidator
*/
private function newFormRequestValidator($formRequest, $selector)
{
// Replace all rules with Noop rules which are checked client-side and always valid to true.
// This is important because jquery-validation expects fields under validation to have rules present. For
// example, if you mark a field as invalid without a defined rule, then unhighlight won't be called.
$rules = method_exists($formRequest, 'rules') ? $formRequest->rules() : [];
foreach ($rules as $key => $value) {
$rules[$key] = 'proengsoft_noop';
}
// This rule controls AJAX validation of all fields.
$rules['proengsoft_jsvalidation'] = RuleParser::FORM_REQUEST_RULE_NAME;
$baseValidator = $this->getValidatorInstance($rules);
return $this->validator($baseValidator, $selector);
}
/**
* Create a form request validator instance.
*
* @param IlluminateFormRequest $formRequest
* @param string $selector
* @return JavascriptValidator
*/
private function oldFormRequestValidator($formRequest, $selector)
{
$rules = method_exists($formRequest, 'rules') ? $this->app->call([$formRequest, 'rules']) : [];
$validator = $this->getValidatorInstance($rules, $formRequest->messages(), $formRequest->attributes());
$jsValidator = $this->validator($validator, $selector);
if (method_exists($formRequest, 'withJsValidator')) {
$formRequest->withJsValidator($jsValidator);
}
return $jsValidator;
}
/**
* @param string|array $class
* @return array
*/
protected function parseFormRequestName($class)
{
$params = [];
if (is_array($class)) {
$params = empty($class[1]) ? $params : $class[1];
$class = $class[0];
}
return [$class, $params];
}
/**
* Creates and initializes an Form Request instance.
*
* @param string $class
* @return IlluminateFormRequest
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function createFormRequest($class)
{
/*
* @var $formRequest \Illuminate\Foundation\Http\FormRequest
* @var $request Request
*/
[$class, $params] = $this->parseFormRequestName($class);
$request = $this->app->__get('request');
$formRequest = $this->app->build($class, $params);
if ($request->hasSession() && $session = $request->session()) {
$formRequest->setLaravelSession($session);
}
$formRequest->setUserResolver($request->getUserResolver());
$formRequest->setRouteResolver($request->getRouteResolver());
$formRequest->setContainer($this->app);
$formRequest->query = $request->query;
return $formRequest;
}
/**
* Creates JsValidator instance based on Validator.
*
* @param \Illuminate\Validation\Validator $validator
* @param null|string $selector
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
public function validator(Validator $validator, $selector = null)
{
return $this->jsValidator($validator, $selector);
}
/**
* Creates JsValidator instance based on Validator.
*
* @param \Illuminate\Validation\Validator $validator
* @param null|string $selector
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
*/
protected function jsValidator(Validator $validator, $selector = null)
{
$remote = ! $this->options['disable_remote_validation'];
$view = $this->options['view'];
$selector = is_null($selector) ? $this->options['form_selector'] : $selector;
$ignore = $this->options['ignore'];
$delegated = new DelegatedValidator($validator, new ValidationRuleParserProxy($validator->getData()));
$rules = new RuleParser($delegated, $this->getSessionToken());
$messages = new MessageParser($delegated, isset($this->options['escape']) ? $this->options['escape'] : false);
$jsValidator = new ValidatorHandler($rules, $messages);
return new JavascriptValidator($jsValidator, compact('view', 'selector', 'remote', 'ignore'));
}
/**
* Get and encrypt token from session store.
*
* @return null|string
*/
protected function getSessionToken()
{
$token = null;
if ($session = $this->app->__get('session')) {
$token = $session->token();
}
if ($encrypter = $this->app->__get('encrypter')) {
$token = $encrypter->encrypt($token);
}
return $token;
}
}
@@ -0,0 +1,76 @@
<?php
namespace Proengsoft\JsValidation\Remote;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest as Request;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
class FormRequest extends Request
{
/**
* Field to identify requests originating from this library.
*/
const JS_VALIDATION_FIELD = '__proengsoft_form_request';
/**
* Validate the class instance.
*
* @return void
*/
public function validateResolved()
{
parent::validateResolved();
// BC for Laravel versions prior to 6.x.
$this->passedValidation();
}
/**
* Handle a passed validation attempt.
*
* @return void
*/
protected function passedValidation()
{
if ($this->isJsValidation()) {
throw new HttpResponseException(
new JsonResponse(true, 200)
);
}
parent::passedValidation();
}
/**
* Handle a failed validation attempt.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator)
{
if ($this->isJsValidation()) {
throw new ValidationException(
$validator,
new JsonResponse($validator->errors()->messages(), 200)
);
}
parent::failedValidation($validator);
}
/**
* Whether the request originated from laravel-jsvalidation.
*
* @return bool
*/
private function isJsValidation()
{
return $this->has(static::JS_VALIDATION_FIELD);
}
}
@@ -0,0 +1,111 @@
<?php
namespace Proengsoft\JsValidation\Remote;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Support\Arr;
use Illuminate\Validation\Validator as BaseValidator;
use Proengsoft\JsValidation\Support\AccessProtectedTrait;
class Resolver
{
use AccessProtectedTrait;
/**
* @var \Closure
*/
protected $resolver;
/**
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $factory;
/**
* Whether to escape validation messages.
*
* @var bool
*/
protected $escape;
/**
* RemoteValidator constructor.
*
* @param \Illuminate\Contracts\Validation\Factory $factory
* @param bool $escape
*/
public function __construct(ValidationFactory $factory, $escape = false)
{
$this->factory = $factory;
$this->resolver = $this->getProtected($factory, 'resolver');
$this->escape = $escape;
}
/**
* Closure used to resolve Validator instance.
*
* @param $field
* @return \Closure
*/
public function resolver($field)
{
return function ($translator, $data, $rules, $messages, $customAttributes) use ($field) {
return $this->resolve($translator, $data, $rules, $messages, $customAttributes, $field);
};
}
/**
* Resolves Validator instance.
*
* @param $translator
* @param $data
* @param $rules
* @param $messages
* @param $customAttributes
* @param $field
* @return \Illuminate\Validation\Validator
*/
protected function resolve($translator, $data, $rules, $messages, $customAttributes, $field)
{
$validateAll = Arr::get($data, $field.'_validate_all', false);
$validationRule = 'bail|'.Validator::EXTENSION_NAME.':'.$validateAll;
$rules = [$field => $validationRule] + $rules;
$validator = $this->createValidator($translator, $data, $rules, $messages, $customAttributes);
return $validator;
}
/**
* Create new validator instance.
*
* @param $translator
* @param $data
* @param $rules
* @param $messages
* @param $customAttributes
* @return \Illuminate\Validation\Validator
*/
protected function createValidator($translator, $data, $rules, $messages, $customAttributes)
{
if (is_null($this->resolver)) {
return new BaseValidator($translator, $data, $rules, $messages, $customAttributes);
}
return call_user_func($this->resolver, $translator, $data, $rules, $messages, $customAttributes);
}
/**
* Closure used to trigger JsValidations.
*
* @return \Closure
*/
public function validatorClosure()
{
return function ($attribute, $value, $parameters, BaseValidator $validator) {
$remoteValidator = new Validator($validator, $this->escape);
$remoteValidator->validate($value, $parameters);
return $attribute;
};
}
}
@@ -0,0 +1,187 @@
<?php
namespace Proengsoft\JsValidation\Remote;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\ValidationRuleParser;
use Illuminate\Validation\Validator as BaseValidator;
use Proengsoft\JsValidation\Support\AccessProtectedTrait;
use Proengsoft\JsValidation\Support\RuleListTrait;
class Validator
{
use AccessProtectedTrait;
use RuleListTrait;
/**
* Validator extension name.
*/
const EXTENSION_NAME = 'jsvalidation';
/**
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* Whether to escape validation messages.
*
* @var bool
*/
protected $escape;
/**
* RemoteValidator constructor.
*
* @param \Illuminate\Validation\Validator $validator
* @param bool $escape
*/
public function __construct(BaseValidator $validator, $escape = false)
{
$this->validator = $validator;
$this->escape = $escape;
}
/**
* Validate request.
*
* @param $field
* @param $parameters
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
public function validate($field, $parameters = [])
{
$attribute = $this->parseAttributeName($field);
$validationParams = $this->parseParameters($parameters);
$validationResult = $this->validateJsRemoteRequest($attribute, $validationParams);
$this->throwValidationException($validationResult, $this->validator);
}
/**
* Throw the failed validation exception.
*
* @param mixed $result
* @param \Illuminate\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException|\Illuminate\Http\Exceptions\HttpResponseException
*/
protected function throwValidationException($result, $validator)
{
$response = new JsonResponse($result, 200);
if ($result !== true && class_exists(ValidationException::class)) {
throw new ValidationException($validator, $response);
}
throw new HttpResponseException($response);
}
/**
* Parse Validation input request data.
*
* @param $data
* @return array
*/
protected function parseAttributeName($data)
{
parse_str($data, $attrParts);
$attrParts = is_null($attrParts) ? [] : $attrParts;
$newAttr = array_keys(Arr::dot($attrParts));
return array_pop($newAttr);
}
/**
* Parse Validation parameters.
*
* @param $parameters
* @return array
*/
protected function parseParameters($parameters)
{
$newParams = ['validate_all' => false];
if (isset($parameters[0])) {
$newParams['validate_all'] = ($parameters[0] === 'true') ? true : false;
}
return $newParams;
}
/**
* Validate remote Javascript Validations.
*
* @param $attribute
* @param array $parameters
* @return array|bool
*/
protected function validateJsRemoteRequest($attribute, $parameters)
{
$this->setRemoteValidation($attribute, $parameters['validate_all']);
$validator = $this->validator;
if ($validator->passes()) {
return true;
}
$messages = $validator->messages()->get($attribute);
if ($this->escape) {
foreach ($messages as $key => $value) {
$messages[$key] = e($value);
}
}
return $messages;
}
/**
* Sets data for validate remote rules.
*
* @param $attribute
* @param bool $validateAll
* @return void
*/
protected function setRemoteValidation($attribute, $validateAll = false)
{
$validator = $this->validator;
$rules = $validator->getRules();
$rules = isset($rules[$attribute]) ? $rules[$attribute] : [];
if (in_array('no_js_validation', $rules)) {
$validator->setRules([$attribute => []]);
return;
}
if (! $validateAll) {
$rules = $this->purgeNonRemoteRules($rules, $validator);
}
$validator->setRules([$attribute => $rules]);
}
/**
* Remove rules that should not be validated remotely.
*
* @param $rules
* @param BaseValidator $validator
* @return mixed
*/
protected function purgeNonRemoteRules($rules, $validator)
{
$protectedValidator = $this->createProtectedCaller($validator);
foreach ($rules as $i => $rule) {
$parsedRule = ValidationRuleParser::parse($rule);
if (! $this->isRemoteRule($parsedRule[0])) {
unset($rules[$i]);
}
}
return $rules;
}
}
@@ -0,0 +1,75 @@
<?php
namespace Proengsoft\JsValidation;
use Closure;
use Illuminate\Contracts\Config\Repository as Config;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Http\Request;
use Proengsoft\JsValidation\Remote\Resolver;
use Proengsoft\JsValidation\Remote\Validator as RemoteValidator;
class RemoteValidationMiddleware
{
/**
* Validator factory instance to wrap.
*
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $factory;
/**
* Field used to detect Javascript validation.
*
* @var mixed
*/
protected $field;
/**
* Whether to escape messages or not.
*
* @var bool
*/
protected $escape;
/**
* RemoteValidationMiddleware constructor.
*
* @param \Illuminate\Contracts\Validation\Factory $validator
* @param \Illuminate\Contracts\Config\Repository $config
*/
public function __construct(ValidationFactory $validator, Config $config)
{
$this->factory = $validator;
$this->field = $config->get('jsvalidation.remote_validation_field');
$this->escape = (bool) $config->get('jsvalidation.escape', false);
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($request->has($this->field)) {
$this->wrapValidator();
}
return $next($request);
}
/**
* Wraps Validator resolver with RemoteValidator resolver.
*
* @return void
*/
protected function wrapValidator()
{
$resolver = new Resolver($this->factory, $this->escape);
$this->factory->resolver($resolver->resolver($this->field));
$this->factory->extend(RemoteValidator::EXTENSION_NAME, $resolver->validatorClosure());
}
}
@@ -0,0 +1,59 @@
<?php
namespace Proengsoft\JsValidation\Support;
use Closure;
trait AccessProtectedTrait
{
/**
* Create closure to call inaccessible method.
*
* @param $instance
* @return \Closure
*/
protected function createProtectedCaller($instance)
{
$closure = function ($method, $args) {
$callable = [$this, $method];
return call_user_func_array($callable, $args);
};
return $closure->bindTo($instance, $instance);
}
/**
* Gets inaccessible property.
*
* @param $instance
* @param $property
* @return \Closure
*/
protected function getProtected($instance, $property)
{
$closure = function ($property) {
return $this->$property;
};
$callback = $closure->bindTo($instance, $instance);
return $callback($property);
}
/**
* Calls inaccessible method.
*
* @param object|\Closure $instance
* @param $method
* @param $args
* @return mixed
*/
protected function callProtected($instance, $method, $args = [])
{
if (! ($instance instanceof Closure)) {
$instance = $this->createProtectedCaller($instance);
}
return call_user_func($instance, $method, $args);
}
}
@@ -0,0 +1,206 @@
<?php
namespace Proengsoft\JsValidation\Support;
use Illuminate\Validation\Validator as BaseValidator;
class DelegatedValidator
{
use AccessProtectedTrait;
/**
* The Validator resolved instance.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* Validation rule parser instance.
*
* @var \Proengsoft\JsValidation\Support\ValidationRuleParserProxy
*/
protected $ruleParser;
/**
* Closure to invoke non accessible Validator methods.
*
* @var \Closure
*/
protected $validatorMethod;
/**
* DelegatedValidator constructor.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Proengsoft\JsValidation\Support\ValidationRuleParserProxy $ruleParser
*/
public function __construct(BaseValidator $validator, ValidationRuleParserProxy $ruleParser)
{
$this->validator = $validator;
$this->ruleParser = $ruleParser;
$this->validatorMethod = $this->createProtectedCaller($validator);
}
/**
* Call validator method.
*
* @param string $method
* @param array $args
* @return mixed
*/
private function callValidator($method, $args = [])
{
return $this->callProtected($this->validatorMethod, $method, $args);
}
/**
* Get current \Illuminate\Validation\Validator instance.
*
* @return \Illuminate\Validation\Validator
*/
public function getValidator()
{
return $this->validator;
}
/**
* Get the data under validation.
*
* @return array
*/
public function getData()
{
return $this->validator->getData();
}
/**
* Set the data under validation.
*
* @param array
*/
public function setData($data)
{
$rules = $this->validator->getRules();
$this->validator->setData($data);
if (is_array($rules)) {
$this->validator->setRules($rules);
}
}
/**
* Get the validation rules.
*
* @return array
*/
public function getRules()
{
return $this->validator->getRules();
}
/**
* Determine if a given rule implies the attribute is required.
*
* @param string $rule
* @return bool
*/
public function isImplicit($rule)
{
return $this->callValidator('isImplicit', [$rule]);
}
/**
* Replace all error message place-holders with actual values.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
public function makeReplacements($message, $attribute, $rule, $parameters)
{
if (is_object($rule)) {
$rule = get_class($rule);
}
return $this->callValidator('makeReplacements', [$message, $attribute, $rule, $parameters]);
}
/**
* Determine if the given attribute has a rule in the given set.
*
* @param string $attribute
* @param string|array $rules
* @return bool
*/
public function hasRule($attribute, $rules)
{
return $this->callValidator('hasRule', [$attribute, $rules]);
}
/**
* Get the validation message for an attribute and rule.
*
* @param string $attribute
* @param string $rule
* @return string
*/
public function getMessage($attribute, $rule)
{
if (is_object($rule)) {
$rule = get_class($rule);
}
return $this->callValidator('getMessage', [$attribute, $rule]);
}
/**
* Extract the rule name and parameters from a rule.
*
* @param array|string $rules
* @return array
*/
public function parseRule($rules)
{
return $this->ruleParser->parse($rules);
}
/**
* Explode the rules into an array of rules.
*
* @param string|array $rules
* @return array
*/
public function explodeRules($rules)
{
return $this->ruleParser->explodeRules($rules);
}
/**
* Add conditions to a given field based on a Closure.
*
* @param string $attribute
* @param string|array $rules
* @param callable $callback
* @return void
*/
public function sometimes($attribute, $rules, callable $callback)
{
$this->validator->sometimes($attribute, $rules, $callback);
}
/**
* Delegate method calls to validator instance.
*
* @param $method
* @param $params
* @return mixed
*/
public function __call($method, $params)
{
$arrCaller = [$this->validator, $method];
return call_user_func_array($arrCaller, $params);
}
}
@@ -0,0 +1,113 @@
<?php
namespace Proengsoft\JsValidation\Support;
use Proengsoft\JsValidation\Javascript\RuleParser;
trait RuleListTrait
{
/**
* Rules validated with Javascript.
*
* @var array
*/
protected $clientRules = [
'Accepted', 'After', 'AfterOrEqual', 'Alpha', 'AlphaDash',
'AlphaNum', 'Array', 'Bail', 'Before', 'BeforeOrEqual', 'Between', 'Boolean', 'Confirmed', 'Date', 'Dimensions',
'DateFormat', 'Different', 'Digits', 'DigitsBetween', 'Distinct', 'Email', 'File', 'Filled', 'Image',
'In', 'InArray', 'Integer', 'Ip', 'Json', 'Max', 'Mimes', 'Mimetypes', 'Min', 'NotIn', 'Nullable',
'Numeric', 'Regex', 'Required', 'RequiredIf', 'RequiredUnless', 'RequiredWith', 'RequiredWithAll',
'RequiredWithout', 'RequiredWithoutAll', 'Same', 'Size', 'Sometimes',
'String', 'Timezone', 'ProengsoftNoop',
];
/**
* Rules validated in Server-Side.
*
* @var array
*/
protected $serverRules = ['ActiveUrl', 'Exists', 'Unique', 'Url'];
/**
* Rules applyed to files.
*
* @var array
*/
protected $fileRules = ['File', 'Image', 'Mimes', 'Mimetypes'];
/**
* Rule used to disable validations.
*
* @var string
*/
private $disableJsValidationRule = 'NoJsValidation';
/**
* Returns if rule is validated using Javascript.
*
* @param $rule
* @return bool
*/
protected function isImplemented($rule)
{
return in_array($rule, $this->clientRules) || in_array($rule, $this->serverRules);
}
/**
* Check if rule must be validated in server-side.
*
* @param $rule
* @return bool
*/
protected function isRemoteRule($rule)
{
return in_array($rule, $this->serverRules) ||
! in_array($rule, $this->clientRules);
}
/**
* Form request rule.
*
* @param string $rule
* @return bool
*/
protected function isFormRequestRule($rule)
{
return $rule === RuleParser::FORM_REQUEST_RULE_NAME;
}
/**
* Check if rule disables rule processing.
*
* @param $rule
* @return bool
*/
protected function isDisableRule($rule)
{
return $rule === $this->disableJsValidationRule;
}
/**
* Check if rules should be validated.
*
* @param $rules
* @return bool
*/
protected function validationDisabled($rules)
{
$rules = (array) $rules;
return in_array($this->disableJsValidationRule, $rules);
}
/**
* Check if rules is for input file type.
*
* @param $rule
* @return bool
*/
protected function isFileRule($rule)
{
return in_array($rule, $this->fileRules);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Proengsoft\JsValidation\Support;
trait UseDelegatedValidatorTrait
{
/**
* Delegated validator.
*
* @var \Proengsoft\JsValidation\Support\DelegatedValidator
*/
protected $validator;
/**
* Sets delegated Validator instance.
*
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
* @return void
*/
public function setDelegatedValidator(DelegatedValidator $validator)
{
$this->validator = $validator;
}
/**
* Gets current DelegatedValidator instance.
*
* @return \Proengsoft\JsValidation\Support\DelegatedValidator
*/
public function getDelegatedValidator()
{
return $this->validator;
}
}
@@ -0,0 +1,71 @@
<?php
namespace Proengsoft\JsValidation\Support;
use Illuminate\Validation\ValidationRuleParser;
class ValidationRuleParserProxy
{
use AccessProtectedTrait;
/**
* ValidationRuleParser instance.
*
* @var ValidationRuleParser
*/
protected $parser;
/**
* Closure to invoke non accessible Validator methods.
*
* @var \Closure
*/
protected $parserMethod;
/**
* ValidationRuleParserProxy constructor.
*
* @param array $data
*/
public function __construct($data = [])
{
$this->parser = new ValidationRuleParser((array) $data);
$this->parserMethod = $this->createProtectedCaller($this->parser);
}
/**
* Extract the rule name and parameters from a rule.
*
* @param array|string $rules
* @return array
*/
public function parse($rules)
{
return $this->parser->parse($rules);
}
/**
* Explode the rules into an array of explicit rules.
*
* @param array $rules
* @return mixed
*/
public function explodeRules($rules)
{
return $this->callProtected($this->parserMethod, 'explodeRules', [$rules]);
}
/**
* Delegate method calls to parser instance.
*
* @param string $method
* @param mixed $params
* @return mixed
*/
public function __call($method, $params)
{
$arrCaller = [$this->parser, $method];
return call_user_func_array($arrCaller, $params);
}
}