I am new to symfony 3 and I would like to understand how to get a value from a table according to the result found.
Let me explain :
According to the bass diagram below, each "produit" has a "poids"(nom) and a "valeur"(valeur)
view bdd:
I would like in my basket view to display the total value of the weight according to the quantity of course.
For example, I have a product at 2kg and another at 0.300kg, it would have to result in the value of 2.3kg which is in the weight table.
I can not perform this "function".
Here is my PanierController.
class PanierController extends Controller
{
public function supprimerAction(SessionInterface $session, $id)
{
$panier = $session->get('panier');
if (array_key_exists($id, $panier))
{
unset($panier[$id]);
$session->set('panier', $panier);
$this->addFlash('success', 'Article supprimé avec succès !');
}
return $this->redirect($this->generateUrl('panier'));
}
public function ajouterAction(SessionInterface $session, Request $request, $id)
{
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');
}
$this->addFlash('success', 'Quantité modifié avec succès !');
} else {
if ($request->query->get('qte') != null) {
$panier[$id] = $request->query->get('qte');
} else {
$panier[$id] = 1;
}
$this->addFlash('success', 'Article ajouté avec succès !');
}
$session->set('panier', $panier);
return $this->redirect($this->generateUrl('panier'));
}
public function panierAction(SessionInterface $session)
{
if (!$session->has('panier')) {
$session->set('panier', array());
}
$em = $this->getDoctrine()->getManager();
$produits = $em->getRepository('EcommerceBundle:Produits')->findArray(array_keys($session->get('panier')));
return $this->render('EcommerceBundle:Default:panier/layout/panier.html.twig', array('produits' => $produits, 'panier' => $session->get('panier')));
}
public function livraisonAction()
{
// servira pour l'adresse de livraison
return $this->render('EcommerceBundle:Default:panier/layout/livraison.html.twig');
}
public function validationAction()
{
return $this->render('EcommerceBundle:Default:panier/layout/validation.html.twig');
}
}
If you need more information, please let me know.
#JasonRoman,
That is to say ?
For example to display the products in the Shopping Cart view, I use the ProductsRepository in the Shopping CartController:
public function panierAction(SessionInterface $session)
{
if (!$session->has('panier')) {
$session->set('panier', array());
}
$em = $this->getDoctrine()->getManager();
$produits = $em->getRepository('EcommerceBundle:Produits')->findArray(array_keys($session->get('panier')));
return $this->render('EcommerceBundle:Default:panier/layout/panier.html.twig', array('produits' => $produits, 'panier' => $session->get('panier')));
}
ProductsRepository:
class ProduitsRepository extends EntityRepository
{
public function findArray($array)
{
$qb = $this->createQueryBuilder('u')
->select('u')
->where('u.id IN (:array)')
->setParameter('array', $array);
return $qb->getQuery()->getResult();
}
}
The result is correct in the Cart view.
In the basket view, if I ask him to show me the total weight in the basket, I do:
{% Extends "::layout/layout.html.twig"%}
{% Set totalHT = 0%}
{% Set livraisonHT = 0%}
{% Block body%}
{% Set livraisonHT = livraisonHT + (panier[produit.id] * produit.poids.nom)%}
livraisonHT gives me the total weight
On the other hand, I do not know what function to write so that it shows me the corresponding value.
Currently I have in my basket:
One product at 2kg and another product at 0.3kg
{% Set livraisonHT = livraisonHT + (panier[produit.id] * product.poids.non)%}
I think I have put my finger on something,
In my basket view, if I do a dump (produits) i get, that:
array:1 [▼
0 => Produits {#546 ▼
-id: 5
-image: Media {#445 ▶}
-gamme: Gamme {#396 ▶}
-marque: Marque {#467 ▶}
-tva: Tva {#563 ▼
+__isInitialized__: true
-id: 11
-multiplicate: 0.83333333333334
-nom: "TVA 20 %"
-valeur: 20.0
…2
}
-poids: Poids {#670 ▼
+__isInitialized__: false
-id: 209
-nom: null
-valeur: null
…2
}
-categorie: Categories {#684 ▶}
-nom: "Phantom 4 Standard"
-resume: "le résumé"
-description: "La description longue"
-details: "details à voir"
-prix: 1000.0
-disponible: true
}
]
In "weight" the name and value are zero?
Related
I have a very basic symfony 5 + easyadmin 3 app.
I created using the make:entity two entities: Posts and Categories
When I try to edit Category to assign Posts, posts are not saved in DB.
But If I add the category on the post edit is saves in db.
Any idea what I'm missing here?
CategoryCrudController.php
public function configureFields(string $pageName): iterable
{
if (Crud::PAGE_EDIT === $pageName)
{
yield TextField::new('title');
yield DateTimeField::new('created_at')
->setFormTypeOption('disabled','disabled');
yield AssociationField::new('posts')
->autocomplete();
Entity Category.php
/**
* #ORM\OneToMany(targetEntity=Post::class, mappedBy="category")
*/
private $posts;
public function __construct()
{
$this->posts = new ArrayCollection();
}
/**
* #return Collection|Post[]
*/
public function getPosts(): Collection
{
return $this->posts;
}
public function addPost(Post $post): self
{
if (!$this->posts->contains($post)) {
$this->posts[] = $post;
$post->setCategory($this);
}
return $this;
}
public function removePost(Post $post): self
{
if ($this->posts->removeElement($post)) {
// set the owning side to null (unless already changed)
if ($post->getCategory() === $this) {
$post->setCategory(null);
}
}
return $this;
}
Found the solution thanks to:
https://github.com/EasyCorp/EasyAdminBundle/issues/860#issuecomment-192605475
For Easy Admin 3 you just need to add
->setFormTypeOptions([
'by_reference' => false,
])
CategoryCrudController.php
public function configureFields(string $pageName): iterable
{
if (Crud::PAGE_EDIT === $pageName)
{
yield TextField::new('title');
yield DateTimeField::new('created_at')
->setFormTypeOption('disabled','disabled');
yield AssociationField::new('posts')
->setFormTypeOptions([
'by_reference' => false,
])
->autocomplete();
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())
I have two actions that edit the entity 'user' attribute 'etat' : activateAction makes the 'etat' equals to 1 if it was equal to 0, else it returns a flashbag message 'the account is already activated', and the desactivateAction is supposed to do the opposite, but it doesn't work!!! Here is the code of both activate and desactivate actions:
/**
* #Route("/admin/gestEtat/act/{iduser}", name="act")
*
* #Template()
*/
public function activateAction($iduser)
{
$user=new user();
$em=$this->getDoctrine()->getManager();
$repository = $em->getRepository("CNAMCMSBundle:user");
$user = $repository->find($iduser);
if($user)
{
if ($user->getEtat()==1) {
$this->get("session")->getFlashBag()->add('act',"Ce compte est déjà activé!");
return $this->redirectToRoute('gestEtat',
array());
}
elseif ($user->getEtat()==0) {
$user->setEtat('1');
$em->merge($user);
$em->flush();
return $this->redirectToRoute('gestEtat',
array());
}
}
}
/**
* #Route("/admin/gestEtat/desact/{id}",name="desact")
*
* #Template()
*/
public function desactivateAction($id)
{
$user=new user();
$em=$this->getDoctrine()->getManager();
$repository = $em->getRepository("CNAMCMSBundle:user");
$user = $repository->find($id);
//$session = new Session();
//$session->start();
//$users=$session->get('users_table');
if($user)
{
if ($user->getEtat()==0) {
$this->get("session")->getFlashBag()->add('desact',"Ce compte est déjà désactivé!");
// return $this->render('CNAMCMSBundle:Default:gestEtat.html.twig',
return $this->redirectToRoute('gestEtat',
array());
}
elseif ($user->getEtat()==1) {
$user->setEtat('0');
$em->merge($user);
$em->flush();
// return $this->render('CNAMCMSBundle:Default:gestEtat.html.twig',
return $this->redirectToRoute('gestEtat',
array());
}
}
}
Seems like you're performing setEtat('0') by passing in the string '0'. If the entity variable is a boolean, you should send it as a (true/false) or (1/0). If it is a string, you should be checking in your code elseif (getEtat()=='1')
The way it stands, checking if (getEtat()==1) will be the same as if (getEtat()), which will return true if getEtat() is not explicitly a false/null boolean, or a null variable.
I'm using Symfony 2.1 for a project. I use the FOSUserBundle for managing users & SonataAdminBundle for administration usage.
I have some questions about that:
As an admin, I want to set roles from users in users edit form. How can I have access to roles in role_hierarchy? And how can I use them as choice fields so the admin can set roles to users?
When I show roles in a list, it is shown as string like this:
[0 => ROLE_SUPER_ADMIN] [1 => ROLE_USER]
How can I change it to this?
ROLE_SUPER_ADMIN, ROLE_USER
I mean, having just the value of the array.
Based on the answer of #parisssss although it was wrong, here is a working solution. The Sonata input field will show all the roles that are under the given role if you save one role.
On the other hand, in the database will be stored only the most important role. But that makes absolute sense in the Sf way.
protected function configureFormFields(FormMapper $formMapper) {
// ..
$container = $this->getConfigurationPool()->getContainer();
$roles = $container->getParameter('security.role_hierarchy.roles');
$rolesChoices = self::flattenRoles($roles);
$formMapper
//...
->add('roles', 'choice', array(
'choices' => $rolesChoices,
'multiple' => true
)
);
And in another method:
/**
* Turns the role's array keys into string <ROLES_NAME> keys.
* #todo Move to convenience or make it recursive ? ;-)
*/
protected static function flattenRoles($rolesHierarchy)
{
$flatRoles = array();
foreach($rolesHierarchy as $roles) {
if(empty($roles)) {
continue;
}
foreach($roles as $role) {
if(!isset($flatRoles[$role])) {
$flatRoles[$role] = $role;
}
}
}
return $flatRoles;
}
See it in action:
As for the second question I added a method in the User class that looks like this
/**
* #return string
*/
public function getRolesAsString()
{
$roles = array();
foreach ($this->getRoles() as $role) {
$role = explode('_', $role);
array_shift($role);
$roles[] = ucfirst(strtolower(implode(' ', $role)));
}
return implode(', ', $roles);
}
And then you can declare in your configureListFields function:
->add('rolesAsString', 'string')
i found an answer for my first question!(but the second one in not answered yet..)
i add the roles like below in configureFormFields function :
protected function configureFormFields(FormMapper $formMapper) {
//..
$formMapper
->add('roles','choice',array('choices'=>$this->getConfigurationPool()->getContainer()->getParameter('security.role_hierarchy.roles'),'multiple'=>true ));
}
I would be very happy if anyone answers the second question :)
Romain Bruckert's solution is almost perfect, except that it doesn't allow to set roles, which are roots of role hierrarchy. For instance ROLE_SUPER_ADMIN.
Here's the fixed method flattenRoles, which also returns root roles:
protected static function flattenRoles($rolesHierarchy)
{
$flatRoles = [];
foreach ($rolesHierarchy as $key => $roles) {
$flatRoles[$key] = $key;
if (empty($roles)) {
continue;
}
foreach($roles as $role) {
if(!isset($flatRoles[$role])) {
$flatRoles[$role] = $role;
}
}
}
return $flatRoles;
}
Edit: TrtG already posted this fix in comments
Just to overplay it a bit, here is my enhanced version of Romain Bruckert and Sash which gives you an array like this:
array:4 [▼
"ROLE_USER" => "User"
"ROLE_ALLOWED_TO_SWITCH" => "Allowed To Switch"
"ROLE_ADMIN" => "Admin (User, Allowed To Switch)"
"ROLE_SUPER_ADMIN" => "Super Admin (Admin (User, Allowed To Switch))"
]
This helps you find all roles, that include a specific role:
I know its much code, it could be done much better, but maybe it helps somebody or you can at least use pieces of this code.
/**
* Turns the role's array keys into string <ROLES_NAME> keys.
* #param array $rolesHierarchy
* #param bool $niceName
* #param bool $withChildren
* #param bool $withGrandChildren
* #return array
*/
protected static function flattenRoles($rolesHierarchy, $niceName = false, $withChildren = false, $withGrandChildren = false)
{
$flatRoles = [];
foreach ($rolesHierarchy as $key => $roles) {
if(!empty($roles)) {
foreach($roles as $role) {
if(!isset($flatRoles[$role])) {
$flatRoles[$role] = $niceName ? self::niceRoleName($role) : $role;
}
}
}
$flatRoles[$key] = $niceName ? self::niceRoleName($key) : $key;
if ($withChildren && !empty($roles)) {
if (!$recursive) {
if ($niceName) {
array_walk($roles, function(&$item) { $item = self::niceRoleName($item);});
}
$flatRoles[$key] .= ' (' . join(', ', $roles) . ')';
} else {
$childRoles = [];
foreach($roles as $role) {
$childRoles[$role] = $niceName ? self::niceRoleName($role) : $role;
if (!empty($rolesHierarchy[$role])) {
if ($niceName) {
array_walk($rolesHierarchy[$role], function(&$item) { $item = self::niceRoleName($item);});
}
$childRoles[$role] .= ' (' . join(', ', $rolesHierarchy[$role]) . ')';
}
}
$flatRoles[$key] .= ' (' . join(', ', $childRoles) . ')';
}
}
}
return $flatRoles;
}
/**
* Remove underscors, ROLE_ prefix and uppercase words
* #param string $role
* #return string
*/
protected static function niceRoleName($role) {
return ucwords(strtolower(preg_replace(['/\AROLE_/', '/_/'], ['', ' '], $role)));
}
The second answer is below.
Add lines in sonata admin yml file .
sonata_doctrine_orm_admin:
templates:
types:
list:
user_roles: AcmeDemoBundle:Default:user_roles.html.twig
and in user_roles.html.twig files add below lines
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{% for row in value %}
{{row}}
{% if not loop.last %}
,
{% endif %}
{% endfor %}
{% endblock %}
then into your admin controller and inconfigureListFields function add this line
->add('roles', 'user_roles')
hope this will solve your problem
I have a form in which you can edit the attributes of object "one". This object has a one-to-many relationship with another object, "many". I want a user to be able to select assign a "many" object to the "one" from the form. I can't figure out how to do that!
Right now:
\Entity\One.php
class One
{
...
/*
* #ORM\ManyToOne(targetEntity="many", inversedBy="one")
* #ORM\JoinColumn(name="manyId", referencedColumnName="id")
*/
protected $manyId;
...
}
\Controller\OneController.php
class OneController extends Controller
{
...
public function editAction($oneId, Request $request)
{
if ($oneId) {
$one = $this->getDoctrine()
->getRepository('One')
->find($oneId);
} else {
$one = new One();
}
$em = $this->getDoctrine()->getEntityManager();
$manyEntity = 'Bundle\Entity\Many';
$manyList = new EntityChoiceList($em, $manyEntity);
$form = $this->createFormBuilder($one)
->add('many', 'choice', array('choice_list' => $manyList))
->getForm();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$entityManager = $this->getDoctrine()->getEntityManager();
$entityManager->persist($one);
}
}
}
...
}
This results in the error message "Expected argument of type "scalar", "Proxies\BundleEntityManyProxy" given".
Thanks for your help!
Solved! I should have written ->add('many', 'entity', array('class' => 'BundleMany')).
See http://forum.symfony-project.org/viewtopic.php?f=23&t=36604.