comsa/sulu-reservations

Sulu的预订组件

安装: 155

依赖项: 0

建议者: 0

安全性: 0

星标: 1

分支: 0

类型:symfony-bundle

3.1.3 2022-04-27 17:00 UTC

README

工作原理

这个组件是什么?

  • 预订系统
  • 与Sulu FormBundle集成

该组件利用您可创建的可预订项目。这些可以链接到您也可以创建的可预订选项。组件支持单次付款和按人付款。每个可预订项目都可以有不同的价格组,并有自己的价格(例如,成人 => €5,儿童 => €3)。付款配置在模块的设置选项卡内。支持3种类型,每种类型都有自己的额外费用(银行、现金或mollie)。

安装

添加到 assets/admin/package.json

"sulu-reservations-bundle": "file:node_modules/@sulu/vendor/comsa/sulu-reservations/Resources/js"

添加到 assets/website/package.json

"sulu-reservations-bundle": "file:../../vendor/comsa/sulu-reservations/Resources/js",

在两个地方运行 npm install

添加到 assets/admin/index.js

import 'sulu-reservations-bundle/admin'

添加到 assets/website/index.js

import 'sulu-reservations-bundle/website'

使用 npm run build 构建它们,这可能需要一些时间 :)

添加路由到 routes_admin.yamlroutes_website.yaml

在:config/routes_admin.yaml

sulu_reservations_admin:
  type: rest
  resource: "@SuluReservationsBundle/Resources/config/routes/admin.yaml"
  prefix: /admin/reservations/api

在:config/routes_website.yaml

sulu_reservations_website:
  resource: "@SuluReservationsBundle/Resources/config/routes/website.yaml"
  prefix: /sulu-reservations

在 config/services.yaml 中创建以下参数并给出正确的值

    comsa_sulu_reservations_mollie_api_key: '%env(COMSA_RE_MOLLIE_API_KEY)%'

创建一个名为 comsa_reservable 的模板(此键用于在添加可预订项目时生成页面)并添加以下字段

<property name="reservable" type="single_reservable_selection">
    <meta>
        <title lang="en">Reservable</title>
        <title lang="nl">Reserveerbaar Item</title>
    </meta>
</property>

在 config/services.yaml 中添加以下代码。

sulu_form.request_listener:
    class: App\EventListener\RequestListener
    arguments:
        - '@sulu_form.builder'
        - '@sulu_form.handler'
        - '@sulu_form.configuration.form_configuration_factory'
        - '@event_dispatcher'
        - '@router.default'
    tags:
        - { name: 'kernel.event_listener', event: 'kernel.request', method: 'onKernelRequest' }

此代码覆盖了来自 sulu/form-bundle 的标准 RequestListener。创建以下文件

<?php

declare(strict_types=1);

namespace App\EventListener;

use Sulu\Bundle\FormBundle\Configuration\FormConfigurationFactory;
use Sulu\Bundle\FormBundle\Entity\Dynamic;
use Sulu\Bundle\FormBundle\Event\DynFormSavedEvent;
use Sulu\Bundle\FormBundle\Form\BuilderInterface;
use Sulu\Bundle\FormBundle\Form\HandlerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\RouterInterface;

class RequestListener
{
    protected BuilderInterface $formBuilder;
    protected HandlerInterface $formHandler;
    protected FormConfigurationFactory $formConfigurationFactory;
    protected EventDispatcherInterface $eventDispatcher;
    protected RouterInterface $router;

    /**
     * RequestListener constructor.
     */
    public function __construct(
        BuilderInterface $formBuilder,
        HandlerInterface $formHandler,
        FormConfigurationFactory $formConfigurationFactory,
        EventDispatcherInterface $eventDispatcher,
        RouterInterface $router
    ) {
        $this->formBuilder = $formBuilder;
        $this->formHandler = $formHandler;
        $this->formConfigurationFactory = $formConfigurationFactory;
        $this->eventDispatcher = $eventDispatcher;
        $this->router = $router;
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            // do nothing if it's not the master request
            return;
        }

        $request = $event->getRequest();

        if (!$request->isMethod('post')) {
            // do nothing if it's not a post request
            return;
        }

        try {
            $form = $this->formBuilder->buildByRequest($request);

            if (!$form || !$form->isSubmitted() || !$form->isValid()) {
                // do nothing when no form was found or not valid
                return;
            }
        } catch (\Exception $e) {
            // Catch all exception on build form by request
            return;
        }

        /** @var Dynamic $dynamic */
        $dynamic = $form->getData();
        $configuration = $this->formConfigurationFactory->buildByDynamic($dynamic);
        $dynamic->setLocale($request->getLocale()); // Need to be set to request locale for shadow pages, configuraiton will hold the original locale


        if ($this->formHandler->handle($form, $configuration)) {

            if (!$request->request->get("reservable")) {
                $serializedObject = $dynamic->getForm()->serializeForLocale($dynamic->getLocale(), $dynamic);
                $dynFormSavedEvent = new DynFormSavedEvent($serializedObject, $dynamic);
                $this->eventDispatcher->dispatch($dynFormSavedEvent, DynFormSavedEvent::NAME);
                $response = new RedirectResponse('?send=true');
            } else {
                $response = new RedirectResponse($this->router->generate("comsa_sulu_reservations_select_payment_method"));
            }

            $event->setResponse($response);
        }
    }
}

