Symfony 4 / Sonata: Khởi tạo dự án Symfony 4 + Sonata + FosUser + Media

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

Bắt đầu bằng cách cài đặt bộ khung dự án.
composer create-project symfony/skeleton tên-dự-án

Thêm các thành phần cần thiết:

cd nom-du-projet
composer require symfony/debug-pack --no-update
composer require symfony/maker-bundle --dev --no-update
composer require sonata-project/doctrine-orm-admin-bundle --no-update
composer require templating --no-update
composer require symfony/translation --no-update
composer require doctrine/doctrine-fixtures-bundle --dev --no-update
composer require sonata-project/notification-bundle --no-update
composer require jms/serializer-bundle --no-update
composer require sonata-project/user-bundle --no-update
composer require sonata-project/doctrine-orm-admin-bundle --no-update
composer require symfony/serializer-pack --no-update
composer require swiftmailer-bundle --no-update
composer require symfony/apache-pack --no-update
composer require migrations --no-update
composer require symfony/var-dumper --no-update
composer require phpoffice/phpspreadsheet --no-update
composer require pixassociates/sortable-behavior-bundle --no-update
composer require sonata-project/media-bundle --no-update
composer require liip/imagine-bundle --no-update
composer require sonata-project/intl-bundle --no-update
composer require sonata-project/formatter-bundle  --no-update
composer require annotations  --no-update
composer update
composer dump-autoload

Sau đó trong /config/packages/framework.yaml thêm

framework:
    secret: '%env(APP_SECRET)%'
    #csrf_protection: true
    #http_method_override: true

    # Enables session support. Note that the session will ONLY be started if you read or write from it.
    # Remove or comment this section to explicitly disable session support.
    session:
        handler_id: null
        cookie_secure: auto
        cookie_samesite: lax

    #esi: true
    #fragments: true
    php_errors:
        log: true
    translator: { fallbacks: ['%locale%'] }
    serializer:
        enabled: true
    templating:
        engines: ['twig', 'php']

Sau đó trong /config/packages/doctrine.yaml thêm

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        types:
            json: Sonata\Doctrine\Types\JsonType

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

Trong /config/packages/sonata_media.yaml thêm

sonata_media:
    class:
        media: App\Application\Sonata\MediaBundle\Entity\Media
        gallery: App\Application\Sonata\MediaBundle\Entity\Gallery
        gallery_has_media: App\Application\Sonata\MediaBundle\Entity\GalleryHasMedia
    db_driver: doctrine_orm
    default_context: default
    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
    providers:
        file:
            allowed_extensions: ['pdf', 'txt', 'rtf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'odg', 'odp', 'ods', 'odc', 'odf', 'odb', 'odt', 'odp', 'csv', 'jpg', 'png', 'jpeg', 'svg']
            allowed_mime_types: ['application/pdf', 'application/vnd.openxmlformats-officedocument.presentationml.presentation',  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',  'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'application/vnd.ms-word.document.macroEnabled.12', 'application/vnd.ms-word.template.macroEnabled.12',  'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'application/vnd.ms-excel.sheet.macroEnabled.12','application/vnd.ms-excel.template.macroEnabled.12', 'application/vnd.ms-excel.addin.macroEnabled.12',  'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.openxmlformats-officedocument.presentationml.template',  'application/vnd.openxmlformats-officedocument.presentationml.slideshow',  'application/vnd.ms-powerpoint.addin.macroEnabled.12', 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',  'application/vnd.ms-powerpoint.template.macroEnabled.12', 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', 'application/vnd.ms-access', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/x-pdf', 'application/rtf', 'text/html', 'text/rtf', 'text/plain', 'application/vnd.ms-powerpoint', 'image/svg+xml', 'image/gif', 'image/jpeg', 'image/pjpeg', 'image/png']
            service:    sonata.media.provider.file
            resizer:    false
            filesystem: sonata.media.filesystem.local
            cdn:        sonata.media.cdn.server
            generator:  sonata.media.generator.default
            thumbnail:  sonata.media.thumbnail.liip_imagine
        image:
            allowed_extensions: ['gif', 'svg', 'jpg', 'jpeg', 'png']
            allowed_mime_types: ['image/svg+xml', 'image/gif', 'image/jpeg', 'image/pjpeg', 'image/png']
            #thumbnail: sonata.media.thumbnail.format          # default value
            #thumbnail: sonata.media.thumbnail.consumer.format # can be used to dispatch the resize action to async task
            thumbnail: sonata.media.thumbnail.liip_imagine    # use the LiipImagineBundle to resize the image


    resizer:
        simple:
            mode:  outbound

    pixlr:
        enabled:  false
        referrer: Sonata Project

liip_imagine:
     # valid drivers options include "gd" or "gmagick" or "imagick"
    driver: "imagick"
    
    filter_sets:
        test_banner:
            quality: 75
            filters:              
                relative_resize: { widen: 898,  heighten: 610 }
                crop: {size: [ 898, 610 ], start: [ 0, 0 ] }
                background : { size : [898, 610], position : center, color : '#FFFFFF' }
                
        test_thumb_gallery:
            quality: 100
            filters:
                thumbnail: { size: [288, 192], mode: outbound, allow_upscale: true}
                crop: {size: [288, 192], start: [ 0, 0 ] }
                background : { size : [288, 192], position : center, color : '#FFFFFF' }
                
        test_small_center:
            quality: 75
            filters:
                thumbnail: { size: [319, 207], mode: outbound, allow_upscale: true}
                crop: {size: [ 319, 207 ], start: [ 0, 0 ] }
                background : { size : [319, 207], position : center, color : '#FFFFFF' }
                
        test_medium_center_background:
            quality: 75
            filters:
                background : { size : [141, 93], position : center, color : '#FFFFFF' }
                thumbnail: { size: [141, 93], mode: outbound, allow_upscale: true}
                crop: {size: [ 141, 93 ], start: [ 0, 0 ] }
                
        test_widden:
            quality: 75
            filters:
                relative_resize: {widen: 796}

            

Thêm cấu hình formatter

#config/packages/sonata_formatter.yml

sonata_formatter:
    default_formatter: richhtml
    formatters:
        markdown:
            service: sonata.formatter.text.markdown
            extensions:
                - sonata.formatter.twig.control_flow
                - sonata.formatter.twig.gist
        #        - sonata.media.formatter.twig #keep this commented unless you are using media bundle.


        text:
            service: sonata.formatter.text.text
            extensions:
                - sonata.formatter.twig.control_flow
                - sonata.formatter.twig.gist
        #        - sonata.media.formatter.twig


        rawhtml:
            service: sonata.formatter.text.raw
            extensions:
                - sonata.formatter.twig.control_flow
                - sonata.formatter.twig.gist
        #        - sonata.media.formatter.twig


        richhtml:
            service: sonata.formatter.text.raw
            extensions:
                - sonata.formatter.twig.control_flow
                - sonata.formatter.twig.gist
        #        - sonata.media.formatter.twig


        twig:
            service: sonata.formatter.text.twigengine
            extensions: [] # Twig formatter cannot have extensions
            
    ckeditor:
        templates:
            browser: '@App/Ckeditor/browser.html.twig'
            upload: '@App/Ckeditor/upload.html.twig'
            
            
fos_ck_editor:
    default_config: default
    configs:
        default:
            # default toolbar plus Format button
            toolbar:
            - [Bold, Italic, Underline, -, 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ,-, Cut, Copy, Paste, PasteText, PasteFromWord, -, Undo, Redo, -, NumberedList, BulletedList, -, Outdent, Indent, -,Blockquote, -, Image, Link, Unlink, Table]
            - [Format, Maximize, Source, Iframe]

           

Và để hoàn thiện việc triển khai CKeditor, thêm chủ đề trong twig

#twig.yaml
twig:
    default_path: '%kernel.project_dir%/templates'
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    exception_controller: null

    form_themes:
        - '@SonataFormatter/Form/formatter.html.twig'

Thêm các tuyến đường cho media bundle trong config/routes.yaml

#index:
#    path: /
#    controller: App\Controller\DefaultController::index

gallery:
    resource: '@SonataMediaBundle/Resources/config/routing/gallery.xml'
    prefix: /media/gallery

media:
    resource: '@SonataMediaBundle/Resources/config/routing/media.xml'
    prefix: /media
    
#for 3.x change admin with admin_area    
admin:
    resource: "@SonataAdminBundle/Resources/config/routing/sonata_admin.xml"
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

Sau đó trong /config/routes/sonata_admin.yaml thêm

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    
    
admin_area:
    resource: "@SonataAdminBundle/Resources/config/routing/sonata_admin.xml"
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin    

Sau đó trong /config/packages/sonata_user.yaml thêm

sonata_user:
    security_acl: false
    manager_type: orm # can be orm or mongodb
    class:
        user: App\Application\Sonata\UserBundle\Entity\User
        group: App\Application\Sonata\UserBundle\Entity\Group
    

Sau đó trong /config/packages/security.yaml thêm

security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    encoders:
        FOS\UserBundle\Model\UserInterface: bcrypt

    providers:
        in_memory: { memory: null }
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:
        # Disabling the security for the web debug toolbar, the profiler and Assetic.
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        # -> custom firewall for the admin area of the URL
        admin:
            pattern:            /admin(.*)
            context:            user
            form_login:
                provider:       fos_userbundle
                login_path:     /admin/login
                use_forward:    false
                check_path:     /admin/login_check
                failure_path:   null
            logout:
                path:           /admin/logout
                target:         /admin/login
            anonymous:          true

        # -> end custom configuration

        # default login area for standard users

        # This firewall is used to handle the public login area
        # This part is handled by the FOS User Bundle
        main:
            pattern:             .*
            context:             user
            form_login:
                provider:       fos_userbundle
                login_path:     /login
                use_forward:    false
                check_path:     /login_check
                failure_path:   null
            logout:             true
            anonymous:          true
            
    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # Admin login page needs to be accessed without credential
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Secured part of the site
        # This config requires being logged for the whole site and having the admin role for the admin part.
        # Change these rules to adapt them to your needs
        - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN, ROLE_SUPER_ADMIN] }
        - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }

Sau đó trong /config/packages/swiftmailer.yaml thêm

swiftmailer:
    url: '%env(MAILER_URL)%'
    #pour envoyer directement un email sans attendre
    #spool: { type: 'memory' }
    #pour utiliser le spooler d'envois.
    #dans ce cas, inscrire une cron : 
    #* * * * *  cd /var/www/monprojet/ && APP_ENV=prod php bin/console swiftmailer:spool:send --message-limit=3
    spool:
        type: file
        path: '%kernel.project_dir%/var/spool'

Sau đó trong /config/packages/fos_user.yaml thêm

fos_user:
    db_driver:      orm # can be orm or odm
    firewall_name:  main
    #user_class:     Sonata\UserBundle\Entity\BaseUser
    user_class:     App\Application\Sonata\UserBundle\Entity\User

    group:
        #group_class:   Sonata\UserBundle\Entity\BaseGroup
        group_class:   App\Application\Sonata\UserBundle\Entity\Group
        group_manager: sonata.user.orm.group_manager # If you're using doctrine orm (use sonata.user.mongodb.group_manager for mongodb)

    service:
        user_manager: sonata.user.orm.user_manager

    from_email:
        address: "tbourdin@partitech.com"
        sender_name: "tbourdin@partitech.com"

Cấu hình ngôn ngữ để có giao diện tiếng Pháp trong /config/packages/translation.yaml

framework:
    default_locale: fr
    translator:
        default_path: '%kernel.project_dir%/translations'
        fallbacks:
            - en

Sau đó cấu hình múi giờ:

#config/packages/sonata_intl.yaml
sonata_intl:
    timezone:
        default: Europe/Paris
        locales:
            fr:    Europe/Paris
            en_UK: Europe/London

Tiếp theo, mở rộng bundle:

bin/console sonata:easy-extends:generate SonataUserBundle --dest=src --namespace_prefix=App

Bạn cũng cần tạo entity cho media bundle

bin/console sonata:easy-extends:generate --dest=src SonataMediaBundle --namespace_prefix=App

Và đăng ký nó trong các bundles cần tải (/config/bundles.php) thêm lời gọi đến ApplicationSonataUserBundle:

<?php

return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Sonata\DatagridBundle\SonataDatagridBundle::class => ['all' => true],
    Sonata\CoreBundle\SonataCoreBundle::class => ['all' => true],
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
    Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
    Sonata\BlockBundle\SonataBlockBundle::class => ['all' => true],
    Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
    Sonata\AdminBundle\SonataAdminBundle::class => ['all' => true],
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
    Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle::class => ['all' => true],
    Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
    Sonata\EasyExtendsBundle\SonataEasyExtendsBundle::class => ['all' => true],
    Sonata\NotificationBundle\SonataNotificationBundle::class => ['all' => true],
    FOS\UserBundle\FOSUserBundle::class => ['all' => true],
    Sonata\UserBundle\SonataUserBundle::class => ['all' => true],
    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
    Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
    Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
    Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
    JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
    Pix\SortableBehaviorBundle\PixSortableBehaviorBundle::class => ['all' => true],
    Sonata\MediaBundle\SonataMediaBundle::class => ['all' => true],
    App\Application\Sonata\UserBundle\ApplicationSonataUserBundle::class => ['all' => true],
    App\Application\Sonata\MediaBundle\ApplicationSonataMediaBundle::class => ['all' => true],
Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],
Sonata\IntlBundle\SonataIntlBundle::class => ['all' => true],
];

Loại trừ thư mục Application khỏi tự động ghép nối của các dịch vụ

# config/services.yaml

services:
    App\:
        resource: '../src/*'
        exclude: '../src/{Entity,Tests,Application}'

Điểm cuối cùng, cấu hình cơ sở dữ liệu trong tệp .env

DATABASE_URL=mysql://root:toor@127.0.0.1:3306/delef?serverVersion=5.7

Bắt đầu việc tạo bảng:

php bin/console doctrine:schema:update --force

Cài đặt các tài sản:

php bin/console assets:install
php bin/console ckeditor:install

Tạo thư mục lưu trữ tệp

mkdir -p public/uploads/media

Xóa bộ nhớ cache:

php bin/console cache:clear

Và tạo người dùng quản trị

php bin/console fos:user:create admin mail@mail.com p@ssword --super-admin