PHPackages                             vincenzoraco/recurrences - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. vincenzoraco/recurrences

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

vincenzoraco/recurrences
========================

A Laravel package for managing recurring events using the RFC 5545 RRULE specification

v1.2.0(1mo ago)03MITPHPPHP ^8.4

Since Feb 8Pushed 1mo agoCompare

[ Source](https://github.com/vincenzoraco/recurrences)[ Packagist](https://packagist.org/packages/vincenzoraco/recurrences)[ Docs](https://github.com/vincenzoraco/recurrences)[ RSS](/packages/vincenzoraco-recurrences/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (12)Versions (6)Used By (0)

Laravel Recurrences
===================

[](#laravel-recurrences)

[![Latest Version on Packagist](https://camo.githubusercontent.com/9cc42331c17eb08e617c94b21fca1892acb84ce888d8a0c8604cd1b071b833d1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f76696e63656e7a6f7261636f2f726563757272656e6365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/vincenzoraco/recurrences)[![Total Downloads](https://camo.githubusercontent.com/ad50d28b6c3613db7c14fdc84e9342f07f0dbb4fa48ec30c0273211e7a072952/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f76696e63656e7a6f7261636f2f726563757272656e6365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/vincenzoraco/recurrences)[![GitHub Actions](https://github.com/vincenzoraco/recurrences/actions/workflows/main.yml/badge.svg)](https://github.com/vincenzoraco/recurrences/actions/workflows/main.yml/badge.svg)

A Laravel package for managing recurring events using the RFC 5545 RRULE specification. Built on top of `rlanvin/php-rrule`, this package provides a Laravel-native interface for working with recurring dates and events.

Why this package?
-----------------

[](#why-this-package)

While the bare `rlanvin/php-rrule` library is powerful, this package offers significant advantages for Laravel applications:

- **Eloquent Integration**: Attach recurrence conditions to any Eloquent model using a simple trait
- **Type-Safe Data Objects**: All configuration is done through typed data objects with validation
- **Laravel Events**: Dispatchable events for when recurrence conditions are created, updated, or deleted
- **MorphMany Relationship**: Attach multiple recurrence rules to any model without creating additional tables
- **Facade Access**: Convenient facade for accessing the service layer
- **Occurrence Hashing**: Built-in utilities for generating unique hashes for occurrences (useful for caching)
- **Exclusion Support**: Easily exclude specific dates or date ranges from recurring events

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require vincenzoraco/recurrences
```

Usage
-----

[](#usage)

### Making a model recurrable

[](#making-a-model-recurrable)

Add the `HasRecurrences` trait and `Recurrable` contract to any Eloquent model:

```
use VincenzoRaco\Recurrences\Concerns\HasRecurrences;
use VincenzoRaco\Recurrences\Contracts\Recurrable;
use Illuminate\Database\Eloquent\Model;

class Event extends Model implements Recurrable
{
    use HasRecurrences;
}
```

### Creating a recurring event

[](#creating-a-recurring-event)

Use the data objects to define recurrence conditions:

```
use Illuminate\Support\Carbon;
use VincenzoRaco\Recurrences\Enums\RecurringFrequency;
use VincenzoRaco\Recurrences\DataObjects\MultipleOccurrencesConditionDataObject;
use VincenzoRaco\Recurrences\DataObjects\EndingConditionUntilDataObject;

$event = Event::find(1);

$condition = new MultipleOccurrencesConditionDataObject(
    start: Carbon::parse('2024-01-01'),
    frequency: RecurringFrequency::WEEKLY,
    interval: 1,
    endingCondition: new EndingConditionUntilDataObject(
        until: Carbon::parse('2024-03-31'),
    ),
);

app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->createMultipleOccurrencesCondition($event, $condition);
```

### Creating a one-time occurrence

[](#creating-a-one-time-occurrence)

Add single dates to a recurrable model:

```
use Illuminate\Support\Carbon;
use VincenzoRaco\Recurrences\DataObjects\SingleOccurrenceConditionDataObject;

$event = Event::find(1);

$condition = new SingleOccurrenceConditionDataObject(
    date: Carbon::parse('2024-02-14'),
);

app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->createOneTimeOccurrenceCondition($event, $condition);
```

### Excluding dates from a recurring event

[](#excluding-dates-from-a-recurring-event)

Exclude specific dates or date ranges:

```
use Illuminate\Support\Carbon;
use VincenzoRaco\Recurrences\DataObjects\ExcludeOneTimeOccurrenceDataObject;
use VincenzoRaco\Recurrences\DataObjects\ExcludeOccurrencesRangeDataObject;

// Exclude a single date
$excludeSingle = new ExcludeOneTimeOccurrenceDataObject(
    date: Carbon::parse('2024-02-14'),
);

app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->createExcludeOneTimeOccurrenceCondition($event, $excludeSingle);

// Exclude a range of dates
$excludeRange = new ExcludeOccurrencesRangeDataObject(
    start: Carbon::parse('2024-12-24'),
    end: Carbon::parse('2024-12-26'),
);

app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->createExcludeOccurrencesRangeCondition($event, $excludeRange);
```

### Getting occurrences

[](#getting-occurrences)

Retrieve occurrences from a recurrable model:

```
use Illuminate\Support\Carbon;
use RRule\RSet;
use VincenzoRaco\Recurrences\DataObjects\GetRSetOccurrencesBetweenDataObject;

$event = Event::find(1);

// Build the RSet from all recurrence conditions
$rset = app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->getRSet($event->recurrenceConditions);

// Get occurrences within a date range
$dataObject = new GetRSetOccurrencesBetweenDataObject(
    startDate: Carbon::parse('2024-01-01'),
    endDate: Carbon::parse('2024-01-31'),
);

$occurrences = app(\VincenzoRaco\Recurrences\RecurrencesService::class)
    ->getRSetOccurrencesBetween($rset, $dataObject);

foreach ($occurrences->getOccurrences() as $occurrence) {
    echo $occurrence->toDateString();
}
```

### Using the facade

[](#using-the-facade)

```
use VincenzoRaco\Recurrences\Facades\Recurrences;
use Illuminate\Support\Carbon;
use VincenzoRaco\Recurrences\DataObjects\GetRSetOccurrencesBetweenDataObject;

$event = Event::find(1);
$rset = Recurrences::getRSet($event->recurrenceConditions);

$dataObject = new GetRSetOccurrencesBetweenDataObject(
    startDate: Carbon::parse('2024-01-01'),
    endDate: Carbon::parse('2024-01-31'),
);

$occurrences = Recurrences::getRSetOccurrencesBetween($rset, $dataObject);
```

### Using the facade alias

[](#using-the-facade-alias)

```
use VincenzoRaco\Recurrences\Recurrences;

// Same as above, but shorter
$rset = Recurrences::getRSet($event->recurrenceConditions);
```

Configuration
-------------

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --provider="VincenzoRaco\Recurrences\RecurrencesServiceProvider"
```

Available configuration options:

```
return [
    'max_occurrences' => 1000,
];
```

Available Frequencies
---------------------

[](#available-frequencies)

- `RecurringFrequency::DAILY`
- `RecurringFrequency::WEEKLY`
- `RecurringFrequency::MONTHLY`
- `RecurringFrequency::YEARLY`

Ending Conditions
-----------------

[](#ending-conditions)

- `NoEndingConditionDataObject` - Never ends
- `EndingConditionUntilDataObject` - Ends on a specific date
- `EndingConditionTimesDataObject` - Ends after a specific number of occurrences

Events
------

[](#events)

The package dispatches Laravel events for lifecycle hooks:

- `RecurringConditionCreatedEvent`
- `RecurringConditionUpdatedEvent`
- `RecurringConditionDeletedEvent`

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

### Security

[](#security)

If you discover any security related issues, please email vincenzo \[at\] vincenzoraco.dev instead of using the issue tracker.

Credits
-------

[](#credits)

- [Vincenzo Raco](https://github.com/vincenzoraco)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance92

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Total

5

Last Release

39d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3c687c2983ce5409447d3fc2d5129e34103a8dd9b16db7438d23fbace0412f4e?d=identicon)[vincenzoraco](/maintainers/vincenzoraco)

---

Top Contributors

[![vincenzoraco](https://avatars.githubusercontent.com/u/5623078?v=4)](https://github.com/vincenzoraco "vincenzoraco (4 commits)")

---

Tags

schedulerlaravelrrulerecurrencerecurring-events

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/vincenzoraco-recurrences/health.svg)

```
[![Health](https://phpackages.com/badges/vincenzoraco-recurrences/health.svg)](https://phpackages.com/packages/vincenzoraco-recurrences)
```

###  Alternatives

[barryvdh/laravel-ide-helper

Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.

14.9k123.0M683](/packages/barryvdh-laravel-ide-helper)[rlanvin/php-rrule

Lightweight and fast recurrence rules for PHP (RFC 5545)

69810.6M39](/packages/rlanvin-php-rrule)[interaction-design-foundation/laravel-geoip

Support for multiple Geographical Location services.

17221.0k3](/packages/interaction-design-foundation-laravel-geoip)[nedwors/navigator

A Laravel package to ease defining navigation menus

433.1k](/packages/nedwors-navigator)[dcblogdev/laravel-junie

Install pre-configured guides for Jetbrains Junie

392.5k](/packages/dcblogdev-laravel-junie)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
