Skip to content

Установка

В этом руководстве описана установка административной панели bia на чистую Symfony 6.4.

Установка Symfony и зависимостей

  1. Устанавливаем чистую Symfony версии 6.4, если еще не установлена:

    bash
    composer create-project symfony/skeleton:"6.4.*" .
  2. Добавляем репозиторий с исходным кодом bia/admin-bundle:

    json
    "repositories": [
        {
            "type": "git",
            "url": "https://gitlab.srvdev.ru/bia-cms/bundles/admin-bundle.git"
        }
    ],
  3. Создаём файл конфигурации config/packages/bia_admin.yaml

    yaml
    bia_admin:
       exporter:
          default_handlers: ['json', 'csv', 'xlsx']
          only_delayed_strictly: false
          default_only_delayed: false
          handlers:
             csv:
                delimiter: ','
                enclosure: '"'
                escape: "\\"
                show_headers: true
  4. В config/services.yaml добавляем сервис загрузки маршрутов и параметр для переводов:

    yaml
    parameters:
       defaults.admin.translation_domain: 'AdminTranslationDomain'
    
    services:
       admin.routing.loader:
           class: Bia\AdminBundle\Routing\AdminLoader
           public: true
           arguments:
               $adminServiceIds: []
               $container: '@service_container'
           tags:
               - { name: 'routing.loader' }
  5. Устанавливаем необходимые зависимости (TODO добавить зависимости в admin-bundle/composer.json):

    bash
    composer require symfony/orm-pack
    composer require symfony/validator
    composer require symfony/form
    composer require lexik/jwt-authentication-bundle
    composer require lcobucci/jwt
    composer require phpdocumentor/reflection-docblock
    composer require symfony/var-exporter:6.4.4
  6. В .env или .env.dist добавляем:

     ###> lexik/jwt-authentication-bundle ###
     JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
     JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
     JWT_PASSPHRASE=85d8de1a30ac46474f2f91c4ff97a477
     JWT_NAME=jwt
     JWT_TTL=130000
     AUTH_PROTECTED_LEVEL=IS_AUTHENTICATED_FULLY
     ###< lexik/jwt-authentication-bundle ###
    
     ###> admin front api service ###
     VITE_ADMIN_API_SERVICE='http://127.0.0.1:8001/'
     ###< admin front api service ###
  7. В config/services.yaml добавляем:

    yaml
       form.factory:
         class: Symfony\Component\Form\FormFactory
         public: true
         arguments: ['@form.registry']
    
       Bia\AdminBundle\Repository\AdminUserRepository:
         autowire: true
         tags: ['doctrine.repository_service']
    
       Bia\AdminBundle\DataFixtures\:
         resource: '../vendor/bia/admin-bundle/DataFixtures'
  8. В config/routes.yaml добавляем:

    yaml
    admin_login_token:
       path: /admin/login_token
    
    admin_logout:
       path: /admin/logout
       methods: ['POST']
    
    bia_admin_bundle:
       resource: "@BiaAdminBundle/Resources/config/routing.php"
    
    admin_routes:
       resource: '.'
       type: 'admin_routes'
  9. Устанавливаем пакет:

    bash
     composer require bia/admin-bundle:0.9.0
  10. Создаем файл config/packages/roles.yaml с содержимым:

yaml
parameters:
  roles: []
  1. В config/packages/security.yaml добавляем:
yaml
security:
 enable_authenticator_manager: true
 password_hashers:
     Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
 providers:
     app_admin_provider:
         entity:
             class: Bia\AdminBundle\Entity\AdminUser
             property: email
     app_user_provider:
         entity:
             class: App\Entity\User
             property: email
 firewalls:
     dev:
         pattern: ^/(_(profiler|wdt)|css|images|js)/
         security: false
     login:
         provider: app_admin_provider
         pattern: ^/admin/login
         stateless: true
         json_login:
             check_path: /admin/login_token
             username_path: email
             password_path: password
             success_handler: lexik_jwt_authentication.handler.authentication_success
             failure_handler: lexik_jwt_authentication.handler.authentication_failure
     logout:
         pattern: ^/admin/logout
         logout:
             path: /admin/logout
             invalidate_session: true
             delete_cookies:
                 jwt: true
             target: admin_user_logout
     admin:
         provider: app_admin_provider
         pattern: ^/admin
         stateless: true
         jwt: ~
          
                          
 access_control:
     - { path: ^/admin/login_token, roles: PUBLIC_ACCESS }
     - { path: ^/admin/user_logout, roles: PUBLIC_ACCESS }
     - { path: ^/admin,       roles: '%env(AUTH_PROTECTED_LEVEL)%' }
    

