Installation:
composer require axi/mycalendar
Ensure eluceo/ical is installed if using the ical format:
composer require eluceo/ical
First Use Case: Calculate special dates for a given birthdate (e.g., 15,000th day):
use Axi\MyCalendar\Service\CalendarService;
$calendar = new CalendarService();
$events = $calendar->getEventsFromDate(
new DateTime("1990-05-15"),
'json'
);
echo $events->getContent();
Key Files:
vendor/axi/mycalendar/src/Service/CalendarService.php (Core logic)vendor/axi/mycalendar/src/Recipe/ (Predefined recipes like ThousandsDays, PlanetsRevolutions)Instantiate the Service:
$calendar = new CalendarService();
DateTime object or use the default constructor (today).Fetch Events:
$events = $calendar->getEventsFromDate(
$birthDate, // DateTime
'json' // Format: 'json', 'ical', or 'none'
);
json: Returns a JSON string (e.g., {"15000": "1990-05-15 00:00:00"}).ical: Requires eluceo/ical; returns an iCalendar string.none: Returns an internal Event object for custom processing.Leverage Recipes:
// Example: Add a custom recipe (e.g., "SleepTime")
$calendar->addRecipe(new \Axi\MyCalendar\Recipe\SleepTime());
$events = $calendar->getEventsFromDate($birthDate, 'none');
foreach ($events->getEvents() as $event) {
echo $event->getName() . ": " . $event->getDate()->format('Y-m-d');
}
Integration with Laravel:
Service Provider:
Bind the service to the container in AppServiceProvider:
public function register()
{
$this->app->singleton(CalendarService::class, function () {
return new CalendarService();
});
}
Facade (Optional): Create a facade for cleaner syntax:
// app/Facades/MyCalendar.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class MyCalendar extends Facade { protected static function getFacadeAccessor() { return 'calendar'; } }
Register the facade in config/app.php and bind the service in AppServiceProvider.
Usage in Controllers:
use App\Facades\MyCalendar;
public function showBirthdayEvents(Request $request)
{
$birthDate = new \DateTime($request->input('birthdate'));
$events = MyCalendar::getEventsFromDate($birthDate, 'json');
return response()->json(['events' => json_decode($events, true)]);
}
Dynamic Date Handling:
Carbon for seamless date manipulation:
use Carbon\Carbon;
$birthDate = Carbon::parse($request->birthdate);
$events = $calendar->getEventsFromDate($birthDate, 'none');
Missing eluceo/ical Dependency:
ical format, ensure eluceo/ical is installed. The package does not auto-install it.composer.json:
"require": {
"eluceo/ical": "^2.0"
}
Timezone Sensitivity:
$birthDate = new \DateTime("1990-05-15", new \DateTimeZone('UTC'));
.env:
APP_TIMEZONE=UTC
Recipe Overrides:
ThousandsDays) may not cover all use cases. Custom recipes must extend \Axi\MyCalendar\Recipe\RecipeInterface and implement getEvents().namespace App\Recipes;
use Axi\MyCalendar\Recipe\RecipeInterface;
use Axi\MyCalendar\Event\Event;
class CustomMilestone implements RecipeInterface {
public function getEvents(\DateTime $date): array {
$events = [];
$targetDays = [1000, 5000, 10000];
foreach ($targetDays as $days) {
$eventDate = clone $date;
$eventDate->modify("+$days days");
$events[] = new Event("Custom Milestone $days", $eventDate);
}
return $events;
}
}
Performance with Large Date Ranges:
$events = Cache::remember("calendar_events_{$birthDate->format('Y-m-d')}", now()->addDays(365), function () use ($calendar, $birthDate) {
return $calendar->getEventsFromDate($birthDate, 'none');
});
Event Object Quirks:
none format returns an Event object with methods like:
getName(): Event name (e.g., "15000th Day").getDate(): DateTime object of the event.getContent(): Only available for json/ical formats.none format:
$event = $events->getEvents()[0];
echo $event->getName() . " on " . $event->getDate()->format('Y-m-d');
Inspect Internal Events:
none format to debug event generation:
$events = $calendar->getEventsFromDate($birthDate, 'none');
dd($events->getEvents()); // Dump all generated events
Validate Input Dates:
DateTime is valid:
if (!$birthDate instanceof \DateTime) {
throw new \InvalidArgumentException("Invalid birthdate provided.");
}
Check for Recipe Conflicts:
$calendar->addRecipe(new \Axi\MyCalendar\Recipe\ThousandsDays());
$calendar->addRecipe(new \Axi\MyCalendar\Recipe\SleepTime());
Custom Recipes:
namespace App\Recipes;
use Axi\MyCalendar\Recipe\RecipeInterface;
use Axi\MyCalendar\Event\Event;
class ZodiacSigns implements RecipeInterface {
public function getEvents(\DateTime $date): array {
$zodiacDates = [
'Aries' => '03-21', 'Taurus' => '04-19', // ... (add all signs)
];
$events = [];
foreach ($zodiacDates as $sign => $startDate) {
$eventDate = \DateTime::createFromFormat('Y-m-d', $date->format('Y') . '-' . $startDate);
$events[] = new Event("Zodiac: $sign", $eventDate);
}
return $events;
}
}
Modify Event Formatting:
json or ical output by extending CalendarService:
namespace App\Services;
use Axi\MyCalendar\Service\CalendarService;
class CustomCalendarService extends CalendarService {
public function getEventsFromDate(\DateTime $dateTime, string $format = 'json') {
$events = parent::getEventsFromDate($dateTime, $format);
if ($format === 'json') {
$content = $events->getContent();
$content = str_replace('"', "'", $content); // Custom JSON tweak
$events->setContent($content);
}
return $events;
}
}
Localization:
resources/lang/ directory in your project and publishing theHow can I help you explore Laravel packages today?