Symfony2 EWZRecaptchaBundle never validate recaptcha field - validation

I'm using Symfony 2.7 and I'm trying to use EWZRecaptchaBundle (dev-master) in my registration form. I have followed the steps of documentation but it's not work, never validate the recaptcha field.
I've configured the bundle:
ewz_recaptcha:
public_key: my_public_key
private_key: my_private_key
locale_key: %kernel.default_locale%
I've added recaptcha in my class Register:
// ...
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints as Recaptcha;
class Register
{
// ...
/**
* #Recaptcha\IsTrue
*/
public $recaptcha;
// ...
}
and in my RegisterType:
// ...
class RegisterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
->add('recaptcha', 'ewz_recaptcha');
}
public function getName()
{
return 'register';
}
}
and in my form template:
{# ... #}
{{ form_widget(form.recaptcha) }}
{# ... #}
But when I submit the form, never validate recaptcha field and never show error message "This value is not a valid captcha." although I don't check it. Is it necessary to do something in the controller that get the form submit?
Thanks.

Found the solution. The key is not to use AJAX. Set the config.yml and the RegisterType as follows:
In app/config.yml you should set the following:
ewz_recaptcha:
public_key: public_key_here
private_key: private_key_here
locale_key: '%kernel.default_locale%'
enabled: true
ajax: false
Inside the RegisterType you should have:
->add('recaptcha', EWZRecaptchaType::class,
[
'label' => 'Captcha check:',
'mapped' => false,
'constraints' => [
new Recaptcha()
],
'attr' => [
'options' => [
'type' => 'image',
'defer' => false,
'async' => false,
'size' => 2
]
]
])

I suggest to use gregwar captcha bundle , it is a powerful bundle and easy to use
https://github.com/Gregwar/CaptchaBundle

Related

In listing page of users in the column of action want add a change_password link and its process of working

I am using laravel-backpack 4.0. want to add a password change link with a page and all the functionality with validation and all, to a listing of users like edit, in the Action column.
It seems a bit odd to want another page where you can update only the password when the package's built in user crud lets you update that, and all the other user fields. That said, assuming you have your reasons (and that I've understood the usage correctly), one approach would be to use the users addon package suggested but then make a second CRUD controller for the user model that only supports the "update" operation and only allows editing the password.
NOTE
This is untested so there might be some minor issues to iron out, but the approach is sound.
Install and configure the users addon package. Then, create a second controller for users but edit such that only the "update" action is allowed and only the password and password confirmation fields are editable. We'll make the name and email read only so you can see who its for but cant edit those fields. You can make those fields hidden if you want, or remove them, but if you remove them, note that you'll need to create a custom request class and update the rules to not require those fields on submission.
<?php
namespace App\Http\Controllers;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Http\Requests\CrudRequest;
use EduardoArandaH\UserManager\app\Http\Requests\UserStoreCrudRequest as StoreRequest;
use EduardoArandaH\UserManager\app\Http\Requests\UserUpdateCrudRequest as UpdateRequest;
class UserPasswordCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation { update as traitUpdate; }
public function setup()
{
$this->crud->setModel(config('backpack.permissionmanager.models.user'));
$this->crud->setEntityNameStrings('User Password', 'User Passwords');
$this->crud->setRoute(backpack_url('userPasswords'));
$this->crud->denyAccess('create');
$this->crud->denyAccess('list');
$this->crud->denyAccess('delete');
$this->crud->denyAccess('reorder');
$this->crud->denyAccess('revisions');
}
public function setupUpdateOperation()
{
$this->addUserFields();
$this->crud->setValidation(UpdateRequest::class);
}
/**
* Update the specified resource in the database.
*
* #return \Illuminate\Http\RedirectResponse
*/
public function update()
{
$this->crud->setRequest($this->crud->validateRequest());
$this->crud->setRequest($this->handlePasswordInput($this->crud->getRequest()));
$this->crud->unsetValidation(); // validation has already been run
return $this->traitUpdate();
}
/**
* Handle password input fields.
*/
protected function handlePasswordInput($request)
{
// Remove fields not present on the user.
$request->request->remove('password_confirmation');
$request->request->remove('roles_show');
$request->request->remove('permissions_show');
// Encrypt password if specified.
if ($request->input('password')) {
$request->request->set('password', Hash::make($request->input('password')));
} else {
$request->request->remove('password');
}
return $request;
}
protected function addUserFields()
{
$this->crud->addFields([
[
'name' => 'name',
'label' => trans('backpack::permissionmanager.name'),
'type' => 'text',
'attributes' => ['readonly' => 'readonly'],
],
[
'name' => 'email',
'label' => trans('backpack::permissionmanager.email'),
'type' => 'email',
'attributes' => ['readonly' => 'readonly'],
],
[
'name' => 'password',
'label' => trans('backpack::permissionmanager.password'),
'type' => 'password',
],
[
'name' => 'password_confirmation',
'label' => trans('backpack::permissionmanager.password_confirmation'),
'type' => 'password',
],
]);
}
}
Load the route for the new controller:
<?php
Route::group([
'namespace' => 'App\Http\Controllers',
'prefix' => config('backpack.base.route_prefix', 'admin'),
'middleware' => ['web', backpack_middleware()],
], function () {
Route::crud('userPasswords', 'UserPasswordCrudController');
});
Create a custom button at resources/views/vendor/backpack/crud/buttons/update_password.blade.php with this content:
#if ($crud->hasAccess('update'))
<!-- Single edit button -->
<i class="la la-edit"></i>Edit Password
#endif
Finally, in your normal user crud controller (or whatever controller you want the button in) add the button to the line stack in your controller's setupListOperation method:
public function setupListOperation()
{
$this->crud->addButtonFromView('line', 'update_password', 'view', 'end');
// ... normal setup code
}

