How to add multiple attributes in InstallData Magento 2 - php

Please specify how to add multiple attributes in single InstallData script

Magento 2 uses Data scripts to add attributes.
In folder Vendor/Module/Setup/Patch/Data add a .php file (eg: AddCustomerAttributes)
The following will add a few customer attributes.
After adding this bin/magento setup:upgrade command is required.
There will be an entry added to patch_list datatable, if the script file was executed correctly and also the attributes in the eav attribute table of course.
<?php
namespace Vendor\Module\Setup\Patch\Data;
use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
class AddCustomerAttributes implements DataPatchInterface
{
/**
* #var ModuleDataSetupInterface
*/
protected $moduleDataSetup;
/**
* #var CustomerSetupFactory
*/
protected $customerSetupFactory;
/**
* #var AttributeSetFactory
*/
protected $attributeSetFactory;
/**
* AddCustomerPhoneNumberAttribute constructor.
* #param ModuleDataSetupInterface $moduleDataSetup
* #param CustomerSetupFactory $customerSetupFactory
* #param AttributeSetFactory $attributeSetFactory
*/
public function __construct(
ModuleDataSetupInterface $moduleDataSetup,
CustomerSetupFactory $customerSetupFactory,
AttributeSetFactory $attributeSetFactory
) {
$this->moduleDataSetup = $moduleDataSetup;
$this->customerSetupFactory = $customerSetupFactory;
$this->attributeSetFactory = $attributeSetFactory;
}
/**
* {#inheritdoc}
*/
public function apply()
{
$customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
$customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
$attributeSetId = $customerEntity->getDefaultAttributeSetId();
$attributeSet = $this->attributeSetFactory->create();
$attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
/** attribute_1 */
$customerSetup->addAttribute(
Customer::ENTITY,
'attribute_1',
[
'type' => 'text',
'label' => 'Attribute One',
'input' => 'text',
'required' => false,
'user_defined' => true,
'sort_order' => 1000,
'position' => 1000,
'default' => 0,
'system' => 0
]
);
$attribute = $customerSetup->getEavConfig()->getAttribute(
Customer::ENTITY,
'attribute_1'
);
$attribute->addData(
[
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer']
]
);
$attribute->save();
/** attribute_2 */
$customerSetup->addAttribute(
Customer::ENTITY,
'attribute_2',
[
'type' => 'int',
'label' => 'Attribute Two',
'input' => 'select',
'source' => 'Vendor\Module\Model\Options',
'required' => false,
'user_defined' => true,
'sort_order' => 1000,
'position' => 1000,
'default' => 0,
'system' => 0
]
);
$attribute = $customerSetup->getEavConfig()->getAttribute(
Customer::ENTITY,
'attribute_2'
);
$attribute->addData(
[
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer']
]
);
$attribute->save();
}
/**
* {#inheritdoc}
*/
public static function getDependencies()
{
return [];
}
/**
* {#inheritdoc}
*/
public function getAliases()
{
return [];
}
}
Please let me know if you need help with anything on this.

thanks for the above solution using patches. It's working and I used the same methodology using InstallData/UpgradeData.php according to my requirement.
Please check my answer
This will save the data in the database in table customer_entity_varchar and attributes in eav_attribute.
Check the code:
<?php
namespace CustomB2BRFQ\Module\Setup;
use Magento\Customer\Model\Customer;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
{
private $eavSetupFactory;
private $eavConfig;
private $attributeResource;
private $customerSetupFactory;
/**
* #var AttributeSetFactory
*/
protected $attributeSetFactory;
protected $moduleDataSetup;
public function __construct(
\Magento\Eav\Setup\EavSetupFactory $eavSetupFactory,
\Magento\Eav\Model\Config $eavConfig,
\Magento\Customer\Model\ResourceModel\Attribute $attributeResource,
CustomerSetupFactory $customerSetupFactory,
AttributeSetFactory $attributeSetFactory,
ModuleDataSetupInterface $moduleDataSetup
) {
$this->eavSetupFactory = $eavSetupFactory;
$this->eavConfig = $eavConfig;
$this->attributeResource = $attributeResource;
$this->customerSetupFactory = $customerSetupFactory;
$this->attributeSetFactory = $attributeSetFactory;
$this->moduleDataSetup = $moduleDataSetup;
}
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
//$customerSetup->removeAttribute(Customer::ENTITY, "phonenumber");
$customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
$attributeSetId = $customerEntity->getDefaultAttributeSetId();
$attributeSet = $this->attributeSetFactory->create();
$attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
/** attribute_1 */
$customerSetup->addAttribute(
Customer::ENTITY,
'phonenumber',
[
'type' => 'varchar',
'label' => 'Phone Number',
'input' => 'text',
'required' => true,
'visible' => true,
'user_defined' => true,
'sort_order' => 991,
'position' => 991,
'system' => 0,
]
);
$attribute = $customerSetup->getEavConfig()->getAttribute(
Customer::ENTITY,
'phonenumber'
);
$attribute->addData(
[
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer',
'customer_account_create',
'customer_account_edit']
]
);
$attribute->save();
/** attribute_2 */
$customerSetup->addAttribute(
Customer::ENTITY,
'gstnumber',
[
'type' => 'varchar',
'label' => 'GST Number',
'input' => 'text',
'required' => true,
'visible' => true,
'user_defined' => true,
'sort_order' => 992,
'position' => 992,
'system' => 0,
]
);
$attribute = $customerSetup->getEavConfig()->getAttribute(
Customer::ENTITY,
'gstnumber'
);
$attribute->addData(
[
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer',
'customer_account_create',
'customer_account_edit']
]
);
$attribute->save();
}
}
?>

Related

Magento 2 Overriding a custom module

