Unable to override Sonata User Bundle registration form - forms

I keep getting an error while trying to override sonata registration template.
I extended Sonata User Bundle with EasyExtendsBundle, so I now have src/Application/Sonata/UserBundle.
EDIT: Symfony 2.7, Sonata Admin 2.3, Sonata User dev-master
I added a field in my User Entity
UserEntity.php
<?php
/**
* This file is part of the <name> project.
*
* (c) <yourname> <youremail>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Application\Sonata\UserBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
/**
* This file has been generated by the Sonata EasyExtends bundle ( http://sonata-project.org/bundles/easy-extends )
*
* References :
* working with object : http://www.doctrine-project.org/projects/orm/2.0/docs/reference/working-with-objects/en
*
* #author <yourname> <youremail>
*/
class User extends BaseUser
{
/**
* #var integer $id
*/
protected $id;
/*
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
*/
protected $age;
/**
* Get id
*
* #return integer $id
*/
public function getId()
{
return $this->id;
}
public function getAge()
{
return $this->age;
}
public function setAge($age)
{
$this->age = $age;
}
}
I then created a new RegisterForm
Application/Sonata/UserBundle/Form/Type/RegisterType.php
<?php
namespace Application\Sonata\UserBundle\Form\Type;
use FOS\UserBundle\Form\Type\RegistrationFormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RegisterType extends RegistrationFormType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('age');
}
public function setDefaultOption(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('Default', 'Register')
));
}
public function getName()
{
return 'front_user_registration';
}
}
I tell sonata_user to use my form
config.yml
sonata_user:
profile:
register:
form:
type: front_user_registration
handler: sonata.user.profile.form.handler.default
name: front_user_registration_form
fos_user:
db_driver: orm # can be orm or odm
firewall_name: main
# if you change the class configuration, please also alter the sonata_user.yml file
user_class: Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\Group
group_manager: sonata.user.orm.group_manager
service:
user_manager: sonata.user.orm.user_manager
registration:
form:
type: front_user_registration
profile:
form:
type: fos_user_profile
handler: fos_user.profile.form.handler.default
name: fos_user_profile_form
validation_groups: [Authentication]
which I declare as a service
services.yml
user.form.register.type:
class: Application\Sonata\UserBundle\Form\Type\RegisterType
parent: fos_user.registration.form.type
tags:
- { name: form.type, alias: front_user_registration }
When I try to display the form, I get the following error :
Catchable Fatal Error: Argument 1 passed to
Sonata\UserBundle\Form\Handler\ProfileFormHandler::process() must
implement interface FOS\UserBundle\Model\UserInterface, boolean given,
called in
/Users/sylv/Sites/generajobs/vendor/sonata-project/user-bundle/Controller/RegistrationFOSUser1Controller.php
on line 49 and defined
Same goes if I add
arguments: [%fos_user.model.user.class%]
into my services.yml configuration.
Am i missing something here ?

That was a pretty stupid mistake, I had to change my "handler" line in config.yml to
handler: sonata.user.registration.form.handler.default
instead of sonata.user.profile.form.handler.default as I saw on several examples on S.O.
The two handlers process() function do not except the same parameters.

Related

Laravel Backpack basic request validation

I'm having an issue that I thought would be VERY simple to accomplish. I can not get this very basic request validation to work. I can enter "Bob" on the create form and the edit form and get no error messages. It simply inserts into the database.
Here's my code. I feel I'm doing/not doing something stupid.
UserCrudController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UserRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class UserCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* #return void
*/
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
/**
* Define what happens when the List operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-list-entries
* #return void
*/
protected function setupListOperation()
{
CRUD::column('name');
CRUD::column('email');
//CRUD::column('password');
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}
/**
* Define what happens when the Create operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-create
* #return void
*/
protected function setupCreateOperation()
{
CRUD::setValidation(UserRequest::class);
CRUD::field('name');
CRUD::field('email');
//CRUD::field('password');
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
}
/**
* Define what happens when the Update operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-update
* #return void
*/
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
}
}
UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
I think what is happening is that you are not loading that controller.
If you have installed PermissionManager and now want to configure the UserCrudController you need to either manually register the routes yourself and point to your new controller, or alternativelly (and probably recommended) bind your new controller to the package one so your controller gets "served" instead of the package controller.
// In AppServiceProvider.php or any other provider of your choice:
$this->app->bind(
\Backpack\PermissionManager\app\Http\Controllers\UserCrudController::class,
\App\Http\Controllers\Admin\UserCrudController::class
);
If you don't need to change everything in the Controller you can directly extend the package UserCrudController and only change the things you need.
<?php
namespace App\Http\Controllers\Admin;
class UserCrudController extends \Backpack\PermissionManager\app\Http\Controllers\UserCrudController
{
}
The package controller already extends the CrudController.
The validation is added on setupCreateOperation() that you can override to fit your needs.
Cheers

symfony 3 - how to add a eventsubscriber as a service in a form

