in zend framework 2 how to save fieldset data to database - collections

I just start to study zend framwork2 , and read the document about how to use fieldset http://zf2.readthedocs.org/en/latest/modules/zend.form.collections.html
I can use tablegateway insert product data into database.but don't know how to insert data to brand table and I don't know how to link product and brand . thank you very much!!!!!

Many people has the same problem and rlandas wrote and uploaded a working code to github
i post the code of the controller in case the url changes. but take a look at the complete module in github
<?php
namespace Product\Controller;
use Product\Table\ProductTable;
use Product\Entity\Product as ProductEntity;
use Product\Form\CreateProduct;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Http\PhpEnvironment\Response;
use Zend\View\Model\ViewModel;
class ManageController extends AbstractActionController
{
public function indexAction ()
{
$product = $this->getProductTable();
$products = $product->getAllOrderByName();
$view = new ViewModel();
$view->setVariable('products', $products);
return $view;
}
public function viewAction ()
{
if ($id = $this->params('id')) {
$product = $this->getProductTable()
->getByProductId($id);
}
$view = new ViewModel();
$view->setVariable('product', $product);
return $view;
}
public function addAction ()
{
$form = new CreateProduct();
$product = $this->getServiceLocator()->get('Product\Entity\Product');
$form->bind($product);
$data = array(
'product' => array(
'name' => 'product name ' . mt_rand(1, 1000),
'price' => mt_rand(100.000, 5000.999) / 100,
'brand' => array(
'name' => 'My brand ' . mt_rand(1, 200),
'url' => 'http://www.mybrand.com'
),
'categories' => array(
array('name' => 'Sony'),
array('name' => 'Panasonic'),
array('name' => 'Phillips')
)
)
);
$form->populateValues($data);
// action viewscript
$view = new ViewModel(array(
'form' => $form
));
// do Post/Redirect/Get (PRG) strategy to stop user refresh/back button
$prg = $this->prg($this->getRequest()->getRequestUri(), true);
if ($prg instanceof Response) {
return $prg;
}
// this is when the user first arrives to this url, display the form
else if ($prg === false) {
return $view;
}
// lets retrieve the post data stored in the PRG session
$post = $prg;
// validate the form
$form->setData($post);
if(!$form->isValid())
return $view;
// if data are valid, then save
// save the brand
$brand = $product->getBrand();
$brandTable = $this->getBrandTable();
$brand = $brandTable->save($brand);
$brandId = $brandTable->getLastInsertValue();
$product->setBrandId($brandId);
// save the categories
$categoryTable = $this->getCategoryTable();
$categoryTable->persist($product->getCategories())->flush();
$categoryIds = implode(",", $categoryTable->getEntityIds());
$product->setCategoryIds($categoryIds);
// save the product
$productTable = $this->getProductTable();
$product = $productTable->save($product);
$this->redirect()->toRoute('product');
return $view;
}
public function editAction ()
{
$form = new CreateProduct();
$product = $this->getServiceLocator()->get('Product\Entity\Product');
$form->bind($product);
// action viewscript
$view = new ViewModel(array(
'form' => $form
));
$productTable = $this->getProductTable();
if ($id = $this->params('id')) {
$product = $this->getProductTable()->getByProductId($id);
// get the brands
$brand = $this->getBrandTable()->getByBrandId($product->getBrandId());
$product->setBrand($brand);
// get the categories
$categoryIds = explode(",", $product->getCategoryIds());
$categories = $this->getCategoryTable()->getAllByCategoryId($categoryIds);
$product->setCategories($categories);
$form->bind($product);
}
// do Post/Redirect/Get (PRG) strategy to stop user refresh/back button
$prg = $this->prg($this->getRequest()->getRequestUri(), true);
if ($prg instanceof Response) {
return $prg;
}
// this is when the user first arrives to this url, display the form
else if ($prg === false) {
return $view;
}
// lets retrieve the post data stored in the PRG session
$post = $prg;
// validate the form
$form->setData($post);
if(!$form->isValid())
return $view;
\Zend\Debug\Debug::dump(__METHOD__.' '.__LINE__);
\Zend\Debug\Debug::dump($post);
\Zend\Debug\Debug::dump($product);
return $view;
}
/**
*
* #return \Product\Table\ProductTable
*/
public function getProductTable ()
{
$sm = $this->getServiceLocator();
$table = $sm->get('Product\Table\ProductTable');
return $table;
}
/**
*
* #return \Product\Table\BrandTable
*/
public function getBrandTable ()
{
return $this->getServiceLocator()
->get('Product\Table\BrandTable');
}
/**
*
* #return \Product\Table\CategoryTable
*/
public function getCategoryTable ()
{
return $this->getServiceLocator()
->get('Product\Table\CategoryTable');
}
}

