2015-05-25 27 views
7

Symfony command doctrine: genera: il modulo di controllo crud generato < e le sue viste. Ma l'indice non contiene altri campi di riferimento tabella "molti-a-uno". modelloSymfony crud ha generato la vista dell'indice, dove non sono presenti i campi di riferimento

Entity:

<?php 

namespace Acme\Bundle\AdminBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* Albums 
* 
* @ORM\Table(name="albums", indexes={@ORM\Index(name="IDX_F4E2474F3D8E604F", columns={"parent"})}) 
* @ORM\Entity 
*/ 
class Albums 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer", nullable=false) 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="SEQUENCE") 
    * @ORM\SequenceGenerator(sequenceName="albums_id_seq", allocationSize=1, initialValue=1) 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="name", type="string", length=60, nullable=false) 
    */ 
    private $name; 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="sort", type="integer", nullable=false) 
    */ 
    private $sort; 

    /** 
    * @var \ParentAlbums 
    * 
    * @ORM\ManyToOne(targetEntity="ParentAlbums") 
    * @ORM\JoinColumns({ 
    * @ORM\JoinColumn(name="parent", referencedColumnName="id") 
    * }) 
    */ 
    private $parent; 



    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set name 
    * 
    * @param string $name 
    * @return Albums 
    */ 
    public function setName($name) 
    { 
     $this->name = $name; 

     return $this; 
    } 

    /** 
    * Get name 
    * 
    * @return string 
    */ 
    public function getName() 
    { 
     return $this->name; 
    } 

    /** 
    * Set sort 
    * 
    * @param integer $sort 
    * @return Albums 
    */ 
    public function setSort($sort) 
    { 
     $this->sort = $sort; 

     return $this; 
    } 

    /** 
    * Get sort 
    * 
    * @return integer 
    */ 
    public function getSort() 
    { 
     return $this->sort; 
    } 

    /** 
    * Set parent 
    * 
    * @param \Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent 
    * @return Albums 
    */ 
    public function setParent(\Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent = null) 
    { 
     $this->parent = $parent; 

     return $this; 
    } 

    /** 
    * Get parent 
    * 
    * @return \Acme\Bundle\AdminBundle\Entity\ParentAlbums 
    */ 
    public function getParent() 
    { 
     return $this->parent; 
    } 
} 

index.html.twig - sezione di testa tavolo:

<thead> 
     <tr> 
      <th>Id</th> 
      <th>Name</th> 
      <th>Sort</th> 
      <th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th> 
     </tr> 
    </thead> 
comando

enter image description here

+0

Deve contenere 3 campi: nome, ordinamento, genitore. Campo principale non generato. –

+0

symfony crud generateor command: php app/console doctrine: generate: crud --entity = AdminBundle: Album --route-prefix = admin/albums --with-write --format = annotation --no-interaction --overwrite –

risposta

7

Questo è il comportamento normale del DoctrineCrudGenerator, poiché il generatore utilizza solo la matrice Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings per generare la tabella, ma il ParentAlbum-ManyToOne l'associazione si trova nell'array Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings. Quindi non verrà mai riconosciuto nella generazione Crud.

Per dimostrare una possibile soluzione che uso l'entità Commento dell'applicazione symfony-demo:

<?php 

/* 
* This file is part of the Symfony package. 
* 
* (c) Fabien Potencier <[email protected]> 
* 
* For the full copyright and license information, please view the LICENSE 
* file that was distributed with this source code. 
*/ 

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
* @ORM\Entity 
* 
* Defines the properties of the Comment entity to represent the blog comments. 
* See http://symfony.com/doc/current/book/doctrine.html#creating-an-entity-class 
* 
* Tip: if you have an existing database, you can generate these entity class automatically. 
* See http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html 
* 
* @author Ryan Weaver <[email protected]> 
* @author Javier Eguiluz <[email protected]> 
*/ 
class Comment 
{ 
    /** 
    * @ORM\Id 
    * @ORM\GeneratedValue 
    * @ORM\Column(type="integer") 
    */ 
    private $id; 

    /** 
    * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments") 
    * @ORM\JoinColumn(nullable=false) 
    */ 
    private $post; 

