PHPackages                             nncodes/laravel-meeting - 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. nncodes/laravel-meeting

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

nncodes/laravel-meeting
=======================

Handle online meeting with Laravel

v1.1.0(5y ago)2237214[2 issues](https://github.com/99codes/laravel-meeting/issues)MITPHPPHP ^7.2.5|^7.3|^8.0

Since Dec 31Pushed 4y ago1 watchersCompare

[ Source](https://github.com/99codes/laravel-meeting)[ Packagist](https://packagist.org/packages/nncodes/laravel-meeting)[ Docs](https://github.com/99codes/laravel-meeting)[ RSS](/packages/nncodes-laravel-meeting/feed)WikiDiscussions v1 Synced yesterday

READMEChangelog (4)Dependencies (6)Versions (7)Used By (0)

Laravel Meeting
===============

[](#laravel-meeting)

[![Latest Version on Packagist](https://camo.githubusercontent.com/94aeb10080af4640abd255d8bb3769e2298105297706922e56aa3daf78bcb35e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e6e636f6465732f6c61726176656c2d6d656574696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nncodes/laravel-meeting)[![License](https://camo.githubusercontent.com/7de50d5197b99ed663377dce97580aeb25e1ce8e4cdc12c56a48dfd72f083d14/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6c61726176656c2f666f7267652d73646b3f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nncodes/laravel-meeting)[![Total Downloads](https://camo.githubusercontent.com/1eeecf68265e03f3960cd2d2c89197821227ab0dc3afa6a996899f6d3007356c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6e6e636f6465732f6c61726176656c2d6d656574696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nncodes/laravel-meeting)

Official Documentation
----------------------

[](#official-documentation)

- [Introduction](#introduction)
- [Requirements](#requirements)
- [Installation &amp; setup](#installation-setup)
- [Preparing your models](#preparing-your-models)
    - [Scheduler](#scheduler)
    - [Presenter](#presenter)
    - [Host](#host)
    - [Participant](#participant)
- [Scheduling a meeting](#scheduling-a-meeting)
- [Retrieving meetings](#retrieving-meetings)
    - [Eloquent scopes](#eloquent-scopes)
- [Handling a scheduled meeting](#handling-a-scheduled-meeting)
    - [Meeting](#meeting)
    - [Participants](#participants)
    - [Hosts](#hosts)
- [Contributing](#contributing)
- [Security Vulnerabilities](#security-vulnerabilities)
- [License](#license)

Introduction
------------

[](#introduction)

This package can handle online meetings with Eloquent models. It provides a simple, fluent API to work with and by default uses Zoom as provider.

```
use Nncodes\Meeting\Models\Meeting;
use Nncodes\Meeting\Models\MeetingRoom;
use App\Models\Event;
use App\Models\Teacher;

$meeting = Meeting::schedule()
  	->withTopic('English class: verb to be')
  	->startingAt(now()->addMinutes(30))
  	->during(40) //in Minutes
  	->scheduledBy(Event::find(1))
  	->presentedBy(Teacher::find(1))
  	->hostedBy(MeetingRoom::find(1))
  	->save();
```

Requirements
------------

[](#requirements)

This package requires PHP 7.3+ and Laravel 6+.

This package uses [`nncodes/meta-attributes`](https://github.com/99codes/laravel-meta-attributes) to attach meta attributes to the models.

Installation &amp; setup
------------------------

[](#installation--setup)

You can install the package via composer:

```
composer require nncodes/laravel-meeting
```

The package will automatically register itself.

You can use the `meeting:install` command to publish the migrations and use `--config` if you also want to publish the config file.

```
php artisan meeting:install --config
```

Or you can publish by the traditional way:

```
php artisan vendor:publish --provider="Nncodes\Meeting\MeetingServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="Nncodes\MetaAttributes\MetaAttributesServiceProvider" --tag="migrations"
```

After the migration has been published you can create the tables by running the migrations:

```
php artisan migrate
```

You can publish the config file with:

```
php artisan vendor:publish --provider="Nncodes\Meeting\MeetingServiceProvider" --tag="config"
```

This is the contents of the published config file:

```
/**
 * Default Meeting Provider
 *
 * Here you can specify which meeting provider the package should use by
 * default. Of course you may use many providers at once using the package.
 */
'default' => env('MEETING_PROVIDER', 'zoom'),

/**
 * Meeting Providers
 *
 * Here are each of the meetings provider setup for the package.
 */

'providers' => [

    'zoom' => [

         /**
         * Provider class
         **/
        'type' => \Nncodes\Meeting\Providers\Zoom\ZoomProvider::class,

        /**
         * JWT Zoom Token
         * @see https://marketplace.zoom.us/docs/guides/auth/jwt
         **/
        'jwt_token' => env('ZOOM_TOKEN'),

        /**
         * Zoom Group ID
         *
         * @see https://marketplace.zoom.us/docs/api-reference/zoom-api/groups/group
         **/
        'group_id' => env('ZOOM_GROUP'),

         /**
         * Share Rooms
         *
         * Delegate to the package the responsability of handling the allocations of rooms.
         **/
        'share_rooms' => true,

         /**
         * Meeting resource seetings
         *
         * @see https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meeting
         **/
        'meeting_settings' => [
            "host_video" => false,
            "participant_video" => false,
            "join_before_host" => false,
            "jbh_time" => 0,
            "mute_upon_entry" => true,
            "approval_type" => 0,
            "registration_type" => 1,
            "close_registration" => true,
            "waiting_room" => true,
            "registrants_confirmation_email" => false,
            "registrants_email_notification" => false,
            "meeting_authentication" => false
        ]
    ]
],

/**
 * Allow concurrent Meetings
 */
'allow_concurrent_meetings' => [
    'host' => false,
    'participant' => false,
    'presenter' => false,
    'scheduler' => true,
]
```

Preparing your models
---------------------

[](#preparing-your-models)

### Scheduler

[](#scheduler)

Responsible for scheduling the meeting, the model must implement the following interface and trait:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Nncodes\Meeting\Concerns\SchedulesMeetings;
use Nncodes\Meeting\Contracts\Scheduler;

class Event extends Model implements Scheduler
{
    use SchedulesMeetings;
}
```

### Presenter

[](#presenter)

Responsible for present the meeting, the model must implement the following interface and trait:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Nncodes\Meeting\Concerns\PresentsMeetings;
use Nncodes\Meeting\Contracts\Presenter;

class Teacher extends User implements Presenter
{
    use PresentsMeetings;
}
```

### Host

[](#host)

Responsible for hosting the meeting, the model must implement the following interface and trait:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Nncodes\Meeting\Concerns\HostsMeetings;
use Nncodes\Meeting\Contracts\Host;

class Room extends Model implements Host
{
    use HostsMeetings;
}
```

### Participant

[](#participant)

Allowed to join a meeting, the model must implement the following interface, trait and the `getEmailAddress`, `getFirstName` and `getLastName` methods:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Nncodes\Meeting\Concerns\JoinsMeetings;
use Nncodes\Meeting\Contracts\Participant;

class Student extends User implements Participant
{
    use JoinsMeetings;

    /**
     * Email Address of the participant
     *
     * @return string
     */
    public function getParticipantEmailAddress(): string
    {
        return $this->email;
    }

    /**
     * First name of the participant
     *
     * @return string
     */
    public function getParticipantFirstName(): string
    {
        return $this->first_name;
    }

    /**
     * Last name of the participant
     *
     * @return string
     */
    public function getParticipantLastName(): string
    {
        return $this->last_name;
    }
}
```

Scheduling a meeting
--------------------

[](#scheduling-a-meeting)

To schedule a meeting you need to use the methods below to properly fill the meeting data:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Event;
use App\Models\Teacher;
use App\Models\Room;

$event = Event::find(1);
$teacher = Teacher::find(1);
$room = Room::find(1);

$meeting = Meeting::schedule()
  	->withTopic('English class: verb to be')
  	->startingAt(now()->addMinutes(30))
  	->during(40) //minutes
  	->scheduledBy($event)
  	->presentedBy($teacher)
  	->hostedBy($room)
  	->save();
```

Or you can also schedule by the `scheduler` model:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Event;
use App\Models\Teacher;
use App\Models\Room;

$event->scheduleMeeting()
  	->withTopic('English class: verb to be')
  	->startingAt(now()->addMinutes(30))
  	->during(40) //minutes
  	->presentedBy($teacher)
  	->hostedBy($room)
  	->save()
```

Of course if needed, you can update the meeting:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Event;
use App\Models\Teacher;
use App\Models\Room;

$meeting = Meeting::find(1);

$meeting->updateTopic('English class: Introducing Yourself')
    ->updateDuration(60)
    ->updateStartTime(now())
    ->updateScheduler(Event::find(1))
    ->updatePresenter(Teacher::find(5))
    ->updateHost(Room::find(1))
    ->save();
```

Then you can add a participant:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Student;

$meeting = Meeting::find(1);
$student = Student::find(1);

//By the meeting model
$meeting->addParticipant($student);

//Or by the participant model
$student->bookMeeting($meeting);
```

To provide the access to the presenter use:

```
use Nncodes\Meeting\Models\Meeting;

Meeting::find(1)->getPresenterAccess();
```

And for the participant use:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Student;

$student = Student::find(1);

Meeting::find(1)>getParticipantAccess($student);
```

More: [handling a scheduled meeting](#handling-a-scheduled-meeting).

Retrieving meetings
-------------------

[](#retrieving-meetings)

**You can just call from the meeting model:**

Scoping meetings by `Nncodes\Meeting\Models\Meeting`.

```
$query = Meeting::query();
```

**or call `meetings()` from any actor:**

Scoping meetings from scheduler model, e.g. `App\Models\Event` with `id:1`.

```
$query = Event::find(1)->meetings();
```

Scoping meetings from presenter model, e.g. `App\Models\Teacher` with `id:1`.

```
$query = Teacher::find(1)->meetings();
```

Scoping meetings from host model, e.g. `App\Models\Room` with `id:1`.

```
$query = Room::find(1)->meetings();
```

Scoping meetings from participant model, e.g. `App\Models\Student` with `id:1`.

```
$query = Student::find(1)->meetings();
```

### Eloquent scopes

[](#eloquent-scopes)

**General scopes**

scoping by `uuid`, e.g `b33cac3a-c8da-4b33-a296-30a6acff5af6`.

```
$query->byUuid('b33cac3a-c8da-4b33-a296-30a6acff5af6');
```

scoping by `id`, e.g `1`.

```
$query->byId(1);
```

scoping by provider, e.g. `zoom`.

```
$query->provider('zoom');
```

**Scopes for `start_time`, `started_at` and `ended_at`**

scoping by start time from, e.g. `15 days ago`.

```
$query->startsFrom(Carbon::now()->sub('15 days'));
```

scoping by start time until, e.g. `15 days from now`.

```
$query->startsUntil(Carbon::now()->add('15 days'));
```

Or scoping by start time within a period, e.g. from `15 days ago` and `15 days from now`.

```
$query->startsBetween(
    Carbon::now()->sub('15 days'),
    Carbon::now()->add('15 days')
);
```

scoping by status `live`, the started but not ended meetings.

```
$query->live();
```

scoping by status `past`, the started and ended meetings.

```
$query->past();
```

scoping by status `scheduled`, the not started meetings.

```
$query->scheduled();
```

scoping by `scheduled` status and where `start_time` is past. Queries the late to start meetings.

```
$query->late();
```

scoping by `live` status and where `started_at` + `duration` is past. Queries the meetings that had exceeded the scheduled duration.

```
$query->exceeded();
```

scoping by `scheduled` status ordering by `start_time` asc. Queries the next neetings

```
$query->next();
```

scoping by `last` status ordering by `ended_at` desc queries the last meetings

```
$query->last();
```

**Scopes for actors**

scoping by scheduler, e.g. `App\Models\Event` with `id:1`.

```
$query->scheduler(Event::find(1));
```

scoping by host, e.g. `App\Models\Room` with `id:1`.

```
$query->host(Room::find(1));
```

scoping by participant, e.g. `App\Models\Student` with `id:1`.

```
$query->participant(Student::find(1));
```

scoping by presenter, e.g. `App\Models\Teacher` with `id:1`.

```
$query->presenter(Teacher::find(1));
```

Finally to retrieve the data you can call any eloquent retriever method, e.g. `count`, `first`, `get`, `paginate` and etc.

Handling a scheduled meeting
----------------------------

[](#handling-a-scheduled-meeting)

### Meeting

[](#meeting)

When using zoom provider, you can set `share_rooms` to `true`, then you don't need to inform a host when scheduling a meeting. The package handles the allocation of rooms.

In this case you can schedule using:

```
use Nncodes\Meeting\Models\Meeting;
use App\Models\Event;
use App\Models\Teacher;

$meeting = Meeting::schedule()
  	->withTopic('English class: verb to be')
  	->startingAt(now()->addMinutes(30))
  	->during(40) //minutes
  	->scheduledBy(Event::find(1))
  	->presentedBy(Teacher::find(1))
  	->save();
```

If no rooms is available the expcetion `\Nncodes\Meeting\Exceptions\NoZoomRoomAvailable` is thrown.

```
use Nncodes\Meeting\Models\Meeting;
```

Starting a meeting.

```
Meeting::find(1)->start();
```

Ending a meeting.

```
Meeting::find(1)->end();
```

Canceling a meeting.

```
Meeting::find(1)->cancel();
```

### Participants

[](#participants)

#### Add a participant

[](#add-a-participant)

Adding a participant by `Nncodes\Meeting\Models\Meeting`

```
$student = Student::find(1);
Meeting::find(1)->addParticipant($student);
```

Adding a participant by participant model `App\Models\Student`

```
$meeting = Meeting::find(1);
Student::find(1)->bookMeeting($meeting);
```

#### Cancel a participation

[](#cancel-a-participation)

Canceling a participation by `Nncodes\Meeting\Models\Meeting`

```
$student = Student::find(1);
Meeting::find(1)->cancelParticipation($student);
```

Adding a participant by participant model `App\Models\Student`

```
$meeting = Meeting::find(1);
Student::find(1)->cancelMeetingParticipation($meeting);
```

#### Join meeting

[](#join-meeting)

Joining by `Nncodes\Meeting\Models\Meeting`

```
$student = Student::find(1);
Meeting::find(1)->joinParticipant($student);
```

Joining by participant model `App\Models\Student`

```
$meeting = Meeting::find(1);
Student::find(1)->joinMeeting($meeting);
```

##### Leave meeting

[](#leave-meeting)

Leaving by `Nncodes\Meeting\Models\Meeting`

```
$student = Student::find(1);
Meeting::find(1)->leaveParticipant($student);
```

Leaving by participant model `App\Models\Student`

```
$meeting = Meeting::find(1);
Student::find(1)->leaveMeeting($meeting);
```

##### Getting participants

[](#getting-participants)

Getting a participant

```
$student = Student::find(1);
$participant = Meeting::find(1)->participant($student);
```

Checking if a meeting has a participant:

```
$student = Student::find(1);
$bool = Meeting::find(1)->hasParticipant($student);
```

Getting a list of participants using the morphMany relationship:

```
//Must inform the participant model type
$participants = Meeting::find(1)->participants(App\Models\Student::class)->get();
```

Or using the participantsPivot relation.

```
//Doesn't need to inform participant model type, it gets all types.
$participants = Meeting::find(1)->participantsPivot;
```

Getting the first participant ordering by `created_at` desc, it allows to use a meeting as queue mode service.

```
$participant = Meeting::find(1)->getNextParticipant();
```

### Hosts

[](#hosts)

#### Scoping and verification methods

[](#scoping-and-verification-methods)

Given the code:

```
use Nncodes\Meeting\Models\MeetingRoom;

$startTime = Carbon::now()->addMinutes(30);
$duration = 40;
$endTime = (clone $startTime)->addMinutes($duration);
```

Scoping an available host:

```
MeetingRoom::availableBetween($startTime, $endTime);
```

Scoping a busy host:

```
MeetingRoom::busyBetween($startTime, $endTime);
```

Scoping busy and available hosts except for a meeting

```
use Nncodes\Meeting\Models\Meeting;

$except = Meeting::find(1);

MeetingRoom::availableBetween($startTime, $endTime, $except);
MeetingRoom::busyBetween($startTime, $endTime, $except);
```

Then you can call any eloquent retriever method, e.g. `count`, `first`, `get`, `paginate` and etc.

You can also check if a room instance is busy or available:

```
use Nncodes\Meeting\Models\MeetingRoom;

MeetingRoom::find(1)->isAvailableBetween($startTime, $endTime);
MeetingRoom::find(1)->isBusyBetween($startTime, $endTime);
```

As the scope methods, you can also specify meeting to exclude from the query:

```
use Nncodes\Meeting\Models\MeetingRoom;
use Nncodes\Meeting\Models\Meeting;

$except = Meeting::find(1);

MeetingRoom::find(1)->isAvailableBetween($startTime, $endTime, $except);
MeetingRoom::find(1)->isBusyBetween($startTime, $endTime, $except);
```

Changelog
---------

[](#changelog)

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

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

[](#contributing)

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

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Leonardo Poletto](https://github.com/leopoletto)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance18

Infrequent updates — may be unmaintained

Popularity24

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 93.9% 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 ~63 days

Recently: every ~79 days

Total

6

Last Release

1641d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1036401?v=4)[Leonardo Poletto](/maintainers/leopoletto)[@leopoletto](https://github.com/leopoletto)

---

Top Contributors

[![leopoletto](https://avatars.githubusercontent.com/u/1036401?v=4)](https://github.com/leopoletto "leopoletto (46 commits)")[![aaronaccessvr](https://avatars.githubusercontent.com/u/79271047?v=4)](https://github.com/aaronaccessvr "aaronaccessvr (2 commits)")[![aaronredwood](https://avatars.githubusercontent.com/u/50202473?v=4)](https://github.com/aaronredwood "aaronredwood (1 commits)")

---

Tags

laravel-meetingphp-online-meetingzoom-laravelzoom-meetingszoom-phpnncodeslaravel-meeting

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/nncodes-laravel-meeting/health.svg)

```
[![Health](https://phpackages.com/badges/nncodes-laravel-meeting/health.svg)](https://phpackages.com/packages/nncodes-laravel-meeting)
```

###  Alternatives

[maestroerror/laragent

Power of AI Agents in your Laravel project

630106.4k](/packages/maestroerror-laragent)[nativephp/mobile

NativePHP for Mobile

82724.0k43](/packages/nativephp-mobile)[bensampo/laravel-embed

Painless responsive embeds for videos, slideshows and more.

142146.8k](/packages/bensampo-laravel-embed)[flarum/core

Delightfully simple forum software.

211.3M1.9k](/packages/flarum-core)[spatie/laravel-rdap

Perform RDAP queries in a Laravel app

72108.3k2](/packages/spatie-laravel-rdap)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)

PHPackages © 2026

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