Creating sorted array for KnpLabs/KnpMenu - arrays

I want to create a sorted Menu in PHP, Symfony which could be very deep.
Therefor I have added 2 fields in category db (parent_id, sort).
My problem is to get a sorted array like:
array(
//MAIN CATEGORY 1
array(
'id' => 1,
'name' => 'Main',
'child'=> false
),
//MAIN CATEGORY 2
array(
'id' => 2,
'name' => 'Main2',
'child'=> false
),
//MAIN CATEGORY 3
array(
'id' => 6,
'name' => 'Main3',
'child'=> array(
array(
'id' => 4,
'name' => 'Sub of Main3',
'child'=> array(
'id' => 4,
'name' => 'Sub Sub og Main3',
'child'=> false
)
),
array(
'id' => 7,
'name' => '2. Sub og Main3',
'child'=> false
)
)
)
);
So I can use it to create the menu with KnpMenu Bundle.
I could not find another way, which is economical in performance and works with this bundle.
Can anybody help me, how to create the array out of the DB?
I tested something around and found a solution with knpMenuBundle like this:
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function mainMenu(FactoryInterface $factory, array $options)
{
$em = $this->container->get('doctrine')->getManager();
$mandant = $this->container->get('session')->get('mandantId');
$nodes = $em->getRepository('AppBundle:Categories')->findSorted($mandant);
$menu = $factory->createItem('root');
$menu->addChild('Startseite', array('route' => 'homepage'));
foreach($nodes as $node)
{
$childMenu = $menu->addChild($node['name'],array('route' => $node['route']));
$this->loadChild($childMenu,$node);
}
return $menu;
}
private function loadChild($childMenu,array $node)
{
if(isset($node['child']))
{
foreach ($node['child'] as $child)
{
$childMenu = $childMenu->addChild($child['name'],array('route' => $child['route']));
$this->loadChild($childMenu,$child);
}
}
return;
}

