Move timetable to a plugin
Plugin repository: https://github.com/kanboard/plugin-timetable
This commit is contained in:
@@ -150,13 +150,14 @@ class SubtaskTimeTracking extends Base
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @param string $start ISO-8601 format
|
||||
* @param string $end
|
||||
* @return array
|
||||
*/
|
||||
public function getUserCalendarEvents($user_id, $start, $end)
|
||||
{
|
||||
$result = $this->getUserQuery($user_id)
|
||||
$hook = 'model:subtask-time-tracking:calendar:events';
|
||||
$events = $this->getUserQuery($user_id)
|
||||
->addCondition($this->getCalendarCondition(
|
||||
$this->dateParser->getTimestampFromIsoFormat($start),
|
||||
$this->dateParser->getTimestampFromIsoFormat($end),
|
||||
@@ -165,9 +166,16 @@ class SubtaskTimeTracking extends Base
|
||||
))
|
||||
->findAll();
|
||||
|
||||
$result = $this->timetable->calculateEventsIntersect($user_id, $result, $start, $end);
|
||||
if ($this->hook->exists($hook)) {
|
||||
$events = $this->hook->first($hook, array(
|
||||
'user_id' => $user_id,
|
||||
'events' => $events,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
));
|
||||
}
|
||||
|
||||
return $this->toCalendarEvents($result);
|
||||
return $this->toCalendarEvents($events);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,6 +301,7 @@ class SubtaskTimeTracking extends Base
|
||||
*/
|
||||
public function getTimeSpent($subtask_id, $user_id)
|
||||
{
|
||||
$hook = 'model:subtask-time-tracking:calculate:time-spent';
|
||||
$start_time = $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('subtask_id', $subtask_id)
|
||||
@@ -300,14 +309,23 @@ class SubtaskTimeTracking extends Base
|
||||
->eq('end', 0)
|
||||
->findOneColumn('start');
|
||||
|
||||
if ($start_time) {
|
||||
$start = new DateTime;
|
||||
$start->setTimestamp($start_time);
|
||||
|
||||
return $this->timetable->calculateEffectiveDuration($user_id, $start, new DateTime);
|
||||
if (empty($start_time)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
$end = new DateTime;
|
||||
$start = new DateTime;
|
||||
$start->setTimestamp($start_time);
|
||||
|
||||
if ($this->hook->exists($hook)) {
|
||||
return $this->hook->first($hook, array(
|
||||
'user_id' => $user_id,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
));
|
||||
}
|
||||
|
||||
return $this->dateParser->getHours($start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DateTime;
|
||||
use DateInterval;
|
||||
|
||||
/**
|
||||
* Timetable
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Timetable extends Base
|
||||
{
|
||||
/**
|
||||
* User time slots
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $day;
|
||||
private $week;
|
||||
private $overtime;
|
||||
private $timeoff;
|
||||
|
||||
/**
|
||||
* Get a set of events by using the intersection between the timetable and the time tracking data
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param array $events Time tracking data
|
||||
* @param string $start ISO8601 date
|
||||
* @param string $end ISO8601 date
|
||||
* @return array
|
||||
*/
|
||||
public function calculateEventsIntersect($user_id, array $events, $start, $end)
|
||||
{
|
||||
$start_dt = new DateTime($start);
|
||||
$start_dt->setTime(0, 0);
|
||||
|
||||
$end_dt = new DateTime($end);
|
||||
$end_dt->setTime(23, 59);
|
||||
|
||||
$timetable = $this->calculate($user_id, $start_dt, $end_dt);
|
||||
|
||||
// The user has no timetable
|
||||
if (empty($this->week)) {
|
||||
return $events;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$results = array_merge($results, $this->calculateEventIntersect($event, $timetable));
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a serie of events based on the timetable and the provided event
|
||||
*
|
||||
* @access public
|
||||
* @param array $event
|
||||
* @param array $timetable
|
||||
* @return array
|
||||
*/
|
||||
public function calculateEventIntersect(array $event, array $timetable)
|
||||
{
|
||||
$events = array();
|
||||
|
||||
foreach ($timetable as $slot) {
|
||||
|
||||
$start_ts = $slot[0]->getTimestamp();
|
||||
$end_ts = $slot[1]->getTimestamp();
|
||||
|
||||
if ($start_ts > $event['end']) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($event['start'] <= $start_ts) {
|
||||
$event['start'] = $start_ts;
|
||||
}
|
||||
|
||||
if ($event['start'] >= $start_ts && $event['start'] <= $end_ts) {
|
||||
|
||||
if ($event['end'] >= $end_ts) {
|
||||
$events[] = array_merge($event, array('end' => $end_ts));
|
||||
}
|
||||
else {
|
||||
$events[] = $event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate effective worked hours by taking into consideration the timetable
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param \DateTime $start
|
||||
* @param \DateTime $end
|
||||
* @return float
|
||||
*/
|
||||
public function calculateEffectiveDuration($user_id, DateTime $start, DateTime $end)
|
||||
{
|
||||
$end_timetable = clone($end);
|
||||
$end_timetable->setTime(23, 59);
|
||||
|
||||
$timetable = $this->calculate($user_id, $start, $end_timetable);
|
||||
$found_start = false;
|
||||
$hours = 0;
|
||||
|
||||
// The user has no timetable
|
||||
if (empty($this->week)) {
|
||||
return $this->dateParser->getHours($start, $end);
|
||||
}
|
||||
|
||||
foreach ($timetable as $slot) {
|
||||
|
||||
$isStartSlot = $this->dateParser->withinDateRange($start, $slot[0], $slot[1]);
|
||||
$isEndSlot = $this->dateParser->withinDateRange($end, $slot[0], $slot[1]);
|
||||
|
||||
// Start and end are within the same time slot
|
||||
if ($isStartSlot && $isEndSlot) {
|
||||
return $this->dateParser->getHours($start, $end);
|
||||
}
|
||||
|
||||
// We found the start slot
|
||||
if (! $found_start && $isStartSlot) {
|
||||
$found_start = true;
|
||||
$hours = $this->dateParser->getHours($start, $slot[1]);
|
||||
}
|
||||
else if ($found_start) {
|
||||
|
||||
// We found the end slot
|
||||
if ($isEndSlot) {
|
||||
$hours += $this->dateParser->getHours($slot[0], $end);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
// Sum hours of the intermediate time slots
|
||||
$hours += $this->dateParser->getHours($slot[0], $slot[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The start date was not found in regular hours so we get the nearest time slot
|
||||
if (! empty($timetable) && ! $found_start) {
|
||||
$slot = $this->findClosestTimeSlot($start, $timetable);
|
||||
|
||||
if ($start < $slot[0]) {
|
||||
return $this->calculateEffectiveDuration($user_id, $slot[0], $end);
|
||||
}
|
||||
}
|
||||
|
||||
return $hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nearest time slot
|
||||
*
|
||||
* @access public
|
||||
* @param DateTime $date
|
||||
* @param array $timetable
|
||||
* @return array
|
||||
*/
|
||||
public function findClosestTimeSlot(DateTime $date, array $timetable)
|
||||
{
|
||||
$values = array();
|
||||
|
||||
foreach ($timetable as $slot) {
|
||||
$t1 = abs($slot[0]->getTimestamp() - $date->getTimestamp());
|
||||
$t2 = abs($slot[1]->getTimestamp() - $date->getTimestamp());
|
||||
|
||||
$values[] = min($t1, $t2);
|
||||
}
|
||||
|
||||
asort($values);
|
||||
return $timetable[key($values)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timetable for a user for a given date range
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param \DateTime $start
|
||||
* @param \DateTime $end
|
||||
* @return array
|
||||
*/
|
||||
public function calculate($user_id, DateTime $start, DateTime $end)
|
||||
{
|
||||
$timetable = array();
|
||||
|
||||
$this->day = $this->timetableDay->getByUser($user_id);
|
||||
$this->week = $this->timetableWeek->getByUser($user_id);
|
||||
$this->overtime = $this->timetableExtra->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
|
||||
$this->timeoff = $this->timetableOff->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
|
||||
|
||||
for ($today = clone($start); $today <= $end; $today->add(new DateInterval('P1D'))) {
|
||||
$week_day = $today->format('N');
|
||||
$timetable = array_merge($timetable, $this->getWeekSlots($today, $week_day));
|
||||
$timetable = array_merge($timetable, $this->getOvertimeSlots($today, $week_day));
|
||||
}
|
||||
|
||||
return $timetable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return worked time slots for the given day
|
||||
*
|
||||
* @access public
|
||||
* @param \DateTime $today
|
||||
* @param string $week_day
|
||||
* @return array
|
||||
*/
|
||||
public function getWeekSlots(DateTime $today, $week_day)
|
||||
{
|
||||
$slots = array();
|
||||
$dayoff = $this->getDayOff($today);
|
||||
|
||||
if (! empty($dayoff) && $dayoff['all_day'] == 1) {
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach ($this->week as $slot) {
|
||||
if ($week_day == $slot['day']) {
|
||||
$slots = array_merge($slots, $this->getDayWorkSlots($slot, $dayoff, $today));
|
||||
}
|
||||
}
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the overtime time slots for the given day
|
||||
*
|
||||
* @access public
|
||||
* @param \DateTime $today
|
||||
* @param string $week_day
|
||||
* @return array
|
||||
*/
|
||||
public function getOvertimeSlots(DateTime $today, $week_day)
|
||||
{
|
||||
$slots = array();
|
||||
|
||||
foreach ($this->overtime as $slot) {
|
||||
|
||||
$day = new DateTime($slot['date']);
|
||||
|
||||
if ($week_day == $day->format('N')) {
|
||||
|
||||
if ($slot['all_day'] == 1) {
|
||||
$slots = array_merge($slots, $this->getDaySlots($today));
|
||||
}
|
||||
else {
|
||||
$slots[] = $this->getTimeSlot($slot, $day);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get worked time slots and remove time off
|
||||
*
|
||||
* @access public
|
||||
* @param array $slot
|
||||
* @param array $dayoff
|
||||
* @param \DateTime $today
|
||||
* @return array
|
||||
*/
|
||||
public function getDayWorkSlots(array $slot, array $dayoff, DateTime $today)
|
||||
{
|
||||
$slots = array();
|
||||
|
||||
if (! empty($dayoff) && $dayoff['start'] < $slot['end']) {
|
||||
|
||||
if ($dayoff['start'] > $slot['start']) {
|
||||
$slots[] = $this->getTimeSlot(array('end' => $dayoff['start']) + $slot, $today);
|
||||
}
|
||||
|
||||
if ($dayoff['end'] < $slot['end']) {
|
||||
$slots[] = $this->getTimeSlot(array('start' => $dayoff['end']) + $slot, $today);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$slots[] = $this->getTimeSlot($slot, $today);
|
||||
}
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get regular day work time slots
|
||||
*
|
||||
* @access public
|
||||
* @param \DateTime $today
|
||||
* @return array
|
||||
*/
|
||||
public function getDaySlots(DateTime $today)
|
||||
{
|
||||
$slots = array();
|
||||
|
||||
foreach ($this->day as $day) {
|
||||
$slots[] = $this->getTimeSlot($day, $today);
|
||||
}
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start and end time slot for a given day
|
||||
*
|
||||
* @access public
|
||||
* @param array $slot
|
||||
* @param \DateTime $today
|
||||
* @return array
|
||||
*/
|
||||
public function getTimeSlot(array $slot, DateTime $today)
|
||||
{
|
||||
$date = $today->format('Y-m-d');
|
||||
|
||||
return array(
|
||||
new DateTime($date.' '.$slot['start']),
|
||||
new DateTime($date.' '.$slot['end']),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return day off time slot
|
||||
*
|
||||
* @access public
|
||||
* @param \DateTime $today
|
||||
* @return array
|
||||
*/
|
||||
public function getDayOff(DateTime $today)
|
||||
{
|
||||
foreach ($this->timeoff as $day) {
|
||||
|
||||
if ($day['date'] === $today->format('Y-m-d')) {
|
||||
return $day;
|
||||
}
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Timetable Workweek
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TimetableDay extends Base
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'timetable_day';
|
||||
|
||||
/**
|
||||
* Get the timetable for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return array
|
||||
*/
|
||||
public function getByUser($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('start')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new time slot in the database
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @param string $start Start hour (24h format)
|
||||
* @param string $end End hour (24h format)
|
||||
* @return boolean|integer
|
||||
*/
|
||||
public function create($user_id, $start, $end)
|
||||
{
|
||||
$values = array(
|
||||
'user_id' => $user_id,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
);
|
||||
|
||||
return $this->persist(self::TABLE, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific time slot
|
||||
*
|
||||
* @access public
|
||||
* @param integer $slot_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove($slot_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate creation
|
||||
*
|
||||
* @access public
|
||||
* @param array $values Form values
|
||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||
*/
|
||||
public function validateCreation(array $values)
|
||||
{
|
||||
$v = new Validator($values, array(
|
||||
new Validators\Required('user_id', t('Field required')),
|
||||
new Validators\Required('start', t('Field required')),
|
||||
new Validators\Required('end', t('Field required')),
|
||||
));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Timetable over-time
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TimetableExtra extends TimetableOff
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'timetable_extra';
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Timetable time off
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TimetableOff extends Base
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'timetable_off';
|
||||
|
||||
/**
|
||||
* Get query to fetch everything (pagination)
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getUserQuery($user_id)
|
||||
{
|
||||
return $this->db->table(static::TABLE)->eq('user_id', $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timetable for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return array
|
||||
*/
|
||||
public function getByUser($user_id)
|
||||
{
|
||||
return $this->db->table(static::TABLE)->eq('user_id', $user_id)->desc('date')->asc('start')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timetable for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @param string $start_date
|
||||
* @param string $end_date
|
||||
* @return array
|
||||
*/
|
||||
public function getByUserAndDate($user_id, $start_date, $end_date)
|
||||
{
|
||||
return $this->db->table(static::TABLE)
|
||||
->eq('user_id', $user_id)
|
||||
->gte('date', $start_date)
|
||||
->lte('date', $end_date)
|
||||
->desc('date')
|
||||
->asc('start')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new time slot in the database
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @param string $date Day (ISO8601 format)
|
||||
* @param boolean $all_day All day flag
|
||||
* @param float $start Start hour (24h format)
|
||||
* @param float $end End hour (24h format)
|
||||
* @param string $comment
|
||||
* @return boolean|integer
|
||||
*/
|
||||
public function create($user_id, $date, $all_day, $start = '', $end = '', $comment = '')
|
||||
{
|
||||
$values = array(
|
||||
'user_id' => $user_id,
|
||||
'date' => $date,
|
||||
'all_day' => (int) $all_day, // Postgres fix
|
||||
'start' => $all_day ? '' : $start,
|
||||
'end' => $all_day ? '' : $end,
|
||||
'comment' => $comment,
|
||||
);
|
||||
|
||||
return $this->persist(static::TABLE, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific time slot
|
||||
*
|
||||
* @access public
|
||||
* @param integer $slot_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove($slot_id)
|
||||
{
|
||||
return $this->db->table(static::TABLE)->eq('id', $slot_id)->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate creation
|
||||
*
|
||||
* @access public
|
||||
* @param array $values Form values
|
||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||
*/
|
||||
public function validateCreation(array $values)
|
||||
{
|
||||
$v = new Validator($values, array(
|
||||
new Validators\Required('user_id', t('Field required')),
|
||||
new Validators\Required('date', t('Field required')),
|
||||
new Validators\Numeric('all_day', t('This value must be numeric')),
|
||||
));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
|
||||
/**
|
||||
* Timetable Workweek
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TimetableWeek extends Base
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'timetable_week';
|
||||
|
||||
/**
|
||||
* Get the timetable for a given user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return array
|
||||
*/
|
||||
public function getByUser($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('day')->asc('start')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new time slot in the database
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @param string $day Day of the week (ISO-8601)
|
||||
* @param string $start Start hour (24h format)
|
||||
* @param string $end End hour (24h format)
|
||||
* @return boolean|integer
|
||||
*/
|
||||
public function create($user_id, $day, $start, $end)
|
||||
{
|
||||
$values = array(
|
||||
'user_id' => $user_id,
|
||||
'day' => $day,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
);
|
||||
|
||||
return $this->persist(self::TABLE, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific time slot
|
||||
*
|
||||
* @access public
|
||||
* @param integer $slot_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove($slot_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate creation
|
||||
*
|
||||
* @access public
|
||||
* @param array $values Form values
|
||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||
*/
|
||||
public function validateCreation(array $values)
|
||||
{
|
||||
$v = new Validator($values, array(
|
||||
new Validators\Required('user_id', t('Field required')),
|
||||
new Validators\Required('day', t('Field required')),
|
||||
new Validators\Numeric('day', t('This value must be numeric')),
|
||||
new Validators\Required('start', t('Field required')),
|
||||
new Validators\Required('end', t('Field required')),
|
||||
));
|
||||
|
||||
return array(
|
||||
$v->execute(),
|
||||
$v->getErrors()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user