Sylius Product customized model : fields not showed in form - php

I started to learn Sylius few days ago. I need an ecommerce module within my Symfony 3 project. So I gonna extend my project with Sylius, I'll just use the Core/Components stack.
I started with the installation of the Sylius ProductBundle (cf. http://docs.sylius.org/en/latest/bundles/SyliusProductBundle/installation.html)
Seems simple but didn't work at first because Composer installed a stable version (0.19) which is not supported anymore... Anyway, I finally installed the sylius/sylius ~1.0#dev package so my composer.json looks like that :
"minimum-stability" : "dev",
"prefer-stable" : true,
"require" : {
"php" : "^7.0",
"sylius/sylius" : "^1.0#beta",
"friendsofsymfony/user-bundle" : "~2.0#dev",
"symfony/assetic-bundle" : "^2.8",
"gedmo/doctrine-extensions" : "^2.4"
},
=> First question : is this the right way ???
Then I created a SyliusBundle within my project to decouple the entire Sylius configuration from the rest of my project.
In SyliusBundle/app/config.yml :
imports:
- { resource: "#SyliusProductBundle/Resources/config/app/config.yml" }
# Doctrine
stof_doctrine_extensions:
default_locale: "%locale%"
orm:
default:
tree: true
sluggable: true
timestampable: true
loggable: false
sortable: true
# Product
sylius_product:
driver: doctrine/orm
resources:
product:
classes:
model: OfferBundle\Entity\Offer
repository: OfferBundle\Entity\OfferRepository
form: OfferBundle\Form\OfferType
I followed the Sylius guideline to customize my Offer model inherited from Sylius Product model (quite simple)
in OfferBundle/Entity/Offer.php :
<?php
namespace OfferBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\Product as BaseProduct;
/**
* #ORM\Table(name="offer")
* #ORM\Entity(repositoryClass="OfferRepository")
*/
class Offer extends BaseProduct
{
=> question 2 : sounds good to you ?
Then I customized the form extended my Offer form with the Sylius Product form (cf. http://docs.sylius.org/en/latest/customization/form.html)
in OfferBundle/Form/OfferType.php :
<?php
namespace OfferBundle\Form;
use Symfony\Component\OptionsResolver\OptionsResolver;
use OfferBundle\Entity\Offer;
use Symfony\Component\Form\AbstractType;
class OfferType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Offer::class]);
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'offer';
}
/**
* {#inheritdoc}
*/
public function getParent()
{
return \Sylius\Bundle\ProductBundle\Form\Type\ProductType::class;
}
}
In OfferBundle/Form/Extension/OfferTypeExtension.php :
<?php
namespace OfferBundle\Form\Extension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Form\Type\WysiwygType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use OfferBundle\Form\Type\TagsType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use OfferBundle\Entity\Offer;
use MediaBundle\Form\MediaFileType;
use MediaBundle\Form\MediaVideoType;
use CompanyBundle\Entity\Company;
use Tetranz\Select2EntityBundle\Form\Type\Select2EntityType;
use Admin\CompanyBundle\Controller\CompanyController;
use Symfony\Component\Form\AbstractTypeExtension;
use OfferBundle\Form\ContactType;
use OfferBundle\Form\PriceType;
use OfferBundle\Form\OfferType;
final class OfferTypeExtension extends AbstractTypeExtension
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('advantage', WysiwygType::class)
->add('ecommerce')
->add('enabled')
->add('bestseller')
->add('company', Select2EntityType::class, [
'multiple' => false,
'remote_route' => 'admin_company_company_autocomplete',
'class' => Company::class,
'primary_key' => 'id',
'text_property' => 'name',
'minimum_input_length' => 0,
'page_limit' => CompanyController::NB_PER_PAGE,
'allow_clear' => false,
'delay' => 250,
'cache' => false,
'cache_timeout' => 60000,
'language' => 'fr',
'placeholder' => 'form.choose',
'required' => true,
])
->add('state', ChoiceType::class, [
'choices' => Offer::getStates(),
'placeholder' => 'form.choose',
])
...
And the form extension is loaded by service.
in OfferBundle/Resources/config/services.yml :
offer.form.extension.type.offer:
class: OfferBundle\Form\Extension\OfferTypeExtension
tags:
- { name: form.type_extension, extended_type: OfferBundle\Form\OfferType }
Question 3 : It works BUT in see that Sylius\Bundle\CoreBundle\Form\Extension\ProductTypeExtension contains additionnal fields like $images, $variantSelectionMethod... But it doesn't appear in my form. So I suppose that a service.yml somewhere is not loaded ?
Hope somebody can help me on that !