I had a very similar issue and here is how I solved it.
So my page entity looks something like this:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Knp\Menu\NodeInterface;
/**
* Page
*
* #ORM\Table(name="PAGE")
* #ORM\Entity()
*/
class Page implements NodeInterface
{
/**
* #var int
*
* #ORM\Column(name="ID", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="TITLE", type="string", length=255)
*/
private $title;
/**
* page | link | pdf
* #var string
*
* #ORM\Column(name="CONTENT_TYPE", type="string", length=255)
*/
private $contentType;
/**
* A page can have one parent
*
* #var FacetPage
*
* #ORM\ManyToOne(targetEntity="Page", inversedBy="childrenPages")
* #ORM\JoinColumn(name="PARENT_PAGE_ID", referencedColumnName="ID")
*/
private $parentPage;
/**
* A parent can have multiple children
*
* #var arrayCollection
*
* #ORM\OneToMany(targetEntity="Page", mappedBy="parentPage")
*
*/
private $childrenPages;
/**
* #var resource
*
* #ORM\Column(name="CONTENT", type="text", length=200000)
*/
private $content;
/**
* Many pages could have many allowed roles
*
* #var arrayCollection
*
* #ORM\ManyToMany(targetEntity="Role")
* #ORM\JoinTable(name="PAGE_ALLOWED_ROLES",
* joinColumns={#ORM\JoinColumn(name="page_id", referencedColumnName="ID")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="ID")}
* )
*/
private $allowedRoles;
/**
* #var string
*
* #ORM\Column(name="SLUG", type="string", nullable=true)
*/
private $slug;
/**
* #var string
*
* #ORM\Column(name="PERMALINK", type="string", nullable=true)
*/
private $permalink;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="CREATED_BY", referencedColumnName="ID", nullable=false)
* })
*
*/
private $author;
/**
* #var \DateTime
*
* #ORM\Column(name="CREATED_ON", type="datetime", nullable=false)
*/
private $createdOn;
/**
* The default status of new pages is published
*
* #var string
*
* #ORM\Column(name="STATUS", type="string", nullable=false, )
*/
private $status = 'published';
/**
* Page constructor.
*/
public function __construct( ) {
//https://knpuniversity.com/screencast/collections/many-to-many-setup#doctrine-arraycollection
$this->allowedRoles = new ArrayCollection();
$this->childrenPages = new ArrayCollection();
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
*/
public function setId( int $id )
{
$this->id = $id;
}
/**
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* #param string $title
*/
public function setTitle( string $title )
{
$this->title = $title;
}
/**
* #return string
*/
public function getContentType()
{
return $this->contentType;
}
/**
* #param string $contentType
*/
public function setContentType( string $contentType )
{
$this->contentType = $contentType;
}
/**
* #return Page
*/
public function getParentPage()
{
return $this->parentPage;
}
/**
* #param Page $parentPage
*/
public function setParentPage( Page $parentPage )
{
$this->parentPage = $parentPage;
}
/**
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* #param string $content
*/
public function setContent( string $content )
{
$this->content = $content;
}
/**
* #return ArrayCollection|Role[]
*/
public function getAllowedRoles()
{
return $this->allowedRoles;
}
/**
* #param arrayCollection $allowedRoles
*/
public function setAllowedRoles( $allowedRoles )
{
$this->allowedRoles = $allowedRoles;
}
/**
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* #param string $slug
*/
public function setSlug( string $slug )
{
$this->slug = $slug;
}
/**
* #return string
*/
public function getPermalink()
{
return $this->permalink;
}
/**
* #param string $permalink
*/
public function setPermalink( string $permalink )
{
$this->permalink = $permalink;
}
/**
* #return User
*/
public function getAuthor()
{
return $this->author;
}
/**
* #param FacetUser $author
*/
public function setAuthor( User $author )
{
$this->author = $author;
}
/**
* #return \DateTime
*/
public function getCreatedOn()
{
return $this->createdOn;
}
/**
* #param \DateTime $createdOn
*/
public function setCreatedOn( \DateTime $createdOn )
{
$this->createdOn = $createdOn;
}
/**
* #return string
*/
public function getStatus()
{
return $this->status;
}
/**
* #param string $status
*/
public function setStatus( string $status )
{
$this->status = $status;
}
/**
* #return ArrayCollection
*/
public function getChildrenPages()
{
return $this->childrenPages;
}
/**
* #param ArrayCollection $childrenPages
*/
public function setChildrenPages( $childrenPages )
{
$this->childrenPages = $childrenPages;
}
/**
* Get the name of the node
*
* Each child of a node must have a unique name
*
* #return string
*/
public function getName() {
return $this->title;
}
/**
* Get the options for the factory to create the item for this node
*
* #return array
* #throws \Exception
*/
public function getOptions() {
if($this->contentType == 'page'){
return [
'route' => 'core_page_id',
'routeParameters' => ['id'=>$this->id]
];
}
if($this->contentType == 'doc'){
return [
'uri'=>'/'.$this->getContent()
];
}
if($this->contentType == 'link'){
return [
'uri'=>$this->content
];
}
throw new \Exception('No valid options found for page type',500);
}
/**
* Get the child nodes implementing NodeInterface
*
* #return \Traversable
*/
public function getChildren() {
return $this->getChildren();
}
}
The main difference here is that it implements Knp's NodeInterface and its functions which are defined at the end of the entity, getName(), getOptions(), and getChildren().
Now on to my Builder, which basically does the same thing as your recursive function.
<?php
namespace AppBundle\Menu;
use AppBundle\Entity\Page;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
/** #var ItemInterface */
private $menu;
/**
* #param FactoryInterface $factory
* #param array $options
*
* #return ItemInterface
*/
public function mainMenu(FactoryInterface $factory, array $options)
{
$this->menu = $factory->createItem('root');
$this->menu->addChild('Home', array('route' => 'core_homepage'));
$em = $this->container->get('doctrine')->getManager();
// get all published pages
$pages = $em->getRepository(Page::class)->findBy(['status'=>'published']);
// build pages
try {
$this->buildPageTree( $pages );
} catch ( \Exception $e ) {
error_log($e->getMessage());
}
return $this->menu;
}
/**
*
* #param array $pages
* #param Page $parent
* #param MenuItem $menuItem
*
* #throws \Exception
*/
private function buildPageTree(array $pages, $parent = null, $menuItem = null)
{
/** #var Page $page */
foreach ($pages as $page) {
// If page doesn't have a parent, and no menuItem was passed then this is a top level add.
if(empty($page->getParentPage()) && empty($menuItem) )
$parentMenu = $this->menu->addChild($page->getTitle(), $page->getOptions());
// if the current page's parent is === supplied parent, go deeper
if ($page->getParentPage() === $parent) {
// if a menuItem was given, then this page is a child so added it to the provided menu.
if(!empty($menuItem))
$parentMenu = $menuItem->addChild($page->getTitle(), $page->getOptions());
// go deeper
$this->buildPageTree($pages, $page, $parentMenu);
}
}
}
}
I hope this helps in some way!

