SonataMediaBundle Many to Many extra field nothing work - sonata-admin

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.

Related

Disable swagger for some entites only in API Platform

I would like to use a controller for downloading files.
The request is coming via an entity url and an included custom controller.
In the invoke function the requested file will be sent to the browser.
The problem is that the swagger documentation will be shown in a browser, the output of the controller will be ignored.
Only via a postman request the file content will be shown.
A solution would be to disable swagger for this entity.
Entity:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\GetMediaObjectAction;
/**
* #ApiResource(
* attributes={
* "route_prefix"="/api"
* },
* collectionOperations={},
* itemOperations={
* "archiveapi_get_file"={
* "path"="/file/{company_id}/{id}/{filename}",
* "defaults"={"_api_receive"=false},
* "read"=false,
* "requirements" = {
* "company_id" = "\d+",
* "id" = ".+",
* "filename" = "(.+)\.(.+)",
* },
* }
* },
* normalizationContext={"groups"={"MediaObject:read"}}
* )
*/
class MediaObject
{
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $id = null;
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $companyId = null;
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $filename = null;
/**
* #return string|null
*/
public function getId(): ?string
{
return $this->id;
}
/**
* #param string|null $id
* #return MediaObject
*/
public function setId(?string $id): MediaObject
{
$this->id = $id;
return $this;
}
/**
* #return string|null
*/
public function getCompanyId(): ?string
{
return $this->companyId;
}
/**
* #param string|null $companyId
* #return MediaObject
*/
public function setCompanyId(?string $companyId): MediaObject
{
$this->companyId = $companyId;
return $this;
}
/**
* #return string|null
*/
public function getFilename(): ?string
{
return $this->filename;
}
/**
* #param string|null $filename
* #return MediaObject
*/
public function setFilename(?string $filename): MediaObject
{
$this->filename = $filename;
return $this;
}
}
Controller:
<?php
namespace App\Controller;
use App\Entity\MediaObject;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use function PHPUnit\Framework\throwException;
final class GetMediaObjectAction extends AbstractController
{
/**
* #Route(
* name="archiveapi_get_file",
* path="/file/{companyId}/{id}/{filename}",
* methods={"GET"},
* defaults={
* "_api_resource_class"=MediaObject::class,
* "_api_item_operation_name"="archiveapi_get_file",
* "_api_receive"=false,
* "_api_respond"=false
* }
* )
*/
public function __invoke(Request $request, $companyId, $id, $filename): BinaryFileResponse
{
$projectDir = $this->getParameter('kernel.project_dir');
$file = sprintf("%s/var/data/invoices_%s/%s/%s", $projectDir, $companyId, $id, $filename);
if (!file_exists($file)) {
throw new NotFoundHttpException('file not available');
}
return new BinaryFileResponse($file);
}
}

Creating sorted array for KnpLabs/KnpMenu

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!

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.

Symfony2 Association class form