Paginate results with Vue.Js / Inertia.js and Laravel

I'm trying to paginate data from Laravel in Vue.Js. I'm using Inertia.js as well.
In my Laravel Controller I have:
$data['participants'] = User::with('groups')->select('id', 'name')->paginate(2);
return inertia('Dashboard/Participants', $data);
This outputs my two users in a row well in Vue. I am also expecting the links object to use for pagination. I don't see this in my Vue props.
If I inspect my Vue props I have the following object:
participants:Object
current_page:1
data:Array[2]
first_page_url:"http://localhost:3000/dashboard/participants?page=1"
from:1
last_page:51
last_page_url:"http://localhost:3000/dashboard/participants?page=51"
next_page_url:"http://localhost:3000/dashboard/participants?page=2"
path:"http://localhost:3000/dashboard/participants"
per_page:2
prev_page_url:null
to:2
total:101
If I:
dd($data['participants']->links());
in the controller I can see:
Illuminate\View\View {#316 ▼
#factory: Illuminate\View\Factory {#310 ▶}
#engine: Facade\Ignition\Views\Engines\CompilerEngine {#328 ▶}
#view: "pagination::bootstrap-4"
#data: array:2 [▶]
#path: "/Users/ejntaylor/Documents/Laravel/motional/vendor/laravel/framework/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php"
}
I have been looking at PingCRM for inspiration but without luck - I've referenced in the link. Help appreciated.
It would seem the default Laravel pagination does not work with Inertia.JS so you must head to your AppServiceProvider.php file and add the following to get pagination to work.
This is taken from PingCRM
protected function registerLengthAwarePaginator()
{
$this->app->bind(LengthAwarePaginator::class, function ($app, $values) {
return new class(...array_values($values)) extends LengthAwarePaginator {
public function only(...$attributes)
{
return $this->transform(function ($item) use ($attributes) {
return $item->only($attributes);
});
}
public function transform($callback)
{
$this->items->transform($callback);
return $this;
}
public function toArray()
{
return [
'data' => $this->items->toArray(),
'links' => $this->links(),
];
}
public function links($view = null, $data = [])
{
$this->appends(Request::all());
$window = UrlWindow::make($this);
$elements = array_filter([
$window['first'],
is_array($window['slider']) ? '...' : null,
$window['slider'],
is_array($window['last']) ? '...' : null,
$window['last'],
]);
return Collection::make($elements)->flatMap(function ($item) {
if (is_array($item)) {
return Collection::make($item)->map(function ($url, $page) {
return [
'url' => $url,
'label' => $page,
'active' => $this->currentPage() === $page,
];
});
} else {
return [
[
'url' => null,
'label' => '...',
'active' => false,
],
];
}
})->prepend([
'url' => $this->previousPageUrl(),
'label' => 'Previous',
'active' => false,
])->push([
'url' => $this->nextPageUrl(),
'label' => 'Next',
'active' => false,
]);
}
};
});
}
I had a similar problem and noticed the basic links() wouldn't work with Inertia and Vue so i made a simple Vue component where I use the Paginator Object I get from the Inertia render method and it works very well for me without the ServiceProvider workaround.
I can just use
public function index()
{
return Inertia::render('MyUserList',[
'paginator' => User::paginate(10)
]);
}
as I normally would.
Then i bind the paginator Object to my Vue Component so I can leverage it to create a basic Paginator component. This way I can use and reuse the <Paginator :paginator="paginator" /> anywhere I want.
<template>
<Paginator :paginator="paginator" />
</template>
<script>
import Paginator from "#/Components/Paginator";
export default {
props: {
paginator: Object
},
}
</script>
I also created a package so you can pull it in via composer if you want.
See https://github.com/svnwa/InertiaVuePaginator for more Info and the "Components" folder for the paginator component i created.
I hope it helps others in the future :)