Related

How to pass parameter to ajax callback from hook_form_alter in Drupal 8

I'm trying to implement a hook_form_alter method to modify the behaviour of one field through ajax callback in the form display of node.
The idea is when I select one option from the select list field (field_country) modify the values of other field list (field_laws). Specificly, when I select one country, the hook method pass this value (current) through ajax callback to changeLawsData. This callback get one external service that returns one array of values filtered by the country selected previously.
The issue is inside of callback method, i can't access to $form and $form_state objects that contain the previous hook_form_alter.
My question is: Is posible to pass by arguments this objects to the callback? With this i could handler the state of form and its field, for example.
Something like this:
$form['field_country']['widget']['#ajax'] = array(
'callback' => [$this,'changeLawsData'],
'event' => 'change',
'disable-refocus' => FALSE,
**'arguments' = array($form, $form_state)**
);
Here is the full code of this implementation.
<?php
namespace Drupal\obs_urban_system\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
/**
* Our event subscriber class.
*/
class NodeUrbanSystemFormAlterEventSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
HookEventDispatcherInterface::FORM_ALTER => 'hookFormAlter'
];
}
/**
* Implements hook_form_alter
*/
public function hookFormAlter($event) {
if($event->getFormId() == 'node_urban_system_edit_form') {
$form = $event->getForm();
$country = $form['field_country']['widget']['#default_value'];
$form['field_laws']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');
$form['field_law_articles']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawArticlesByCountry($country);
$form['field_country']['widget']['#ajax'] = array(
'callback' => [$this,'changeLawsData'],
'event' => 'change',
'disable-refocus' => FALSE
);
$event->setForm($form);
}
}
/**
* #param $form
* #param \Drupal\Core\Form\FormStateInterface $form_state
* #return \Drupal\Core\Ajax\AjaxResponse
*/
function changeLawsData(&$form, FormStateInterface $form_state) {
<!--- HERE IM USING THE $form object --->
$country = $form['field_country']['widget']['#default_value'];
<!--- --->
$laws = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');
foreach ($laws as $key => $value) {
$option .= "<option value='" . $key . "'>" . $value . " </option>";
}
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#edit-field-laws-0-value', $option));
return $response;
}
}
Thanks to all very much.
You need to do all the form manipulation within the form_alter.
When the ajax callback is fired, the form will be rebuilt and the current values of the form will be available in the form_state.
Your ajax callback should only return what is needed on the front end, it should not actually manipulate the form array.
Here is an example with your code (example only, untested)
<?php
namespace Drupal\obs_urban_system\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
/**
* Our event subscriber class.
*/
class NodeUrbanSystemFormAlterEventSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
HookEventDispatcherInterface::FORM_ALTER => 'hookFormAlter'
];
}
/**
* Implements hook_form_alter
*/
public function hookFormAlter($event) {
if($event->getFormId() == 'node_urban_system_edit_form') {
$form = $event->getForm();
$country = $form['field_country']['widget']['#default_value'];
// Get the form state object.
$form_state = $event->getFormState();
// Here we should check if a country has been selected.
$country = $form_state->getValue('country');
if ($country) {
// populate the options from service here.
$form['field_laws']['widget']['#options'] = \Drupal::service('custom_services.law')->getLawsByContent($country, 'country');
} else {
// Populate with default options.
$form['field_laws']['widget']['#options'] = [];
}
$form['field_law_articles']['widget'][0]['value']['#options'] = \Drupal::service('custom_services.law')->getLawArticlesByCountry($country);
$form['field_country']['widget']['#ajax'] = array(
'callback' => [$this,'changeLawsData'],
'event' => 'change',
'disable-refocus' => FALSE
);
$event->setForm($form);
}
}
/**
* #param $form
* #param \Drupal\Core\Form\FormStateInterface $form_state
* #return \Drupal\Core\Ajax\AjaxResponse
*/
function changeLawsData(&$form, FormStateInterface $form_state) {
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#edit-field-laws', $form['field_laws']));
return $response;
}
}
Please remember that the above is an example...

