umanit/tree-bundle

管理数据库中的内容树

安装次数: 1,688

依赖关系: 0

建议者: 0

安全性: 0

星星: 5

观察者: 9

分支: 5

开放性问题: 6

类型:symfony-bundle

1.0.7 2024-04-16 10:01 UTC

This package is auto-updated.

Last update: 2024-09-16 10:56:04 UTC


README

此包允许您轻松管理内容类型路由,包括slug、面包屑和SEO

通用配置

由于所有内容的路由都由包管理,您必须在您的 config/routes.yaml 的末尾注册唯一路由(以免覆盖您的自定义路由)

umanit_tree:
    resource: "@UmanitTreeBundle/Resources/config/routes.yaml"
    prefix:   /

如果您不使用Symfony Flex,请在 config/bundles.php 中注册该包。

    Umanit\TreeBundle\UmanitTreeBundle::class => ['all' => true],

在您的 services.yaml 或单独的 packages/gedmo.yaml 中添加Gedmo配置。查看文档

services:
  # Doctrine Extension listeners to handle behaviors
  gedmo.listener.tree:
    class: Gedmo\Tree\TreeListener
    tags:
      - { name: doctrine.event_subscriber, connection: default, priority: 10 }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]

  Gedmo\Translatable\TranslatableListener:
    tags:
      - { name: doctrine.event_subscriber, connection: default }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]
      - [setDefaultLocale, ['%locale%']]
      - [setTranslationFallback, [false]]

  gedmo.listener.timestampable:
    class: Gedmo\Timestampable\TimestampableListener
    tags:
      - { name: doctrine.event_subscriber, connection: default }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]

  gedmo.listener.sluggable:
    class: Gedmo\Sluggable\SluggableListener
    tags:
      - { name: doctrine.event_subscriber, connection: default, priority: 100 }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]

  gedmo.listener.sortable:
    class: Gedmo\Sortable\SortableListener
    tags:
      - { name: doctrine.event_subscriber, connection: default }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]

  gedmo.listener.loggable:
    class: Gedmo\Loggable\LoggableListener
    tags:
      - { name: doctrine.event_subscriber, connection: default }
    calls:
      - [setAnnotationReader, ['@annotation_reader']]

更新数据库模式以添加我们的模型

bin/console doctrine:schema:update --force

或者如果您使用 DoctrineMigrationsBundle

bin/console doctrine:migrations:migrate

现在,您必须创建根节点。默认对象是 RootEntity,但您可以在配置中覆盖它(参数 umanit_tree.root_class)。

要创建根节点,请执行以下命令

bin/console umanit:tree:initialize

创建一个新的节点类型

现在,您可以轻松管理新的节点类型

  • 创建一个实体
  • 实现 Umanit\TreeBundle\Model\TreeNodeInterfaceUmanit\TreeBundle\Model\SeoInterface
  • 现在,您可以使用 Umanit\TreeBundle\Model\TreeNodeTraitUmanit\TreeBundle\Model\SeoTrait 来为大多数需要实现的方法提供默认实现

TreeNodeInterface 的 4 个方法是

  • public function getTreeNodeName(): string; : 返回节点名称,用于构建路由的slug
  • public function getParents(): array; : 返回父对象。例如,如果您想为"My Product"创建路径 /category/my-product,则必须返回一个包含实现 TreeNodeInterface 的对象 "Category" 的数组
  • public function createRootNodeByDefault(): bool; : 如果节点有或没有父节点,是否应该创建节点?(例如 /my-product)
  • public function getLocale(): ?string : 对象的本地化(由 Symfony 的 $request->getLocale() 识别的本地化)

您可以使用 Umanit\TreeBundle\Model\SeoInterfaceUmanit\TreeBundle\Model\SeoTrait 来管理一些SEO选项,如标题、描述和关键词,并自动将属性 "seoMetadata" 添加到实体中

绑定控制器并获取实体

为了绑定控制器(或模板)到实体,您必须配置 node_types

    node_types:
      -   class: App\Entity\Page # your entity
          controller: App\Controller\PageController::get # action to call

实体(或节点)将可在请求属性中访问。

    public function getAction(Request $request)
    {
        $entity = $request->attributes->get('contentObject'); // Your entity
        $node = $request->attributes->get('contentNode'); // TreeBundle's node
    }

创建父节点选择器

用法示例

$builder
    ->add('parents', \Umanit\TreeBundle\Form\Type\TreeNodeType::class, [
        'required'     => false,
        'by_reference' => false,
    ]);

创建SEO元数据表单

用法示例

$builder
    ->add('seoMetadata', \Umanit\TreeBundle\Form\Type\SeoMetadataType::class, [
        'required'     => false,
    ]);

创建链接选择器

您可以创建指向一个或多个节点(或外部链接)的链接。

在将包含链接的实体中,添加与实体 Umanit\TreeBundle\Entity\Link 的关系。

在您的表单中,您可以使用 Umanit\TreeBundle\Form\Type\LinkType 来具体化关系。默认情况下,您将有两个字段,"内部链接"(一个文本字段)和"外部链接"(一个选择框)。默认情况下,选择框将是空的。您必须通过提供允许的模型来填充它。您可以保留一个具有选项的字段:allow_internal: falseallow_external: false。注意:一次只能填写一个字段。

您可以使用 label_internallabel_external 定义标签

用法示例

$builder
    ->add('link', 'umanit_link_type_translatable', [
            'label' => 'Link',
            // List of content types available
            'models' => [
                'Page'    => 'Umanit\App\Entity\Page',
                'Article' => 'Umanit\App\Entity\Article',
            ],
        ], [
            // Filters for some content types (if needed)
            'query_filters' => [
                'App\Entity\Page' => ['locale' => 'en'],
            ],
            'allow_external' => false,   
        ]
    ]);

事件

您可以订阅一些事件来修改某些行为

(为了)

  • umanit.node.before_update:在实体任何节点保存之前被调用
  • umanit.node.parent_register:允许向实体添加/删除父级
  • umanit.node.updated:当实体保存其节点和父级后被调用一次

Twig 辅助函数

  • get_seo_title(default = "", override = false)
  • get_seo_description(default = "", override = false)
  • get_seo_keywords(default = "", override = false)

如果路由由实现 SeoInterface 的实体管理,则返回当前文档的标题、描述和关键词。否则,使用默认值(来自配置),或如果设置了,则使用 "default" 参数的值。如果将 override 设置为 true,则始终使用 "default" 参数的值。

  • get_breadcrumb(elements = array())

返回面包屑(名称/链接数组)。如果路由由实体管理,它将解析当前实体的所有父级。您可以使用 "elements" 参数添加额外的链接。一个名称/链接数组。

  • get_path(object, parentObject = null, root = false, absolute = false, parameters = [])

返回给定实体的路由(如果实体实现了 TreeNodeInterface)

  • get_path_from_node(node, absolute = false, parameters = [])

返回给定节点(Umanit\TreeBundle\Entity\Node 实例)的路由

  • get_path_from_link(link)

返回给定链接实例(Umanit\TreeBundle\Entity\Link 实例)的路径

  • is_external_link(link)

如果给定的链接指向外部 URL(Umanit\TreeBundle\Entity\Link 实例),则返回 true。

使用菜单管理

/!\ 由于性能考虑,我们仅支持 PostgreSQL。

按照以下两个步骤开始

1. 创建您的菜单实体(使用注解或属性)

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Umanit\TreeBundle\Entity\AbstractMenu as BaseMenu;
use Umanit\TreeBundle\Repository\MenuRepository;

/**
 * Menu
 *
 * @ORM\Table(name="menu")
 * @ORM\Entity(repositoryClass="Umanit\TreeBundle\Repository\MenuRepository") // Using TreeBundle's repository is
 *                                                                            mandatory
 * @ORM\HasLifecycleCallbacks() // This is mandatory too
 */
#[ORM\Table(name: 'menu')]
#[ORM\Entity(repositoryClass: MenuRepository::class)] // Using TreeBundle's repository is mandatory
#[ORM\HasLifecycleCallbacks] // Mandatory
class Menu extends BaseMenu
{
}

2. 配置 TreeBundle 以使用您的菜单实体

# app/config/config.yml
umanit_tree:
  # ...
  menu_entity_class: App\Entity\Menu

使用方法

前端

TreeBundle 不提供菜单的模板。一个全局 twig 变量被注入到您的网站中,请使用它来构建您的菜单模板。

示例

<nav class="nav-primary">
  <ul class="nav-primary__list nav-primary__lvl-1">
    {% for menu in menus %}
      {% if menu.position == 'primary' %}
        <li class="nav-primary__item">
          <a href="{{ menu.link is empty ? '#' : get_path_from_link(menu.link) }}" class="nav-primary__link">
            {{- menu.title|raw -}}
            {#- <br class="hidden-xs hidden-sm"> -#}
          </a>
          {% if menu.children is not empty %}
            <ul class="nav-primary__list nav-primary__lvl-2">
              {% for subMenu in menu.children %}
                {%  if subMenu.link is empty %}
                  <li class="nav-primary__label">{{ subMenu.title|raw }}</li>
                {% else %}
                  <li class="nav-primary__item">
                    <a href="{{ get_path_from_link(subMenu.link) }}" class="nav-primary__link"
                      <span class="nav-primary__text">{{ subMenu.title|raw }}</span>
                    </a>
                  </li>
                {% endif %}
              {% endfor %}
            </ul>
          {% endif %}
        </li>
      {%  endif %}
    {% endfor %}
  </ul>
</nav>

菜单管理

提供了一个 CRUD,用于管理您的菜单。它在路由 tree_admin_menu_dashboard、/admin/menu 上可用。

/!\ 您需要具有 ROLE_TREE_MENU_ADMIN 角色才能访问该路由。

首先运行 php bin/console assets:install 以获取您的 web/public 目录中的资产。

自定义管理布局

可以通过设置 admin_layout 配置值来根据需要自定义布局。

示例:如果您想使用 Sonata Admin 的布局

# config.yml
umanit_tree:
  # ...
  admin_layout: '@SonataAdmin/standard_layout.html.twig' # Default is '@UmanitTree/admin/default_layout.html.twig'

菜单管理有 3 个 JavaScript 依赖项,您还应该将它们包含在内。查看默认布局文件 default_layout.html.twig。

<!-- @UmanitTree/admin/default_layout.html.twig -->
<script src="{{ asset('bundles/umanittree/vendor/js/jquery-ui.min.js') }}"></script>
<script src="{{ asset('bundles/umanittree/vendor/js/jquery.fancytree-all-deps.min.js') }}"></script>
<script src="{{ asset('bundles/umanittree/vendor/js/jquery.fancytree.dnd.js') }}"></script>

TreeBundle 附带这些资产,您可以使用它们或您自己的。

再次,如果您想与 SonataAdmin 一起使用,请按以下方式配置

sonata_admin:
  # ...
  assets:
    extra_stylesheets:
      # TreeBundle's assets
      - bundles/umanittree/css/admin.css
      - bundles/umanittree/css/vendor/ui.fancytree.min.css
    extra_javascripts:
      # TreeBundle's assets
      - bundles/umanittree/js/vendor/jquery-ui.min.js
      - bundles/umanittree/js/vendor/jquery.fancytree-all-deps.min.js
      - bundles/umanittree/js/vendor/jquery.fancytree.dnd.js
自定义管理表单

假设您在菜单实体上添加了一个图像属性,并想使用 VichUploader 来管理它。

首先,创建一个表单类型

namespace App\Form;

use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Vich\UploaderBundle\Form\Type\VichImageType;
use Umanit\TreeBundle\Form\Type\MenuType as BaseMenuType;

class MenuType extends BaseMenuType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder
            ->add('imageFile', VichImageType::class, [
                'label'        => 'Image',
                'required'     => false,
                'allow_delete' => true,
                'attr'         => [
                    'imagine_pattern' => 'admin',
                ],
            ])
            ->add('altImage')
        ;
    }
}

然后将您的表单类型添加到 TreeBundle 的配置中

umanit_tree:
  # ...
  menu_form_class: App\Form\MenuType

配置参考

umanit_tree:
  locale: '%locale%'                                    # Optional. Default locale to use
  root_class: '\Umanit\TreeBundle\Entity\RootEntity' # Optional. Class for the root node. If you have a homepage object, put it there
  admin_layout: '@UmanitTree/admin/default_layout.html.twig'  # Optional. Default layout for the menu admin section
  menu_form_class: 'Umanit\TreeBundle\Form\Type\MenuType' # Optional. Default form for Menu
  menu_entity_class: 'App\Entity\Menu'                             # Optional. Your menu entity. Required if you want to use the menu admin
  menus: ['primary']                                   # Optional. Configure you menus.

  # Defines configuration per node types. You can set a specific controller per class and set if the node type must appear in the menu admin.
  node_types:
    # Prototype
    -   class: ~ # Required. Ex. : App\Entity\Page
        controller: ~ # Optional. Default FrameworkBundle:Template:template. Ex. : App:Page:show
        template: ~ # Required if controller is not set.
        menu: ~ # Optional. Default is false


  # Seo default values and translation domain
  seo:
    redirect_301: true   # Redirect old URLs to new ones
    default_title: 'Umanit Tree'
    default_description: 'Umanit tree bundle'
    default_keywords: 'umanit, web, bundle, symfony2'
    translation_domain: 'messages'

  # Root node and translation domain for breadcrumb elements
  breadcrumb:
    root_name: 'Home'
    translation_domain: 'messages'