Drupal 8 custom module from with ajax and template override

I'm creating a module that has a custom admin 2-col page that uses ajax to populate a div, showing content based on a dropdown selection before form submission.
It all works fine, and I can see the container updated by ajax.
But when I try use a custom template for 2-col layout, I get the following inserted into the container:
An unrecoverable error occurred. The uploaded file likely exceeded the
maximum file size (50 MB) that this server supports.
There are no watchdog messages or log details, so this might suggest an apache configuration issue (https://www.drupal.org/forum/support/post-installation/2013-02-27/an-unrecoverable-error-occurred-the-uploaded-file-likely), but mod_security does not appear to be enabled, and the form does not contain any files and it's no way near 50MB! So I don't know where this is coming from. This is currently in my dev environment on my laptop and I've not faced this before, so I don't think apache config is an issue.
It strikes me that there may be a core bug in the form API for ajax with custom templates, because it works fine without a custom template... unless I'm implementing the custom template incorrectly.
A possible workaround would be to use CSS for force the container onto the RHS, but this should ideally be in the template so that admin themes can work with it.
I've put the code in pastebin: https://pastebin.com/F1zkd5rg.
or listed below:
my_module.links.menu.yml
my_module.main:
route_name: my_module.main
title: My Module
parent: system.admin
weight: -6
my_module.form_page:
route_name: my_module.form_page
title: My Module Form
parent: my_module.main
weight: -6
my_module.routing.yml
my_module.main:
path: '/admin/my_module'
defaults:
_controller: 'Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
_title: 'My Module'
requirements:
_permission: 'administrator'
my_module.form_page:
path: '/admin/my_module/form'
defaults:
_form: 'Drupal\my_module\Form\MyModuleForm'
_title: 'My Module Form'
requirements:
_permission: 'administrator'
my_module.module
<?php
/**
* Implements hook_theme_registry_alter
*/
function my_module_theme($existing, $type, $theme, $path) {
return [
'my_module_form' => [
'render element' => 'form',
],
];
}
templates/my-module-form.html.twig
<form {{ attributes }}>
<div class="layout-column layout-column--half">
{{ form.user_view }}
{{ form.submit }}
</div>
<div class="layout-column layout-column--half">
{{ form.user_list_wrapper }}
</div>
</form>
src/Form/MyModuleForm.php
<?php
/**
* #file
* Contains \Drupal\my_module\Form\MyModuleForm.
*/
namespace Drupal\my_module\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Views;
/**
* Configure custom_rest settings for this site.
*/
class MyModuleForm extends FormBase {
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'my_module_form';
}
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
...
$form['#theme'] = 'my_module_form';
$form['user_view'] = [
'#type' => 'select',
'#title' => $this->t('Select element'),
'#options' => $userViews,
'#ajax' => [
'callback' => '::findUsers',
'event' => 'change',
'wrapper' => 'edit-user-list',
'progress' => array(
'type' => 'throbber',
'message' => t('Searching Users...'),
),
],
];
$form['user_list_wrapper'] = [
'#type' => 'container',
'#attributes' => array(
'class' => array(
'user-list-wrapper',
),
),
];
$form['user_list_wrapper']['user_list'] = [
'#type' => 'item',
'#attributes' => [
'id' => ['user_list'],
],
'#markup' => '<ul><li>None</li></ul>'
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Submit'),
];
return $form;
}
/**
* Ajax callback to list users.
*/
public function findUsers(array &$form, FormStateInterface $form_state) {
// Create the user list HTML
$selected = $form_state->getValue('user_view');
...
$user_list = '';
...
if (strlen($user_list) == 0) {
$user_list = 'None';
} else {
$user_list = "<ul>$user_list</ul>";
}
// Generate the AJAX response
$ajax_response = new AjaxResponse();
$ajax_response->addCommand(new HtmlCommand('#edit-user-list', $user_list));
return $ajax_response;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_set_message('Nothing Submitted. Just an Example.');
}
}
Thanks in advance