undefined variable company in zendframework 3

undefined variable company
undefined variable i m getting error
public function addPolicyAction()
{
if ($this->sessionContainer->empId == "")
{
return $this->redirect()->toRoute('admin_user_login');
}
$ouCode = $this->sessionContainer->ouCode;
$langCode = $this->sessionContainer->langCode;
$empId = $this->sessionContainer->empId;
$arrLabel = array('company_policy','pdid','pdname','file_name','active');
$commonTransalationLabel = $this->commonTranslation->getCommonTransactionInformation($arrLabel, $langCode);
$companyPolicyForm = new CompanyPolicyForm($commonTransalationLabel);
if ($this->getRequest()->isPost()) {
// $data = $this->params()->fromPost();
$request = $this->getRequest();
$data = array_merge_recursive(
$request->getPost()->toArray(), $request->getFiles()->toArray()
);
$data['ouCode'] = $ouCode;
$data['langCode'] = $langCode;
$companyPolicyForm->setData($data);
$chkValidate = $this->hrCompanypolicy->findBy([
'ouCode' => $this->sessionContainer->ouCode,
'langCode' => $this->sessionContainer->langCode
]);
if ($companyPolicyForm->isValid()) {
$data = $companyPolicyForm->getData();
if(isset($_POST['Submit'])){
$name = $_FILES['fileName']['name'];
$target_dir = 'public/media/policy_photos/';
$target_file = $target_dir . basename($_FILES["fileName"]["name"]);
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
$extensions_arr = array("jpg","jpeg","png","gif");
if( in_array($imageFileType,$extensions_arr) ){
move_uploaded_file($_FILES['fileName']['tmp_name'],$target_dir.$name);
}
}
$company = $this->companyPolicyManager->add($data,$ouCode, $langCode,$empId);
$cpData = $this->companyPolicyManager->getcpDataBycpId($data,$ouCode,$langCode);
$companyPolicyForm->buildCompanyPolicyData($cpData);
$this->flashMessenger()->addMessage($commonTransalationLabel['success_message']);
}
}
return new ViewModel([
'form' => $company,
'companypolicydata' => $cpData,
'label' => $commonTransalationLabel,
'form' => $companyPolicyForm,
'flashMessages' => $this->flashMessenger()->getMessages()
]);
}
i want to remove undefined variable in zendframework 3
i m using zendframework 3 and getting undefined variable in zendframework 3 what is the issue in the code ?
How to defined a variable in zendframework 3 i want to solve the issue
Problem is that you're using the $company variable in your return new ViewModel statement, but you only create the variable when the entire form is valid.
Instead of what you're doing, make sure that you provide a Form instance (whichever you need, e.g. CompanyForm) to your controller via the Factory. Then have your function along the lines like below (I've removed some error checking):
public function editAction()
{
$id = $this->params()->fromRoute('id', null);
/** #var Company $entity */
$entity = $this->getObjectManager()->getRepository(Company::class)->find($id);
/** #var CompanyForm $form */
$form = $this->getForm();
$form->bind($entity);
/** #var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
/** #var Company $entity */
$entity = $form->getObject();
$this->getObjectManager()->persist($entity);
try {
$this->getObjectManager()->flush();
} catch (Exception $e) {
throw new Exception('Could not save. Error was thrown, details: ', $e->getMessage());
}
return $this->redirectToRoute('companies/view', ['id' => $entity->getId()]);
}
}
return [
'form' => $form,
];
}