So in summary I'm trying to override a third party module to include an extra dropdown menu on the admin Ui
Heres the third party file at
Prince/Productattach/Block/Adminhtml/Productattach/Edit/Tab/Main.php
namespace Prince\Productattach\Block\Adminhtml\Productattach\Edit\Tab;
/**
*Class Main
*#package Prince\Productattach\Block\Adminhtml\Productattach\Edit\Tab
*/
class Main extends \Magento\Backend\Block\Widget\Form\Generic implements
\Magento\Backend\Block\Widget\Tab\TabInterface
{
/**
* #var \Magento\Store\Model\System\Store
*/
private $systemStore;
/**
* #var \Magento\Customer\Model\ResourceModel\Group\Collection
*/
private $customerCollection;
/**
* Main constructor.
* #param \Magento\Backend\Block\Template\Context $context
* #param \Magento\Framework\Registry $registry
* #param \Magento\Framework\Data\FormFactory $formFactory
* #param \Magento\Store\Model\System\Store $systemStore
* #param \Magento\Customer\Model\ResourceModel\Group\Collection $customerCollection
* #param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Store\Model\System\Store $systemStore,
\Magento\Customer\Model\ResourceModel\Group\Collection $customerCollection,
array $data = []
) {
$this->_systemStore = $systemStore;
$this->_customerCollection = $customerCollection;
parent::__construct($context, $registry, $formFactory, $data);
}
/**
* Prepare form
*
* #return $this
*/
public function _prepareForm()
{
$model = $this->_coreRegistry->registry('productattach');
/*
* Checking if user have permissions to save information
*/
if ($this->_isAllowedAction('Prince_Productattach::save')) {
$isElementDisabled = false;
} else {
$isElementDisabled = true;
}
/** #var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('productattach_main_');
$fieldset = $form->addFieldset(
'base_fieldset',
['legend' => __('Attachment Information')]
);
$customerGroup = $this->customerCollection->toOptionArray();
if ($model->getId()) {
$fieldset->addField('productattach_id', 'hidden', ['name' => 'productattach_id']);
}
$fieldset->addField(
'name',
'text',
[
'name' => 'name',
'label' => __('Attachment Name'),
'title' => __('Attachment Name'),
'required' => true,
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'description',
'textarea',
[
'name' => 'description',
'label' => __('Description'),
'title' => __('Description'),
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'files',
'file',
[
'name' => 'file',
'label' => __('File'),
'title' => __('File'),
'required' => false,
'note' => 'File size must be less than 2 Mb.', // TODO: show ACCTUAL file-size
'disabled' => $isElementDisabled
]
);
$fieldset->addType(
'uploadedfile',
\Prince\Productattach\Block\Adminhtml\Productattach\Renderer\FileIconAdmin::class
);
$fieldset->addField(
'file',
'uploadedfile',
[
'name' => 'uploadedfile',
'label' => __('Uploaded File'),
'title' => __('Uploaded File'),
]
);
$fieldset->addField(
'url',
'text',
[
'name' => 'url',
'label' => __('URL'),
'title' => __('URL'),
'required' => false,
'disabled' => $isElementDisabled,
'note' => 'Upload file or Enter url'
]
);
$fieldset->addField(
'customer_group',
'multiselect',
[
'name' => 'customer_group[]',
'label' => __('Customer Group'),
'title' => __('Customer Group'),
'required' => true,
'value' => [0,1,2,3], // todo: preselect ALL customer groups, not just 0-3
'values' => $customerGroup,
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'store',
'multiselect',
[
'name' => 'store[]',
'label' => __('Store'),
'title' => __('Store'),
'required' => true,
'value' => [0],
'values' => $this->systemStore->getStoreValuesForForm(false, true),
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'active',
'select',
[
'name' => 'active',
'label' => __('Active'),
'title' => __('Active'),
'value' => 1,
'options' => ['1' => __('Yes'), '0' => __('No')],
'disabled' => $isElementDisabled
]
);
$this->_eventManager->dispatch('adminhtml_productattach_edit_tab_main_prepare_form', ['form' => $form]);
if ($model->getId()) {
$form->setValues($model->getData());
}
$this->setForm($form);
return parent::_prepareForm();
}
/**
* Prepare label for tab
*
* #return string
*/
public function getTabLabel()
{
return __('Attachment Information');
}
/**
* Prepare title for tab
*
* #return string
*/
public function getTabTitle()
{
return __('Attachment Information');
}
/**
* {#inheritdoc}
*/
public function canShowTab()
{
return true;
}
/**
* {#inheritdoc}
*/
public function isHidden()
{
return false;
}
/**
* Check permission for passed action
*
* #param string $resourceId
* #return bool
*/
public function _isAllowedAction($resourceId)
{
return $this->_authorization->isAllowed($resourceId);
}
}
I have my module setup and my di.xml configured with the usual plus below to override the class.
<preference for="Prince\Productattach\Block\Adminhtml\Productattach\Edit\Tab" type="Vendor\Filecategory\Block\Adminhtml\Productattach\Edit\Tab"/>
then and exact replica of the class with namespace and my extra field added at
Vendor/Filecategory/Block/Adminhtml/Productattach/Edit/Tab/Main.php
namespace Vendor\Filecategory\Block\Adminhtml\Productattach\Edit\Tab;
use \Prince\Productattach\Block\Adminhtml\Productattach\Edit\Tab\Main as Main;
class MainExt extends Main
{
/**
* #var \Magento\Store\Model\System\Store
*/
private $systemStore;
/**
* #var \Magento\Customer\Model\ResourceModel\Group\Collection
*/
private $customerCollection;
/**
* Main constructor.
* #param \Magento\Backend\Block\Template\Context $context
* #param \Magento\Framework\Registry $registry
* #param \Magento\Framework\Data\FormFactory $formFactory
* #param \Magento\Store\Model\System\Store $systemStore
* #param \Magento\Customer\Model\ResourceModel\Group\Collection $customerCollection
* #param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Store\Model\System\Store $systemStore,
\Magento\Customer\Model\ResourceModel\Group\Collection $customerCollection,
array $data = []
) {
$this->systemStore = $systemStore;
$this->customerCollection = $customerCollection;
parent::__construct($context, $registry, $formFactory, $data, $systemStore);
}
/**
* Prepare form
*
* #return $this
*/
public function _prepareForm()
{
$model = $this->_coreRegistry->registry('productattach');
/*
* Checking if user have permissions to save information
*/
if ($this->_isAllowedAction('Prince_Productattach::save')) {
$isElementDisabled = false;
} else {
$isElementDisabled = true;
}
/** #var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('productattach_main_');
$fieldset = $form->addFieldset(
'base_fieldset',
['legend' => __('Attachment Information')]
);
$customerGroup = $this->customerCollection->toOptionArray();
if ($model->getId()) {
$fieldset->addField('productattach_id', 'hidden', ['name' => 'productattach_id']);
}
$fieldset->addField(
'name',
'text',
[
'name' => 'name',
'label' => __('Attachment Name'),
'title' => __('Attachment Name'),
'required' => true,
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'Category',
'select',
[
'name' => 'Category',
'label' => __('Category'),
'title' => __('Category'),
'value' => 0,
'options' => ['0' => __('Technical Specification'), '1' => __('Installation Instructions')],
]
);
$fieldset->addField(
'description',
'textarea',
[
'name' => 'description',
'label' => __('Description'),
'title' => __('Description'),
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'files',
'file',
[
'name' => 'file',
'label' => __('File'),
'title' => __('File'),
'required' => false,
'note' => 'File size must be less than 2 Mb.', // TODO: show ACCTUAL file-size
'disabled' => $isElementDisabled
]
);
$fieldset->addType(
'uploadedfile',
\Prince\Productattach\Block\Adminhtml\Productattach\Renderer\FileIconAdmin::class
);
$fieldset->addField(
'file',
'uploadedfile',
[
'name' => 'uploadedfile',
'label' => __('Uploaded File'),
'title' => __('Uploaded File'),
]
);
$fieldset->addField(
'url',
'text',
[
'name' => 'url',
'label' => __('URL'),
'title' => __('URL'),
'required' => false,
'disabled' => $isElementDisabled,
'note' => 'Upload file or Enter url'
]
);
$fieldset->addField(
'customer_group',
'multiselect',
[
'name' => 'customer_group[]',
'label' => __('Customer Group'),
'title' => __('Customer Group'),
'required' => true,
'value' => [0,1,2,3], // todo: preselect ALL customer groups, not just 0-3
'values' => $customerGroup,
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'store',
'multiselect',
[
'name' => 'store[]',
'label' => __('Store'),
'title' => __('Store'),
'required' => true,
'value' => [0],
'values' => $this->systemStore->getStoreValuesForForm(false, true),
'disabled' => $isElementDisabled
]
);
$fieldset->addField(
'active',
'select',
[
'name' => 'active',
'label' => __('Active'),
'title' => __('Active'),
'value' => 1,
'options' => ['1' => __('Yes'), '0' => __('No')],
'disabled' => $isElementDisabled
]
);
$this->_eventManager->dispatch('adminhtml_productattach_edit_tab_main_prepare_form', ['form' => $form]);
if ($model->getId()) {
$form->setValues($model->getData());
}
$this->setForm($form);
return parent::_prepareForm();
}
/**
* Prepare label for tab
*
* #return string
*/
public function getTabLabel()
{
return __('Attachment Information');
}
/**
* Prepare title for tab
*
* #return string
*/
public function getTabTitle()
{
return __('Attachment Information');
}
/**
* {#inheritdoc}
*/
public function canShowTab()
{
return true;
}
/**
* {#inheritdoc}
*/
public function isHidden()
{
return false;
}
/**
* Check permission for passed action
*
* #param string $resourceId
* #return bool
*/
public function _isAllowedAction($resourceId)
{
return $this->_authorization->isAllowed($resourceId);
}
}
However I keep getting Error
Incompatible argument type: Required type: \Magento\Store\Model\System\Store. Actual type: array;
I have tried flush cache and reindex but no luck. Please can someone tell me what im doing wrong here? Also happy to listen to any alternative ways of completing the same thing.
Thanks in advance.
I have managed to complete this by creating a plugin class instead of overriding the whole class. I have attached the post I followed for any one interested in adding a form field to n existing form attached to a third part module.
https://magento.stackexchange.com/questions/174209/magento-2-add-new-field-to-magento-user-admin-form

Doctrine Table inheritance with zf3 fieldset

I'm working on a project using Zend Framework 3 and Doctrine 2, using for DcotrineModule integration, the following is the Entity modeling I'm having problems with:
To work with this modeling with the doctrine I'm using #InheritanceType, below are the relevant excerpts from Entities:
Pessoa Entity:
/**
* Abstração de Pessoa
*
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="tipo", type="string")
* #DiscriminatorMap( { "pessoa" = "Pessoa",
* "pessoa_fisica" = "PessoaFisica",
* "pessoa_juridica" = "PessoaJuridica" } )
* #Table(name="pessoa")
*/
abstract class Pessoa implements JsonSerializable, PessoaInterface
{
use JsonSerializeTrait;
/**
* #Id
* #GeneratedValue(strategy="IDENTITY")
* #Column(type="integer", length=32, unique=true, nullable=false, name="id_pessoa")
* #var integer
*/
protected $idPessoa;
/**
* Usuário
* #OneToOne(targetEntity="User\Entity\User", inversedBy="pessoa", cascade={"persist"})
* #JoinColumn(name="usuario", referencedColumnName="id")
*
* #var User
*/
protected $usuario;
/**
* #OneToOne(targetEntity="EnderecoPessoa", mappedBy="pessoa", cascade={"persist"})
* #var EnderecoPessoa
*/
protected $endereco;
/**
* Contatos da pessoa
* #OneToMany(targetEntity="ContatoPessoa", mappedBy="pessoa", cascade={"persist"}, orphanRemoval=true)
* #var ArrayCollection|array
*/
protected $contatos;
const PESSOA_FISICA = "pessoa_fisica", PESSOA_JURIDICA = "pessoa_juridica";
public function __construct()
{
$this->contatos = new ArrayCollection();
}
}
PessoaFisica Entity:
/**
* Abstração da pessoa física
*
* #Entity
* #Table(name="pessoa_fisica")
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*/
class PessoaFisica extends Pessoa implements JsonSerializable {
use JsonSerializeTrait;
/**
* Nome da pessoa física
* #Column(type="string", length=14)
* #var string
*/
private $nome;
/**
* Número do CPF da pessoa (quando brasileiro)
* #Column(type="string", length=14)
* #var string
*/
private $cpf;
/**
* Número do RG (quando brasileiro)
* #Column(type="string", length=13)
* #var string
*/
private $rg;
/**
* Data de nascimento
* #Column(type="date", name="data_nascimento")
* #var DateTime
*/
private $dataNascimento;
}
PessoaJuridica Entity:
/**
* Abstração de Pessoa Jurídica
*
* #Entity
* #Table(name="pessoa_juridica")
* #InheritanceType("JOINED")
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*/
class PessoaJuridica extends Pessoa implements JsonSerializable {
use JsonSerializeTrait;
/**
* #Id
* #GeneratedValue(strategy="IDENTITY")
* #Column(type="integer", length=32, unique=true, nullable=false, name="id_pessoa")
* #var integer
*/
protected $idPessoa;
/**
* Nome fantasia
* #Column(type="string", length=32, name="nome_fantasia")
* #var String
*/
protected $nomeFantasia;
/**
* Número do CNPJ
* #Column(type="string", length=14, unique=true, name="cnpj")
* #var string
*/
protected $cnpj;
/**
* Razão social da empresa
* #Column(type="string", length=32, name="razao_social")
* #var string Razão social da empresa, quando necessário
*/
protected $razaoSocial;
}
So far everything works perfectly, the problem is when I need to generate a form for this information, I'm currently working on the "Customer" module, basically what I did for it was:
Create a form with client ID + Pessoa Fieldset
In the Pessoa Fieldset, I created the fieldsets for shared information (user, address, contacts etc)
In the Pessoa Fieldset, it also includes two other Fieldsets, one for each Pessoa's child class (PessoaFisica and PessoaJuridica) - and here come's the problem.
In the screen below you can see my registration form:
This form displays or hides the fieldset of PessoaJuridica or PessoaFisica according to the selected type using javascript, however as they are different fieldsets within the form, when zend hydrates them they are hydrated as different objects as well, ie the inheritance is not applied to the Person object, which should be selected according to the type.
Basically what, in my point of view, would need to happen, would be that there is a way for zend not to render the fieldsets referring to the child classes of the Person class as separate objects, at the moment the form is rendered with these fields so (for example) :
person [fsPeople] [name]
person [fsPessoaJuridica] [nameFantasica]
And this causes the zend not to generate the correct class to be saved in the database.
What would be the correct way to do this implementation of the form?
Well, the response from the #rkeet helped me a lot to understand where the problem was, which is not really a problem =]
Due to the usage of inheritance, you've created separate Entities.
However, the form you initially create in the back-end works with a
single Entity. The front-end you've modified to handle 2. So your
front-end does not match your back-end. As, due to the inheritance,
you now have 2 separate Entities, you should create 2 separate forms,
using different fieldsets (PessoaJuridica or PessoaFisica) as the base
fieldsets.
I'll leave the path I followed here, it might help someone with the same doubt as me.
First, following the logic explained in his comment, I created an abstract fieldset for the PessoaEntity with the information shared between the two types of person, and extended it into two child classes PessoaFisicaFieldset and PessoaJuridicaFieldset, which I describe below:
/**
* Fieldset com dados para a pessoa
*
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*/
abstract class PessoaFieldset extends Fieldset implements InputFilterProviderInterface
{
private $em;
private $userFs;
private $enderecoFs;
private $contatoFs;
public function __construct(ObjectManager $em,
UserFieldset $userFs,
PessoaEnderecoFieldset $enderecoFs,
ContatoFieldset $contatoFs)
{
parent::__construct('pessoa');
$this->em = $em;
$this->userFs = $userFs;
$this->enderecoFs = $enderecoFs;
$this->contatoFs = $contatoFs;
$this->init();
}
protected function getEm()
{
return $this->em;
}
public function init()
{
$this
->setHydrator(new DoctrineObject($this->getEm()));
$this->add(array(
'type' => 'Hidden',
'name' => 'id_pessoa',
'attributes' => array(
'id' => 'txtId'
)
));
$this->add(array(
'type' => 'hidden',
'name' => 'tipo',
));
$this->add($this->userFs);
$this->add($this->enderecoFs);
$elCollection = new Collection;
$elCollection
->setName('contatos')
->setLabel('Informações de Contato')
->setCount(1)
->setShouldCreateTemplate(true)
->setAllowAdd(true)
->setAllowRemove(true)
->setTargetElement($this->contatoFs);
$this->add($elCollection);
$this->add(array(
'type' => 'Button',
'name' => 'btAddContato',
'options' => array(
'label' => '<i class="fa fa-fw fa-plus"></i> Adicionar',
'label_options' => array(
'disable_html_escape' => true
)
),
'attributes' => array(
'class' => 'btn btn-info',
'id' => 'btAddContato'
)
));
}
public function getInputFilterSpecification(): array
{
return array(
'id_pessoa' => array(
'required' => false,
'filters' => array(
['name'=>'Int']
)
),
'tipo' => array(
'required' => true,
)
);
}
}
This is my PessoaFisicaFieldset class.
/**
* Fieldset com dados para a pessoa Física
*
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*/
class PessoaFisicaFieldset extends PessoaFieldset implements InputFilterProviderInterface
{
private $em;
public function __construct(ObjectManager $em,
\User\Form\UserFieldset $userFs,
PessoaEnderecoFieldset $enderecoFs,
\Common\Form\ContatoFieldset $contatoFs)
{
parent::__construct($em, $userFs, $enderecoFs, $contatoFs);
$this->init();
}
public function init()
{
parent::init();
$this
->setObject(new PessoaFisica());
$this->get('tipo')->setValue(\Pessoa\Entity\Pessoa::PESSOA_FISICA);
$this->add(array(
'type' => 'Text',
'name' => 'cpf',
'options' => array(
'label' => 'CPF',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtCpf'
)
));
$this->add(array(
'type' => 'Text',
'name' => 'nome',
'options' => array(
'label' => 'Nome',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtNome'
)
));
$this->add(array(
'type' => 'Text',
'name' => 'rg',
'options' => array(
'label' => 'RG',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtRazaoSocial'
)
));
$this->add(array(
'type' => 'DateTime',
'name' => 'dataNascimento',
'options' => array(
'format' => 'd/m/Y',
'label' => 'Data de Nascimento',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line data',
)
));
}
public function getInputFilterSpecification(): array
{
return array(
'nome' => array(
'required' => true,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
)
),
'rg' => array(
'required' => false,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
)
),
'cpf' => array(
'required' => false,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
),
'validators' => array(
['name' => CpfValidator::class]
)
),
'dataNascimento' => array(
'required' => true,
'filters' => array(
array(
'name' => 'Zend\Filter\DatetimeFormatter',
'options' => array (
'format' => 'd/m/Y',
),
),
),
'validators' => array(
array(
'name' => Date::class,
'options' => array(
'format' => 'd/m/Y'
)
)
)
)
);
}
}
And here is my PessoaJuridicaFieldset
/**
* Fieldset com dados específicos para a pessoa jurídica
*
* #author Rodrigo Teixeira Andreotti <ro.andriotti#gmail.com>
*/
class PessoaJuridicaFieldset extends PessoaFieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $em,
\User\Form\UserFieldset $userFs, PessoaEnderecoFieldset $enderecoFs,
\Common\Form\ContatoFieldset $contatoFs)
{
parent::__construct($em, $userFs, $enderecoFs, $contatoFs);
$this->init();
}
public function init()
{
parent::init();
$this
->setObject(new PessoaJuridica());
$this->get('tipo')->setValue(\Pessoa\Entity\Pessoa::PESSOA_JURIDICA);
$this->add(array(
'type' => 'Text',
'name' => 'cnpj',
'options' => array(
'label' => 'CNPJ',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtCnpj'
)
));
$this->add(array(
'type' => 'Text',
'name' => 'razaoSocial',
'options' => array(
'label' => 'Razão Social',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtRazaoSocial'
)
));
$this->add(array(
'type' => 'Text',
'name' => 'nomeFantasia',
'options' => array(
'label' => 'Nome Fantasia',
'label_attributes' => array(
'class' => 'col-sm-12'
)
),
'attributes' => array(
'class' => 'form-control form-control-line',
'id' => 'txtNomeFantasia'
)
));
}
public function getInputFilterSpecification(): array
{
return array(
'razaoSocial' => array(
'required' => true,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
)
),
'nomeFantasia' => array(
'required' => true,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
)
),
'cnpj' => array(
'required' => true,
'filters' => array(
['name' => 'StripTags'],
['name' => 'StringTrim']
),
'validators' => array(
['name' => CnpjValidator::class]
)
)
);
}
}
And to complete I did the entity type treatment on the Controller that will load this form, as below: (only relevant parts)
//...
if ($id) {
$cliente = $this->repository->getById($id);
$form->remove('pessoa');
// loads form according to the type loaded from the database
if (!$request->isXmlHttpRequest()) {
if ($cliente->getPessoa() instanceof \Pessoa\Entity\PessoaFisica) {
$form->add($this->pessoaFisicaFieldset);
} elseif ($cliente->getPessoa() instanceof \Pessoa\Entity\PessoaJuridica) {
$form->add($this->pessoaJuridicaFieldset);
}
var_dump($cliente->getPessoa());
}
$form->bind($cliente);
}
if ($request->isPost()) {
$form->remove('pessoa');
// loads form according to the type selected in the post
if ($request->getPost('tipo') == \Pessoa\Entity\Pessoa::PESSOA_FISICA) {
$form->add($this->pessoaFisicaFieldset);
} elseif ($request->getPost('tipo') == \Pessoa\Entity\Pessoa::PESSOA_JURIDICA) {
$form->add($this->pessoaJuridicaFieldset);
}
$form->get('tipo')->setValue($request->getPost('tipo'));
$form->setData($request->getPost());
if(!$request->isXmlHttpRequest()) {
if ($form->isValid()) {
$cliente = $form->getObject();
if ($cliente->getId() != 0) {
$cliente->getPessoa()->setCadastradoEm(new \DateTime);
}
// ...
}
}
}
//...
Again, thanks #rkeet!