In my application, I created a listener for onPostSubmit event in forms.
I created a new class that implement EventSubscriberInterface.
In the builderForm I added the evnet subscriber like this :
->addEventSubscriber(new MyNewListener())
Everything is working well, but not as I would like...
In my listener, I need the entity manager to query the database.
The first solution I have found is to add the entity manager in the form via the options and pass it to the listener via the constructor. The code is now :
->addEventSubscriber(new MyNewListener($options['entity_manager']))
This solution works but I don't want to use it like this, I prefer to use a service and add the entity manager in the service definition.
Then, my question is: How to declare the listener as a service (and pass the entity manager) and how to call it in the form declaration ?
Thank you for your help.
Just treat your subscriber as a service.
Yml configuration. You can spare autowire:true if you have all classes autowired:
services:
My\Form\Type:
autowire: true
tags:
- { name: form.type }
My\Form\Listener\MyNewListener:
autowire: true
Form class:
...
class MyForm extends AbstractType
{
/**
* #var MyNewListener
*/
private $listener;
/**
* #param MyNewListener $listener
*/
public function __construct(MyNewListener $listener)
{
$this->listener = $listener;
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->addEventSubscriber($this->listener);
}
}
You can define your form as a service in the container, like Cerad mentioned in his comment.
Since you are using Symfony 3 you can either choose to configure the service with autowire: true, or manually declare your arguments. Then inside your FormType you can pass those class properties to your Subscriber class. When you define your form as a service, be sure to tag it with form.type. Here is example code below.
Services.yml
services:
your.form.type:
class: EventsBundle\Form\MarketerType
autowire: true # this is not needed if using arguments
arguments: [ '#doctrine.orm.entity_manager' ] # this is not needed if using autowire
tags:
- { name: form.type }
FormType.php
<?php
namespace EventsBundle\Form;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
...
class FormType extends AbstractType
{
/** #var EntityManager */
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->addEventSubscriber(new YourNewListener($this->em));
}
...
Then, to be on the safe side, you'll want to clear the application cache. I hope this helps!

How get basepath from model or helper en Zend Framework 3

I recently decided to use Zend Framework 3 after 3 years of using Zend Framework 1. This decision has given me headaches, Zend 3 instead of making things easier made things more difficult.
In Zend 1, I customize the url for the selected template in the database as follows:
public function getUrl(string $file = '')
{
if($this->_helperBaseUrl === null) {
$this->_helperBaseUrl = new Zend_View_Helper_BaseUrl();
}
return $this->_helperBaseUrl->baseUrl($file);
}
public function getSkinUrl(string $file = '')
{
$themePath = 'themes/my-theme/'; //get from database
return $this->getUrl($themePath . ltrim($file, '/\\'));
}
Then in any part of the application (models, helpers, plugins and views) I can access this function like this:
//view/scripts/index/index.phtml
$url_logo = My::app()->getSkinUrl('logo.jpg');
//this return http://example.com/themes/my-theme/logo.jpg
In Zend 3 it has been very difficult for me. Does anyone know of any way to do it in Zend 3? Or How to get the baseUrl from a model in Zend 3?
In Zend Framework 2/3 you can inject almost any class into another. For example if you need basePath plugin (which is available in view context) you can inject this plugin into your model/service or controller class. This is the recommended way:
This is class where you need this plugin or any other service
use Zend\View\Helper\BasePath;
class MyService
{
/**
* #var BasePath
*/
protected $plugin;
/**
* MyService constructor.
*
* #param BasePath $basePath
*/
public function __construct(BasePath $basePath)
{
$this->plugin = $basePath;
}
/**
* #return BasePath
*/
public function getPlugin()
{
return $this->plugin;
}
/**
* #param BasePath $plugin
*/
public function setPlugin($plugin)
{
$this->plugin = $plugin;
}
}
Now, you need to factory to inject one dependency into another
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyNamespace\Service\MyService;
class MyServiceFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return MyService
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : MyService::class;
$plugin = $container->get('ViewHelperManager')->get('BasePath'); // inject this class
$myService = new $class($plugin); // into this class
return $myService;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return MyService
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, MyService::class);
}
}
Ok, now MyService has basePath plugin, but to use it in controller you have to inject your service into controller. So...
IndexController
use MyNamespace\Service\MyService;
use Zend\Mvc\Controller\AbstractActionController;
class IndexController extends AbstractActionController
{
/**
* #var MyService
*/
protected $service;
/**
* IndexController constructor.
*
* #param MyService $service
*/
public function __construct(MyService $service)
{
$this->service = $service;
}
public function indexAction()
{
$plugin = $this->service->getPlugin(); // Zend\View\Helper\BasePath object
//...
}
}
... and factory for our controller...
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyNamespace\Controller\IndexController;
class IndexControllerFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return IndexController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : IndexController::class;
$myService = $container->getServiceLocator()->get('MyNamespace\Service\MyService');
$controller = new $class($myService);
return $controller;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return IndexController
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, IndexController::class);
}
}
It's almost done. Last step is to set configuration in module.config.php file
use MyNamespace\Controller;
use MyNamespace\Factory;
return [
//...
'service_manager' => [
'factories' => [
Service\MyService::class => Factory\Service\MyServiceFactory::class
]
],
'controllers' => [
'factories' => [
Controller\IndexController::class => Factory\Controller\IndexControllerFactory::class
],
],
]
Easy, isn't it?
If you need plugin in controller, but not in your model/service class, you can skip MyService part of this "tutorial" and inject plugin directly into controller class