Retrieve session value and pass to an entity attribute

I want to retrieve a quantity for each item that I store in session and store it in database.
How do I retrieve the quantity in session and passed to my quantity attribute of my article entity during database persistence?
For example for this article:
(id 4, quantity 2).
I would store 2 in the quantity attribute of my article entity.
I tried :
$article->setQuantity($session->get('panier'));
I have this error:
An exception occurred while executing 'INSERT INTO article ....... {"4": "2"}
Notice: Array to string conversion
/**
* #Route("/payment", name="payment")
*/
public function paymentAction(Request $request)
{
$session = $request->getSession();
$produits = $this->getDoctrine()->getManager()->getRepository('AppBundle:Stock')->findArray(array_keys($session->get('panier')));
$commande = $session->get('commande');
var_dump($session->get('panier'));
if ($request->isMethod('POST')) {
$token = $request->get('stripeToken');
\Stripe\Stripe::setApiKey($this->getParameter("private_key"));
\Stripe\Charge::create(array(
"amount" => $commande->getTotal() * 100,
"currency" => "EUR",
"source" => $token,
"description" => ""
));
foreach ($produits as $produit) {
$article = new Article();
$article->setTitle($produit->getStock()->getTitle());
$article->setContent($produit->getStock()->getContent());
//problem here
$article->setQuantity($session->get('panier'));
//
$article->setPrice($produit->getPrice());
$commande->addArticle($article);
$em = $this->getDoctrine()->getManager();
$em->persist($commande);
$em->flush();
}
return $this->redirectToRoute('confirmation');
}
return $this->render(':default:payment.html.twig', array(
'commande' => $commande,
'panier' => $session->get('panier'),
'produits' => $produits,
'public_key' => $this->getParameter("public_key"),
));
}
Add article in session :
/**
* #Route("/shop/add/{id}", name="add_article")
*
*/
public function addArticlelAction(Request $request, $id)
{
$session = $request->getSession();
if (!$session->has('panier'))
$session->set('panier', array());
$panier = $session->get('panier');
if (array_key_exists($id, $panier)) {
if ($request->query->get('qte') != null)
$panier[$id] = $request->query->get('qte');
} else {
if ($request->query->get('qte') != null)
$panier[$id] = $request->query->get('qte');
else
$panier[$id] = 1;
}
$session->set('panier', $panier);
return $this->redirectToRoute('panier');
}
UPDATE:
If $id in addArticlelAction is the product id then:
foreach ($produits as $produit) {
$article = new Article();
$article->setTitle($produit->getStock()->getTitle());
$article->setContent($produit->getStock()->getContent());
//problem here
$article->setQuantity($session->get('panier')[$produit->getId()]);
//
$article->setPrice($produit->getPrice());
$commande->addArticle($article);
$em = $this->getDoctrine()->getManager();
$em->persist($commande);
$em->flush();
}
should work, because for the moment you have two products (product1 who has id 1 and product 4 who has id 4). When you call /shop/add/{id}, you are adding to $session->get('panier')[1] and $session->get('panier')[4] the quantities. So, when you're in foreach (to store in DB), you need to access index 1 and index 4 ($produit->getId())

Best way to manage filer form and result page