    /** 
    * @ORM\Column(type="text") 
    * @Assert\NotBlank(message="Please don't leave your comment blank!") 
    * @Assert\Length(
    *  min = "5", 
    *  minMessage = "Comment is too short ({{ limit }} characters minimum)", 
    *  max = "10000", 
    *  maxMessage = "Comment is too long ({{ limit }} characters maximum)" 
    *) 
    */ 
    private $content; 

    /** 
    * @ORM\Column(type="string") 
    * @Assert\Email() 
    */ 
    private $authorEmail; 

    /** 
    * @ORM\Column(type="datetime") 
    * @Assert\DateTime() 
    */ 
    private $publishedAt; 

    public function __construct() 
    { 
     $this->publishedAt = new \DateTime(); 
    } 

    /** 
    * @Assert\True(message = "The content of this comment is considered spam.") 
    */ 
    public function isLegitComment() 
    { 
     $containsInvalidCharacters = false !== strpos($this->content, '@'); 

     return !$containsInvalidCharacters; 
    } 

    public function getId() 
    { 
     return $this->id; 
    } 

    public function getContent() 
    { 
     return $this->content; 
    } 

    public function setContent($content) 
    { 
     $this->content = $content; 
    } 

    public function getAuthorEmail() 
    { 
     return $this->authorEmail; 
    } 

    public function setAuthorEmail($authorEmail) 
    { 
     $this->authorEmail = $authorEmail; 
    } 

    public function getPublishedAt() 
    { 
     return $this->publishedAt; 
    } 

    public function setPublishedAt($publishedAt) 
    { 
     $this->publishedAt = $publishedAt; 
    } 

    public function getPost() 
    { 
     return $this->post; 
    } 

    public function setPost(Post $post = null) 
    { 
     $this->post = $post; 
    } 
} 

Ci sono colonne "normali" come l'identificazione, il contenuto, authorEmail e publishedAt e associazione uno ManyToOne il Post entità. Per questa entità i seguenti metadati vengono generati:

Doctrine\ORM\Mapping\ClassMetadata {#437 
    +name: "AppBundle\Entity\Comment" 
    +namespace: "AppBundle\Entity" 
    +rootEntityName: "AppBundle\Entity\Comment" 
    +customGeneratorDefinition: null 
    +customRepositoryClassName: null 
    +isMappedSuperclass: false 
    +isEmbeddedClass: false 
    +parentClasses: [] 
    +subClasses: [] 
    +embeddedClasses: [] 
    +namedQueries: [] 
    +namedNativeQueries: [] 
    +sqlResultSetMappings: [] 
    +identifier: array:1 [ 
    0 => "id" 
    ] 
    +inheritanceType: 1 
    +generatorType: 4 
    +fieldMappings: array:4 [ 
    "id" => array:9 [ 
     "fieldName" => "id" 
     "type" => "integer" 
     "scale" => 0 
     "length" => null 
     "unique" => false 
     "nullable" => false 
     "precision" => 0 
     "id" => true 
     "columnName" => "id" 
    ] 
    "content" => array:8 [ 
     "fieldName" => "content" 
     "type" => "text" 
     "scale" => 0 
     "length" => null 
     "unique" => false 
     "nullable" => false 
     "precision" => 0 
     "columnName" => "content" 
    ] 
    "authorEmail" => array:8 [ 
     "fieldName" => "authorEmail" 
     "type" => "string" 
     "scale" => 0 
     "length" => null 
     "unique" => false 
     "nullable" => false 
     "precision" => 0 
     "columnName" => "authorEmail" 
    ] 
    "publishedAt" => array:8 [ 
     "fieldName" => "publishedAt" 
     "type" => "datetime" 
     "scale" => 0 
     "length" => null 
     "unique" => false 
     "nullable" => false 
     "precision" => 0 
     "columnName" => "publishedAt" 
    ] 
    ] 
    +fieldNames: array:4 [ 
    "id" => "id" 
    "content" => "content" 
    "authorEmail" => "authorEmail" 
    "publishedAt" => "publishedAt" 
    ] 
    +columnNames: array:4 [ 
    "id" => "id" 
    "content" => "content" 
    "authorEmail" => "authorEmail" 
    "publishedAt" => "publishedAt" 
    ] 
    +discriminatorValue: null 
    +discriminatorMap: [] 
    +discriminatorColumn: null 
    +table: array:1 [ 
    "name" => "Comment" 
    ] 
    +lifecycleCallbacks: [] 
    +entityListeners: [] 
    +associationMappings: array:1 [ 
    "post" => array:19 [ 
     "fieldName" => "post" 
     "joinColumns" => array:1 [ 
     0 => array:6 [ 
      "name" => "post_id" 
      "unique" => false 
      "nullable" => false 
      "onDelete" => null 
      "columnDefinition" => null 
      "referencedColumnName" => "id" 
     ] 
     ] 
     "cascade" => [] 
     "inversedBy" => "comments" 
     "targetEntity" => "AppBundle\Entity\Post" 
     "fetch" => 2 
     "type" => 2 
     "mappedBy" => null 
     "isOwningSide" => true 
     "sourceEntity" => "AppBundle\Entity\Comment" 
     "isCascadeRemove" => false 
     "isCascadePersist" => false 
     "isCascadeRefresh" => false 
     "isCascadeMerge" => false 
     "isCascadeDetach" => false 
     "sourceToTargetKeyColumns" => array:1 [ 
     "post_id" => "id" 
     ] 
     "joinColumnFieldNames" => array:1 [ 
     "post_id" => "post_id" 
     ] 
     "targetToSourceKeyColumns" => array:1 [ 
     "id" => "post_id" 
     ] 
     "orphanRemoval" => false 
    ] 
    ] 
    +isIdentifierComposite: false 
    +containsForeignIdentifier: false 
    +idGenerator: Doctrine\ORM\Id\IdentityGenerator {#439 
    -sequenceName: null 
    } 
    +sequenceGeneratorDefinition: null 
    +tableGeneratorDefinition: null 
    +changeTrackingPolicy: 1 
    +isVersioned: null 
    +versionField: null 
    +cache: null 
    +reflClass: null 
    +isReadOnly: false 
    #namingStrategy: Doctrine\ORM\Mapping\DefaultNamingStrategy {#407} 
    +reflFields: array:5 [ 
    "id" => null 
    "content" => null 
    "authorEmail" => null 
    "publishedAt" => null 
    "post" => null 
    ] 
    -instantiator: Doctrine\Instantiator\Instantiator {#438} 
} 

Si può vedere, che i campi normali si trovano nella matrice fieldMappings, mentre l'associazione vive nella matrice associationMappings. Esecuzione del generatore CRUD per l'entità Commento produce la tabella solo per le colonne "normali", senza l'associazione posta:

<thead> 
    <tr> 
     <th>Id</th> 
     <th>Content</th> 
     <th>Authoremail</th> 
     <th>Publishedat</th> 
     <th>Actions</th> 
    </tr> 
</thead> 

Ora, per cambiare questo comportamento, è sufficiente a "fondere" la matrice associationMappings nel array fieldMappings sulla generazione crud. È possibile farlo nello Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator. Per la produzione, è necessario sostituire lo Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator e lo Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand e apportare le modifiche nella propria classe. Ma proprio come un proof of concept che farò mod rapido e molto sporca, un aggiungere le seguenti modifiche al DoctrineCrudGenerator direttamente:

/** 
* Generates a CRUD controller. 
* 
* @author Fabien Potencier <[email protected]> 
*/ 
class DoctrineCrudGenerator extends Generator 
{ 

    // ... 

    /** 
    * Generates the index.html.twig template in the final bundle. 
    * 
    * @param string $dir The path to the folder that hosts templates in the bundle 
    */ 
    protected function generateIndexView($dir) 
    { 
     $this->renderFile(
      'crud/views/index.html.twig.twig', 
      $dir . '/index.html.twig', 
      array(
       'bundle' => $this->bundle->getName(), 
       'entity' => $this->entity, 
       'identifier' => $this->metadata->identifier[0], 

       // Use the function instead of the "raw" fieldMappings array 
       // 'fields' => $this->metadata->fieldMappings, 
       'fields' => $this->processFieldMappings(), 

       'actions' => $this->actions, 
       'record_actions' => $this->getRecordActions(), 
       'route_prefix' => $this->routePrefix, 
       'route_name_prefix' => $this->routeNamePrefix, 
      ) 
     ); 
    } 

    // ... 
    /** 
    * Add the associations to the array 
    * 
    * @return array 
    */ 
    protected function processFieldMappings() 
    { 

     /** @var \Doctrine\ORM\Mapping\ClassMetadata $metadata */ 
     $metadata = $this->metadata; 

     $fields = $metadata->fieldMappings; 
     $associationMappings = $metadata->associationMappings; 

     foreach ($associationMappings as $k => $a) { 
      // Add the field only if it is a ToOne association and if the targetEntity implements the __toString method 
      if ($a['type'] & ClassMetadataInfo::TO_ONE && method_exists($a['targetEntity'], '__toString')) { 
       $fields[$k] = array(
        "fieldName" => $a["fieldName"], 
        "type" => "text", 
        "scale" => 0, 
        "length" => null, 
        "unique" => false, 
        "nullable" => false, 
        "precision" => 0, 
        "columnName" => $k 
       ); 
      } 
     } 

     return $fields; 
    } 
} 

Dopo le modifiche e se si aggiunge il __toString all'entità Post, il generatore produce il seguente codice:

<table class="records_list"> 
    <thead> 
     <tr> 
      <th>Id</th> 
      <th>Content</th> 
      <th>Authoremail</th> 
      <th>Publishedat</th> 
      <th>Post</th> 
      <th>Actions</th> 
     </tr> 
    </thead> 
    <tbody> 
    {% for entity in entities %} 
     <tr> 
      <td><a href="{{ path('comment_show', { 'id': entity.id }) }}">{{ entity.id }}</a></td> 
      <td>{{ entity.content }}</td> 
      <td>{{ entity.authorEmail }}</td> 
      <td>{% if entity.publishedAt %}{{ entity.publishedAt|date('Y-m-d H:i:s') }}{% endif %}</td> 
      <td>{{ entity.post }}</td> 
      <td> 
      <ul> 
       <li> 
        <a href="{{ path('comment_show', { 'id': entity.id }) }}">show</a> 
       </li> 
       <li> 
        <a href="{{ path('comment_edit', { 'id': entity.id }) }}">edit</a> 
       </li> 
      </ul> 
      </td> 
     </tr> 
    {% endfor %} 
    </tbody> 
</table> 

È possibile vedere, l'associazione di post è riconosciuta ora. È possibile utilizzare questo come punto di ingresso se si desidera iniziare a scrivere il proprio generatore . Ma devi indagare, come gestire le associazioni ToMany e come gestire le associazioni nei moduli e così via.

+0

In realtà, ho risolto il problema con un altro metodo 'campi' => array_merge ($ this-> metadata-> fieldMappings, $ this-> metadata-> associationMappings), –

+0

Certo, puoi. Ma se vuoi usare 'array_merge' per le associazioni ToMany, senza personalizzare i template, avrai dei problemi. Inoltre, non sostengo che il mio approccio sia l'unico. Spetta a voi ;) – skroczek

-1

Il crud si aiuta con una rapida generazione di file multipli, ma è non tutto $ parent è un puntatore a un'altra entità. Il metodo crud non è in grado di sapere cosa vuoi mostrare da questa entità. Immagina che ParentAlbums abbia una proprietà '$ name'. è possibile visualizzare molto semplice cambiando index.html.twig un bit:

<thead> 
    <tr> 
     <th>Id</th> 
     <th>Name</th> 
     <th>Parent</th> 
     <th>Sort</th> 
     <th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th> 
    </tr> 
</thead> 
    <tbody> 
    {% for entity in entities %} 
     <tr> 
      <td>{{ entity.id }}</td> 
      <td>{{ entity.name }}</td> 
      <td>{{ entity.parent.name }}</td> 
      <td>{{ entity.sort }}</td> 
      <td> 
      <ul> 
        // actions here 
      </ul> 
      </td> 
     </tr> 
    {% endfor %} 
    </tbody> 
+0

Non è necessario scrivere entity.parent.name, entity.parent abbastanza semplice. –