Related

Foreign key not stored in database using embed form in symfony 3

I have the following entities, form types and controller
Entity Client
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Client
*
* #ORM\Table(name="client")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ClientRepository")
*/
class Client
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="address", type="string", length=255)
*/
private $address;
/**
* #ORM\OneToMany(targetEntity="Contacts", mappedBy="client", cascade={"persist"})
*/
private $contacts;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Client
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set address
*
* #param string $address
*
* #return Client
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
/**
* Get address
*
* #return string
*/
public function getAddress()
{
return $this->address;
}
/**
* Constructor
*/
public function __construct()
{
$this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add contact
*
* #param \AppBundle\Entity\Contacts $contact
*
* #return Client
*/
public function addContact(\AppBundle\Entity\Contacts $contact)
{
$this->contacts[] = $contact;
return $this;
}
/**
* Remove contact
*
* #param \AppBundle\Entity\Contacts $contact
*/
public function removeContact(\AppBundle\Entity\Contacts $contact)
{
$this->contacts->removeElement($contact);
}
/**
* Get contacts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getContacts()
{
return $this->contacts;
}
}
Contacts entity is as below
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Contacts
*
* #ORM\Table(name="contacts")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ContactsRepository")
*/
class Contacts
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="fullname", type="string", length=255)
*/
private $fullname;
/**
* #var int
*
* #ORM\Column(name="user_type", type="smallint")
*/
private $userType;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="contacts")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set fullname
*
* #param string $fullname
*
* #return Contacts
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set userType
*
* #param integer $userType
*
* #return Contacts
*/
public function setUserType($userType)
{
$this->userType = $userType;
return $this;
}
/**
* Get userType
*
* #return int
*/
public function getUserType()
{
return $this->userType;
}
/**
* Set client
*
* #param \AppBundle\Entity\Client $client
*
* #return Contacts
*/
public function setClient(\AppBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* #return \AppBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
}
Client form type is as below
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use AppBundle\Entity\Client;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class ClientForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Client Name')))
->add('address', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Address')))
->add('contacts', CollectionType::class, array(
// each entry in the array will be an "email" field
'entry_type' => ContactsForm::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
))
->add('save', SubmitType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Client::class,
));
}
}
Contacts form type is as below
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Contacts;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class ContactsForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('fullname', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Full Name')))
->add('user_type', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Co-Owner'))
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Contacts::class,
));
}
}
Finally the controller to store data in two different tables being client as main table and contacts having foreign ken as client_id from table client is as below
/
**
* #Route("/client/add", name="add_client")
*/
public function addClientAction(Request $request)
{
$client = new Client();
$form = $this->createForm(ClientForm::class, $client);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$client = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($client);
$em->flush();
$this->addFlash(
'notice',
'Client Added!'
);
return $this->redirectToRoute('homepage');
}
return $this->render('default/addClient.html.twig', array('form' => $form->createView()));
}
The problem here is the data is added in both tables but the foreign key of the added client is not stored in table contacts, the value is null
This solution seems to work for some people may be for older version of symfony
But not luck to me. How to insert the foreign id as well. Am new to symfony and I am using symfony 3.2
It seems for me like a little mess up.
I guess you should add a contact from ContactController addAction.
Than in your Contact form type add EntityType, so you can choose a client for your contact. Here is some examples: http://symfony.com/doc/current/reference/forms/types/entity.html
Or you can set client manually by simple $contact->setClient($client) before you presist.
PS: rename Contacts entity to Contact. It is a little confusing)

