Symfony 6 / Sonata 5: Khởi tạo dự án Symfony 6 + Sonata Admin 5 + UserBundle + MediaBundle

Đây là các lệnh để khởi tạo một dự án Symfony với quản trị an toàn.

Để chạy Symfony 6, chúng ta cần cài đặt php8.0 hoặc php8.1

Đối với php8.0

sudo apt-get install php8.0-cli libapache2-mod-php8.0 php8.0-common php8.0-opcache php8.0-igbinary php8.0-imagick  php8.0-msgpack php8.0-readline  php8.0-memcached  php8.0-xml php8.0-mbstring php8.0-gd php8.0-mysql php8.0-curl php8.0-intl php8.0-memcache php8.0-memcached  memcached libapache2-mod-php8.0 php8.0-zip php8.0-mysql

Đối với php8.1

sudo apt-get install php8.1-cli libapache2-mod-php8.1 php8.1-common php8.1-opcache php8.1-igbinary php8.1-imagick  php8.1-msgpack php8.1-readline  php8.1-memcached  php8.1-xml php8.1-mbstring php8.1-gd php8.1-mysql php8.1-curl php8.1-intl php8.1-memcache php8.1-memcached  memcached libapache2-mod-php8.1 php8.1-zip php8.1-mysql

Sau đó, chúng ta cài đặt khung sườn của dự án.

php8.1 composer.phar create-project symfony/skeleton:"6.0.x-dev" skeleton-sf6
cp composer.phar skeleton-sf6/
cd skeleton-sf6
php8.1 composer.phar require webapp

Lúc này, chúng ta kiểm tra xem mọi thứ có hoạt động không bằng cách khởi chạy máy chủ web tích hợp của PHP.

php8.1 -S localhost:8000 -t public

Điều này cung cấp cho chúng ta URL sau trong trình duyệt: http://localhost:8000/

Selection_249
Symfony 6.0.6

Tiếp theo, chúng ta cài đặt user-bundle, là cần thiết cho quản trị Sonata. Nó sẽ cài đặt tất cả các phụ thuộc cần thiết, bao gồm Sonata/admin.
Chúng ta chú ý hạ cấp Symfony/translation vì nó quá mới trong khung sườn của chúng ta cho Sonata tại thời điểm này.

php8.1 composer.phar require symfony/translation-contracts:2.5
php8.1 composer.phar require sonata-project/user-bundle:5.x-dev
php8.1 bin/console assets:install

Chúng ta gặp phải vấn đề đầu tiên:

 The child config "resetting" under "sonata_user" must be configured. 

Đối với điều này, chúng ta cần thêm cấu hình mặc định trong /config/packages/sonata_user.yaml

#####/config/packages/sonata_user.yaml
sonata_user:
    class:
        user: App\Entity\User
    resetting:
        email:
            address: "test@test.com"
            sender_name: Backoffice

Và thực hiện lệnh console/bin cache:clear

php8.1 bin/console cache:clear

Sau đó, chúng ta cài đặt Sonata/admin. Bằng cách cài đặt doctrine-orm-admin-bundle, chúng ta sẽ tự động cài đặt admin-bundle, tránh mọi xung đột.

php8.1 composer.phar require sonata-project/doctrine-orm-admin-bundle
php8.1 bin/console assets:install


Chúng ta kiểm tra trang web của mình từ máy chủ web.

php8.1 -S localhost:8000 -t public

Chúng ta nên nhận được lỗi sau:

An exception has been thrown during the rendering of a template ("Asset manifest file "/public/build/manifest.json" does not exist.").
Il faudra installer webpack
yarn add --dev @symfony/webpack-encore
yarn add webpack-notifier --dev
yarn encore dev

Sonata admin đã được cài đặt đúng. Xác thực chưa được cấu hình, và chúng ta vẫn thiếu quản lý media và phân loại (chúng ta sẽ xem xét phân loại trong một bài viết tương lai).

image

Chúng ta cài đặt và cấu hình ACLs.

php8.1 composer.phar require symfony/acl-bundle

Chúng ta cấu hình sonata_user.yml

#####/config/packages/sonata_user.yaml

sonata_user:
    class:
        user: App\Entity\User
    resetting:
        email:
            address: "test@test.com"
            sender_name: Backoffice
            
    security_acl: true
    manager_type: orm # can be orm or mongodb


Chúng ta cấu hình security.yaml

#####/config/packages/security.yaml
security:
    enable_authenticator_manager: true
    password_hashers:
        Sonata\UserBundle\Model\UserInterface:
            algorithm: auto
    providers:
        sonata_user_bundle:
            id: sonata.user.security.user_provider
    access_decision_manager:
        strategy: unanimous   
    
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        admin:
            lazy: true
            pattern: /admin(.*)
            provider: sonata_user_bundle
            context: user
            switch_user: true
            form_login:
                login_path: sonata_user_admin_security_login
                check_path: sonata_user_admin_security_check
                default_target_path: sonata_admin_dashboard
            logout:
                path: sonata_user_admin_security_logout
                target: sonata_user_admin_security_login
            remember_me:
                #secret: "%env(APP_SECRET)%"
                secret: "123456"
                lifetime: 2629746
                path: /admin


    
    access_control:
        - { path: ^/admin/login$, role: PUBLIC_ACCESS }
        - { path: ^/admin/logout$, role: PUBLIC_ACCESS }
        - { path: ^/admin/login_check$, role: PUBLIC_ACCESS }
        - { path: ^/admin/request$, role: PUBLIC_ACCESS }
        - { path: ^/admin/check-email$, role: PUBLIC_ACCESS }
        - { path: ^/admin/reset/.*$, role: PUBLIC_ACCESS }
        - { path: ^/admin/, role: ROLE_ADMIN }    
    
    role_hierarchy:
        ROLE_ADMIN:
            - ROLE_USER
            - ROLE_SONATA_ADMIN
            - ROLE_SONATA_USER_ADMIN_USER_VIEW
        ROLE_SUPER_ADMIN:
            - ROLE_ADMIN
            - ROLE_ALLOWED_TO_SWITCH        
   

Chúng ta thêm các tuyến đường admin.

#####/config/route.yaml
sonata_user_admin_security:
    resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml'
    prefix: /admin

sonata_user_admin_resetting:
    resource: '@SonataUserBundle/Resources/config/routing/admin_resetting.xml'
    prefix: /admin/resetting

Chúng ta tạo ra thực thể người dùng của mình.

#/src/Entity/User.php
<?php 
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sonata\UserBundle\Entity\BaseUser;

/**
 * @ORM\Entity
 * @ORM\Table(name="user__user")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;
}

Chúng ta cập nhật sơ đồ cơ sở dữ liệu và tạo người dùng admin của mình.

php8.1 bin/console doctrine:schema:update --force
php8.1 bin/console sonata:user:create admin admin@test.com admin123456
php8.1 bin/console sonata:user:promote --super-admin admin

Chúng ta khởi động lại máy chủ của mình và kiểm tra URL: http://localhost:8000/admin/dashboard

php8.1 -S localhost:8000 -t public

Chúng ta được chuyển hướng chính xác đến màn hình đăng nhập.

Selection_260

Người dùng được phép nhập vào quản trị.

image-1

Bây giờ, chúng ta cấu hình quản lý media.

Chúng ta tạo 3 thực thể: Gallery, GalleryItem, và Media trong một cấu trúc thư mục riêng biệt để không làm lộn xộn ứng dụng của chúng ta. Chúng ta sẽ làm tương tự cho UserBundle và ClassificationBundle.
Chúng ta sẽ đặt tất cả trong src/Application/Sonata/MediaBundle/Entity

<?php

declare(strict_types=1);

namespace App\Application\Sonata\MediaBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sonata\MediaBundle\Entity\BaseGallery;

/**
 * @phpstan-extends BaseGallery<GalleryItem>
 *
 * @ORM\Entity
 * @ORM\Table(name="media__gallery")
 */
class Gallery extends BaseGallery
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

    public function getId(): ?int
    {
        return $this->id;
    }
}
<?php

declare(strict_types=1);

namespace App\Application\Sonata\MediaBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sonata\MediaBundle\Entity\BaseGalleryItem;

/**
 * @ORM\Entity
 * @ORM\Table(name="media__gallery_media")
 */
class GalleryItem extends BaseGalleryItem
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

    public function getId(): ?int
    {
        return $this->id;
    }
}
<?php

declare(strict_types=1);

namespace App\Application\Sonata\MediaBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sonata\MediaBundle\Entity\BaseMedia;
use App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationCategory as SonataClassificationCategory;

/**
 * @ORM\Entity
 * @ORM\Table(name="media__media")
 */
class Media extends BaseMedia
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;
    
    /**
     * @var SonataClassificationCategory|null
     */
    protected ?object $category = null;

    public function getId(): ?int
    {
        return $this->id;
    }
    
    
    public function getCategory(): ?object
    {
        return $this->category;
    }
    
    public function setCategory(?object $category = null): void
    {
        $this->category = $category;
    }
}

Chúng ta thêm cấu hình trong sonata_media.yaml

sonata_media:
    class:
        media: App\Application\Sonata\MediaBundle\Entity\Media
        gallery: App\Application\Sonata\MediaBundle\Entity\Gallery
        gallery_item: App\Application\Sonata\MediaBundle\Entity\GalleryItem
    default_context: default
    db_driver: doctrine_orm
    providers:
        file:
            allowed_extensions: [jpg, png, jpeg, pdf, ogv, mp4, webm]
            allowed_mime_types:
                - image/pjpeg
                - image/jpeg
                - image/png
                - image/x-png
                - application/pdf
                - application/x-pdf
                - application/ogg
                - video/mp4
                - video/webm

    contexts:
        default:
            providers:
                - sonata.media.provider.dailymotion
                - sonata.media.provider.youtube
                - sonata.media.provider.image
                - sonata.media.provider.file
                - sonata.media.provider.vimeo

            formats:
                small: { width: 100 , quality: 70}
                big:   { width: 500 , quality: 70}

    cdn:
        server:
            path: /upload/media

    filesystem:
        local:
            # Directory for uploads should be writable
            directory: "%kernel.project_dir%/public/upload/media"
            create: false

Chúng ta thêm cấu trúc ghi đè của chúng ta cho MediaBundle trong config/packages/doctrine.yaml

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'

        # IMPORTANT: You MUST configure your server version,
        # either here or in the DATABASE_URL env var (see .env file)
        #server_version: '13'
    orm:
        auto_generate_proxy_classes: true
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        mappings:
            App:
                is_bundle: false
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App

            App\Application\Sonata\MediaBundle:
                is_bundle: false
                dir: '%kernel.project_dir%/src/Application/Sonata/MediaBundle/Entity'
                prefix: 'App\Application\Sonata\MediaBundle\Entity'
                alias: App\Application\Sonata\MediaBundle
 
        filters:
            softdeleteable:
                class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter

Chúng ta cập nhật sơ đồ cơ sở dữ liệu.

php8.1 bin/console doctrine:schema:update --force

Chúng ta cấu hình sonata_admin.yml mặc định của chúng ta.

sonata_admin:
    title: Backoffice
    title_logo: /bundles/sonataadmin/images/logo_title.png
    show_mosaic_button: false
    security:
        handler: sonata.admin.security.handler.role
    options:
        default_admin_route: edit
        html5_validate: false
    global_search:
        admin_route: edit
    breadcrumbs:
        child_admin_route: edit
    dashboard:
        groups:
            users:
                label: Users
                icon: <i class="fa fa-users"></i>
                on_top: true
                items:
                    - sonata.user.admin.user
            media:
                label: Media
                icon: <i class="fa fa-photo"></i>
                on_top: true
                items:
                    - sonata.media.admin.media

Và mọi thứ hoạt động.

image-2
image-3