Symfony3实体设计用于具有多个时间间隔的重复日期

时间:2017-02-10 10:02:23

标签: mysql symfony datetime doctrine-orm calendar

设计重复日期的最佳方法是什么。我有class MenuItemModelFactory extends Database { public function __construct() { $this->table_name = 'menus'; $this->primary_key = 'menu_id'; parent::__construct(); } public function loadById($id) { $data = parent::loadSingle($this->table_name, $this->primary_key, $id); return new MenuItemModel($data); } public function loadAll() { $list = array(); $data = parent::loadAll(); foreach ($data as $row) { $list[] = new MenuItemModel($row); } return $list; } } 实体,与<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <p style="color:red;" onmouseover="ch(event)">This text should be changed</p> <h1>How to change this element when hovered on p element</h1> <script> function ch(e) { e.target.style.color = "black"; alert(); } </script> </body> </html> 实体有一对多的关系。因此,我希望我的服务可以在重复日期提供,但有例外。例如:

  • 每个星期一从今天09:00到12:00从今天到3月3日,除了2月20日
  • 每周二08:00至10:00和12:30至14:30至4月1日
  • 除了3月17日和24日之外,每个星期四都是永远的。

这就是我已经拥有的:

Service

我的问题是存储这些数据的最佳方法是什么?我该如何更改我的实体?每个领域应该具备什么类型?

我需要能够按日期搜索服务,例如在工作日早晨查找服务,所以我希望我的Availability实体能够满足此搜索需求。

1 个答案:

答案 0 :(得分:2)

我们使用了库Recurr

我们的Entity类看起来基本上如下(它被剥离,没有以这种方式测试,但它适用于我们的情况)。我们只是将它用于重复日期而不是时间,但使用我们的示例来继续使用它应该不是问题。

检查一下 - 因为我很确定尝试自己构建它需要花费更多的精力。

<?php

use Doctrine\ORM\Mapping as ORM;
use Recurr\Recurrence;
use Recurr\Rule;
use Recurr\Transformer\ArrayTransformer;
use Recurr\Transformer\ArrayTransformerConfig;

class Availability
{

private static $frequencyList = array(0 => 'DAILY', 1 => 'WEEKLY', 2 => 'MONTHLY', 3 => 'YEARLY');
private static $weekDays = array(0 => 'SU', 1 => 'MO', 2 => 'TU', 3 => 'WE', 4 => 'TH', 5 => 'FR', 6 => 'SA');

/**
 * @var ProductService
 * @ORM\ManyToOne(targetEntity="YourBundle\Service", inversedBy="availabilities")
 */
private $service;

/**
 * @var \DateTime - indicates 'first date' of recurring timeframe
 * @ORM\Column(type="date", nullable=true)
 */
private $dateStart;

/**
 * @var \DateTime - indicates 'until date' of rRule
 * @ORM\Column(type="date", nullable=true)
 */
private $dateUntil;

/**
 * @var int - indicates 'how often' rRule applies
 * @ORM\Column(type="integer", nullable=true)
 */
private $count;

/**
 * @var int - indicates 'how often' per frequency, ex. 1 means every month, 2 every other month
 * @ORM\Column(type="integer", nullable=true, name="freq_interval")
 */
private $interval;

/**
 * @var int - indicates 'frequency', uses self::$frequencyList
 * @ORM\Column(type="integer", nullable=true)
 */
private $freq;

/**
 * @var array - indicates 'every day', uses self::$weekDays
 * @ORM\Column(type="simple_array", nullable=true)
 */
private $byDay;

/**
 * @var array - integer indicates 'day of month', e.g. 1 is first day of month, -1 is last day
 * @ORM\Column(type="simple_array", nullable=true)
 */
private $byMonthDay;

/**
 * @var array - integer indicates 'day of year', e.g. 1 is first day of year, -1 is last day of year
 * @ORM\Column(type="simple_array", nullable=true)
 */
private $byYearDay;

/**
 * @var array - indicates 'every month' January is 0, December = 12
 * @ORM\Column(type="simple_array", nullable=true)
 */
private $byMonth;

// ...getter and setter for all attributes HERE...

/**
 * @return null|\DateTime[]
 */
public function getRecurrenceCollection()
{

    if ($this->getDateEffective() !== null) {
        return null;
    }

    if ($this->getFreq() === null) {
        return null;
    }

    $result = array();

    if ($this->getFreq() !== null) {
        $rulePart[] = 'FREQ=' . self::$frequencyList[$this->getFreq()];
    }

    if ($this->getCount() !== null) {
        $rulePart[] = 'COUNT=' . $this->getCount();
    }

    if ($this->getDateUntil() !== null) {
        $rulePart[] = 'UNTIL=' . TimeUtil::canonicalDateFormat($this->getDateUntil());
    }

    if ($this->getInterval() === null) {
        $rulePart[] = 'INTERVAL=1';
    } else {
        $rulePart[] = 'INTERVAL=' . $this->getInterval();
    }
    if (count($this->getByDay()) > 0) {
        $byWeekDayArray = array();
        foreach ($this->getByDay() as $byDay) {
            $byWeekDayArray[] = self::$weekDays[$byDay];
        }

        $rulePart[] = 'BYDAY=' . implode(',', $byWeekDayArray);
    }
    if (count($this->getByMonth()) > 0) {
        $rulePart[] = 'BYMONTH=' . implode(',', $this->getByMonth());
    }
    if (count($this->getByMonthDay()) > 0) {
        $rulePart[] = 'BYMONTHDAY=' . implode(',', $this->getByMonthDay());
    }
    if (count($this->getByYearDay()) > 0) {
        $rulePart[] = 'BYYEARDAY=' . implode(',', $this->getByYearDay());
    }

    $ruleString = implode(';', $rulePart);

    $rule = new Rule($ruleString, $this->getDateStart(), null, 'UTC');

    $transformer = new ArrayTransformer();

    // enable fix for MONTHLY
    if ($this->getFreq() === 2) {
        $transformerConfig = new ArrayTransformerConfig();
        $transformerConfig->enableLastDayOfMonthFix();
        $transformer->setConfig($transformerConfig);
    }

    $elements = $transformer->transform($rule);

    /** @var Recurrence $element */
    foreach ($elements as $element) {
        $result[] = $element->getEnd();
    }

    return $result;
}

}