when@test:
 security:
     password_hashers:
         Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
             algorithm: auto
             cost: 4
             time_cost: 3
             memory_cost: 10
  1. В config/packages/lexik_jwt_authentication.yaml добавляем:
yaml
 lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'
    token_ttl: '%env(JWT_TTL)%'
    user_identity_field: email
 
    # token extraction settings
    token_extractors:
        authorization_header:
            enabled: true
        cookie:
            enabled: true
            name: '%env(JWT_NAME)%'
 
    set_cookies:
        '%env(JWT_NAME)%':
            httpOnly: true
            secure: false
 
    remove_token_from_body_when_cookies_used: false
  1. Генерируем приватный и публичный ключ для JWT:
bash
mkdir config/jwt
openssl genrsa -out config/jwt/private.pem 4096
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem
  1. Выполняем миграции:
bash
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
  1. Генерируем администратора:
bash
php bin/console bia:admin:create-super-admin
  1. Генерируем меню:
bash
php bin/console bia:admin:generate-menu
  1. Генерируем роли и права:
bash
php bin/console bia:admin:generate-roles-config

Установка SPA-фронта

  1. Конфигурация nginx:

    server
    {
     listen 80;
     listen 443 ssl http2;
     server_name "~^(?<domain>.+).pers.bia.terranova.srvdev.ru$";
    
     root /www/bia.terranova.srvdev.ru/personal/$host/public;
    
     location /
     {
         try_files $uri $uri/ /index.php$is_args$args;
     }
    
     location ~ ^/(index)\.php(/|$)
     {
         fastcgi_pass unix:/run/php-fpm/www.sock;
         fastcgi_split_path_info ^(.+\.php)(/.*)$;
         include fastcgi_params;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
     }
    
     location /bia
     {
         try_files $uri /bia/$uri /bia/index.html;
     }
    
     charset utf-8;
     client_max_body_size 100m;
    
     error_log /var/log/nginx/personal.bia.srvdev.ru_error.log;
     access_log /var/log/nginx/personal.bia.srvdev.ru_access.log;
    
     fastcgi_read_timeout 960;
    }
  2. Создаем package.json:

    json
    {
       "name": "development",
       "private": true,
       "version": "0.0.0",
       "type": "module",
       "scripts": {
          "dev": "vite",
          "build": "vite build",
          "preview": "vite preview"
       },
       "devDependencies": {
          "typescript": "^5.2.2",
          "vite": "^5.1.4"
       },
       "dependencies": {
          "bia-cms": "file:vendor/bia/admin-bundle/frontend"
       }
    }
  3. Создаем vite.config.ts:

    ts
    import { defineConfig, loadEnv } from 'vite'
    
    export default ({mode}: { mode: string }) => {
       process.env = Object.assign(process.env, loadEnv(mode, process.cwd()))
    
       return defineConfig({
          server: {
             proxy: {
                '^/(upload|admin)': {
                   target: process.env.VITE_ADMIN_API_SERVICE,
                   changeOrigin: true,
                   secure: false,
                },
             },
          },
          build: {
             assetsDir: 'bia',
             outDir: 'public/bia'
          },
          publicDir: false
       })
    }
  4. Создаем файл index.html в корне проекта:

    html
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Dev project</title>
      </head>
      <body>
        <div id="app"></div>
        <script type="module" src="/src/frontend/main.js"></script>
      </body>
    </html>
  5. Создаем файл src/frontend/main.js:

    js
    import {mountApp} from "bia-cms"
    import 'bia-cms/dist/style.css'
    
    mountApp('app', {
        apiService: import.meta.env.MODE === 'production' ? import.meta.env.VITE_ADMIN_API_SERVICE : undefined,
        components: import.meta.glob('./fields/GroupUserList.vue'),
    })
  6. Создаем файл src/frontend/fields/GroupUserList.vue:

    vue
    <template>
      <h2>test</h2>
    </template>
    
    <script setup lang="ts">
    import type { IFormField } from "bia-cms/src/views/dynamicPage/types/form";
    import { IApiWrapper } from "bia-cms/src/assets/js/helpers/useApi";
    
    const props = defineProps<{
      modelValue: any | undefined,
      field: IFormField,
      formValues: Record<string, any>,
      api: IApiWrapper,
      route: any,
    }>()
    
    const emit = defineEmits(['update:modelValue'])
    
    </script>
    
    <style scoped>
    
    </style>
  7. Затем запускаем

    bash
    php bin/console bia:admin:build-frontend