Different pagination conditions with query strings [CakePHP 3] - php

The user has to pass in the URL a query string which will return different pagination, if he entered none, one or both queries, the result will change. The code below works in CakePHP, but it looks horrible, is there a better way to achieve what I'm trying to do without those if, else if conditions?
if($this->request->query('date'))
{
$this->paginate = [
'conditions' => [
'Reservations.id_venue' => $this->Auth->user('id_venue_manager'),
'Reservations.date' => $this->request->query('date'),
],
];
}
else if($this->request->query('id_user'))
{
$this->paginate = [
'conditions' => [
'Reservations.id_venue' => $this->Auth->user('id_venue_manager'),
'Reservations.id_user' => $this->request->query('id_user'),
],
];
}
else if($this->request->query('id_user') && $this->request->query('date'))
{
$this->paginate = [
'conditions' => [
'Reservations.id_venue' => $this->Auth->user('id_venue_manager'),
'Reservations.id_user' => $this->request->query('id_user'),
'Reservations.date' => $this->request->query('date'),
],
];
}
else
{
$this->paginate = [
'conditions' => [
'Reservations.id_venue' => $this->Auth->user('id_venue_manager'),
],
];
}

Try this
<?php
public function someMethod() {
$this->paginate = [
'conditions' => $this->getPaginationConditions();
];
}
private function getPaginationConditions()
{
$conditions = ['Reservations.id_venue' => $this->Auth->user('id_venue_manager')];
if ($date = $this->request->query('date')) {
$conditions['Reservations.date'] = $date;
}
if ($user = $this->request->query('id_user')) {
$conditions['Reservations.id_user'] = $user;
}
return $conditions;
}

Related

Getting error: Class name must be a valid object or a string

So I've got an issue with element-api in php, which is a plugin for CRAFT cms, could someone help - what am I doing wrong here? I can't print time.json - always getting :
{"error":{"code":0,"message":"Class name must be a valid object or a
string"}}
here's the code:
<?php
use Craft;
use craft\elements\Entry;
use craft\controllers\TemplatesController;
use League\Fractal\TransformerAbstract;
use craft\web\View;
use craft\elements\User;
return [
'endpoints' => [
'tooltip-modal.json' => function() {
$affiliateId = Craft::$app->request->getParam('entryId');
$siteLanguage = Craft::$app->request->getParam('siteLanguage');
$data = [
'elementType' => Entry::class,
'paginate' => false,
'transformer' => function(Entry $affiliate) {
$view = Craft::$app->getView();
// $view->setTemplateMode($view::TEMPLATE_MODE_SITE);
return [
'affiliate' => $view->renderTemplate('modals/tooltipAffModal.twig', ['affiliate' => $affiliate])
];
},
'criteria' => ['id' => $affiliateId, 'site' => $siteLanguage]
];
return $data;
},
'time.json' => function() {
// $userId = Craft::$app->request->request->getParam('userId');
$data = [
'elementType' => User::class,
'paginate' => false,
'transformer' => function(User $user) {
return [
'date' => $user->winHistory::find()->orderBy(['id' => SORT_DESC])->one()
];
},
// 'criteria' => ['id' => $affiliateId, 'site' => $siteLanguage]
];
return $data;
}
]
];

Php parses function without create_function and without eval

I am trying to create a class to clean data for a brand before adding it to my database. As you can see I have added general filters (which can be used elsewhere). On the other hand, some fields will need a personalized cleaning. That's why I created 'function' in my array. My code is currently functional however the "create_function" function is deprecated and I would like to remove it but I cannot find an alternative without using "eval". Can you help me find a solution? Thank you.
<?php
class VehMarques
{
private static $fields_allowed = [
'_id' =>
[
'instanceof' => '\MongoDB\BSON\ObjectID',
],
'name' =>
[
'function' => 'if(!isset($name) && !isset($age)){return false;}',
],
'user' =>
[
'required',
'instanceof' => '\MongoDB\BSON\ObjectID',
],
'centre' =>
[
'required',
'instanceof' => '\MongoDB\BSON\ObjectID',
],
'time' =>
[
'instanceof' => 'MongoDB\BSON\UTCDateTime',
],
];
public static function add(array $fields)
{
$fields_options=array();
foreach(self::$fields_allowed as $key => $val)
{
foreach($val as $key1 => $val1)
{
if(in_array($val1, array('required')))
{
$fields_options[$val1][$key] = null;
}
else
{
$fields_options[$key1][$key] = $val1;
}
}
}
if(!empty(self::$fields_allowed) && !empty(array_diff_key($fields, self::$fields_allowed)))
{
return false;
}
if(!empty($fields_options['function']))
{
foreach($fields_options['function'] as $func)
{
$func = preg_replace('/\$([a-zA-Z0-9]+)/', '$fields[\'$1\']', $func);
if(create_function('$fields', $func)($fields) === false)
{
return false;
}
}
}
if(!empty($fields_options['required']) && !empty(array_diff_key($fields_options['required'], $fields)))
{
return false;
}
if(!empty($fields_options['instanceof']))
{
foreach($fields_options['instanceof'] as $key => $val)
{
if(!($fields[$key] instanceof $val))
{
return false;
}
}
}
if(!isset($fields['_id']))
{
$fields['_id'] = new \MongoDB\BSON\ObjectID();
}
if(!isset($fields['time']))
{
$fields['time'] = new MongoDB\BSON\UTCDateTime();
}
return true;
}
}
$insert_marque = array(
'_id' => new \MongoDB\BSON\ObjectID(),
'name' => 'Test',
'user' => new \MongoDB\BSON\ObjectID(),
'centre' => new \MongoDB\BSON\ObjectID(),
'time' => new MongoDB\BSON\UTCDateTime()
);
var_dump(VehMarques::add($insert_marque));
?>

How to show admin specific data in Laravel Tastyigniter(Online food ordering) system

I am using Laravel Tastyigniter system in which I want to show the locations name in dropdown in Menus module according to locations added by admin which is currently logged in.
For Example, If admin A added two locations such as location A and location B and
admin B added two locations such as location C and location D resp.
Note - The locations are getting saved in database with created_by column which is id of admin adding the location.
A) What supposed to happen -
If I logged in as admin A then in location dropdown Location A and Location B should get display
If I logged in as admin B then in location dropdown Location C and Location D should get display.
B) What is happening currently -
For both the admins all the 4 locations are getting displayed.
C) Following is the Code -
Here is Menus_model.php
<?php namespace Admin\Models;
use Admin\Traits\Locationable;
use Igniter\Flame\Database\Traits\Purgeable;
class Menus_model extends Model
{
use Purgeable;
use Locationable;
const LOCATIONABLE_RELATION = 'locations';
public $relation = [
'morphToMany' => [
'locations' => ['Admin\Models\Locations_model', 'name' =>
'locationable'],
],
];
protected $purgeable = ['locations'];
}
Here is menus_model.php which is present under models->config
<?php
$config['form']['tabs'] = [
'fields' => [
'locations' => [
'label' => 'Location',
'type' => 'relation',
'span' => 'right',
'valueFrom' => 'locations',
'nameFrom' => 'location_name',
'locationAware' => 'hide',
],
],
];
return $config;
Here is the Locations_model.php file code under models folder
<?php namespace Admin\Models;
use Admin\Traits\HasDeliveryAreas;
use Admin\Traits\HasWorkingHours;
use Igniter\Flame\Database\Attach\HasMedia;
use Igniter\Flame\Database\Traits\HasPermalink;
use Igniter\Flame\Database\Traits\Purgeable;
use Igniter\Flame\Location\Models\AbstractLocation;
use DB;
/**
* Locations Model Class
*
* #package Admin
*/
class Locations_model extends AbstractLocation
{
use HasWorkingHours;
use HasDeliveryAreas;
use HasPermalink;
use Purgeable;
use HasMedia;
const LOCATION_CONTEXT_SINGLE = 'single';
const LOCATION_CONTEXT_MULTIPLE = 'multiple';
protected $appends = ['location_thumb'];
protected $hidden = ['options'];
public $casts = [
'location_country_id' => 'integer',
'location_lat' => 'double',
'location_lng' => 'double',
'offer_delivery' => 'boolean',
'offer_collection' => 'boolean',
'delivery_time' => 'integer',
'collection_time' => 'integer',
'last_order_time' => 'integer',
'reservation_time_interval' => 'integer',
'reservation_stay_time' => 'integer',
'location_status' => 'boolean',
'options' => 'serialize',
'location_city' => 'integer',
'region_id'=>'integer',
];
public $relation = [
'hasMany' => [
'working_hours' => ['Admin\Models\Working_hours_model', 'delete' =>
TRUE],
'delivery_areas' => ['Admin\Models\Location_areas_model', 'delete'
=> TRUE],
'reviews' => ['Admin\Models\Reviews_model', 'delete' => TRUE],
],
'belongsTo' => [
'country' => ['System\Models\Countries_model', 'otherKey' =>
'country_id', 'foreignKey' => 'location_country_id'],
'city' => ['Admin\Models\City_model', 'otherKey' => 'city_id', 'foreignKey' => 'location_city'],
'region' => ['Admin\Models\Region_model', 'otherKey' => 'region_id', 'foreignKey' => 'region_id'],
],
'belongsToMany' => [
'tables' => ['Admin\Models\Tables_model', 'table' => 'location_tables'],
'cuisines' => ['Admin\Models\Cuisines_model', 'table' => 'location_cuisines'],
],
];
protected $purgeable = ['tables', 'delivery_areas','cuisines'];
public $permalinkable = [
'permalink_slug' => [
'source' => 'location_name',
'controller' => 'local',
],
];
public $mediable = [
'thumb',
'gallery' => ['multiple' => TRUE],
];
protected static $allowedSortingColumns = [
'distance asc', 'distance desc',
'reviews_count asc', 'reviews_count desc',
'location_id asc', 'location_id desc',
'location_name asc', 'location_name desc',
];
public $url;
protected static $defaultLocation;
public static function onboardingIsComplete()
{
if (!$defaultId = params('default_location_id'))
return FALSE;
if (!$model = self::isEnabled()->find($defaultId))
return FALSE;
return isset($model->getAddress()['location_lat'])
AND isset($model->getAddress()['location_lng'])
AND ($model->hasDelivery() OR $model->hasCollection())
AND isset($model->options['hours'])
AND $model->delivery_areas->where('is_default', 1)->count() > 0;
}
public function getWeekDaysOptions()
{
return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
}
//
// Events
//
protected function afterFetch()
{
$this->parseOptionsValue();
}
protected function beforeSave()
{
$this->parseOptionsValue();
}
protected function afterSave()
{
$this->performAfterSave();
}
protected function beforeDelete()
{
Location_tables_model::where('location_id', $this->getKey())->delete();
Location_cuisines_model::where('location_id', $this->getKey())->delete();
}
//
// Scopes
//
/**
* Scope a query to only include enabled location
*
* #return $this
*/
public function scopeIsEnabled($query)
{
return $query->where('location_status', 1);
}
public function scopeListFrontEnd($query, array $options = [])
{
extract(array_merge([
'page' => 1,
'pageLimit' => 20,
'sort' => null,
'search' => null,
'latitude' => null,
'longitude' => null,
], $options));
if ($latitude AND $longitude)
$query->selectDistance($latitude, $longitude);
$searchableFields = ['location_name', 'location_address_1', 'location_address_2', 'location_city',
'location_state', 'location_postcode', 'description'];
if (!is_array($sort)) {
$sort = [$sort];
}
foreach ($sort as $_sort) {
if (in_array($_sort, self::$allowedSortingColumns)) {
$parts = explode(' ', $_sort);
if (count($parts) < 2) {
array_push($parts, 'desc');
}
[$sortField, $sortDirection] = $parts;
$query->orderBy($sortField, $sortDirection);
}
}
$search = trim($search);
if (strlen($search)) {
$query->search($search, $searchableFields);
}
return $query->paginate($pageLimit, $page);
}
//
// Accessors & Mutators
//
public function getLocationThumbAttribute()
{
return $this->hasMedia() ? $this->getThumb() : null;
}
public function getDeliveryTimeAttribute($value)
{
return (int)$value;
}
public function getCollectionTimeAttribute($value)
{
return (int)$value;
}
public function getFutureOrdersAttribute($value)
{
return (bool)$value;
}
public function getReservationTimeIntervalAttribute($value)
{
return (int)$value;
}
//
// Helpers
//
public function setUrl($suffix = null)
{
if (is_single_location())
$suffix = '/menus';
$this->url = site_url($this->permalink_slug.$suffix);
}
public function hasGallery()
{
return $this->hasMedia('gallery');
}
public function getGallery()
{
$gallery = array_get($this->options, 'gallery');
$gallery['images'] = $this->getMedia('gallery');
return $gallery;
}
public function parseOptionsValue()
{
$value = #unserialize($this->attributes['options']) ?: [];
$this->parseHoursFromOptions($value);
$this->parseAreasFromOptions($value);
$this->attributes['options'] = #serialize($value);
return $value;
}
public function listAvailablePayments()
{
$result = [];
$payments = array_get($this->options, 'payments', []);
$paymentGateways = Payments_model::listPayments();
foreach ($paymentGateways as $payment) {
if ($payments AND !in_array($payment->code, $payments)) continue;
$result[$payment->code] = $payment;
}
return collect($result);
}
public function performAfterSave()
{
$this->restorePurgedValues();
if (array_key_exists('hours', $this->options)) {
$this->addOpeningHours($this->options['hours']);
}
if (array_key_exists('delivery_areas', $this->attributes)) {
$this->addLocationAreas($this->attributes['delivery_areas']);
}
if (array_key_exists('tables', $this->attributes)) {
$this->addLocationTables($this->attributes['tables']);
}
if (array_key_exists('cuisines', $this->attributes)) {
$this->addLocationCuisines($this->attributes['cuisines']);
}
}
public static function getDefault()
{
if (self::$defaultLocation !== null) {
return self::$defaultLocation;
}
$defaultLocation = self::isEnabled()->where('location_id', params('default_location_id'))->first();
if (!$defaultLocation) {
$defaultLocation = self::isEnabled()->first();
if ($defaultLocation) {
params('default_location_id', $defaultLocation->getKey());
params()->save();
}
}
return self::$defaultLocation = $defaultLocation;
}
/**
* Create a new or update existing location tables
*
* #param array $tables
*
* #return bool
*/
public function addLocationTables($tables = [])
{
return $this->tables()->sync($tables);
}
public function addLocationCuisines($cuisines = [])
{
return $this->cuisines()->sync($cuisines);
}
}
Here is locations_model.php which is present under models->config folder
<?php
$config['form']['tabs'] = [
'defaultTab' => 'lang:admin::lang.locations.text_tab_general',
'fields' => [
'location_name' => [
'label' => 'lang:admin::lang.label_name',
'type' => 'text',
'span' => 'left',
],
'location_email' => [
'label' => 'lang:admin::lang.label_email',
'type' => 'text',
'span' => 'right',
],
'location_telephone' => [
'label' => 'lang:admin::lang.locations.label_telephone',
'type' => 'text',
'span' => 'left',
],
'location_status' => [
'label' => 'lang:admin::lang.label_status',
'type' => 'switch',
'default' => 1,
'span' => 'right',
],
'created_by' => [
'type' => 'hidden',
'default' => isset($_SESSION['user_id']) ? $_SESSION['user_id'] : '',
],
],
];
return $config;
UPDATED
Basically I want to diaply locations in menus form , Currently in menus form all the locations are getting display and the code for this is mentioned below
This is Menus.php controller
<?php namespace Admin\Controllers;
use Admin\Classes\AdminController;
use Admin\Models\Menu_options_model;
use AdminMenu;
use ApplicationException;
class Menus extends AdminController
{
public $implement = [
'Admin\Actions\ListController',
'Admin\Actions\FormController',
'Admin\Actions\LocationAwareController',
];
public $listConfig = [
'list' => [
'model' => 'Admin\Models\Menus_model',
'title' => 'lang:admin::lang.menus.text_title',
'emptyMessage' => 'lang:admin::lang.menus.text_empty',
'defaultSort' => ['menu_id', 'DESC'],
'configFile' => 'menus_model',
],
];
protected $requiredPermissions = 'Admin.Menus';
public function __construct()
{
parent::__construct();
AdminMenu::setContext('menus');
}
public function edit_onChooseMenuOption($context, $recordId)
{
$menuOptionId = post('Menu._options');
if (!$menuOption = Menu_options_model::find($menuOptionId))
throw new ApplicationException('Please select a menu option to
attach');
$model = $this->asExtension('FormController')->formFindModelObject($recordId);
$menuItemOption = $model->menu_options()->create(['option_id' => $menuOptionId]);
$menuOption->option_values()->get()->each(function ($model) use ($menuItemOption) {
$menuItemOption->menu_option_values()->create([
'menu_option_id' => $menuItemOption->menu_option_id,
'option_value_id' => $model->option_value_id,
'new_price' => $model->price,
]);
});
$model->reload();
$this->asExtension('FormController')->initForm($model, $context);
flash()->success(sprintf(lang('admin::lang.alert_success'), 'Menu item option attached'))->now();
$formField = $this->widgets['form']->getField('menu_options');
return [
'#notification' => $this->makePartial('flash'),
'#'.$formField->getId('group') => $this->widgets['form']->renderField($formField, [
'useContainer' => FALSE,
]),
];
}
}
Below is Locaations.php controller
<?php namespace Admin\Controllers;
use Admin\Facades\AdminLocation;
use Admin\Models\Locations_model;
use AdminMenu;
use Exception;
use Geocoder;
class Locations extends \Admin\Classes\AdminController
{
public $implement = [
'Admin\Actions\ListController',
'Admin\Actions\FormController',
];
public $listConfig = [
'list' => [
'model' => 'Admin\Models\Locations_model',
'title' => 'lang:admin::lang.locations.text_title',
'emptyMessage' => 'lang:admin::lang.locations.text_empty',
'defaultSort' => ['location_id', 'DESC'],
'configFile' => 'locations_model',
],
];
protected $requiredPermissions = 'Admin.Locations';
public function __construct()
{
parent::__construct();
AdminMenu::setContext('locations', 'restaurant');
}
public function remap($action, $params)
{
if ($action != 'settings' AND AdminLocation::check())
return $this->redirect('locations/settings');
return parent::remap($action, $params);
}
public function settings($context = null)
{
if (!AdminLocation::check())
return $this->redirect('locations');
$this->asExtension('FormController')->edit('edit', $this-
>getLocationId());
}
public function index_onSetDefault($context = null)
{
$defaultId = post('default');
if (Locations_model::updateDefault(['location_id' => $defaultId])) {
flash()->success(sprintf(lang('admin::lang.alert_success'),
lang('admin::lang.locations.alert_set_default')));
}
return $this->refreshList('list');
}
public function settings_onSave($context = null)
{
try {
$this->asExtension('FormController')->edit_onSave('edit',
params('default_location_id'));
return $this->refresh();
}
catch (Exception $ex) {
$this->handleError($ex);
}
}
public function listOverrideColumnValue($record, $column, $alias = null)
{
if ($column->type != 'button')
return null;
if ($column->columnName != 'default')
return null;
$attributes = $column->attributes;
$column->iconCssClass = 'fa fa-star-o';
if ($record->getKey() == params('default_location_id')) {
$column->iconCssClass = 'fa fa-star';
}
return $attributes;
}
public function formExtendQuery($query)
{
if ($locationId = $this->getLocationId())
$query->where('location_id', $locationId);
}
public function formAfterSave($model)
{
if (post('Location.options.auto_lat_lng')) {
if ($logs = Geocoder::getLogs())
flash()->error(implode(PHP_EOL, $logs))->important();
}
}
}
Views
Now the n views folder there is folder names menus and under that folder there is create.php file for displaying create menu form
The code in views->menus->create.php file is below
<div class="row-fluid">
<?= form_open(current_url(),
[
'id' => 'edit-form',
'role' => 'form',
'method' => 'POST',
]
); ?>
<?= $this->renderForm(); ?>
<?= form_close(); ?>
</div>
FormController
Now the renderForm() function is present at path app/admin/actions/FormController.php which we have defined in Locations and Menus controller under public $implement = ['Admin\Actions\FormController'];
Ther renderForm() function is as follow
public function renderForm($options = [])
{
if (!$this->formWidget) {
throw new Exception(lang('admin::lang.form.not_ready'));
}
if (!is_null($this->toolbarWidget)) {
$form[] = $this->toolbarWidget->render();
}
$form[] = $this->formWidget->render($options);
return implode(PHP_EOL, $form);
}
Widgets
At last the there are widgets for input fields like select, text, radio, checkbox etc. In our case we have widget name field_selectlist, which is present at path app/admin/widgets/form/field_selectlist.php
The field_selectlist.php file has code as below
<?php
$fieldOptions = $field->options();
//print_r($fieldOptions);die; All the locations are displaying here.
$isCheckboxMode = $field->config['mode'] ?? 'checkbox';
$selectMultiple = $isCheckboxMode == 'checkbox';
$checkedValues = (array)$field->value;
$enableFilter = (count($fieldOptions) > 20);
?>
<div class="control-selectlist">
<select
data-control="selectlist"
id="<?= $field->getId() ?>"
name="<?= $field->getName() ?><?= $selectMultiple ? '[]' : '' ?>"
<?php if ($field->placeholder) { ?>data-non-selected-text="<?=
e(lang($field->placeholder)) ?>"<?php } ?>
<?= $selectMultiple ? 'multiple="multiple"' : '' ?>
data-enable-filtering="<?= $enableFilter; ?>"
data-enable-case-insensitive-filtering="<?= $enableFilter; ?>"
<?= $field->getAttributes() ?>>
<?php if ($field->placeholder) { ?>
<option value=""><?= e(lang($field->placeholder)) ?></option>
<?php } ?>
<?php
foreach ($fieldOptions as $value => $option) { ?>
<?php
if (!is_array($option)) $option = [$option];
if ($field->disabled AND !in_array($value, $checkedValues)) continue;
?>
<option
<?= in_array($value, $checkedValues) ? 'selected="selected"' : '' ?>
value="<?= $value ?>">
<?= e(is_lang_key($option[0]) ? lang($option[0]) : $option[0]) ?>
<?php if (isset($option[1])) { ?>
<span><?= e(is_lang_key($option[1]) ? lang($option[1]) :
$option[1]) ?></span>
<?php } ?>
</option>
<?php } ?>

Create new record using 2amigos SelectizeDropDownList in Yii2

I am trying to implement the 2amigos SelectizeDropDownList widget in a form to add new values to a table directly within the dropdown.
I am using the model Book and the Model Author so basically want to be able to add a new author in the book form.
This is the book controller at the update function:
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['index']);
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}
This is the form:
<?=
$form->field($model, 'author_id')->widget(SelectizeDropDownList::className(), [
// calls an action that returns a JSON object with matched
// tags
'loadUrl' => ['author/list'],
'value' => $authors,
'items' => \yii\helpers\ArrayHelper::map(\common\models\author::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
'options' => [
'class' => 'form-control',
'id' => 'id'
],
'clientOptions' => [
'valueField' => 'id',
'labelField' => 'name',
'searchField' => ['name'],
'autosearch' => ['on'],
'create' => true,
'maxItems' => 1,
],
])
?>
And this is the function author controller:
public function actionList($query) {
$models = Author::findAllByName($query);
$items = [];
foreach ($models as $model) {
$items[] = ['id' => $model->id, 'name' => $model->name];
}
Yii::$app->response->format = \Yii::$app->response->format = 'json';
return $items;
}
The form works fine to load, filter, search and add new items.
But it is not inserting the new typed attribute in the author table.
Do I need to add something in the book controller?
How can I check if it is a new value or a change of an existing author?
Thanks a lot
I made it work with the following code, not sure the most elegant because i am checking the if the author_id is a number or a string.
In my case the author won't be a number anyway.
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
$x = Yii::$app->request->post('Book');
$new_author = $x['author_id'];
if (!is_numeric($new_author)) {
$author = new Author();
$author->name = $new_author;
$author->save();
$model->author_id = $author->id;
}
if ($model->save()) {
return $this->redirect(['index']);
}
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}