API Platform : No resource found for object of type "AppBundle\Document\article"

i'm using symfony2 API platform to generate an api from my mongodb database but i get this error :
hydra:description: "No resource found for object of type "AppBundle\Document\article"",
i have two mongo db documents user and article and each user has multiple articles so i'm trying to list all the users with all their articles titles so i can get something like this :
{
#id: "/user/53edb6200cf2400d584c2617",
#type: "user",
class: "de.freelancer.mongo.domain.User",
email: "feer#de.com",
displayname: "feer",
withnewsletter: false,
language: "de_DE",
active: true,
admin: false,
articles : ['article1','article2','article3']
}
here is my code :
user Document
<?php
namespace AppBundle\Document;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Dunglas\ApiBundle\Annotation\Iri;
use Symfony\Component\Validator\Constraints as Assert;
/**
#MongoDB\Document
#MongoDB\Document(collection="user")
/
class User{
/*
#MongoDB\Id(strategy="AUTO") */
private $id;
/**
#MongoDB\ReferenceMany(targetDocument="articles", mappedBy="user") */
private $articles;
public function __construct()
{
$this->articles = new ArrayCollection();
}
/**
*/
public function getArticles()
{
return $this->articles;
}
}
articles document
<?php
namespace AppBundle\Document;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Dunglas\ApiBundle\Annotation\Iri;
use Symfony\Component\Validator\Constraints as Assert;
/**
#MongoDB\Document
#MongoDB\Document(collection="article")
/
class article
{
/*
#MongoDB\Id(strategy="AUTO") */
private $id;
/**
#MongoDB\ReferenceOne(targetDocument="user", inversedBy="articles") */
private $user;
/**
*/
public function setUser(userProfile $user)
{
$this->user = $user;
return $this;
}
/**
*/
public function getUser() {
return $this->user;
}
}
can any one help me to get the list of the user articles
thanks
Every class managed by API Platform needs to be marked with the #ApiPlatform\Core\Annotation\ApiResource annotation (or the equivalent in YAML or XML).
And there is no native MongoDB support yet (but this is a work in progress).
You can still add MongoDB support by yourself using a custom data provider, but if you're a newcomer to API Platform, you should try to use Doctrine ORM and follow the official tutorial first: https://api-platform.com/docs/distribution/

This value should not be blank

I know that could be a noob error, but I wasted a lot of time in this.
I have a entity that modified with a form. This is my entity:
class RetiroResiduo
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="GestionResiduos\SolicitudRetiroBundle\Entity\SolicitudRetiro")
* #ORM\JoinColumn(name="numeroSolicitudRet_id", onDelete="CASCADE", referencedColumnName="numeroSolicitudRet")
*/
protected $numeroSolicitudRet;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="GestionResiduos\ResiduoBundle\Entity\Residuo")
* #ORM\JoinColumn(name="siglaRepresentativa_id", onDelete="CASCADE",referencedColumnName="siglaRepresentativa")
*/
protected $siglaRepresentativa;
/**
* #ORM\ManyToOne(targetEntity="GestionResiduos\ResiduoBundle\Entity\Contenedor")
* #ORM\JoinColumn(name="nombreContenedor_id", onDelete="CASCADE", referencedColumnName="nombreContenedor")
*/
protected $nombreContenedor;
...
}
This entity is handled with this form:
<?php
// src/Gestionresiudos/SolicitudRetiroBundle/Form/SolicitudRetiroType.php
namespace Gestionresiduos\SolicitudRetiroBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RetiroResiduoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('siglaRepresentativa')
->add('nombreContenedor')
->add('cantidadContenedores')
->add('peso')
->add('volumen')
->add('solicitar', 'submit')
->add('addotro', 'submit')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Gestionresiduos\SolicitudRetiroBundle\Entity\RetiroResiduo',
'cascade_validation' => true,
));
}
public function getName()
{
return 'retiroresiduo';
}
}
my action into my controller look like:
public function RetirarResiduoAction($idsol, Request $request)
{
$numSolRetiro = $idsol;
$residuoARetirar = new RetiroResiduo();
//echo gettype($residuoARetirar);
$formulario = $this->createForm(new RetiroResiduoType(), $residuoARetirar);
$formulario->handleRequest($request);
if ($formulario->isValid())
{
....
}
...
}
This is my form into view:
{{ form_start(formulario, {'attr': {'class': 'form-horizontal'}})}}
{{ form_errors(formulario)}}
{{ form_rest(formulario) }}
{{ form_end(formulario)}}
Finally I give you a print from the error to give my interface.
As you can see when I send my form doesn't enter into if(formulario->isvalid()). Obviously, I selected one option into choice. I saw similar questions but don't working for me. I need some advice or something that help me with this bug.
Note: I know that problem should be into my entity but I still don't see.
NOTE2: I'm using symfony2.3