I think the problem is because you have overridden the form, and not extended it. So you only see your form fields, and not the Product form fields (as this form is not used anymore).
If you want to have the Product form with some changes, you only have to make a form extension to modify the existing Product form.
http://docs.sylius.org/en/latest/customization/form.html
Hope this helps ! :)

you may also need to override the template of the form in order to show those added fields.

Related

validation.yml file is ignored

I'm new to symfony, and I'm currently trying to understand Symfony3.
While validation through annotations works fine, I can't activate validation through validation.yml file.
In my app/config/config.yml, I changed this line :
framework:
validation: { enabled: true, enable_annotations: false }
My src/AppBundle/Resources/config/validation.yml is :
# src/AppBundle/Resources/config/validation.yml
AppBundle\Entity\TaskSetClass:
properties:
taskName:
- NotBlank: ~
dueDate:
- NotBlank: ~
- Type: \DateTime
I added a extension file :
<?php
// src/AppBundle/DependencyInjection/AppExtension.php
namespace AppBundle\DependencyInjection;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Finder\Finder;
/* */
class AppExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container=new ContainerBuilder();
// Services
$loader=new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../../../app/config'));
$loader->load('services.yml');
// Validation
// Commented : No "validator.mapping.loader.yaml_files_loader.mapping_files" parameter.
//$yamlMappingFiles=$container->getParameter('validator.mapping.loader.yaml_files_loader.mapping_files');
$finder=new Finder();
foreach($finder->files()->in(__DIR__.'/../../../app/Resources/config') as $file)
{
$filePath=$file->getRealPath();
if(preg_match('#\.yml$#',$filePath)===1)
{
$yamlMappingFiles[]=$filePath;
}
}
$container->setParameter('validator.mapping.loader.yaml_files_loader.mapping_files', $yamlMappingFiles);
}
}
A dump of the container after the setParameter() in appExtension.php shows the command has succeeded :
[parameterBag:protected] => Symfony\Component\DependencyInjection\ParameterBag\ParameterBag Object
(
[parameters:protected] => Array
(
[validator.mapping.loader.yaml_files_loader.mapping_files] => Array
(
[0] => /mnt/400Go/www/sy1/app/Resources/config/validation.yml
)
)
[resolved:protected] =>
)
In my form controller, if I list the constraints :
[...]
if($form->isSubmitted())
{
if($form->isValid())
{
$metadata=$this->container
->get('validator')
->getMetadataFor('AppBundle\Entity\TaskSetClass');
$propertiesMetadata=$metadata->properties;
$constraints=array();
foreach ($propertiesMetadata as $propertyMetadata)
{
$constraints[$propertyMetadata->name]=$property->constraints;
}
echo'<pre>Constraints : ';
print_r($constraints);
echo'</pre>';
die();
[...]
... the array is empty. so the file seems to be loaded, but the constraints are ignored.
Did anyone encountered this error? It may comes from a difference between symfony 2 and 3.
[SOLVED] The validation file was not in the correct directory. It was supposed to be in AppBundle/Resources/config and I had it into app/Resouces/config. Works fine now.

Symfony2 form not validate email and required constraint

I have a form like this made with Symfony2:
class UsuarioRegistroType extends AbstractType {
public function BuildForm(FormBuilderInterface $builder, array $options) {
$builder->add('email', 'email', array('label' => 'E-mail', 'required' => true))
....
Forms works fine, but if I write something like Email: asdf (not email address), I never get the error assosiated with this issue. Also, if I don't write anything, I don't get any error for required constraint.
Any idea with this issue?
Thanks :)
Required true don't validate anything. It just add a class required on the field on the form view. It's the html5 which validate that.
Try to add that on UsuarioRegistroType class :
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$collectionConstraint = new Collection(array(
'email' => array(
new NotBlank(array('message' => 'Email should not be blank.')),
new Email(array('message' => 'Invalid email address.'))
)
));
$resolver->setDefaults(array(
'constraints' => $collectionConstraint
));
}
don't forget the use statements :
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Collection;
You have just used HTML5 validation, many barowser do not support this. With this old version of different famous browser also not support HTML5 validation.
I think you should use annotation for validation from serverside. I think you know about annotation , which you can use in your Entity class. In your enity class property you may defined your required validation rules using annotaion in symfony2.
Example:
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
/**
* #Assert\Email(
* message = "The email '{{ value }}' is not a valid email.",
* checkMX = true
* )
*/
protected $email;
}
Helpful link from Symfony2 official documentation: Symfony2 Validation

Symfony2 - How do i set the entity manager that the controller createForm function uses?

I have a Form Type that uses a query builder with an entity field to get related options. But because I am using a custom entity manager for the entity it doesnt seem to recognize those options. And i get the error:
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
The controller action:
/**
* #Route("/edit/{keyword_rank_id}/", name="lg.keywordrank.campaign.edit")
* #Template
*/
public function editAction(Request $request, Company $company, $client_slug, $keyword_rank_id)
{
$em = $this->getDoctrine()->getManager($company->getEntityManagerName());
$client = $this->getEntityOrNotFound($em, 'LGClientBundle:Client', 'client_slug', $client_slug);
$kr = $this->getEntityOrNotFound($em, 'LGKeywordRankBundle:KeywordRank', 'keyword_rank_id', $keyword_rank_id);
$form = $this->createForm(new KeywordRankForm(), $kr, array('client'=>$client,'em'=>$em));
...
}
And the Form Type:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name','text',array(
'label'=>'Campaign Name'
))
->add('client_domain', 'entity', array(
'class' => 'LGClientBundle:ClientDomain',
'choices'=> $this->getClientDomains($options['em'], $options['client']),
'property' => 'domain',
'label' => 'Domain: '
));
}
private function getClientDomains($em, $client)
{
$domains = $em->getRepository('LGClientBundle:ClientDomain')->findBy(array('client'=>$client));
return $domains;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'LG\KeywordRankBundle\Entity\KeywordRank',
'client' => null,
'em' => null
));
}
public function getName()
{
return 'lg_project_keywordrank';
}
Anyone have a similar issue or know how to resolve this would be great
You can specify the entity manager to use when you add a field:
->add('client_domain', 'entity', array(
'class' => 'LGClientBundle:ClientDomain',
'choices'=> $this->getClientDomains($options['em'], $options['client']),
'em' => $options['em'],
'property' => 'domain',
'label' => 'Domain: '
));
This option takes the entity manager name, not the option itself, so you have to change
$em = $this->getDoctrine()->getManager($company->getEntityManagerName());
into
$em = $company->getEntityManagerName();
Check out the doc here: http://symfony.com/doc/current/reference/forms/types/entity.html#em
I had the same issue on my app and in fact if I pass entity manager instance to form it works.
In my case the issue was rather in config.yml file and I wanted to solve this globaly.
I have as default entity manager, "mymodule" but in FormType was used different entity manager.
This was my configuration
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: mymodule
entity_managers:
mymodule:
auto_mapping: true
connection: mymodule
mappings:
AppBundle: ~
XBundle: ~
When I changed default_entity_manager to default in my config file:
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: default
entity_managers:
default:
connection: mymodule
mappings:
AppBundle: ~
XBundle: ~
and I changed in my controller:
$em = $this->getDoctrine()->getManager('mymodule');
to:
$em = $this->getDoctrine()->getManager('default');
It works without passing entity manager to FormType so in my case it's about orm entity manager configuration.