Doctrine only persists last entity in a CollectionType

I submit a form in Symfony with a collection of sub-forms. Doctrine seems to only save the last entity in that collection. How should I get it to persist all the entities in collection?
I've double checked my code and followed a few tutorials to make sure I have it correct.
EnrichmentApplication
/**
* #ORM\Entity
*/
class EnrichmentApplication
{
//...
/**
* #var array
*
* #ORM\OneToMany(targetEntity="EnrichmentActivity", mappedBy="application", cascade={"persist"})
*/
private $activities;
/**
* #var array
*
* #ORM\OneToMany(targetEntity="EnrichmentActivityCosts", mappedBy="application", cascade={"persist"})
*/
private $activityCosts;
**
* #var string
*
* #ORM\Column(name="project_outline", type="text")
*/
private $projectOutline;
//...
public function __construct()
{
$this->activities = new ArrayCollection();
$this->activityCosts = new ArrayCollection();
}
/**
* Set activityTypes
*
* #param array $activityTypes
*
* #return EnrichmentApplication
*/
public function setActivityTypes($activityTypes)
{
$this->activityTypes = $activityTypes;
return $this;
}
/**
* Get activityTypes
*
* #return array
*/
public function getActivityTypes()
{
return $this->activityTypes;
}
/**
* Set activities
*
* #param array $activities
*
* #return EnrichmentApplication
*/
public function setActivities($activities)
{
$this->activities = $activities;
return $this;
}
/**
* Get activities
*
* #return array
*/
public function getActivities()
{
return $this->activities;
}
/**
* Add activity
*
* #param array $activity
*
* #return EnrichmentApplication
*/
public function addActivities(EnrichmentActivity $activity)
{
$activity->setApplication($this);
if (!$this->activities->contains($activity))
{
$this->activities->add($activity);
}
return $this;
}
/**
* Set activityCosts
*
* #param array $activityCosts
*
* #return EnrichmentApplication
*/
public function setActivityCosts($activityCosts)
{
$this->activityCosts = $activityCosts;
return $this;
}
/**
* Get activityCosts
*
* #return array
*/
public function getActivityCosts()
{
return $this->activityCosts;
}
/**
* Add activityCost
*
* #param EnrichmentActivityCosts $activityCost
*
* #return EnrichmentApplication
*/
public function addActivityCosts(EnrichmentActivityCosts $activityCost)
{
$activityCost->setApplication($this);
if (!$this->activityCosts->contains($activityCost))
{
$this->activityCosts->add($activityCost);
}
return $this;
}
/**
* Set projectOutline
*
* #param string $projectOutline
*
* #return EnrichmentApplication
*/
public function setProjectOutline($projectOutline)
{
$this->projectOutline = $projectOutline;
return $this;
}
/**
* Get projectOutline
*
* #return string
*/
public function getProjectOutline()
{
return $this->projectOutline;
}
//...
}
EnrichmentActivity
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #ORM\ManyToOne(targetEntity="EnrichmentApplication", inversedBy="activities")
* #ORM\JoinColumn(name="application_id", referencedColumnName="id")
*/
private $application;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="date")
*/
private $date;
/**
* #var \DateTime
*
* #ORM\Column(name="start_time", type="time")
*/
private $startTime;
/**
* #var \DateTime
*
* #ORM\Column(name="end_time", type="time")
*/
private $endTime;
/**
* #var int
*
* #ORM\Column(name="total_students", type="integer")
*/
private $totalStudents;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="date")
*/
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
public function __clone()
{
$this->id = null;
$this->application = null;
}
/**
* Set application
*
* #param EnrichmentApplication $application
*
* #return EnrichmentActivity
*/
public function setApplication($application)
{
$this->application = $application;
return $this;
}
/**
* Get application
*
* #return EnrichmentApplication
*/
public function getApplication()
{
return $this->application;
}
/**
* Set date
*
* #param \DateTime $date
*
* #return EnrichmentActivity
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set startTime
*
* #param \DateTime $startTime
*
* #return EnrichmentActivity
*/
public function setStartTime($startTime)
{
$this->startTime = $startTime;
return $this;
}
/**
* Get startTime
*
* #return \DateTime
*/
public function getStartTime()
{
return $this->startTime;
}
/**
* Set endTime
*
* #param \DateTime $endTime
*
* #return EnrichmentActivity
*/
public function setEndTime($endTime)
{
$this->endTime = $endTime;
return $this;
}
/**
* Get endTime
*
* #return \DateTime
*/
public function getEndTime()
{
return $this->endTime;
}
/**
* Set totalStudents
*
* #param integer $totalStudents
*
* #return EnrichmentActivity
*/
public function setTotalStudents($totalStudents)
{
$this->totalStudents = $totalStudents;
return $this;
}
/**
* Get totalStudents
*
* #return int
*/
public function getTotalStudents()
{
return $this->totalStudents;
}
}
EnrichmentApplicationType (the form)
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as Types;
use Lifo\TypeaheadBundle\Form\Type\TypeaheadType;
class EnrichmentApplicationType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$uniform_col_label = 'col-xs-12 col-sm-5 col-md-4 col-lg-3';
$uniform_col_element = 'col-xs-12 col-sm-7 col-md-8 col-lg-8';
$uniform_col_label_smaller = 'col-xs-12 col-sm-5 col-md-4 col-lg-2';
$uniform_col_element_smaller = 'col-xs-6 col-sm-2 col-md-2 col-lg-2';
$uniform_col_element_offset = ' col-sm-offset-5 col-md-offset-4 col-lg-offset-3';
$uniform_col_fullwidth = 'col-xs-12 col-sm-12';
$builder->add('manager', TypeaheadType::class, array(
'label' => 'Head of Department',
'route' => 'ajax_name_search',
'minLength' => 3,
'render' => 'fullName',
'attr' => array(
'data-second-glyph' => 'user',
'data-label-col' => 'col-xs-12 col-sm-5 col-md-4 col-lg-4 ',
'data-group-col' => 'col-xs-12 col-sm-7 col-md-8 col-lg-6'
)
))
->add('personResponsible', TypeaheadType::class, array(
'label' => 'Person responsible for activity delivery',
'route' => 'ajax_name_search',
'minLength' => 3,
'render' => 'fullName',
'attr' => array(
'data-second-glyph' => 'user',
'data-label-col' => 'col-xs-12 col-sm-5 col-md-5 col-lg-4',
'data-group-col' => 'col-xs-12 col-sm-7 col-md-7 col-lg-6'
)
))
//->add('author') //populated by LDAP
->add('activityTitle', Types\TextType::class, array(
'label' => 'Title of proposed activity',
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('activityTypes', Types\ChoiceType::class, array(
'label' => 'Activity type',
'choices' => $options['activityTypes'],
'expanded' => true,
'help' => 'Please select all that apply.',
'multiple' => true,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('activities', Types\CollectionType::class, array(
'entry_type' => EnrichmentActivityType::class,
'allow_add' => true,
'by_reference' => false,
'entry_options' => array(
'empty_data' => new \AppBundle\Entity\EnrichmentActivity(),
),
'attr' => array(
'data-label-col' => 'col-sm-12',
'data-group-col' => 'col-sm-12'
)
))
->add('activityCosts', Types\CollectionType::class, array(
'entry_type' => EnrichmentActivityCostsType::class,
'allow_add' => true,
'entry_options' => array(
'empty_data' => new \AppBundle\Entity\EnrichmentActivityCosts(),
),
'attr' => array(
'data-label-col' => 'col-xs-12 col-sm-3 col-md-4 col-lg-3',
'data-group-col' => 'col-xs-12 col-sm-9 col-md-8 col-lg-9'
)
))
->add('projectOutline', Types\TextareaType::class, array(
'label' => 'Activity outline and rationale',
'help' => 'Provide background information of your activity, what you intend to do and how it will impact on students\' life skills development.',
#
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('projectObjectives', Types\CollectionType::class, array(
'entry_type' => Types\TextType::class,
'label' => 'Activity objectives & outputs',
'help' => 'Please describe what you intend to achieve. Will there be any specific outputs (eg. deliver a workshop/fundraiser)?',
'allow_add' => true,
'prototype' => true,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('studentConsulted', Types\TextareaType::class, array(
'label' => 'How have the students been consulted/involved with the design of this activity?',
'help' => 'For example, have students requested this activity? Have they been involved in the planning?',
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_fullwidth
)
))
->add('studentInvolvement', Types\TextareaType::class, array(
'label' => 'Will the students be involved in the delivery of the activity?',
'help' => 'Will students be participating only or will they also be volunteering to run this activity?',
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_fullwidth
)
))
->add('communityContribution', Types\ChoiceType::class, array(
'choices' => $options['communityContrib'],
'expanded' => true,
'multiple' => true,
'required' => false,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('studySuccess', Types\ChoiceType::class, array(
'label' => 'Study and Work Success',
'choices' => $options['studySuccess'],
'expanded' => true,
'multiple' => true,
'required' => false,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('lifestyles', Types\ChoiceType::class, array(
'label' => 'Healthy & Happy Lifestyles',
'choices' => $options['lifestyles'],
'expanded' => true,
'multiple' => true,
'required' => false,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('totalStudents', Types\IntegerType::class, array(
'label' => 'Total number of students:',
'scale' => 0,
'attr' => array(
'data-label-col' => $uniform_col_label_smaller,
'data-group-col' => $uniform_col_element_smaller
)
))
->add('studentsUnder16', Types\IntegerType::class, array(
'label' => 'Aged under 16 years:',
'scale' => 0,
'attr' => array(
'data-label-col' => $uniform_col_label_smaller,
'data-group-col' => $uniform_col_element_smaller
)
))
->add('students16To18', Types\IntegerType::class, array(
'label' => 'Aged 16 to 18 years:',
'scale' => 0,
'attr' => array(
'data-label-col' => $uniform_col_label_smaller,
'data-group-col' => $uniform_col_element_smaller
)
))
->add('studentsOver18', Types\IntegerType::class, array(
'label' => 'Aged over 18 years:',
'scale' => 0,
'attr' => array(
'data-label-col' => $uniform_col_label_smaller,
'data-group-col' => $uniform_col_element_smaller
)
))
->add('alsStudents', Types\IntegerType::class, array(
'label' => 'Students accessing Additional Learning Support',
'scale' => 0,
'attr' => array(
'data-label-col' => 'col-xs-12 col-sm-6 col-md-5 col-lg-4',
'data-group-col' => $uniform_col_element_smaller
)
))
->add('availableAccrossCollege', Types\ChoiceType::class, array(
'label' => 'Is the activity only open to students from across college?',
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true,
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_element_offset
)
))
->add('availableOutside', Types\ChoiceType::class, array(
'label' => 'Is the activity open to students from outside college?',
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true,
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_element_offset
)
))
->add('availableOnlyDepartment', Types\ChoiceType::class, array(
'label' => 'Is the activity only open to students from a specific department?',
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true,
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_element_offset
)
))
->add('availableDepartment', Types\TextType::class, array(
'label' => 'If yes, please specify:',
'required' => false,
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
)
))
->add('availableOnlyCurriculumArea', Types\ChoiceType::class, array(
'label' => 'Is the activity only open to students from a specific curriculum area?',
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true,
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_element_offset
)
))
->add('availableCurriculumArea', Types\TextType::class, array(
'label' => 'If yes, please specify:',
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
),
'required' => false,
))
->add('availableOnlyCourse', Types\ChoiceType::class, array(
'label' => 'Is the activity open to students from a specific course?',
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true,
'attr' => array(
'data-label-col' => $uniform_col_fullwidth,
'data-group-col' => $uniform_col_element_offset
)
))
->add('availableCourse', Types\TextType::class, array(
'label' => 'If yes, please specify:',
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
),
'required' => false,
))
->add('availableOutsideDetail', Types\TextType::class, array(
'label' => 'If yes, please specify:',
'attr' => array(
'data-label-col' => $uniform_col_label,
'data-group-col' => $uniform_col_element
),
'required' => false,
))
->add('behaviouralEngagement', Types\CheckboxType::class, array(
'required' => false,
))
->add('emotionalEngagement', Types\CheckboxType::class, array(
'required' => false,
))
->add('cognitiveEngagement', Types\CheckboxType::class, array(
'required' => false,
))
->add('noStudentsBronze', Types\IntegerType::class, array(
'label' => 'Bronze',
'scale' => 0,
'attr' => array(
'data-label-col' => 'col-xs-5 col-sm-2 col-md-2 col-lg-1',
'data-group-col' => 'col-xs-6 col-sm-2 col-md-2 col-lg-2'
)
))
->add('noStudentsSilver', Types\IntegerType::class, array(
'label' => 'Silver',
'scale' => 0,
'attr' => array(
'data-label-col' => 'col-xs-5 col-sm-2 col-md-2 col-lg-1',
'data-group-col' => 'col-xs-6 col-sm-2 col-md-2 col-lg-2'
)
))
->add('noStudentsGold', Types\IntegerType::class, array(
'label' => 'Gold',
'scale' => 0,
'attr' => array(
'data-label-col' => 'col-xs-5 col-sm-2 col-md-2 col-lg-1',
'data-group-col' => 'col-xs-6 col-sm-2 col-md-2 col-lg-2'
)
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\EnrichmentApplication',
'activityTypes' => null,
'communityContrib' => null,
'studySuccess' => null,
'lifestyles' => null,
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_enrichmentapplication';
}
}
Environment
CentOS 7
PHP 7.1
MariaDB 10
I stick into activities in your domain, so feel free to adopt it to your needs.
EnrichmentApplication
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class EnrichmentApplication
{
//...
/**
* #var Collection
*
* #ORM\OneToMany(targetEntity="EnrichmentActivity", mappedBy="application", cascade={"persist"})
*/
private $activities;
public function __construct()
{
$this->activities = new ArrayCollection();
}
/**
* #return Collection
*/
public function getActivities()
{
return $this->activities;
}
public function addActivity(EnrichmentActivity $activity)
{
if (!$this->getActivities()->contains($activity))
{
$this->getActivities()->add($activity);
$activity->setApplication($this);
}
}
public function removeActivity(EnrichmentActivity $activity)
{
if ($this->getActivities()->contains($activity))
{
$this->getActivities()->removeElement($activity);
$activity->setApplication(null);
}
}
}
EnrichmentActivity
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class EnrichmentActivity
{
//...
/**
* #var EnrichmentApplication|null
* #ORM\ManyToOne(targetEntity="EnrichmentApplication", inversedBy="activities")
*/
private $application;
/**
* #param EnrichmentApplication|null $application
*/
public function setApplication(?EnrichmentApplication $application)
{
$this->application = $application;
}
/**
* #return EnrichmentApplication|null
*/
public function getApplication()
{
return $this->application;
}
}
EnrichmentApplicationType
use AppBundle\Entity\EnrichmentApplication;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as Types;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class EnrichmentApplicationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('activities', Types\CollectionType::class, array(
'entry_type' => EnrichmentActivityType::class,
'allow_add' => true,
'by_reference' => false
))
;
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => EnrichmentApplication::class,
'activityTypes' => null,
'communityContrib' => null,
'studySuccess' => null,
'lifestyles' => null,
));
}
}
After much debugging it turned out to be the empty_data property of the activities field that was overwriting the data coming from the form. I removed this and it works fine now
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as Types;
class EnrichmentApplicationType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//...
->add('activities', Types\CollectionType::class, array(
'entry_type' => EnrichmentActivityType::class,
'allow_add' => true,
'by_reference' => false,
'entry_options' => array(
'empty_data' => new \AppBundle\Entity\EnrichmentActivity(), //<<this option
),
'attr' => array(
'data-label-col' => 'col-sm-12',
'data-group-col' => 'col-sm-12'
)
))
//...
;
}

