src/Models/EventRepetition.php
<?php
namespace DavideCasiraghi\LaravelEventsCalendar\Models;
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Carbon\CarbonPeriod;
use DavideCasiraghi\LaravelEventsCalendar\Facades\LaravelEventsCalendar;
use Illuminate\Database\Eloquent\Model;
class EventRepetition extends Model
{
/***************************************************************************/
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'event_repetitions';
/***************************************************************************/
protected $fillable = [
'event_id', 'start_repeat', 'end_repeat',
];
/*public function user()
{
return $this->belongsTo('DavideCasiraghi\LaravelEventsCalendar\Models\Event', 'event_id', 'id');
}*/
/***************************************************************************/
/**
* Get for each event the first event repetition in the near future (JUST THE QUERY to use as SUBQUERY).
* Parameters are Start date and End date of the interval
* Return the query string,.
* @param string|null $searchStartDate
* @param string|null $searchEndDate
* @return string
*/
public static function getLastestEventsRepetitionsQuery($searchStartDate, $searchEndDate)
{
$ret = self::
selectRaw('event_id, MIN(id) AS rp_id, start_repeat, end_repeat')
->when($searchStartDate, function ($query, $searchStartDate) {
return $query->where('event_repetitions.start_repeat', '>=', $searchStartDate);
})
->when($searchEndDate, function ($query, $searchEndDate) {
return $query->where('event_repetitions.end_repeat', '<=', $searchEndDate);
})
->groupBy('event_id');
return $ret;
}
/***************************************************************************/
/**
* Save event repetition in the DB.
* $dateStart and $dateEnd are in the format Y-m-d
* $timeStart and $timeEnd are in the format H:i:s.
* @param int $eventId
* @param string $dateStart
* @param string $dateEnd
* @param string $timeStart
* @param string $timeEnd
* @return void
*/
public static function saveEventRepetitionOnDB(int $eventId, string $dateStart, string $dateEnd, string $timeStart, string $timeEnd)
{
$eventRepetition = new self();
$eventRepetition->event_id = $eventId;
$eventRepetition->start_repeat = Carbon::createFromFormat('Y-m-d H:i', $dateStart.' '.$timeStart);
$eventRepetition->end_repeat = Carbon::createFromFormat('Y-m-d H:i', $dateEnd.' '.$timeEnd);
$eventRepetition->save();
}
/***************************************************************************/
/**
* Save all the weekly repetitions in the event_repetitions table.
* $dateStart and $dateEnd are in the format Y-m-d
* $timeStart and $timeEnd are in the format H:i:s.
* $weekDays - $request->get('repeat_weekly_on_day').
* @param int $eventId
* @param array $weekDays
* @param string $startDate
* @param string $repeatUntilDate
* @param string $timeStart
* @param string $timeEnd
* @return void
*/
public static function saveWeeklyRepeatDates(int $eventId, array $weekDays, string $startDate, string $repeatUntilDate, string $timeStart, string $timeEnd)
{
$beginPeriod = Carbon::createFromFormat('Y-m-d', $startDate);
$endPeriod = Carbon::createFromFormat('Y-m-d', $repeatUntilDate);
//$interval = CarbonInterval::days(1);
$interval = CarbonInterval::make('1day');
$period = CarbonPeriod::create($beginPeriod, $interval, $endPeriod);
foreach ($period as $day) { // Iterate for each day of the period
foreach ($weekDays as $weekDayNumber) { // Iterate for every day of the week (1:Monday, 2:Tuesday, 3:Wednesday ...)
if (LaravelEventsCalendar::isWeekDay($day->format('Y-m-d'), $weekDayNumber)) {
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
}
}
}
}
/***************************************************************************/
/**
* Save all the weekly repetitions in the event_repetitions table
* useful: http://thisinterestsme.com/php-get-first-monday-of-month/.
*
* @param int $eventId
* @param array $monthRepeatDatas - explode of $request->get('on_monthly_kind')
* 0|28 the 28th day of the month
* 1|2|2 the 2nd Tuesday of the month
* 2|17 the 18th to last day of the month
* 3|1|3 the 2nd to last Wednesday of the month
* @param string $startDate (Y-m-d)
* @param string $repeatUntilDate (Y-m-d)
* @param string $timeStart (H:i:s)
* @param string $timeEnd (H:i:s)
* @return void
*/
public static function saveMonthlyRepeatDates(int $eventId, array $monthRepeatDatas, string $startDate, string $repeatUntilDate, string $timeStart, string $timeEnd)
{
$month = Carbon::createFromFormat('Y-m-d', $startDate);
$end = Carbon::createFromFormat('Y-m-d', $repeatUntilDate);
$weekdayArray = [Carbon::MONDAY, Carbon::TUESDAY, Carbon::WEDNESDAY, Carbon::THURSDAY, Carbon::FRIDAY, Carbon::SATURDAY, Carbon::SUNDAY];
//$timeStart = $timeStart.":00";
//$timeEnd = $timeEnd.":00";
switch ($monthRepeatDatas[0]) {
case '0': // Same day number - eg. "the 28th day of the month"
while ($month < $end) {
$day = $month;
//dump("ee_3");
//dump($timeStart);
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
$month = $month->addMonth();
}
break;
case '1': // Same weekday/week of the month - eg. the "1st Monday"
$numberOfTheWeek = $monthRepeatDatas[1]; // eg. 1(first) | 2(second) | 3(third) | 4(fourth) | 5(fifth)
$weekday = $weekdayArray[$monthRepeatDatas[2] - 1]; // eg. monday | tuesday | wednesday
while ($month < $end) {
$month_number = (int) Carbon::parse($month)->isoFormat('M');
$year_number = (int) Carbon::parse($month)->isoFormat('YYYY');
$day = Carbon::create($year_number, $month_number, 30, 0, 0, 0)->nthOfMonth($numberOfTheWeek, $weekday); // eg. Carbon::create(2014, 5, 30, 0, 0, 0)->nthOfQuarter(2, Carbon::SATURDAY);
//dump("ee_4");
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
$month = $month->addMonth();
}
break;
case '2': // Same day of the month (from the end) - the 3rd to last day (0 if last day, 1 if 2nd to last day, 2 if 3rd to last day)
$dayFromTheEnd = $monthRepeatDatas[1];
while ($month < $end) {
$month_number = (int) Carbon::parse($month)->isoFormat('M');
$year_number = (int) Carbon::parse($month)->isoFormat('YYYY');
$day = Carbon::create($year_number, $month_number, 1, 0, 0, 0)->lastOfMonth()->subDays($dayFromTheEnd);
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
$month = $month->addMonth();
}
break;
case '3': // Same weekday/week of the month (from the end) - the last Friday - (0 if last Friday, 1 if the 2nd to last Friday, 2 if the 3nd to last Friday)
$weekday = $weekdayArray[$monthRepeatDatas[2] - 1]; // eg. monday | tuesday | wednesday
$weeksFromTheEnd = $monthRepeatDatas[1];
while ($month < $end) {
$month_number = (int) Carbon::parse($month)->isoFormat('M');
$year_number = (int) Carbon::parse($month)->isoFormat('YYYY');
$day = Carbon::create($year_number, $month_number, 1, 0, 0, 0)->lastOfMonth($weekday)->subWeeks($weeksFromTheEnd);
//dump("ee_2");
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
$month = $month->addMonth();
}
break;
}
}
/***************************************************************************/
/**
* Save multiple single dates in the event_repetitions table
* useful: http://thisinterestsme.com/php-get-first-monday-of-month/.
* $singleDaysRepeatDatas - explode of $request->get('multiple_dates') - eg. ["19/03/2020","20/05/2020","29/05/2020"]
* $startDate (Y-m-d)
* $timeStart (H:i:s)
* $timeEnd (H:i:s).
*
* @param int $eventId
* @param array $singleDaysRepeatDatas
* @param string $startDate
* @param string $timeStart
* @param string $timeEnd
* @return void
*/
public static function saveMultipleRepeatDates(int $eventId, array $singleDaysRepeatDatas, string $startDate, string $timeStart, string $timeEnd)
{
$day = Carbon::createFromFormat('Y-m-d', $startDate);
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
foreach ($singleDaysRepeatDatas as $key => $singleDayRepeatDatas) {
$day = Carbon::createFromFormat('d/m/Y', $singleDayRepeatDatas);
self::saveEventRepetitionOnDB($eventId, $day->format('Y-m-d'), $day->format('Y-m-d'), $timeStart, $timeEnd);
}
}
/***************************************************************************/
/**
* Delete all the previous repetitions from the event_repetitions table.
*
* @param int $eventId
* @return void
*/
public static function deletePreviousRepetitions($eventId)
{
self::where('event_id', $eventId)->delete();
}
/***************************************************************************/
/**
* Return Start and End dates of the first repetition of an event - By Event ID.
*
* @param int $eventId
* @return \DavideCasiraghi\LaravelEventsCalendar\Models\EventRepetition
*/
public static function getFirstEventRpDatesByEventId($eventId)
{
$ret = self::
select('start_repeat', 'end_repeat')
->where('event_id', $eventId)
->first();
return $ret;
}
/***************************************************************************/
/**
* Return Start and End dates of the first repetition of an event - By Event ID.
*
* @param int $eventId
* @return \DavideCasiraghi\LaravelEventsCalendar\Models\EventRepetition
*/
public static function getFirstFutureEventRpDatesByEventId($eventId)
{
$ret = self::
select('start_repeat', 'end_repeat')
->where('event_id', $eventId)
->where('start_repeat', '>', Carbon::now())
->first();
return $ret;
}
/***************************************************************************/
/**
* Return Start and End dates of the first repetition of an event - By Repetition ID.
*
* @param int $repetitionId
* @return \DavideCasiraghi\LaravelEventsCalendar\Models\EventRepetition
*/
public static function getFirstEventRpDatesByRepetitionId($repetitionId)
{
$ret = self::
select('start_repeat', 'end_repeat')
->where('id', $repetitionId)
->first();
return $ret;
}
/***************************************************************************/
/**
* Return the repetition id of the first occurrence of an event in the future - By Event ID.
*
* @param int $eventId
* @return int|null
*/
public static function getFirstEventRpIdByEventId($eventId): ?int
{
$firstFutureEventRpIdByEventId = self::
select('id')
->where('event_id', $eventId)
->where('start_repeat', '>', Carbon::now())
->first();
if (! empty($firstFutureEventRpIdByEventId)) {
$ret = $firstFutureEventRpIdByEventId->id;
} else {
$ret = null;
}
return $ret;
}
}