Deprecated method addValidation and class CallbackValidator in Symfony2

I have a problem. I need to validate a field that is not in entity in form type class. Previously I used this code:
$builder->addValidator(new CallbackValidator(function(FormInterface $form){
if (!$form['t_and_c']->getData()) {
$form->addError(new FormError('Please accept the terms and conditions in order to registe'));
}
}))
But since Symfony 2.1 method addValidator and class CallbackValidator are deprecated. Does anyone know what I should use instead?
I've done it in this way:
add('t_and_c', 'checkbox', array(
'property_path' => false,
'constraints' => new True(array('message' => 'Please accept the terms and conditions in order to register')),
'label' => 'I agree'))
The interface FormValidatorInterface was deprecated and will be removed in Symfony 2.3.
If you implemented custom validators using this interface, you can
substitute them by event listeners listening to the
FormEvents::POST_BIND (or any other of the *BIND events). In case
you used the CallbackValidator class, you should now pass the callback
directly to addEventListener.
via https://github.com/symfony/symfony/blob/master/UPGRADE-2.1.md#deprecations
For anyone else looking for help changing their validators to event subscribers (as it is slightly different to normal subscribers) follow this:
Step 1
Change:
$builder->addValidator(new AddNameFieldValidator());
to
$builder->addEventSubscriber(new AddNameFieldSubscriber());
Step 2
Replace your validator class (and all the namespaces) to a subscriber class.
Your subscriber class should look like the following:
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php
namespace Acme\DemoBundle\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormError;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class AddNameFieldSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(FormEvents::POST_BIND => 'postBind');
}
public function postBind(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$form->addError(new FormError('oh poop'))
}
}
You do not need to register the subscriber in a service file (yml or otherwise)
Reference:
http://symfony.com/doc/2.2/cookbook/form/dynamic_form_modification.html#adding-an-event-subscriber-to-a-form-class

Could not load type "XYZ" error when overriding FOSUserBundle form types

I am attempting to override the RegistrationFormType in the Symfony2 FOSUserBundle. I am following the documentation and believe i've covered everything. I've created a bundle to contain my overrides to the FOSUserBundle and the following code is from this bundle as well as the application config.
Has anyone experienced this when overriding FOSUserBundle, or see anything in my code that would help explain why I keep getting this error.
I'm on symfony v2.0.4
RegistrationFormType.php
<?php
/*
* This file is part of the FOSUserBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Thrive\SaasBundle\Form\Type;
use Symfony\Component\Form\FormBuilder;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
class RegistrationFormType extends BaseType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('firstname', null, array('error_bubbling' => true))
->add('lastname', null, array('error_bubbling' => true))
->add('company', null, array('error_bubbling' => true))
->add('email', 'email', array('error_bubbling' => true))
->add('username', null, array('error_bubbling' => true))
->add('plainPassword', 'repeated', array('type' => 'password', 'error_bubbling' => true))
;
}
public function getName()
{
return 'thrive_user_registration';
}
}
Services.yml
services:
thrive_saas_registration.form.type:
class: Thrive\SaasBundle\Form\Type\RegistrationFormType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: thrive_user_registration}
Application's Config File
fos_user:
...
registration:
form:
type: thrive_user_registration
Turns out my services.yml file wasn't being loaded via dependency injection. After digging around i realized my extension.php file for this bundle was named incorrectly. Early on I had renamed the bundle and made a typo when renaming the extension.php file inside the DependencyInjection folder. After correcting the mispelling everything works again.
Did you tried to just add one new field and look if it works?
public function buildForm(FormBuilder $builder, array $options)
{
parent::buildForm($builder, $options);
// add your custom field
$builder->add('name');
}
Also remember to clear your prod cache if you're testing from there...

Categories