将以下代码添加到 twig 文件以渲染用 Vue.js 编写的预订表单

{% extends "base.html.twig" %}

{% block content %}
  {% include '@SuluReservations/reservable.html.twig' %}
{% endblock %}

以下是为创建可预订概览的示例代码

XML

<?xml version="1.0" ?>
<type name="reservable_overview" xmlns="http://schemas.sulu.io/template/template"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.0.xsd">
    <meta>
        <title lang="en">Reservable overzicht</title>
        <title lang="nl">Reserveerbare items overzicht</title>
    </meta>
    <properties>
        <property name="title" type="text_line">
            <meta>
                <title lang="en">Title</title>
            </meta>
        </property>

        <property name="reservables" type="smart_content">
            <meta>
                <title lang="en">Reservable overview</title>
                <title lang="en">Reserveerbare items overzicht</title>
            </meta>
            <params>
                <param name="provider" value="pages"/>
                <param name="properties" type="collection">
                    <param name="reservable" value="reservable"/>
                </param>
            </params>
        </property>
        <xi:include href="includes/width.xml"/>
    </properties>
</type>

HTML

<section class="container reservables">
  <h2>{{ block.title }}</h2>
  <ul class="row">
    <table class="d-none d-md-block table table-hover">
      <tr>
        <th>Evenement</th>
        <th>Beschikbare plaatsen</th>
        <th>Start op</th>
        <th>Eindigt op</th>
        <th></th>
      </tr>
      {% for page in block.reservables %}
        {% set spacesLeft = get_spaces_left(page.reservable.id) %}
        <tr>
          <td>{{ page.title }}</td>
          <td>{{ spacesLeft }}</td>
          <td>{{ page.reservable.start|date("d/m/Y") }}</td>
          <td>{{ page.reservable.end|date("d/m/Y") }}</td>
          <td>
            {% if spacesLeft == 0 %}
              <button type="button" class="btn btn-danger">VOLZET</button>
            {% else %}
              <a href="{{ sulu_content_path(page.url) }}" class="btn btn-primary">RESERVEER NU</a>
            {% endif %}
          </td>
        </tr>
      {% endfor %}
    </table>
    {% for page in block.reservables %}
      <li class="col-12 d-md-none">
        <div class="reservable-wrapper">
          <h3>{{ page.title }}</h3>
          <div class="limit">
            {% set spacesLeft = get_spaces_left(page.reservable.id) %}
            <i class="fas fa-user {% if spacesLeft < 5 %} text-danger {% endif %}"></i><span {% if spacesLeft < 5 %} class="text-danger" {% endif %}>{{ spacesLeft }}</span>
          </div>
          <div class="button-wrapper">
            {% if spacesLeft == 0 %}
              <button type="button" class="btn btn-danger">VOLZET</button>
            {% else %}
              <a href="{{ sulu_content_path(page.url) }}" class="btn btn-primary">RESERVEER NU</a>
            {% endif %}
          </div>
        </div>
      </li>
    {% endfor %}
  </ul>
</section>

SCSS

.reservables {
  margin-left: 0;
  margin-top: 2rem;
  padding: 0;
  width: 100%;

  h3 {
    color: $black;
  }

  ul {
    list-style-type: none;
    padding: 0;
  }

  .reservable-wrapper {
    align-items: center;
    border: solid 1px $gray-500;
    display: flex;
    justify-content: center;
    margin-bottom: 2rem;
    min-height: 14rem;
    padding: 1.5rem;
    width: 100%;

    .button-wrapper {
      bottom: 0;
      position: absolute;
      transform: translateY(-50%);
    }

    .limit {
      border: 1px solid $gray-500;
      border-right: 0;
      border-top: 0;
      min-height: 2rem;
      min-width: 3rem;
      position: absolute;
      right: 0;
      text-align: center;
      top: 0;
      transform: translateX(-35%);
    }

    svg {
      margin-right: 0.5rem;
    }
  }
}

在 config/packages/doctrine.yaml 中

doctrine:
  orm:
    mappings:
      SuluReservationsBundle:
        is_bundle: true
        type: attribute
        dir: 'Entity'
        prefix: 'Comsa\SuluReservations\Entity'
        alias: SuluReservations

使用 php bin/console doctrine:schema:update -f 更新您的数据库以添加所需的表

加载默认设置

<?php

namespace App\DataFixtures;

use Comsa\SuluReservations\DataFixtures\AppSeed;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;

class AppFixtures extends Fixture implements DependentFixtureInterface
{
    public function load(ObjectManager $manager)
    {

    }

    public function getDependencies()
    {
        return[
          AppSeed::class
        ];
    }

}

将以下内容复制并粘贴到您的应用程序的 DataFixtures 中。运行 Symfony console doctrine:fixtures:load --append