Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Recurr Laravel Package

simshaun/recurr

PHP library for RFC5545 RRULE recurrence rules. Build rules from strings or fluent setters, then transform them into DateTime occurrences via transformers. Useful for calendars and recurring events with time zone support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require simshaun/recurr
    
  2. Basic Usage:
    use Recurr\Rule;
    use Recurr\Transformer\ArrayTransformer;
    
    $rule = new Rule('FREQ=DAILY;COUNT=5', new \DateTime());
    $transformer = new ArrayTransformer();
    $recurrences = $transformer->transform($rule);
    

First Use Case: Fetching Recurring Events

// Example: Fetch monthly meetings for 3 months
$startDate = new \DateTime('2023-10-01');
$rule = new Rule('FREQ=MONTHLY;COUNT=3', $startDate);
$transformer = new ArrayTransformer();

$recurrences = $transformer->transform($rule);
foreach ($recurrences as $recurrence) {
    echo $recurrence->getStart()->format('Y-m-d') . "\n";
}

Implementation Patterns

Rule Creation Patterns

  1. String-Based Rules:
    $rule = new Rule('FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=2023-12-31', $startDate);
    
  2. Fluent Builder:
    $rule = (new Rule)
        ->setFreq('WEEKLY')
        ->setByDay(['MO', 'WE', 'FR'])
        ->setUntil(new \DateTime('2023-12-31'))
        ->setStartDate($startDate);
    

Common Workflows

  1. Generating Recurrences for a Calendar:

    $transformer = new ArrayTransformer();
    $recurrences = $transformer->transform($rule);
    
    // Filter for a specific month
    $filtered = $recurrences->startsBetween(
        new \DateTime('2023-11-01'),
        new \DateTime('2023-11-30')
    );
    
  2. Handling Timezones:

    $rule = new Rule('FREQ=DAILY;COUNT=7', $startDate, null, 'Europe/London');
    
  3. Combining Rules with Constraints:

    $constraint = new BeforeConstraint(new \DateTime('2023-11-15'));
    $recurrences = $transformer->transform($rule, $constraint);
    

Integration with Laravel

  1. Service Provider Binding:

    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->bind(\Recurr\Rule::class, function ($app) {
            return new \Recurr\Rule('FREQ=DAILY', new \DateTime());
        });
    }
    
  2. Eloquent Model Events:

    // app/Models/Event.php
    protected static function booted()
    {
        static::created(function ($event) {
            if ($event->is_recurring) {
                $rule = new Rule($event->rrule, $event->start_date);
                $transformer = new ArrayTransformer();
                $recurrences = $transformer->transform($rule);
    
                // Store or process recurrences
            }
        });
    }
    
  3. API Responses:

    // app/Http/Controllers/EventController.php
    public function getRecurrences(Event $event)
    {
        $rule = new Rule($event->rrule, $event->start_date);
        $transformer = new ArrayTransformer();
        $recurrences = $transformer->transform($rule);
    
        return response()->json($recurrences->toArray());
    }
    

Gotchas and Tips

Common Pitfalls

  1. Monthly Rules with Varying Days:

    • Rules starting on the 31st of January will skip February and March.
    • Fix: Enable enableLastDayOfMonthFix() in ArrayTransformerConfig.
  2. Infinite Loops:

    • Rules without COUNT or UNTIL can generate infinite recurrences.
    • Fix: Set a virtual limit in ArrayTransformerConfig or use constraints.
  3. Timezone Mismatches:

    • Ensure timezone consistency between rule creation and transformation.
    • Fix: Always specify timezone in Rule constructor.
  4. Daylight Saving Time:

    • Recurrences might shift unexpectedly during DST transitions.
    • Fix: Use UTC or a timezone-aware approach.

Debugging Tips

  1. Inspect Rule Strings:

    echo $rule->getString(); // Verify rule correctness
    
  2. Limit Recurrences for Testing:

    $config = new ArrayTransformerConfig();
    $config->setLimit(5); // Test with a small subset
    $transformer->setConfig($config);
    
  3. Check for Valid RRULEs:

    • Use online validators (e.g., RRULE Tester) to verify rules.

Extension Points

  1. Custom Transformers:

    class CustomTransformer extends ArrayTransformer
    {
        public function transform(Rule $rule, ConstraintInterface $constraint = null)
        {
            $recurrences = parent::transform($rule, $constraint);
            // Custom logic here
            return $recurrences;
        }
    }
    
  2. Custom Constraints:

    class CustomConstraint implements ConstraintInterface
    {
        public function isAllowed(Recurrence $recurrence)
        {
            // Custom logic to allow/deny recurrences
            return true;
        }
    }
    
  3. Override Text Transformer:

    class CustomTextTransformer extends TextTransformer
    {
        protected function getTranslation($key, array $params = [])
        {
            // Custom translations
            return parent::getTranslation($key, $params);
        }
    }
    

Performance Considerations

  1. Virtual Limit:

    • Default limit (732) may be too low for long-term rules.
    • Fix: Adjust ArrayTransformerConfig or use COUNT/UNTIL in rules.
  2. Lazy Loading:

    • For large datasets, consider lazy-loading recurrences or pagination.
  3. Caching:

    • Cache transformed recurrences if rules rarely change:
    $cacheKey = 'recurrences_' . md5($rule->getString());
    $recurrences = Cache::remember($cacheKey, now()->addHours(1), function () use ($rule) {
        return $transformer->transform($rule);
    });
    

Laravel-Specific Tips

  1. Store Rules in Database:

    // Migration
    Schema::create('events', function (Blueprint $table) {
        $table->id();
        $table->string('rrule');
        $table->dateTime('start_date');
        $table->dateTime('end_date')->nullable();
        $table->string('timezone')->default('UTC');
    });
    
  2. Use Accessors:

    // app/Models/Event.php
    public function getRecurrencesAttribute()
    {
        $rule = new Rule($this->rrule, $this->start_date, $this->end_date, $this->timezone);
        return (new ArrayTransformer())->transform($rule);
    }
    
  3. Query Scopes:

    // app/Models/Event.php
    public function scopeActive($query)
    {
        return $query->where(function ($q) {
            $q->whereNull('end_date')
              ->orWhere('end_date', '>', now());
        });
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor