Laravel 5.5 - Validation of a string inside an object that is inside an array - laravel-5.5

I have the request:
`array:2 [
"alt_tags" => "1"
"name_pattern" => array:2 [
0 => "{"label":"Main Title","value":"main_title"}"
1 => "{"label":"Store Name","value":"store_name"}"
]
]`
In the class Request, I tried to validate the lines inside the object in the following way:
`$labels = \implode(',', [
'Main Title',
'Store Name',
]);
$values = \implode(',', [
'main_title',
'store_name',
]);
return [
'alt_tags' => 'required|boolean',
'name_pattern' => 'required|array|min:0|max:2',
'name_pattern.*.label' => "sometimes|string|in:{$labels}",
'name_pattern.*.value' => "sometimes|string|in:{$values}",
];`
But since the string is inside the object, then there is no way to get through the file_name_pattern. *.label:
data_get(request()->all(), 'name_pattern.0') // "{"label":"Main Title","value":"main_title"}"
data_get(request()->all(),'name_pattern.0.label'); // return NULL

Related

Drupal - Ajax validation only works when I am connected

I am new in Drupal world and I'm trying to use the Drupal From API to create a contact form with Ajax validation.
I'm facing 2 issues:
My following form (see below) works well but only when the user is connected as administrator. When I am not logged in as an administrator, it does not work.
I also created a custom Block to display my Form, unfortunately the block does not appear when I am logged in.
I try to follow this guide whitout success: https://panshul1410.blog/2018/07/15/drupal-8-ajax-validations-for-custom-form/
Here is the form I created:
<?php
namespace Drupal\dalcom_contact\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class DalcomContactForm extends FormBase {
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'dlcm_cform';
}
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
// Disable caching.
$form['#cache']['max-age'] = 0;
// Disable browser HTML5 validation.
$form['#attributes']['novalidate'] = 'novalidate';
// This will generate an anchor scroll to the form when submitting.
$form['#action'] = '#dlcm_cform';
$form['mail_visitor'] = [
'#type' => 'email',
'#placeholder' => t('E-mail*'),
'#description' => 'Your mail',
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::mailValidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['message_visitor'] = [
'#type' => 'textarea',
'#placeholder' => t('Message*'),
'#description' => 'Your message',
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::messValidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['accept_box'] = [
'#type' => 'checkbox',
'#title' => $this
->t('I accept the CME terms of use'),
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::acceptboxalidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['candidate_copy'] = [
'#type' => 'checkbox',
'#title' => t('Send me a copy of my message.'),
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'button',
'#value' => $this->t('Send'),
'#ajax' => [
'event' => 'click',
'progress' => [
'type' => 'throbber',
'message' => 'Sending...',
],
],
];
$form['#theme'] = 'dalcom_contact_theme';
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
foreach ($form_state->getValues() as $key => $value) {
drupal_set_message($key . ': ' . $value);
}
}
public function mailValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (!$form_state->getValue('mail_visitor') || empty($form_state->getValue('mail_visitor'))) {
$text = 'No email registered';
$color = 'red';
}
elseif (!filter_var($form_state->getValue('mail_visitor'), FILTER_VALIDATE_EMAIL)) {
$text = 'Invalid email address';
$color = 'red';
}
else {
$text = 'Valid mail';
$color = 'green';
}
$ajax_response->addCommand(new HtmlCommand('#edit-mail-visitor--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-mail-visitor--description', 'css', ['color', $color]));
return $ajax_response;
}
public function messValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (!$form_state->getValue('message_visitor') || empty($form_state->getValue('message_visitor'))) {
$text = 'No messages written';
$color = 'red';
}
elseif (strlen($form_state->getValue('message_visitor')) < 6) {
$text = 'At least 7 characters';
$color = 'red';
}
else {
$text = 'Messages written';
$color = 'green';
}
$ajax_response->addCommand(new HtmlCommand('#edit-message-visitor--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-message-visitor--description', 'css', ['color', $color]));
return $ajax_response;
}
public function acceptboxValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (empty($form_state->getValue('accept-box'))) {
$text = 'You must accept our termes of use to continue';
$color = 'red';
}
$ajax_response->addCommand(new HtmlCommand('#edit-accept-box--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-accept-box--description', 'css', ['color', $color]));
return $ajax_response;
}
}
It works very well. But Ajax validation only works when I am connected. When I am not logged in as an administrator, it does not work.
Here is the block to display the form in my footer.
<?php
namespace Drupal\dalcom_contact_block\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormInterface;
/**
* Provides a 'dalcom contact' block.
*
* #Block(
* id = "dalcom_contact_block",
* admin_label = #Translation("Dalcom Contact Block"),
* category = #Translation("Block du formulaire Dalcom Contact")
* )
*/
class DalcomContactBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
$form = \Drupal::formBuilder()->getForm('\Drupal\dalcom_contact\Form\DalcomContactForm');
return $form;
}
}
As explain upper, the block does not appear when I am logged in. I have access to the form only through the path I defined in module.routing.yml. And when it appears (so when I'm not logged in), Ajax doesn't work on this block form either.
Does anyone have any idea what could cause this?
Please help me.
Edited:
Here is the module.routing.yml file
dalcom_contact.form:
path: '/contact-us.html'
defaults:
_title: 'Contact Us'
_form: 'Drupal\dalcom_contact\Form\DalcomContactForm'
requirements:
_permission: 'access content'
block.info.yml
name: Dalcom Contact Block
type: module
description: Block du formulaire Dalcom Contact.
core: 8.x
package: Custom
dependencies:
- node
- block
Updated:
I notice that when the form does not appear (when I am connected), it appears in its place
<span data-big-pipe-placeholder-id="…"></span>
I've done some research on this, but I can't get out of it. Maybe this will help you to know what's going on.
I finally found the solution on the Drupal forum. I put it here, maybe it will help in the future a novice who will be in my case.
What was missing was simply a list of essential javascripts for anonymous users. It seems that at one time it wasn't necessary, but now we have to add them otherwise they wouldn't be loaded for anonymous users.
So what I needed to do was add this to my theme.libraries.yml file
my_scripts:
version: VERSION
js:
js/scripts.js: {}
dependencies:
- core/jquery
- core/drupal.ajax
- core/drupal
- core/drupalSettings
- core/jquery.once

Set values for default address fields in Drupal 8

I need to set values for default address fields(langcode, country_code, administrative_area, address_locality ect.) when I create a node. I used below code in the submitForm function of a Form class which is extends by Drupal\Core\Form\FormBase class. But it not works for me.
$venueNode = Node::create([
'type' => 'venue',
'title' => 'Venue',
'field_address' => [
'country_code' => 'US',
'address_line1' => '1098 Alta Ave',
'locality' => 'Mountain View',
'administrative_area' => 'US-CA',
'postal_code' => '94043',
],
]);
$venueNode->save();
I made a mistake here. There should be a 0 index for field_address. Therefore the code should be like below.
$venueNode = Node::create([
'type' => 'venue',
'title' => 'Venue',
'field_address' => [
0 => [
'country_code' => 'US',
'address_line1' => '1098 Alta Ave',
'locality' => 'Mountain View',
'administrative_area' => 'US-CA',
'postal_code' => '94043',
],
],
]);
$venueNode->save();

Sets a collection of query parameters for the query being constructed

I'm trying to build a query by using array of options, as you see this is my array options:
$sort = $this->getParam('sort', 'creation_date');
$order = $this->getParam('order', 'desc');
$options = [
'sort' => [$sort => $order],
'filters' => [
[
'field' => 'state',
'operator' => 'LIKE',
'bind_name' => 'state1',
'value' => 'read',
'type' => 'OR'
],
[
'field' => 'state',
'operator' => 'LIKE',
'bind_name' => 'state2',
'value' => 'green'
]
]
];
As result i have this query:
SELECT COUNT(*) FROM `mytabel` `mytabel` INNER JOIN state_type t ON t.id_state_type = `mytabel`.id_state_type WHERE (`mytabel`.`state` LIKE :state1) **AND** (`mytabel`.`state` LIKE :state2) ORDER BY `mytabel`.`creation_date` desc
Params
state1 %read%
state2 %green%
My question is how i can have OR instead of AND in my query (array options)? because as result i want to have both of them (state1 %read% ,state2 %green%).
Thank you,

ajax submit forms subscribe simpleNews in drupal8

How do I make Ajax send subscriptions in the subscription block for the SimpleNews module?
I do this, but it does not work.
function simpleNewsAlter_simplenews_subscriptions_block_ico_subscription_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
$form['system_messages'] = [
'#markup' => '<div id="' . Html::getClass($form_id) . '-messages"></div>',
'#weight' => -100,
];
$form['actions']['subscribe']['#ajax'] = [
'callback' => '\Drupal\simplenews\Form\SubscriptionsBlockForm::submitSubscribe',
'event' => 'click',
'progress' => [
'type' => 'throbber',
],
];
}
I tried with the below code, Ajax submission is working fine. but, How can i show the error messages inside the block?
use Drupal\Core\Form\FormStateInterface;
use Drupal\simplenews\Form\SubscriptionsFormBase;
use Drupal\simplenews\SubscriberInterface;
use Drupal\simplenews\Subscription\SubscriptionManager;
function MODULENAME_form_FORM_ID_alter(&$form, FormStateInterface $form_state, $form_id) {
$form['message'] = [
'#type' => 'markup',
'#markup' => '<div id="result-message" class="result_message"></div>'
];
$form['actions']['subscribe']['#ajax'] = [
'callback' => '\Drupal\simplenews\Form\SubscriptionsFormBase::submitForm',
//'callback' => array($this, '\Drupal\simplenews\Form\SubscriptionsBlockForm::submitSubscribe'),
'event' => 'click',
'method' => 'replace',
'effect' => 'fade',
'disable-refocus' => FALSE,
'wrapper' => 'result-message', //Html::getClass($form_id) . '-messages',
//'callback' => '\Drupal\custom\Form\FormController::setMessage',
'progress' => [
'type' => 'throbber',
],
//'#attributes' => array('onclick' => 'return (false);'),
];
}
use Drupal\Core\Ajax\HtmlCommand
function MODULENAME_form_FORM_ID_alter(&$form, FormStateInterface
$form_state, $form_id) {
$form['#prefix'] = '<div class="text-msg">';
$form['#suffix'] = '<span class="simplenews-result-message"></span>
</div>';
$form['actions']['subscribe']['#ajax'] = [
'event' => 'click',
'method' => 'replace',
'effect' => 'fade',
'disable-refocus' => FALSE,
'callback' => 'custom_inscription_simplenews_submit',
'progress' => [
'type' => 'throbber',
],
'options' => ['query' => ['ajax_form' => 1]],
];
// Rebuild the form
$form_state->setRebuild(TRUE);
}
function MODULENAME_simplenews_submit(&$form, &$form_state) {
$email = $form['mail']['widget'][0]['value']["#value"];
if (!\Drupal::service('email.validator')->isValid($email)) {
$msg = t("The email you entered is not valid");
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('.simplenews-result-message',
$msg));
}else{
$msg = t("Thank you for subscribing!");
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('.simplenews-result-message',
$msg));
}
return $response;
}
The below code worked for me to display the default status message from the Simplenews module. In a custom module's .module file include the below code.
use Drupal\Core\Ajax\HtmlCommand
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Form\FormStateInterface;
function MODULENAME_form_FORM_ID_alter(&$form, FormStateInterface
$form_state, $form_id) {
$form['#prefix'] = '<div class="text-msg">';
$form['#suffix'] = '<span class="simplenews-result-message"></span>
</div>';
$form['actions']['subscribe']['#ajax'] = [
'event' => 'click',
'method' => 'replace',
'effect' => 'fade',
'disable-refocus' => FALSE,
'callback' => 'custom_inscription_simplenews_submit',
'progress' => [
'type' => 'throbber',
],
'options' => ['query' => ['ajax_form' => 1]],
];
// Rebuild the form
$form_state->setRebuild(TRUE);
}
function MODULENAME_simplenews_submit(&$form, &$form_state) {
$email = $form['mail']['widget'][0]['value']["#value"];
if (!\Drupal::service('email.validator')->isValid($email)) {
$msg = t("The email you entered is not valid");
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('.simplenews-result-message',
$msg));
}else{
$message = [
'#theme' => 'status_messages',
'#message_list' => \Drupal::messenger()->all(),
];
$messages = \Drupal::service('renderer')->render($message);
$status = $messages;
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('.simplenews-result-message',
$status));
return $response;
}

How to customise the Regex validation messages in a Zend\Form keeping them reusable?

The default validation error message for Regex is
"The input does not match against pattern '%pattern%'"
I can replace it by a custom one like
"Please make an input according to the pattern '%pattern%'"
But then I still have a not really user-friendly message with the internal regex in it. I also can write
"Only capital letters are allowed"
But in this case I need to write a new message for every single regex field.
Is it possible / How to create own, but still flexible/reusable/parameterizable messages?
An example of what I want:
public function getInputFilterSpecification()
{
return [
'foo' => [
'validators' => [
[
'name' => 'Regex',
'options' => [
'pattern' => '/^[A-Z0-9:]*$/',
'pattern_user_friendly' => 'capital letters, numbers, and colons',
'message' => 'The input may only contain the following characters: %pattern_user_friendly%.'
]
],
]
],
'bar' => [
'validators' => [
[
'name' => 'Regex',
'options' => [
// new pattern
'pattern' => '/^[A-Z~:\\\\]*$/',
// new user friendly pattern description
'pattern_user_friendly' => 'capital letters, tildes, colons, and backslashes',
// still the same message
'message' => 'The input may only contain the following characters: %pattern_user_friendly%.'
]
],
]
],
];
}
The solution is to create a custom Validator (extending the Regex), to extend there the list of messageVariables, and to add the logic for setting the value as a property:
class Regex extends ZendRegex
{
protected $patternUserFriendly;
public function __construct($pattern)
{
// s. https://github.com/zendframework/zend-validator/blob/master/src/Regex.php#L34-L36
$this->messageVariables['patternUserFriendly'] = 'patternUserFriendly';
$this->messageTemplates[self::NOT_MATCH] =
'The input may only contain the following characters: %patternUserFriendly%.'
;
parent::__construct($pattern);
if (array_key_exists('patternUserFriendly', $pattern)) {
$this->patternUserFriendly = $pattern['patternUserFriendly'];
}
}
}
class MyFieldset extends ZendFieldset implements InputFilterProviderInterface
{
...
public function init()
{
parent::init();
$this->add(
[
'type' => 'text',
'name' => 'foo',
'options' => [
'label' => _('foo')
]
]);
$this->add(
[
'type' => 'text',
'name' => 'bar',
'options' => [
'label' => _('bar')
]
]);
}
public function getInputFilterSpecification()
{
return [
'bar' => [
'validators' => [
[
'name' => 'MyNamespace\Validator\Regex',
'options' => [
'pattern' => '/^[a-zA-z]*$/',
'patternUserFriendly' => '"a-z", "A-Z"'
]
]
]
]
];
}
}