草庐IT

php - Symfony crud 生成的索引 View ,其中没有引用字段

coder 2024-01-03 原文

Symfony 命令 doctrine:generate:crud 生成的 Controller <表单及其 view="">

实体模型:

<?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 - 表头部分:

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

最佳答案

这是 DoctrineCrudGenerator 的正常行为,因为生成器只使用 Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings 数组来生成表,但是 ParentAlbum-ManyToOne 关联位于在 Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings 数组中。所以它永远不会在 crud generation 上被识别。

为了演示一个可能的解决方案,我使用了 symfony-demo 应用程序的 Comment 实体:

<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * 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 <weaverryan@gmail.com>
 * @author Javier Eguiluz <javier.eguiluz@gmail.com>
 */
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;
    }
}

有“正常”列,如 id、content、authorEmail 和 publishedAt,以及一个与 Post 实体的 ManyToOne 关联。为此实体生成以下元数据:

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

您可以看到,普通字段位于 fieldMappings 数组中,而关联位于 associationMappings 数组中。 为 Comment 实体运行 crud 生成器只为没有帖子关联的“正常”列生成表:

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

现在,要更改此行为,您只需在 crud 生成时将 associationMappings 数组“合并”到 fieldMappings 数组中。 您可以在 Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator 中执行此操作。对于生产,您必须覆盖 Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGeneratorSensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand 并在您自己的类(class)中进行更改。但是,作为概念证明,我将进行快速且非常肮脏的破解,并添加 直接对 DoctrineCrudGenerator 进行以下更改:

/**
 * Generates a CRUD controller.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
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;
    }
}

更改后,如果您将 __toString 添加到 Post 实体,生成器将生成以下代码:

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

可以看到,post关联已经被识别了。如果你想开始写作,你可以以此为切入点 你自己的发电机。但是你必须调查,如何处理 ToMany 关联以及如何处理关联 表格等等..

关于php - Symfony crud 生成的索引 View ,其中没有引用字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30434614/

有关php - Symfony crud 生成的索引 View ,其中没有引用字段的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  5. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  7. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  8. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  9. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  10. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

随机推荐