How to add custom field in Customer Registration on Magento 2.2?

I want to add Custom field in Customer Registration on Magento 2.2
I 've tried following code but it's not working.
I tried InstallData.php
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class InstallData implements InstallDataInterface
{
protected $customerSetupFactory;
private $attributeSetFactory;
public function __construct(CustomerSetupFactory $customerSetupFactory, AttributeSetFactory $attributeSetFactory)
{
$this->customerSetupFactory = $customerSetupFactory;
$this->attributeSetFactory = $attributeSetFactory;
}
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
$customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
$attributeSetId = $customerEntity->getDefaultAttributeSetId();
$attributeSet = $this->attributeSetFactory->create();
$attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
$customerSetup->addAttribute(Customer::ENTITY, 'intrestedin', [
'type' => 'varchar',
'label' => 'Custom Field',
'input' => 'text',
'required' => true,
'visible' => true,
'user_defined' => true,
'sort_order' => 1000,
'position' => 1000,
'system' => 0,
]);
$attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'mobile_number')
->addData([
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer', 'customer_account_create'],
]);
$attribute->save();
}
}
Please try to create a module and add customer attribute. you can create module from here- https://mage2gen.com/
After installing the module , you can run setup upgrade and deploy command.

How to retrive data by model in doctrine 2