Custom Validation Attributes for Array Type Form Fields using proengsoft/laravel-jsvalidation in Laravel 5.2

I am creating a CRUD using dimsav translatable and proengsoft/laravel-jsvalidation packages for Laravel.
The form field names have to follow an array structure like this...
<div class="form-group">
{!! Form::label("es[title]", trans("messages.title"), ["class" => "control-label"]) !!}
{!! Form::text("es[title]", getFormInput($entry, "title", $locale), ["class" => "form-control", "id" => "es[title]"]) !!}
</div>
To be able to use mass asignment easily on the controller.
The create form is being validated with a CreateRequest as follows...
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'es.title' => 'required|max:255',
];
}
}
I don't know how to change the attribute placeholders with more friendly texts at resources/lang/validation.php file. I have tried the following options...
'attributes' => [
'title' => 'título',
//'es.title' => 'título',
//'es[title]' => 'título',
],
...but any of them is working. The form is being validated ok naming the field 'es.title' but the error message showed is not replacing the field name correctly even if I name the attributes array key also 'es.title'. Any ideas?
Inside App/Http/Requests/YourRequest
public function messages()
{
return [
'es.title.required' => 'You forgot título!',
];
}
You can set different messages for different validation rules(required,max etc)
For setting up custom name for an attribute
public function attributes()
{
return [
'es.title' => 'título'
];
}
EDITED
For setting up attribute name globally go to lang/en/validation and you'll see an attribute array. Change it according to you requirement.
'attributes' => [
'es' => [
'title' => 'título'
]
],

Override / remove server-side validation in Symfony2.5

Say I have the following form builder buildForm method:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'travelTime',
'datetime',
array(
'label' => 'Time',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'invalid_message' => 'Please enter a valid date and time',
)
)
->add(
'acmeEntity',
'entity',
array(
'label' => 'Acme Entity:',
'class' => 'AcmeBundle:MyEntity',
'expanded' => false,
'multiple' => false,
)
)
}
How can I override (or remove) validation for the 'acmeEntity' form field (and only that field) so that if I call:
$form->handleRequest($request);
$form->isValid();
in a Controller, then acmeEntity will not be included in the validation that determines whether $form->isValid() returns true? I've tried adding constraints => false, to the field options, but I'm receiving this error message:
Notice: Trying to get property of non-object in /var/www/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php line 67
Does anyone know the proper way to disable server-side validation for a Symfony form field?
EDIT:
Note that I am not looking for how to disable validation completely. This can be done by adding:
// Disable form validation
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$event->stopPropagation();
}, 900); // Always set a higher priority than ValidationListener
to the bottom of a form builder.
Rather, I want to know how to completely disable validation for a single form field. Thanks everyone and good hunting!
You can define a custom form type for your entity and use the 'validation_groups' => false. This should disable the validation only for this field.
The custom form type may look like that:
// .../Your/OwnBundle/Form/Type/AcmeEntityType.php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AcmeEntityType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false
));
}
public function getParent()
{
return 'entity';
}
public function getName()
{
return 'acme_entity';
}
}
You can then use:
$builder
->add(
'travelTime',
'datetime',
array(
'label' => 'Time',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'invalid_message' => 'Please enter a valid date and time',
)
)
->add(
'acmeEntity',
'acme_entity',
array(
'label' => 'Acme Entity:',
'class' => 'AcmeBundle:MyEntity',
'expanded' => false,
'multiple' => false,
)
)
}
I assume that you call buildForm() from MyEntityType extending AbstractType so just use the options resolver by adding the function setDefaultOptions() in your type as said in the symphony doc here
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false,
));
}
You can try this, I have used it in the past :
Create a validation group for your MainEntity
Add this validation group to your form
Do not add this validation group to AcmeEntity

Resources