2015-05-25 5 views
7

Symfony-Befehl doctrine: generate: crud generierter Controller < Formular und seine Ansichten. Der Index enthält jedoch keine anderen Tabellenverweisfelder "Viele-zu-Eins".Symfony Crud generierte Indexansicht, in der keine Referenzfelder enthalten sind

Entity-Modell:

<?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 - Tabellenkopfteil:

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

enter image description here

+0

Es muss 3 Felder enthalten: Name, Sortieren, Eltern. Übergeordnetes Feld wurde nicht generiert. –

+0

symfony crud generatoroder Befehl: php app/console doctrine: generieren: crud --entity = AdminBundle: Alben --route-prefix = admin/alben --with-write --format = anmerkung --no-interaction --overwrite –

Antwort

7

Dies ist das normale Verhalten des DoctrineCrudGenerator, weil der Generator verwendet nur die Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings Array, um die Tabelle zu erzeugen, aber die ParentAlbum-ManyToOne: Sie könnte durch eine Änderung index.html.twig ein bisschen ist es sehr einfach angezeigt werden Assoziation befindet sich im Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings Array. So wird es nie auf Crud Generation erkannt werden.

Um eine mögliche Lösung, die ich die die Kommentar-Einheit der symfony-Demo-Anwendung zu zeigen:

<?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; 
    } 
} 

Es gibt „normale“ Spalten wie id, Inhalt, AUTHOR und publishedAt und eine ManyToOne Vereinigung der Post Entität. Für diese Unternehmen sind die folgenden Metadaten erzeugt:

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} 
} 

Sie sehen können, dass die normalen Felder in der Fieldmappings Array angeordnet sind, während der Verein in der associationMappings Array lebt. den crud Generator für den Kommentar Einheit Laufen erzeugt die Tabelle nur für die „normalen“ Spalten ohne post association:

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

, nun, dieses Verhalten zu ändern, müssen Sie einfach die associationMappings Array in der „merge“ fieldMappings-Array bei Crud-Generierung. Sie können das in der Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator tun. Für die Produktion müssen Sie die Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator und die Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand überschreiben und die Änderungen in Ihrer eigenen Klasse vornehmen. Aber nur als Proof of Concept werde ich tun, schnell und wirklich schmutzig Hack, ein fügen Sie die folgenden Änderungen an den DoctrineCrudGenerator direkt:

/** 
* 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; 
    } 
} 

Nach den Änderungen und wenn Sie den __toString der Post Einheit hinzugefügt, um den Generator erzeugt folgenden Code:

Sie sehen, die Postassoziation wird jetzt erkannt. Sie können dies als Einstiegspunkt verwenden, wenn Sie mit dem Schreiben Ihres eigenen Generators beginnen möchten. Aber Sie müssen untersuchen, wie ToMany-Verknüpfungen und wie mit Zuordnungen in Formulare und so weiter umzugehen.

+0

Eigentlich löste ich das Problem durch eine andere Methode 'Felder' => array_merge ($ this-> Metadaten-> fieldMappings, $ this-> Metadaten-> associationMappings), –

+0

Sicher, Sie können. Wenn Sie jedoch 'array_merge' für ToMany-Zuordnungen verwenden möchten, ohne die Vorlagen anzupassen, werden Sie auf Probleme stoßen. Ich behaupte auch nicht, dass mein Ansatz der einzige ist. Es liegt an dir ;) – skroczek

-1

Der crud Befehl, den Sie mit einer schnellen Erzeugung von mehreren Dateien hilft, aber es nicht alles. $ parent ist ein Zeiger auf eine andere Entität. Die Crud-Methode kann nicht wissen, was Sie von dieser Entität anzeigen möchten. Stellen Sie sich vor, dass ParentAlbums eine Eigenschaft '$ name' hat.

<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

Keine Notwendigkeit, entity.parent.name, entity.parent einfach genug zu schreiben. –