SonataAdminBundle configureFormFields with two step relationated entities

I have the next entities
AppBundle/Entity/User.php
namespace AppBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="fos_user_user")
*
*/
class User extends BaseUser
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="SmsHistory", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
*/
private $smsHistory;
public function __construct()
{
parent::__construct();
$smsHistory = new ArrayCollection;
}
/**
* Get id
*
* #return int $id
*/
public function getId()
{
return $this->id;
}
/**
* #param \Doctrine\Common\Collections\ArrayCollection $smsHistory
*/
public function setSmsHistory($smsHistory){
if (count($smsHistory) > 0) {
foreach ($smsHistory as $i) {
$this->addSmsHistory($i);
}
}
return $this;
}
/**
* Add smsHistory
*
* #param \AppBundle\Entity\SmsHistory $smsHistory
*
* #return User
*/
public function addSmsHistory(\AppBundle\Entity\SmsHistory $smsHistory)
{
$smsHistory->setUser($this);
$this->smsHistory->add($smsHistory);
}
/**
* Remove smsHistory
*
* #param \AppBundle\Entity\SmsHistory $smsHistory
*/
public function removeSmsHistory(\AppBundle\Entity\SmsHistory $smsHistory)
{
$this->smsHistory->removeElement($smsHistory);
}
/**
* Get smsHistory
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSmsHistory()
{
return $this->smsHistory;
}
AppBundle/Entity/SmsHistory.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* SmsHistory
*
* #ORM\Table(name="sms_history")
* #ORM\Entity(repositoryClass="AppBundle\Repository\SmsHistoryRepository")
*/
class SmsHistory
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="smsHistory")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Contact", inversedBy="smsHistory")
* #ORM\JoinColumn(name="contact_id", referencedColumnName="id")
*/
private $contact;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
*
* #return SmsHistory
*/
public function setUser(\AppBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set contact
*
* #param \AppBundle\Entity\Contact $contact
*
* #return SmsHistory
*/
public function setContact(\AppBundle\Entity\Contact $contact = null)
{
$this->contact = $contact;
return $this;
}
/**
* Get contact
*
* #return \AppBundle\Entity\Contact
*/
public function getContact()
{
return $this->contact;
}
AppBundle/SmsHistory/Contact.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Contact
*
* #ORM\Table(name="contact")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ContactRepository")
*/
class Contact
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="contact")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\OneToMany(targetEntity="SmsHistory", mappedBy="contact", cascade={"persist"}, orphanRemoval=true)
*/
private $smsHistory;
public function __construct() {
$smsHistory = new ArrayCollection;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
*
* #return Contact
*/
public function setUser(\AppBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Add smsHistory
*
* #param \AppBundle\Entity\SmsHistory $smsHistory
*
* #return User
*/
public function addSmsHistory(\AppBundle\Entity\SmsHistory $smsHistory)
{
$smsHistory->setContact($this);
$this->smsHistory->add($smsHistory);
}
/**
* Remove smsHistory
*
* #param \AppBundle\Entity\SmsHistory $smsHistory
*/
public function removeSmsHistory(\AppBundle\Entity\SmsHistory $smsHistory)
{
$this->smsHistory->removeElement($smsHistory);
}
/**
* Get smsHistory
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSmsHistory()
{
return $this->smsHistory;
}
All entities are relationed with others.
In my UserAdmin i added in configureFormFields the field for add Contact and for add SmsHistory:
->add('contact', 'sonata_type_collection', array(
'cascade_validation' => true,
'by_reference' => true,
), array(
'edit' => 'inline',
'inline' => 'table',
))
->add('pushHistory', 'sonata_type_collection', array(
'cascade_validation' => true,
'by_reference' => true,
), array(
'edit' => 'inline',
'inline' => 'table',
))
In SmsHistoryAdmin i added the Contact field, to select a Contact:
->add('contact','sonata_type_model')
When I add a SmsHistory from UserAdmin, I want to display only Contact relationated with the current User i am editing, but all Contact of all User are displayed.
How I can do this?
Thank you!
I got the solution, I hope help someone.
In SmsHistoryAdmin, change this line:
->add('contact','sonata_type_model', array())
With this:
->add('contact', null, [
'query_builder' => $this->getAllowedContactQueryBuilder(),
])
And add this functions:
/**
* #return \Doctrine\Common\Persistence\ObjectManager|object
*/
protected function getEntityManager()
{
return $this->getContainer()->get('doctrine')->getManager();
}
/**
* #return null|\Symfony\Component\DependencyInjection\ContainerInterface
*/
protected function getContainer()
{
return $this->getConfigurationPool()->getContainer();
}
/**
* #return mixed
*/
private function getAllowedContactQueryBuilder()
{
if (!$this->getSubject()) {
return null;
}
return $this->getContactRepository()
->getContactByUserQueryBuilder($this->getSubject()->getUser());
}
/**
* #return \Doctrine\Common\Persistence\ObjectRepository
*/
public function getContactRepository()
{
return $this->getEntityManager()->getRepository('AppBundle:Contact');
}
And now the entity is filtering the Contact relationated with User.

SonataMediaBundle Many to Many extra field nothing work

Is there a way to handle on entity easily image with sonata media bundle?
I try all solution I find but nothing work....
Many problems :
- unable to delete image from collection
- unable to add more than one file each time
- unable to see thumbnails
This bundle is not easy to use, I think I will rewrite an another bundle I won't spend no more time.
I think I'm doing to the good thing :
<?php
namespace Immo\FichierBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Immeuble
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Immo\FichierBundle\Entity\ImmeubleRepository")
*/
class Immeuble
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="numero", type="integer")
*/
private $numero;
/**
* #var Immo\EtablissementBundle\Entity\Etablissement
*
* #ORM\OneToOne(targetEntity="Immo\EtablissementBundle\Entity\Etablissement", cascade={"persist"})
*/
private $agence;
/**
* #var Immo\FichierBundle\Entity\Adresse
*
* #ORM\OneToOne(targetEntity="Immo\FichierBundle\Entity\Adresse", cascade={"persist"})
*/
private $adresse;
/**
* #var string
*
* #ORM\Column(name="vente", type="string", length=255)
*/
private $vente;
/**
* #var string
*
* #ORM\Column(name="coproindiv", type="string", length=255)
*/
private $coproindiv;
/**
* #var string
*
* #ORM\Column(name="exregulier", type="string", length=255)
*/
private $exregulier;
/**
* #var string
*
* #ORM\OneToMany(targetEntity="Immo\FichierBundle\Entity\ImmeubleHasPhoto", mappedBy="immeuble",cascade={"all"})
* #ORM\OrderBy({"ordre"="ASC"})
*/
private $photos;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function __toString() {
return $this->getNumero().' '.$this->getAdresse();
}
/**
* Constructor
*/
public function __construct()
{
$this->photo = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set numero
*
* #param integer $numero
* #return Immeuble
*/
public function setNumero($numero)
{
$this->numero = $numero;
return $this;
}
/**
* Get numero
*
* #return integer
*/
public function getNumero()
{
return $this->numero;
}
/**
* Set agence
*
* #param Immo\EtablissementBundle\Entity\Etablissement $agence
* #return Immeuble
*/
public function setAgence(\Immo\EtablissementBundle\Entity\Etablissement $agence)
{
$this->agence = $agence;
return $this;
}
/**
* Get agence
*
* #return Immo\EtablissementBundle\Entity\Etablissement
*/
public function getAgence()
{
return $this->agence;
}
/**
* Set adresse
*
* #param Immo\FichierBundle\Entity\Adresse $adresse
* #return Immeuble
*/
public function setAdresse(\Immo\FichierBundle\Entity\Adresse $adresse)
{
$this->adresse = $adresse;
return $this;
}
/**
* Get adresse
*
* #return Immo\FichierBundle\Entity\Adresse
*/
public function getAdresse()
{
return $this->adresse;
}
/**
* Set vente
*
* #param string $vente
* #return Immeuble
*/
public function setVente($vente)
{
$this->vente = $vente;
return $this;
}
/**
* Get vente
*
* #return string
*/
public function getVente()
{
return $this->vente;
}
/**
* Set coproindiv
*
* #param string $coproindiv
* #return Immeuble
*/
public function setCoproindiv($coproindiv)
{
$this->coproindiv = $coproindiv;
return $this;
}
/**
* Get coproindiv
*
* #return string
*/
public function getCoproindiv()
{
return $this->coproindiv;
}
/**
* Set exregulier
*
* #param string $exregulier
* #return Immeuble
*/
public function setExregulier($exregulier)
{
$this->exregulier = $exregulier;
return $this;
}
/**
* Get exregulier
*
* #return string
*/
public function getExregulier()
{
return $this->exregulier;
}
/**
* Addphoto
*
* #param \Immo\FichierBundle\Entity\ImmeubleHasPhoto $photo
* #return Personne
*/
public function addPhotos(\Immo\FichierBundle\Entity\ImmeubleHasPhoto $photo)
{
$photo->setImmeuble($this);
$this->photos[] = $photo;
return $this;
}
/**
* Remove removePhoto
*
* #param \Immo\FichierBundle\Entity\ImmeubleHasPhoto $photo
*/
public function removePhotos(\Immo\FichierBundle\Entity\ImmeubleHasPhoto $photo)
{
$this->photos->removeElement($photo);
}
/**
* {#inheritdoc}
*/
public function setPhotos($photos)
{
$this->photos = new ArrayCollection();
foreach ($photos as $photo) {
$this->addPhoto($photo);
}
}
/**
* Get photo
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhotos()
{
return $this->photos;
}
}
The admin class :
/**
* #param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->tab('Général')
->with('Général')
->add('numero')
->add('agence')
->add('adresse','sonata_type_model_list')
->add('vente')
->add('coproindiv')
->add('exregulier')
->end()
->end()
->tab('Photos')
->with('Liste photos')
->add('photos', 'sonata_type_collection', array(
'label' => false,
'type_options' => array('delete' => true),
'cascade_validation' => true,
'btn_add' => 'Ajouter une photo',
"required" => false
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'ordre'
)
)
->end()
->end()
;
}
The join entity :
<?php
namespace Immo\FichierBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* ImmeubleHasPhoto
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Immo\FichierBundle\Entity\ImmeubleHasPhotoRepository")
*/
class ImmeubleHasPhoto
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255,nullable=true)
*/
private $nom;
/**
* #var integer
* #ORM\Column(name="ordre", type="integer")
*/
private $ordre;
/**
* #ORM\ManyToOne(targetEntity="Immeuble", inversedBy="photos",cascade={"all"},fetch="LAZY")
* #ORM\JoinColumn(name="immeuble_id", referencedColumnName="id", nullable=false)
*/
private $immeuble;
/**
* #var \Application\Sonata\MediaBundle\Entity\Media
* #ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Media",cascade={"all"},fetch="LAZY")
* #ORM\JoinColumn(name="photo_id", referencedColumnName="id", nullable=false)
*/
private $photo;
public function __construct() {
}
public function __toString() {
return $this->getNom();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setImmeuble(\Immo\FichierBundle\Entity\Immeuble $immeuble)
{
$this->immeuble = $immeuble;
return $this;
}
/**
* Get Immeuble
*
* #return \Immo\FichierBundle\Entity\Immeuble
*/
public function getImmeuble()
{
return $this->immeuble;
}
/**
* Set photo
*
* #param string $photo
* #return Application\Sonata\MediaBundle\Entity\Media
*/
public function setPhoto(\Application\Sonata\MediaBundle\Entity\Media $photo=null)
{
$this->photo = $photo;
return $this;
}
/**
* Get photo
*
* #return Application\Sonata\MediaBundle\Entity\Media
*/
public function getPhoto()
{
return $this->photo;
}
/**
* Set nom
*
* #param string $nom
* #return ImmeubleHasPhoto
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set ordre
*
* #param integer $ordre
* #return ImmeubleHasPhoto
*/
public function setOrdre($ordre)
{
$this->ordre = $ordre;
return $this;
}
/**
* Get ordre
*
* #return integer
*/
public function getOrdre()
{
return $this->ordre;
}
}
And finally the admin class for my join entity :
/**
* #param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$link_parameters = array();
if ($this->hasParentFieldDescription()) {
$link_parameters = $this->getParentFieldDescription()->getOption('link_parameters', array());
}
if ($this->hasRequest()) {
$context = $this->getRequest()->get('context', null);
if (null !== $context) {
$link_parameters['context'] = $context;
}
}
$formMapper
->add('nom',null,array('label'=>'Titre'))
->add('photo','sonata_type_model_list', array('required' => false), array(
'link_parameters' => array('context' => 'Photos_immeuble')
))
->add('ordre','integer')
;
}
Is there something wrong? I've passe many day to find why I'm unable to attache image but I found nothing.... I really think this bundle isn't functionnal....
Thanks for your help.

How to save the accent character é as é in a mysql database when it is inserted in a form in Symfony2 ?

I would like to know how to save the accent character é as é in a mysql database when it is inserted in a form in Symfony2. The explanation is as below:
This the code of the form builder I have:
<?php
namespace Ikproj\GroupeBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MessagesType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('contenu','textarea', array('attr' => array('rows' => '6','cols' => '40')));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ikproj\GroupeBundle\Entity\Messages'
));
}
/**
* #return string
*/
public function getName()
{
return 'ikproj_groupebundle_messages';
}
}
This is the code of the entity belonged to the form builder above:
<?php
namespace Ikproj\GroupeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Messages
*
* #ORM\Table(name="messages")
* #ORM\Entity(repositoryClass="Ikproj\GroupeBundle\Entity\MessagesRepository")
*/
class Messages
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="actor", type="integer")
*/
private $actor;
/**
* #var integer
*
* #ORM\Column(name="subject", type="integer")
*/
private $subject;
/**
* #var string
*
* #ORM\Column(name="contenu", type="string")
*/
private $contenu;
/**
* #var string
*
* #ORM\Column(name="status", type="string", length=10)
*/
private $status;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=10)
*/
private $type;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set actor
*
* #param integer $actor
* #return Messages
*/
public function setActor($actor)
{
$this->actor = $actor;
return $this;
}
/**
* Get actor
*
* #return integer
*/
public function getActor()
{
return $this->actor;
}
/**
* Set subject
*
* #param integer $subject
* #return Messages
*/
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
/**
* Get subject
*
* #return integer
*/
public function getSubject()
{
return $this->subject;
}
/**
* Set contenu
*
* #param string $contenu
* #return Messages
*/
public function setContenu($contenu)
{
$this->contenu = $contenu;
return $this;
}
/**
* Get contenu
*
* #return string
*/
public function getContenu()
{
return $this->contenu;
}
/**
* Set status
*
* #param string $status
* #return Messages
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* #return string
*/
public function getStatus()
{
return $this->status;
}
/**
* Set type
*
* #param string $type
* #return Messages
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
}
This is the code of the controller I have:
public function SendMessageAction(Request $request, $actor, $subject, $cible) {
$message = new Messages();
$form = $this->createForm(new MessagesType(), $message);
$em = $this->getDoctrine()->getManager();
$actor1 = $actor;
$subject1 = $subject;
$status1 = "unseen";
$cible1 = $cible;
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$message->setActor($actor1);
$message->setSubject($subject1);
$message->setStatus($status1);
$message->setType($cible1);
$em->persist($message);
$em->flush();
return $this->redirect($this->generateUrl('task_success'));
}
}
else {
return $this->render('IkprojGroupeBundle:Messages:SendMessage.html.twig', array(
'form' => $form->createView(),
'actor' => $actor,
'subject' => $subject,
'cible' => $cible
));
}
}
And this is the code of the file config.yml belonged to the doctrine configuration:
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
The problem is that when I insert the accent character é in the form then I valid, it will be saved in the database as é not é as you can see in screenshot below:
Whereas when I run the code below in Symfony2:
<?php
$tab = $_REQUEST['table'];
$a = $tab[0];
$b = $tab[1];
$con=mysqli_connect("localhost","root","","wkayetdb");
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"INSERT INTO messages(actor,subject,contenu,status,type) VALUES ($a,$b,'é','unseen','G')");
mysqli_close($con);
?>
it works correctly and the character é will be saved as é as you can see below:
So, my questions are:
What is wrong in my code?
How can I save é as é in a mysql database once it is inserted in a form in Symfony2 ?
I do not know why you want to do that
but if you want to do this, simply comment that line "charset: UTF8"
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
# charset: UTF8

symfony2 file lost upon form error

I am using a standard implementation of file upload in connection with doctrine, as per the example on the symfony2 website tutorials.
When my upload form encounters an error in validation, and sends the user back to the form with error messages, it looses the file chosen for upload, although if I var_dump my $entity->file I can see that it has the file...
//if form is valid, do some stuff... if not:
else {
//var_dump($entity->file); //This works, I get my file
//die;
//Get and check the folder chosen as parent
$entity->setFolder( $this->checkFolderId($request->request->get('folder')) ); //will cause die() if folder doesn't belong to this company
$folders = $this->getFolders();
return $this->render('BizTVMediaManagementBundle:Image:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
'folders' => $folders,
'fileExists' => $fileExists,
));
}
After this is put to the twig view, there is nothing in the file field.
Here is my entity...
<?php
namespace BizTV\MediaManagementBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* BizTV\MediaManagementBundle\Entity\Image
*
* #ORM\Table(name="image")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank
*/
private $name;
/**
* #var integer $width
*
* #ORM\Column(name="width", type="integer")
*/
private $width;
/**
* #var integer $height
*
* #ORM\Column(name="height", type="integer")
*/
private $height;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $path;
/**
* #var object BizTV\BackendBundle\Entity\company
*
* #ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
*/
protected $company;
/**
* #var object BizTV\MediaManagementBundle\Entity\Folder
*
* #ORM\ManyToOne(targetEntity="BizTV\MediaManagementBundle\Entity\Folder")
* #ORM\JoinColumn(name="folder", referencedColumnName="id", nullable=true)
*/
protected $folder;
/**
* #Assert\File(maxSize="6000000")
*/
public $file;
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
$this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/images';
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set width
*
* #param integer $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Get width
*
* #return integer
*/
public function getWidth()
{
return $this->width;
}
/**
* Set height
*
* #param integer $height
*/
public function setHeight($height)
{
$this->height = $height;
}
/**
* Get height
*
* #return integer
*/
public function getHeight()
{
return $this->height;
}
/**
* Set path
*
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set company
*
* #param BizTV\BackendBundle\Entity\company $company
*/
public function setCompany(\BizTV\BackendBundle\Entity\company $company)
{
$this->company = $company;
}
/**
* Get company
*
* #return BizTV\BackendBundle\Entity\company
*/
public function getCompany()
{
return $this->company;
}
/**
* Set folder
*
* #param BizTV\MediaManagementBundle\Entity\Folder $folder
*/
public function setFolder(\BizTV\MediaManagementBundle\Entity\Folder $folder = NULL)
{
$this->folder = $folder;
}
/**
* Get folder
*
* #return BizTV\MediaManagementBundle\Entity\Folder
*/
public function getFolder()
{
return $this->folder;
}
}
And the form:
<?php
namespace BizTV\MediaManagementBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ImageType extends AbstractType
{
function __construct($createAction=0) {
$this->createAction = $createAction;
}
public function buildForm(FormBuilder $builder, array $options)
{
$createAction = $this->createAction;
if ($createAction) {
$builder
->add('file')
;
}
$builder
->add('name', 'text', array('label' => 'Namn'))
;
}
public function getName()
{
return 'biztv_mediamanagementbundle_imagetype';
}
}
You can't, for security purposes, set a file for the upload field. See here for more info. How to set the value of a HTML file field?
I suggest you are trying to access the file property of your entity in twig. Please take a quick look at your upload function.
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
As you can see the file property is being unset after the upload and persist operation has completed.
Now to have twig show your actual image you have to use the webPath property as this is the generated url to your newly uploaded image.
File uploading can be handled a bit easier with the Dustin10/VichUploaderBundle which also supports file system abstraction with KnpLabs/Gaufrette.
Hope this helps :)

Resources