I need to add Entity_id to Rating Edit Form (Stores -> Rating -> Edit Rating).
I try to achieve this with plugin
Vendor/Module/etc/adminhtml/di.xml:
<type name="Magento\Review\Block\Adminhtml\Rating\Edit\Tab\Form">
<plugin name="add_entity_type_rating_form" type="Vendor\Module\Plugin\Block\Adminhtml\Rating\Edit\Tab\Form" sortOrder="1"/>
</type>
And class Vendor\Module\Plugin\Block\Adminhtml\Rating\Edit\Tab\Form:
<?php
namespace Vendor\Module\Plugin\Block\Adminhtml\Rating\Edit\Tab;
class Form
{
public function aroundGetFormHtml(
\Magento\Review\Block\Adminhtml\Rating\Edit\Tab\Form $subject,
\Closure $proceed
) {
$form = $subject->getForm();
if (is_object($form)) {
$fieldset = $form->getElement('rating_form');
if ($fieldset) {
$fieldset->addField(
'entity_id',
'text',
[
'name' => 'entity_id',
'label' => __('Entity Type'),
'title' => __('Entity Type'),
]
);
}
}
return $proceed();
}
}
On the backend I can see filed 'Entity Type', but it has no value
How should I pass data to this filed (entity_id)?
#Smirnov I just solved a similar issue, what you need to do is set the values to the form again in your plugin function. The result should look like this:
<?php
namespace Vendor\Module\Plugin\Block\Adminhtml\Rating\Edit\Tab;
use Magento\Framework\Registry;
class Form
{
/**
* #var \Magento\Framework\Registry
*/
protected $registry;
/**
* #param \Magento\Framework\Registry $registry
*/
public function __construct(
Registry $registry
) {
$this->registry = $registry;
}
/**
* #param \Magento\Review\Block\Adminhtml\Rating\Edit\Tab\Form $subject
* #param \Closure $proceed
* #return \Closure $proceed
*/
public function aroundGetFormHtml(
\Magento\Review\Block\Adminhtml\Rating\Edit\Tab\Form $subject,
\Closure $proceed
) {
$form = $subject->getForm();
if (is_object($form)) {
$ratingData = $this->registry->registry('rating_data');
$fieldset = $form->getElement('rating_form');
if ($fieldset) {
$fieldset->addField(
'entity_id',
'text',
[
'name' => 'entity_id',
'label' => __('Entity Type'),
'title' => __('Entity Type'),
]
);
}
if ($ratingData) {
$form->setValues($ratingData);
}
}
return $proceed();
}
}
Hope this helps you to solve your requirement. Best.
Related
I am trying to extend a new field with fe varient. I have added below code:
ext_tables.sql
#
# Table structure for table 'tx_cartproducts_domain_model_product_fevariant'
#
CREATE TABLE tx_cartproducts_domain_model_product_fevariant (
note text,
);
/myext/Configuration/TCA/Overrides/tx_cartproducts_domain_model_product_fevariant.php
<?php
defined('TYPO3_MODE') or die();
$temporaryColumns = [
'note' => [
'exclude' => 1,
'label' => 'Note',
'config' => [
'type' => 'text',
'eval' => 'trim',
],
],
];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
'tx_cartproducts_domain_model_product_fevariant',
$temporaryColumns
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'tx_cartproducts_domain_model_product_fevariant',
'note',
'',
'after:title'
);
Now, backend working as expected, to render value in frontend. I added model like below:
myext/Classes/Domain/Model/Product/FeVariant.php
<?php
namespace Vendor\myext\Domain\Model\Product;
class FeVariant extends \Extcode\CartProducts\Domain\Model\Product\FeVariant
{
/**
* note
*
* #var string
*/
protected $note = '';
/**
* Returns note
*
* #return string
*/
public function getNote()
{
return $this->note;
}
/**
* Sets note
*
* #param string $note
*/
public function setNote($note)
{
$this->note = $note;
}
}
And added class mapping like below
myext/Configuration/Extbase/Persistence/Classes.php
<?php
declare(strict_types=1);
return [
\Vendor\myext\Domain\Model\Product\FeVariant::class => [
'tableName' => 'tx_cartproducts_domain_model_product_fevariant',
],
];
I also found reference here but it also not working for fe_variant.
I think you have to add some lines to your ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\Extcode\CartProducts\Domain\Model\Product\FeVariant::class] = [
'className' => \Vendor\myext\Domain\Model\Product\FeVariant::class
];
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\Container\Container::class)
->registerImplementation(
\Extcode\CartProducts\Domain\Model\Product\FeVariant::class,
\Vendor\myext\Domain\Model\Product\FeVariant::class
);
I have a taxonomy option list make where I choose say Toyota.
I want the second taxonomy option list with the models of Toyota only (Eg. Corolla, hilux etc...).
When I choose Benz the second list will then contains C-Class, ML, etc...
I have created the entity vehicle from google examples on xampp localhost, windows 10.
In my vehicle form I'm able to populate the first list. But the second appears empty.
Here is my code. Please help:
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
$options = array();
$tax = "make";
$terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
foreach ($terms as $term) {
$options[] = $term->name;
}
$form['make'] = array(
'#type' => 'select',
'#title' => t('Make'),
'weight' => 0,
'#options' => $options,
'#ajax' => array(
'callback' => [$this, 'changeOptionsAjax'],
'wrapper' => 'model_wrapper',
),
);
$form['model'] = array(
'#type' => 'select',
'#title' => t('Model'),
'weight' => 1,
'#options' => $this->getOptions($form_state),
'#prefix' => '<div id="model_wrapper">',
'#suffix' => '</div>',
);
return $form;
}
public function getOptions(FormStateInterface $form_state) {
$options = array();
if ($form_state->getValue('make') == "Benz") {
$tax="benz";
}
elseif ($form_state->getValue('make') == "BMW") {
$tax="bmw";
}
elseif ($form_state->getValue('make') == "Toyota") {
$tax="toyota";
}
else {
$tax="title";
// title is just another taxonomy list I'm using as default if make is not found
}
$terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
foreach ($terms as $term) {
$options[] = $term->name;
}
return $options;
}
public function changeOptionsAjax(array &$form, FormStateInterface $form_state) {
return $form['model'];
}
Here I give you a working sample based on your example VehiculesForm.php:
I took the liberty to rename some variable for better readability.
<?php
namespace Drupal\example\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* VehiculesForm.
*/
class VehiculesForm extends FormBase {
/**
* The term Storage.
*
* #var \Drupal\taxonomy\TermStorageInterface
*/
protected $termStorage;
/**
* {#inheritdoc}
*/
public function __construct(EntityTypeManagerInterface $entity) {
$this->termStorage = $entity->getStorage('taxonomy_term');
}
/**
* {#inheritdoc}
*/
public static function create(ContainerInterface $container) {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('entity_type.manager')
);
}
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'vehicules_form';
}
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
$brands = $this->termStorage->loadTree('make', 0, NULL, TRUE);
$options = [];
if ($brands) {
foreach ($brands as $brand) {
$options[$brand->getName()] = $brand->getName();
}
}
$form['brand'] = array(
'#type' => 'select',
'#title' => $this->t('brand'),
'#options' => $options,
'#ajax' => array(
'callback' => [$this, 'selectModelsAjax'],
'wrapper' => 'model_wrapper',
),
);
$form['model'] = array(
'#type' => 'select',
'#title' => $this->t('Model'),
'#options' => ['_none' => $this->t('- Select a brand before -')],
'#prefix' => '<div id="model_wrapper">',
'#suffix' => '</div>',
'#validated' => TRUE,
);
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Send'),
];
return $form;
}
/**
* {#inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
}
/**
* {#inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
/**
* Called via Ajax to populate the Model field according brand.
*
* #param array $form
* An associative array containing the structure of the form.
* #param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* #return array
* The form model field structure.
*/
public function selectModelsAjax(array &$form, FormStateInterface $form_state) {
$options = [];
$vocabulary = 'title';
switch ($form_state->getValue('brand')) {
case 'Benz':
$vocabulary = 'benz';
break;
case 'BMW':
$vocabulary = 'bmw';
break;
case 'Toyota':
$vocabulary = 'toyota';
break;
}
$models = $this->termStorage->loadTree($vocabulary, 0, NULL, TRUE);
if ($models) {
foreach ($models as $model) {
$options[$model->id()] = $model->getName();
}
}
$form['model']['#options'] = $options;
return $form['model'];
}
}
Also, I suggest you to make some improvments on you code such:
Don't use a switch but link your taxonomies with a reference fields.
Add validation to ensure security (check we don't spoof your field for example) !!
Don't use the brandname but the ID. Avoid $options[$brand->getName()] = $brand->getName(); and use something like $options[$brand->id()] = $brand->getName();.
Hope it will help you !
I've tried to make form input with autonumber using extensions mdmsoft/yii2-autonumber. And the result in my browser this bellow.
And this my code form in view.
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* #var $this yii\web\View */
/* #var $model app\models\Donatur */
/* #var $form yii\widgets\ActiveForm */
?>
<div class="donatur-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'kode_donatur')->textInput(['readonly' => true, 'value' => 'kode_donatur']) ?>
<?= $form->field($model, 'nama_donatur')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'alamat')->textArea(['rows' => 6]) ?>
<?= $form->field($model, 'telepon')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Simpan' : 'Ubah', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
<?php
echo " ";
echo " ";
echo Html::a('Keluar', ['index'],['class'=>'btn btn-primary']);
?>
</div>
<?php ActiveForm::end(); ?>
</div>
And I want autonumber display in textfield "Kode donatur". An example can be seen in the image below.
Code in controller
<?php
namespace app\controllers;
use Yii;
use app\models\Donatur;
use app\models\SearchDonatur;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
/**
* DonaturController implements the CRUD actions for Donatur model.
*/
class DonaturController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all Donatur models.
* #return mixed
*/
public function actionIndex()
{
$searchModel = new SearchDonatur();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single Donatur model.
* #param string $id
* #return mixed
*/
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Donatur model.
* If creation is successful, the browser will be redirected to the 'view' page.
* #return mixed
*/
public function actionCreate()
{
$model = new Donatur();
if (Yii::$app->request->post()) {
$model->load(Yii::$app->request->post());
if ($model->save()) {
\Yii::$app->session->setFlash('success', 'Data berhasil disimpan!');
} else {
Yii::$app->session->setFlash('error', 'Data gagal disimpan!');
}
return $this->redirect(['index']);
return $this->refresh();
}
else {
return $this->render('create', ['model' => $model]);
}
}
/**
* Updates an existing Donatur model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param string $id
* #return mixed
*/
public function actionUpdate($id)
{
$model = Donatur::findOne($id);
if (Yii::$app->request->post()) {
$model->load(Yii::$app->request->post());
if ($model->save()) {
Yii::$app->session->setFlash('success', 'Data berhasil diupdate!');
} else {
Yii::$app->session->setFlash('error', 'Data gagal diupdate!');
}
return $this->redirect(['index']);
return $this->refresh();
}
else {
return $this->render('update', ['model' => $model]);
}
}
/**
* Deletes an existing Donatur model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* #param string $id
* #return mixed
*/
public function actionDelete($kode_donatur)
{
$model = Donatur::findOne($kode_donatur);
$model->delete();
Yii::$app->session->setFlash('delete', 'Data berhasil dihapus!');
return $this->redirect(['index']);
}
/**
* Finds the Donatur model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* #param string $id
* #return Donatur the loaded model
* #throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = Donatur::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}
Code in model
<?php
namespace app\models;
use yii\db\ActiveRecord;
class Donatur extends ActiveRecord
{
public static function tableName()
{
return 'donatur';
}
public function rules()
{
return [
[['nama_donatur', 'alamat', 'telepon'], 'required'],
[['kode_donatur', 'nama_donatur', 'alamat'], 'string'],
[['telepon'], 'integer'],
];
}
public function behaviors()
{
return [
[
'class' => 'mdm\autonumber\Behavior',
'attribute' => 'kode_donatur', // required
//'group' => $this->id_branch, // optional
'value' => 'D'.'?' , // format auto number. '?' will be replaced with generated number
'digit' => 4 // optional, default to null.
],
];
}
}
Your behaviours() function is not in the model it should be in your controller.Like this,
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
[
'class' => 'mdm\autonumber\Behavior',
'attribute' => 'kode_donatur', // required
//'group' => $this->id_branch, // optional
'value' => 'D'.'?' , // format auto number. '?' will be replaced with generated number
'digit' => 4 // optional, default to null.
],
];
}
I want to save the form data in session in case of an error occured then I can display valid form data in my form view.
I've got a file field for an image but I've got this error when I submit my form with an image : Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
My Form Type :
class ContenuType extends AbstractType
{
private $session;
public function __construct($session)
{
$this->session = $session;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$session = $this->session;
$formSession = $session->get('dataCreateContenu');
if (!$formSession) {
$formSession = new Contenu();
}
$builder
->add('description', 'textarea', array(
'label' => 'Description',
'data' => $formSession->getDescription(),
'attr' => array('maxlength' => 560),
)
)
->add('file', 'file', array(
'label' => 'Image',
'data' => $formSession->getImage(),
'required' => false,
)
)
;
}
}
My Form Controller :
/**
* New Contenu
*
* #Route("/", name="contenu_create")
* #Method("POST")
* #Template("MyOwnBundle:Contenu:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Contenu();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
$session = $this->get('session');
$session->set('dataCreateContenu', $form->getData());
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$formAll = $form->all();
foreach ($formAll as $formField) {
if(empty($formField->getData())) {
$this->get('session')->getFlashBag()->add('error', 'Field « '.$formField->getConfig()->getOption("label").' » is empty.');
return $this->redirect($this->generateUrl('contenu_new'));
}
}
$image = $form->get('file')->getData();
if ($image) {
$entity->upload();// Upload
}
$em->persist($entity);
$em->flush();
$session->clear();
return $this->redirect($this->generateUrl('contenu_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
What can I do ?
I have a form in Symfony 2 with basically two fields:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('contactType', 'select', array( 'choices' => $contactTypes ))
->add('value', 'text');
}
Then I added an EventSubscriber that listens to the FormEvents::PRE_SET_DATA event. What I actually want to do, is to change the way of validation depending on the value of contactType (numeric values from 1 to 4, which stand for email, mobile, fixed line and fax).
I followed this tutorial http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html
but I can't figure out, how to add a constraint to the value field.
Can anyone help me? Thanks a lot in advance.
Instead of adding validation constraints dynamically in event subscriber (not sure if this is even possible), you can set groups to field's validation constraints and determine validation groups based on submitted data.
A function to create the form from the controller :
<?php
// ...
class DefaultController extends Controller
{
/**
*
* #param \Clicproxy\DeltadocCabBundle\Entity\Mark $mark
* #param \Clicproxy\DeltadocCabBundle\Entity\Tag $tag
* #return Form
*/
private function createTagForm(Mark $mark, Tag $tag)
{
$form = $this->createForm(new TagType(), $tag, array(
'action' => $this->generateUrl('tag_new', array('slug' => $this->slugify($mark->getName()))),
'method' => 'POST',
));
foreach ($mark->getFields() as $field)
{
$form->add($this->slugify($field->getName()), $field->getFormType(), $field->getOptions());
}
$form->add('submit', 'submit', array('label' => 'crud.default.save'));
return $form;
}
// ...
The code in the entity (type, constraints, ...) :
<?php
// ...
/**
* Field
*
* #ORM\Table()
* #ORM\Entity
* #UniqueEntity({"name", "mark"})
*/
class Field
{
// ...
/**
*
* #return array
*/
public function getOptions()
{
$options = array('label' => $this->getName(), 'mapped' => FALSE);
$options['required'] = $this->getType() != 'checkbox';
if ('date' == $this->getType())
{
$options['attr']['class'] = 'datepicker'; // 'input-group date datepicker';
$options['attr']['data-date-format'] = 'dd/mm/yyyy';
$options['attr']['data-date-autoclose'] = true;
}
if ('choice' == $this->getType())
{
$choices = array();
foreach ($this->getChoices() as $choice)
{
$choices[$choice->getValue()] = $choice->getName();
}
asort($choices);
$options['choices'] = $choices;
}
$options['constraints'] = $this->getValidationConstraint();
return $options;
}
public function getValidationConstraint ()
{
$validation_constraint = array();
if ('number' == $this->getType()) {
if (0 < $this->getMaximum()) {
$validation_constraint[] = new LessThanOrEqual (array(
'message' => 'entity.field.number.lessthanorequal', // {{ compared_value }}
'value' => $this->getMaximum()
));
}
if (0 < $this->getMinimum()) {
$validation_constraint[] = new GreaterThanOrEqual(array(
'message' => 'entity.field.number.greaterthanorequal', // {{ compared_value }}
'value' => $this->getMinimum()
));
}
} elseif ('text' == $this->getType ()) {
if (0 < $this->getMaximum()) {
$validation_constraint[] = new Length(array(
'min' => $this->getMinimum() > 0 ? $this->getMinimum() : 0,
'max' => $this->getMaximum() > 0 ? $this->getMaximum() : 0,
'minMessage' => 'entity.field.text.minMessage', // {{ limit }}
'maxMessage' => 'entity.field.text.maxMessage',
'exactMessage' => 'entity.field.text.exactMessage',
));
}
} elseif ('date' == $this->getType()) {
}
return $validation_constraint;
}
// ...
All this code work actually.
With this you have a solution to generate a form on the fly with constraints.