My Entity is :
<?php
namespace model\base;
use Doctrine\ORM\Mapping as ORM;
/**
* CategoryRelationship
*/
class CategoryRelationship
{
/**
* #var integer
*/
private $id;
/**
* #var \model\base\Product
*/
private $product;
/**
* #var \model\base\Category
*/
private $category;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set product
*
* #param \model\base\Product $product
* #return CategoryRelationship
*/
public function setProduct(\model\base\Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \model\base\Product
*/
public function getProduct()
{
return $this->product;
}
/**
* Set category
*
* #param \model\base\Category $category
* #return CategoryRelationship
*/
public function setCategory(\model\base\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \model\base\Category
*/
public function getCategory()
{
return $this->category;
}
}
Notation is:
<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo;
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
$metadata->setPrimaryTable(array(
'name' => 'category_relationship',
'indexes' =>
array(
'category_id' =>
array(
'columns' =>
array(
0 => 'category_id',
),
),
'product_id' =>
array(
'columns' =>
array(
0 => 'product_id',
),
),
),
));
$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT);
$metadata->mapField(array(
'fieldName' => 'id',
'columnName' => '_id',
'type' => 'integer',
'nullable' => false,
'unsigned' => false,
'id' => true,
));
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_IDENTITY);
$metadata->mapOneToOne(array(
'fieldName' => 'product',
'targetEntity' => 'Product',
'cascade' =>
array(
),
'mappedBy' => NULL,
'inversedBy' => NULL,
'joinColumns' =>
array(
0 =>
array(
'name' => 'product_id',
'referencedColumnName' => 'product_id',
),
),
'orphanRemoval' => false,
));
$metadata->mapOneToOne(array(
'fieldName' => 'category',
'targetEntity' => 'Category',
'cascade' =>
array(
),
'mappedBy' => NULL,
'inversedBy' => NULL,
'joinColumns' =>
array(
0 =>
array(
'name' => 'category_id',
'referencedColumnName' => 'category_id',
),
),
'orphanRemoval' => false,
));
how can retrieve a data by category ?
basically i wan to update CategoryRelationship but first i need to retrieve a object by product_id.

Categories