This is my first Symfony project, and I can't figure out how to solve my problem.
Basically, i'm trying to make an invoice using a form.
I have a "Facturation" (ie invoice) Entity, a "TypeOfService" Entity, and a "Service" Entity (the sole attribute of which is the quantity of the type of service needed for the invoice) that acts as an association class.
I'd like to dynamically add "New Service" fields to my FacturationType form using Javascript (probably AngularJS). So I have to create N new Service entities that each associate with both my Facturation entity and an existing TypeOfService entity.
Here's my Facturation entity:
use Doctrine\ORM\Mapping AS ORM;
/**
* Facturation
*
* #ORM\Table(name="facturation")
* #ORM\Entity
*/
class Facturation
{
...
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="facturation")
*/
private $service;
/**
* Add service
*
* #param \AppBundle\Entity\Service $service
* #return Facturation
*/
public function addService(\AppBundle\Entity\Service $service)
{
$this->service[] = $service;
return $this;
}
/**
* Remove service
*
* #param \AppBundle\Entity\Service $service
*/
public function removeService(\AppBundle\Entity\Service $service)
{
$this->service->removeElement($service);
}
/**
* Get service
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getService()
{
return $this->service;
}
}
Then Service:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* Service
*
* #ORM\Table(name="service")
* #ORM\Entity
*/
class Service
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $quantity;
/**
* #ORM\ManyToOne(targetEntity="TypeOfService", inversedBy="service")
* #ORM\JoinColumn(name="type_of_service_id", referencedColumnName="id")
*/
private $typeOfService;
/**
* #ORM\ManyToOne(targetEntity="Facturation", inversedBy="service")
* #ORM\JoinColumn(name="facturation_id", referencedColumnName="id")
*/
private $facturation;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set quantity
*
* #param integer $quantity
* #return Service
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* #return integer
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set typeOfService
*
* #param \AppBundle\Entity\TypeOfService $typeOfService
* #return Service
*/
public function setTypeOfService(\AppBundle\Entity\TypeOfService $typeOfService = null)
{
$this->typeOfService = $typeOfService;
return $this;
}
/**
* Get typeOfService
*
* #return \AppBundle\Entity\TypeOfService
*/
public function getTypeOfService()
{
return $this->typeOfService;
}
/**
* Set facturation
*
* #param \AppBundle\Entity\Facturation $facturation
* #return Service
*/
public function setFacturation(\AppBundle\Entity\Facturation $facturation = null)
{
$this->facturation = $facturation;
return $this;
}
/**
* Get facturation
*
* #return \AppBundle\Entity\Facturation
*/
public function getFacturation()
{
return $this->facturation;
}
}
And finally TypeOfService
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* TypeOfService
*
* #ORM\Table(name="type_of_service")
* #ORM\Entity
*/
class TypeOfService
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(nullable=true)
*/
private $name;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $pricePerUnit;
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="typeOfService")
*/
private $service;
...
/**
* Constructor
*/
public function __construct()
{
$this->service = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add service
*
* #param \AppBundle\Entity\Service $service
* #return TypeOfService
*/
public function addService(\AppBundle\Entity\Service $service)
{
$this->service[] = $service;
return $this;
}
/**
* Remove service
*
* #param \AppBundle\Entity\Service $service
*/
public function removeService(\AppBundle\Entity\Service $service)
{
$this->service->removeElement($service);
}
/**
* Get service
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getService()
{
return $this->service;
}
}
Can anyone point me in the right direction ?
For anyone looking, I've cracked it.
This was what I was looking for:
http://symfony.com/doc/current/cookbook/form/form_collections.html
This allows for dynamic field additions, using JS.
Be careful to cascade your association. In my case:
class Facturation
{
....
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="facturation", cascade={"persist", "remove"})
*/
private $services;

Symfony 2 doctrine request object by Id giving blank page

When doing a simple query in the main controller such as:
public function newAdCreatedAction($id)
{
$em = $this->getDoctrine()->getManager()->getRepository('websiteAdsBundle:AdsList');
$article = $em->findById($id);
return $this->render('websiteAdsBundle:Default:newAdCreated.html.twig',array('article'=>$article));
}
I've got a blank page in the log file I got the following message error (if that helps):
//Bunch of kernelerrors... here and then:
[2014-06-09 14:07:53] doctrine.DEBUG: SET NAMES UTF8 [] []
[2014-06-09 14:07:53] doctrine.DEBUG: SELECT t0.id AS id1, t0.username AS username2,t0.email AS email3, t0.telephone AS telephone4, t0.display_phone AS display_phone5, t0.title AS title6, t0.description AS description7, t0.country AS country8, t0.region AS region9, t0.department AS department10, t0.address AS address11, t0.city AS city12, t0.zip_code AS zip_code13, t0.status_pro AS status_pro14, t0.creationtime AS creationtime15, t0.updatetime AS updatetime16, t0.publication AS publication17 FROM AdsList t0 WHERE t0.id = ? ["53"] []
[2014-06-09 14:07:55] emergency.EMERGENCY: Allowed memory size of 134217728 bytes exhausted (tried to allocate 125573121 bytes) {"type":1,"file":"/home/alfonso/sites/ads.website.com/public_html/vendor/twig/twig/lib/Twig/Extension/Debug.php","line":66} []
I think this is related to the #ORM\Join statement but I can't figure out what is it.
I guess with bidirectional associations, Twig’s dump is not working
the website/AdsBundle/Entity/AdsList.php class:
<?php
namespace website\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use website\AdsBundle\Entity\Photos;
/**
* AdsList
*
* #ORM\Table()
* #ORM\Entity
* #ORM\Entity(repositoryClass="website\AdsBundle\Entity\AdsListRepository")
* #ORM\HasLifecycleCallbacks()
*/
class AdsList
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="telephone", type="string", length=255)
*/
private $telephone;
/**
* #var string
*
* #ORM\Column(name="display_phone", type="string", length=255)
*/
private $displayPhone;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="country", type="string", length=255)
*/
private $country;
/**
* #var string
*
* #ORM\Column(name="region", type="string", length=255)
*/
private $region;
/**
* #var string
*
* #ORM\Column(name="department", type="string", length=255)
*/
private $department;
/**
* #var string
*
* #ORM\Column(name="address", type="string", length=255)
*/
private $address;
/**
* #var string
*
* #ORM\Column(name="city", type="string", length=255)
*/
private $city;
/**
* #var string
*
* #ORM\Column(name="zip_code", type="string", length=255)
*/
private $zipCode;
/**
* #var string
*
* #ORM\Column(name="status_pro", type="string", length=255)
*/
private $statusPro;
/**
* #var \DateTime
*
* #ORM\Column(name="creationtime", type="datetime")
*/
private $creationtime;
/**
* #var \DateTime
*
* #ORM\Column(name="updatetime", type="datetime")
*/
private $updatetime;
/**
* #var boolean
*
* #ORM\Column(name="publication", type="boolean")
*/
private $publication;
/**
* #ORM\OneToMany(targetEntity="website\AdsBundle\Entity\Photos",mappedBy="adslist", cascade={"persist"})
*/
protected $photos;
/**
* Set photos
*
* #param \website\AdsBundle\Entity\Photos $photos
* #return AdsList
*/
public function setPhotos(\website\AdsBundle\Entity\Photos $photos = null)
{
$this->photos = $photos;
return $this;
}
/**
* Get photos
*
* #return \website\AdsBundle\Entity\Photos
*/
public function getPhotos()
{
return $this->photos;
}
/**
* Add photos
*
* #param \website\AdsBundle\Entity\Photos $photos
* #return AdsList
*/
public function addPhoto(\website\AdsBundle\Entity\Photos $photos)
{
$this->photos[] = $photos;
$photos->setAdslist($this);
return $this;
}
/**
* Remove photos
*
* #param \website\AdsBundle\Entity\Photos $photos
*/
public function removePhoto(\website\AdsBundle\Entity\Photos $photos)
{
$this->photos->removeElement($photos);
}
public function __construct() {
$this->creationtime=new \Datetime;
$this->photos = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
* #return AdsList
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set email
*
* #param string $email
* #return AdsList
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set telephone
*
* #param string $telephone
* #return AdsList
*/
public function setTelephone($telephone)
{
$this->telephone = $telephone;
return $this;
}
/**
* Get telephone
*
* #return string
*/
public function getTelephone()
{
return $this->telephone;
}
/**
* Set displayPhone
*
* #param string $displayPhone
* #return AdsList
*/
public function setDisplayPhone($displayPhone)
{
$this->displayPhone = $displayPhone;
return $this;
}
/**
* Get displayPhone
*
* #return string
*/
public function getDisplayPhone()
{
return $this->displayPhone;
}
/**
* Set title
*
* #param string $title
* #return AdsList
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set description
*
* #param string $description
* #return AdsList
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set country
*
* #param string $country
* #return AdsList
*/
public function setCountry($country)
{
$this->country = $country;
return $this;
}
/**
* Get country
*
* #return string
*/
public function getCountry()
{
return $this->country;
}
/**
* Set region
*
* #param string $region
* #return AdsList
*/
public function setRegion($region)
{
$this->region = $region;
return $this;
}
/**
* Get region
*
* #return string
*/
public function getRegion()
{
return $this->region;
}
/**
* Set department
*
* #param string $department
* #return AdsList
*/
public function setDepartment($department)
{
$this->department = $department;
return $this;
}
/**
* Get department
*
* #return string
*/
public function getDepartment()
{
return $this->department;
}
/**
* Set address
*
* #param string $address
* #return AdsList
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
/**
* Get address
*
* #return string
*/
public function getAddress()
{
return $this->address;
}
/**
* Set city
*
* #param string $city
* #return AdsList
*/
public function setCity($city)
{
$this->city = $city;
return $this;
}
/**
* Get city
*
* #return string
*/
public function getCity()
{
return $this->city;
}
/**
* Set zipCode
*
* #param string $zipCode
* #return AdsList
*/
public function setZipCode($zipCode)
{
$this->zipCode = $zipCode;
return $this;
}
/**
* Get zipCode
*
* #return string
*/
public function getZipCode()
{
return $this->zipCode;
}
/**
* Set statusPro
*
* #param string $statusPro
* #return AdsList
*/
public function setStatusPro($statusPro)
{
$this->statusPro = $statusPro;
return $this;
}
/**
* Get statusPro
*
* #return string
*/
public function getStatusPro()
{
return $this->statusPro;
}
/**
* Set creationtime
*
* #param \DateTime $creationtime
* #return test
*/
public function setCreationtime($creationtime)
{
$this->creationtime = $creationtime;
return $this;
}
/**
* Get creationtime
*
* #return \DateTime
*/
public function getCreationtime()
{
return $this->creationtime;
}
/**
* Set updatetime
*
* #param \DateTime $updatetime
* #return Test
*/
public function setUpdatetime($updatetime)
{
$this->updatetime = $updatetime;
return $this;
}
/**
* Get updatetime
*
* #return \DateTime
*/
public function getUpdatetime()
{
return $this->updatetime;
}
/**
* Set publication
*
* #param boolean $publication
* #return test
*/
public function setPublication($publication)
{
$this->publication = $publication;
return $this;
}
/**
* Get publication
*
* #return boolean
*/
public function getPublication()
{
return $this->publication;
}
// Callback
/**
* #ORM\PreUpdate
*/
public function udpateDate()
{
$this->setUpdatetime(new \DateTime());
}
}
And the photos class is the following:
<?php
namespace website\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Photos
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="website\AdsBundle\Entity\PhotosRepository")
* #ORM\HasLifecycleCallbacks
*/
class Photos
{
/**
* #ORM\ManyToOne(targetEntity="website\AdsBundle\Entity\AdsList", inversedBy="photos")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="adslist_id", referencedColumnName="id")
* })
*/
protected $adslist;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="photo_path", type="string", length=255)
*/
private $photoPath;
/**
* #var string
*
* #ORM\Column(name="thumbnail_path", type="string", length=255)
*/
private $thumbnailPath;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
private $tempFilename;
public function setFile(UploadedFile $file)
{
$this->file = $file;
if (null !== $this->photoPath) {
$this->tempFilename = $this->photoPath;
// reset values
}
}
public function getFile()
{
return $this->file;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set photoPath
*
* #param string $photoPath
* #return Photos
*/
public function setPhotoPath($photoPath)
{
$this->photoPath = $photoPath;
return $this;
}
/**
* Get photoPath
*
* #return string
*/
public function getPhotoPath()
{
return $this->photoPath;
}
/**
* Set thumbnailPath
*
* #param string $thumbnailPath
* #return Photos
*/
public function setThumbnailPath($thumbnailPath)
{
$this->thumbnailPath = $thumbnailPath;
return $this;
}
/**
* Get thumbnailPath
*
* #return string
*/
public function getThumbnailPath()
{
return $this->thumbnailPath;
}
/**
*
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if($this->file === null){
return;
}
//$this->extension = $this->file->guessExtention(); // In my case I don't need it
$this->photoPath = $this->file->getClientOriginalName();
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if($this->file === null){
return;
}
if(null !== $this->tempFilename)
{
$oldFile = $this->getUploadRootDir().'/'.$this->tempFilename;
if(file_exists($oldFile)){
unlink($oldFile);
}
}
$this->file->move(
$this->getUploadRootDir(),
$this->id.'.'.$this->photoPath
);
}
/**
* #ORM\PreRemove()
*/
public function PreRemoveUpload()
{
$this->tempFilename = $this->getUploadRootDir().'/'.$this->id.''.$this->photoPath;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if(filex_exists($this->tempFilename))
{
unlink($this->tempFilename);
}
}
public function getUploadDir()
{
return '/upload/img';
}
public function getUploadRootDir()
{
return __DIR__.'/../../../../web'.$this->getUploadDir();
}
public function getWebPath()
{
return $this->getUploadDir().'/'.$this->getId().'.'.$this->getPhotoPath();
}
public function getMyWebPath()
{
return $this->getUploadDir().'/'.$this->getPhotoPath();
}
/**
* Set adslist
*
* #param \website\AdsBundle\Entity\AdsList $adslist
* #return Photos
*/
public function setAdslist(\website\AdsBundle\Entity\AdsList $adslist = null)
{
$this->adslist = $adslist;
return $this;
}
/**
* Get adslist
*
* #return \website\AdsBundle\Entity\AdsList
*/
public function getAdslist()
{
return $this->adslist;
}
}
EDIT:
I add the piece of twig template asked by bartek:
<body class="metro">
<div class="page secondary">
<div class="page-header">
<div class="div_header">
<img class="logo" src="{{ website_path_swap }}/files/images/logo.png" />
</div>
<div class="div_header">
<h2 class=""></h2>
</div>
</div>
<div class="page-region">
<div class="row">
<div class="span6">
<div>
{{ dump(article) }}
</div>
</div>
</div>
</div>
</div>
</body>
Intermediary answer:
for now I am using
\Doctrine\Common\Util\Debug::dump($article);
in order to get the output without problem. Apparently there are extensions that allows to echo the output in a more properly manner.
If I find something better I will come back to post it here.
In case you ended up here using Symfony 2.6+, make sure you register the DebugBundle in your AppKernel.php
public function registerBundles()
{
//...
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
// ...
}
return $bundles;
}

Resources