Zend Framework 2 filter / validate array of contents

How do I apply a filter to a field element with the contents of an array?
For example:
$this->add(
"name" => "tags",
"type" => "text",
"filter" => array(
array("name" => "StripTags"),
array("name" => "StringTrim")
)
);
$tags[0] = "PHP";
$tags[1] = "CSS";
If I attempt to filter I receive an error saying a scalar object is excepted, array given.
This isn't really possible at this time. Your best bet is to use a Callback filter and filter each Item individually. Something like this
$this->add(
"name" => "tags",
"type" => "text",
"filter" => array(
array("name" => "Callback", "options" => array(
"callback" => function($tags) {
$strip = new \Zend\Filter\StripTags();
$trim = new \Zend\Filter\StringTrim();
foreach($tags as $key => $tag) {
$tag = $strip->filter($tag);
$tag = $trim->filter($tag);
$tags[$key] = $tag;
}
return $tags;
}))
)
);
I realize this is old but you can specify the input type as ArrayInput and InputFilter will handle it as expected:
"name" => "tags",
"type" => "Zend\\InputFilter\\ArrayInput", // Treat this field as an array of inputs
"filter" => array(
array("name" => "StripTags"),
array("name" => "StringTrim")
)
I've made a CollectionValidator that applies an existing validator to all items in an array.
I'm using it with Apigility as such:
'input_filter_specs' => [
'Api\\Contact\\Validator' => [
[
'name' => 'addresses',
'required' => false,
'filters' => [],
'validators' => [
[
'name' => 'Application\\Validator\\CollectionValidator',
'options' => ['validator' => 'Api\\Address\\Validator']
]
],
'description'=> 'List of addresses for contact'
],
[
'name' => 'birthdate',
# ...
]
],
]
I'm not sure if this is how you would use a validator inside a controller, but probably something like this:
new Collection(array('validator' => 'Zend\Validator\CreditCard'))
It returns validation_messages per index. Let's say it was REST POST request to create a contact, it indicates that the second address contains an error in the zipcode field.
{
"detail": "Failed Validation",
"status": 422,
"title": "Unprocessable Entity",
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
"validation_messages": {
"addresses": {
"1": {
"zipcode": {
"notAlnum": "The input contains characters which are non alphabetic and no digits"
}
}
},
"birthdate": {
"dateInvalidDate": "The input does not appear to be a valid date"
}
}
}
The Collection validator:
<?php
namespace Application\Validator;
class Collection extends \Zend\Validator\AbstractValidator implements \Zend\ServiceManager\ServiceLocatorAwareInterface {
protected $serviceLocator;
protected $em;
protected $messages;
protected $options = array(
'validator' => null
);
public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator->getServiceLocator();
}
public function getServiceLocator() {
return $this->serviceLocator;
}
public function isValid($array) {
$inputFilterManager = $this->getServiceLocator()->get('inputfiltermanager');
$validatorName = $this->getOption('validator');
$this->messages = [];
$isvalid = true;
foreach($array as $index => $item) {
$inputFilter = $inputFilterManager->get($validatorName);
$inputFilter->setData($item);
$isvalid = $isvalid && $inputFilter->isValid($item);
foreach($inputFilter->getMessages() as $field => $errors) {
foreach($errors as $key => $string) {
$this->messages[$index][$field][$key] = $string;
}
}
}
return $isvalid;
}
public function getMessages() {
return $this->messages;
}
}
Current limitations:
No support for translation
Only the errors for the first erroneous array item are returned.
I had a very simular issue and I was able to solve it with Zend\Form\Element\Collection.
With the Collection Element I was able to validate inputs that looks like
$post = [
[
'idUser' => 1,
'address' => 'foo street',
],
[
'idUser' => 2,
'address' => 'bar street',
],
];
For a more detailed explanation check out the Zend Documentation and this working example

Categories