29

我有一个具有以下字段和关联的商家实体:-

/**
 * @ORM\ManyToMany(targetEntity="Category", inversedBy="merchants")
 */
public $categories;

/**
 * @ORM\ManyToMany(targetEntity="Tag", inversedBy="merchants")
 */
public $tags;

/**
 * @ORM\ManyToOne(targetEntity="Category", inversedBy="merchants")
 */
protected $primaryCategory;

/**
 * @ORM\ManyToOne(targetEntity="Tag", inversedBy="merchants")
 */
protected $primaryTag;

标签和类别也有一个多对多映射。所以我们有 Tag_Category、Merchant_Tag、Merchant_Category 映射表。

现在我想在这些字段上执行一些 ajax。

我想允许用户首先选择主标签。在Primary Tag的基础上,ajax将类别刷新为只属于该Tag的类别和一些操作。

我怎样才能做到这一点?

谢谢!

4

4 回答 4

61

几个月前我能够完成这项工作。虽然 a.aitboudad 分享的内容是准确的。Symfony/Sonata 的初学者可能会遇到一些问题。

以下是步骤。

1> 扩展 Sonata CRUD 的edit.html.twig/ base_edit.html.twig 为简单起见,我将只使用后者。复制vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig到与 MerchantAdminController 对应的视图文件夹中 -YourBundle/Resources/views/Merchant/base_edit.html.twig

2> 我们需要告诉 MerchantAdmin 类使用这个模板。所以我们像这样重写 SonataAdmin 的getEditTemplate方法:

public function getEditTemplate()
{
    return 'YourBundle:Merchant:base_edit.html.twig';
}

3>接下来,我们需要在base_edit.html.twig. 标准 Ajax 包括以下内容:

3.1> -- 在控制器中为Ajax 请求创建一个Action 我们主要想得到一个与特定标签对应的类别ID 列表。但很可能你只是在使用 Sonata 的 CRUD 控制器。

定义扩展 CRUDController 的 MerchantAdminController

<?php

namespace GD\AdminBundle\Controller;

use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use GD\AdminBundle\Entity\Merchant;

class MerchantAdminController extends Controller
{

}

3.2> -- 告诉你的管理服务使用这个新创建的控制器而不是默认的 CRUDControllerYourBundle/Resources/config/services.yml

gd_admin.merchant:
        class: %gd_admin.merchant.class%
        tags:
            - { name: sonata.admin, manager_type: orm, group: gd_merchant, label: Merchants }
        arguments: [null, GD\AdminBundle\Entity\Merchant, GDAdminBundle:MerchantAdmin]

请注意,第三个参数是控制器的名称。默认情况下,它将为空。

3.3> -- 创建一个getCategoryOptionsFromTagAction在你的控制器中命名的动作。您的 Ajax 调用将针对此操作。

// route - get_categories_from_tag
public function getCategoryOptionsFromTagAction($tagId)
    {   
        $html = ""; // HTML as response
        $tag = $this->getDoctrine()
            ->getRepository('YourBundle:Tag')
            ->find($tagId);

        $categories = $tag->getCategories();

        foreach($categories as $cat){
            $html .= '<option value="'.$cat->getId().'" >'.$cat->getName().'</option>';
        }

        return new Response($html, 200);
    }

3.4> -- 在app/config/routing.yml. 如果您使用 FOSJsRoutingBundle,请记住公开您的路线(否则您将不得不硬编码,这不是一个好主意)。

get_categories_from_tag:
    pattern: /{_locale}/admin/gd/admin/merchant/get-categories-from-tag/{tagId}
    defaults: {_controller: GDAdminBundle:MerchantAdmin:getCategoryOptionsFromTag}
    options:
        expose: true

3.5> -- 发出 Ajax 请求并使用响应

{% block javascripts %}
    {{ parent() }}
    <script type="text/javascript">

        $(document).ready(function(){
            var primaryTag = $("#{{ admin.uniqId }}_primaryTag");
            primaryTag.change(updateCategories()); // Bind the function to updateCategories
            primaryTag.change(); // Manual trigger to update categories in Document load.

            function updateCategories(){
                return function () {
                    var tagId = $("#{{ admin.uniqId }}_primaryTag option:selected").val();
                    var primaryCategory = $("#{{ admin.uniqId }}_primaryCategory");
                    primaryCategory.empty();
                    primaryCategory.trigger("liszt:updated");
                    var locale = '{{ app.request.get('_locale') }}';

                    var objectId = '{{ admin.id(object) }}'

                    var url = Routing.generate('get_categories_from_tag', { '_locale': locale, 'tagId': tagId, _sonata_admin: 'gd_admin.merchant', id: objectId });
                    $.post(url, { tagId: tagId }, function(data){
                        primaryCategory.empty().append(data);
                        primaryCategory.trigger("liszt:updated");
                    },"text");

                    primaryCategory.val("option:first").attr("selected", true);
                };
            }
        });
    </script>
{% endblock %}

问题 1:如何获取附加到所有奏鸣曲元素的唯一 ID

解决方案:使用 admin 变量,它可以让您访问所有 Admin Class 的属性,包括 uniqId。请参阅有关如何使用它的代码。

问题 2:如何在 JS 中获取路由器。

解决方案:默认情况下 Symfony2 Routing 在 JS 中不起作用。您需要使用一个名为 FOSJSRouting 的包(如上所述)并公开路由。这将使您也可以访问 JS 中的 Router 对象。

我稍微修改了我的解决方案以使这个示例更清晰。如果您发现任何错误,请随时发表评论。

于 2012-05-28T11:08:31.333 回答
4

在 Amit 和 Lumbendil 回答的第 1 步,您应该更改

{% extends base_template %}

进入

{% extends 'SonataAdminBundle::standard_layout.html.twig' %}

如果您收到类似的错误

Unable to find template "" in YourBundle:YourObject:base_edit.html.twig at line 34.  
于 2014-03-31T12:47:42.840 回答
4

很详细的帖子,只是为了更新覆盖的方式,使用Admin类中的编辑模板。
现在,你应该这样做:

// src/AppBundle/Admin/EntityAdmin.php  

class EntityAdmin extends Admin
{  
    public function getTemplate($name)
    {
        if ( $name == "edit" ) 
        {
            // template 'base_edit.html.twig' placed in app/Resources/views/Entity
            return 'Entity/base_edit.html.twig' ;
        }
        return parent::getTemplate($name);
    }
}

或者将其注入使用提供的方法的服务定义中,以使 Admin 类尽可能干净:

// app/config/services.yml  

app.admin.entity:
    class: AppBundle\Admin\EntityAdmin
    arguments: [~, AppBundle\Entity\Entity, ~]
    tags:
        - {name: sonata.admin, manager_type: orm, group: "Group", label: "Label"}
    calls:
        - [ setTemplate, [edit, Entity/base_edit.html.twig]]
于 2015-06-24T14:36:44.950 回答
2

在块 javascripts 中,您必须更改"liszt:updated""chosen:updated"

希望它可以帮助某人;)

于 2016-06-24T09:46:58.457 回答