What's the best way to manage filter page and result page in Symfony?
I have a controller that manage filter form and execute query. The result of this query must pass in another controller action. The result must show in another controller action because I used knp_paginator. If I render the result in same controller action of filter form, when change page the controller show filter form and not result.
this is the approach that I used:
Action for create find form:
public function findAction(Request $request)
{
$form = $this->createFindForm($request);
$form->handleRequest($request);
if(($form->isSubmitted() && !$request->isXmlHttpRequest()))
{
if(($this->isValidFindForm($form) && $form->isValid()))
{
$parm = $request->request->get('findForm');
return $this->redirect($this->generateUrl('list_documents',$parm));
}
}
return $this->render(
'myBundle:Documents:document\document_find.html.twig',
array('form' => $form->createView())
);
}
private function createFindForm(Request $request)
{
$form = $this->createForm(
new findDocumentType(
$this->getDoctrine()->getManager(),
$request
),
null,
array(
'action' => $this->generateUrl('find_documents'),
'method' => 'POST',
)
);
return $form;
}
I used $parm = $request->request->get('findForm'); to get the querystring. "findForm" is the name of my filter form.
The redirecting action :
public function listAction(Request $request)
{
$documents = $this->searchDocument($request);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$documents,
$this->get('request')->query->get('page', 1)
);
return $this->render(
'myBundle:Documents:document\document_list.html.twig',
array('pagination' => $pagination)
);
}
The request is passed to search function (request contains querystring)
In search action:
private function searchDocument(Request $request)
{
$parm = $request->query;
$repository = $this->getDoctrine()->getRepository('docliteBundle:Document\\document');
$query = $repository
->createQueryBuilder('d');
....
With $request->query->get() I have access to all parameter.
Hope this help someone.
P.S. for the pagination I used KNP_paginator

How to handle in a generic way the session storage of filters avoiding the "Entity must be managed"

We've all been confronted to that problem : "Entity must be managed" when we are trying to setFilters() / getFilters()
So how to handle the session storage of filters in a generic way, in order to avoid merging and detaching or re-hydrating manually the entities ?
See the answer just below.
Well, some colleague (#benji07) at work have written this :
/**
* Set filters
* #param string $name Name of the key to store filters
* #param array $filters Filters
*/
public function setFilters($name, array $filters = array())
{
foreach ($filters as $key => $value) {
// Transform entities objects into a pair of class/id
if (is_object($value)) {
if ($value instanceof ArrayCollection) {
if (count($value)) {
$filters[$key] = array(
'class' => get_class($value->first()),
'ids' => array()
);
foreach ($value as $v) {
$identifier = $this->getDoctrine()->getEntityManager()->getUnitOfWork()->getEntityIdentifier($v);
$filters[$key]['ids'][] = $identifier['id'];
}
}
}
elseif (!$value instanceof \DateTime) {
$filters[$key] = array(
'class' => get_class($value),
'id' => $this->getDoctrine()->getEntityManager()->getUnitOfWork()->getEntityIdentifier($value)
);
}
}
}
$this->getRequest()->getSession()->set(
$name,
$filters
);
}
/**
* Get Filters
* #param string $name Name of the key to get filters
* #param array $filters Filters
*
* #return array
*/
public function getFilters($name, array $filters = array())
{
$filters = array_merge(
$this->getRequest()->getSession()->get(
$name,
array()
),
$filters
);
foreach ($filters as $key => $value) {
// Get entities from pair of class/id
if (is_array($value) && isset($value['class']) && isset($value['id'])) {
$filters[$key] = $this->getDoctrine()->getEntityManager()->find($value['class'], $value['id']);
} elseif (isset($value['ids'])) {
$data = $this->getDoctrine()->getEntityManager()->getRepository($value['class'])->findBy(array('id' => $value['ids']));
$filters[$key] = new ArrayCollection($data);
}
}
return $filters;
}
It works for basic entities, and multivalued choices
PS: Don't forget to add a use statement for the ArrayCollection
Disclaimer, we don't know if it's a good practice, and we know at least one limitation : you have to be sure that the object you try to save in the session has an id (it's 99,9% the case)

Resources