• Stars
    star
    1,036
  • Rank 44,478 (Top 0.9 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 9 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

User to Team associations with invitation system for the Laravel 5 Framework

Teamwork

This package supports Laravel 6 and above.

Latest Version Software License Build Status codecov.io SensioLabsInsight Scrutinizer Code Quality

Teamwork is the fastest and easiest method to add a User / Team association with Invites to your Laravel 6+ project.

Installation

composer require mpociot/teamwork

The Teamwork Facade will be discovered by Laravel automatically.

Configuration

To publish Teamwork's configuration and migration files, run the vendor:publish command.

php artisan vendor:publish --provider="Mpociot\Teamwork\TeamworkServiceProvider"

This will create a teamwork.php in your config directory. The default configuration should work just fine for you, but you can take a look at it, if you want to customize the table / model names Teamwork will use.

User relation to teams

Run the migration command, to generate all tables needed for Teamwork. If your users are stored in a different table other than users be sure to modify the published migration.

php artisan migrate

After the migration, 3 new tables will be created:

  • teams — stores team records
  • team_user — stores many-to-many relations between users and teams
  • team_invites — stores pending invites for email addresses to teams

You will also notice that a new column current_team_id has been added to your users table. This column will define the Team, the user is currently assigned to.

Models

Team

Create a Team model inside app/Team.php using the following example:

<?php namespace App;

use Mpociot\Teamwork\TeamworkTeam;

class Team extends TeamworkTeam
{
}

The Team model has two main attributes:

  • owner_id — Reference to the User model that owns this Team.
  • name — Human readable name for the Team.

The owner_id is an optional attribute and is nullable in the database.

When extending TeamworkTeam, remember to change the team_model variable in config/teamwork.php to your new model. For instance: 'team_model' => App\Team::class

User

Add the UserHasTeams trait to your existing User model:

<?php namespace App;

use Mpociot\Teamwork\Traits\UserHasTeams;

class User extends Model {

    use UserHasTeams; // Add this trait to your model
}

This will enable the relation with Team and add the following methods teams(), ownedTeams() currentTeam(), invites(), isTeamOwner(), isOwnerOfTeam($team), attachTeam($team, $pivotData = []), detachTeam($team), attachTeams($teams), detachTeams($teams), switchTeam($team) within your User model.

Don't forget to dump composer autoload

composer dump-autoload

Middleware

If you would like to use the middleware to protect to current team owner then just add the middleware provider to your app\Http\Kernel.php file.

    protected $routeMiddleware = [
        ...
        'teamowner' => \Mpociot\Teamwork\Middleware\TeamOwner::class,
        ...
    ];

Afterwards you can use the teamowner middleware in your routes file like so.

Route::get('/owner', function(){
    return "Owner of current team.";
})->middleware('auth', 'teamowner');

Now only if the authenticated user is the owner of the current team can access that route.

This middleware is aimed to protect routes where only the owner of the team can edit/create/delete that model

And you are ready to go.

Usage

Scaffolding

The easiest way to give your new Laravel project Team abilities is by using the make:teamwork command.

php artisan make:teamwork

This command will create all views, routes and controllers to make your new project team-ready.

Out of the box, the following parts will be created for you:

  • Team listing
  • Team creation / editing / deletion
  • Invite new members to teams

Imagine it as a the make:auth command for Teamwork.

To get started, take a look at the new installed /teams route in your project.

Basic concepts

Let's start by creating two different Teams.

$team    = new Team();
$team->owner_id = User::where('username', '=', 'sebastian')->first()->getKey();
$team->name = 'My awesome team';
$team->save();

$myOtherCompany = new Team();
$myOtherCompany->owner_id = User::where('username', '=', 'marcel')->first()->getKey();
$myOtherCompany->name = 'My other awesome team';
$myOtherCompany->save();

Now thanks to the UserHasTeams trait, assigning the Teams to the user is super easy:

$user = User::where('username', '=', 'sebastian')->first();

// team attach alias
$user->attachTeam($team, $pivotData); // First parameter can be a Team object, array, or id

// or eloquent's original technique
$user->teams()->attach($team->id); // id only

By using the attachTeam method, if the User has no Teams assigned, the current_team_id column will automatically be set.

Alternatively, you can also use createOwnedTeam method from UserHasTeams trait. It will create team for the user as owner, attach the user to the team and switch to the newly created team.

// Create user owned team and switch the current team to this new team.
$team = $user->createOwnedTeam(['name' => 'My awesome team']);

// If user has another current team active, you should pass second parameter as true to force switch to the new team.
$team = $user->createOwnedTeam(['name' => 'My awesome team'], true);

The function will return the newly created instance of your team model.

Get to know my team(s)

The currently assigned Team of a user can be accessed through the currentTeam relation like this:

echo "I'm currently in team: " . Auth::user()->currentTeam->name;
echo "The team owner is: " . Auth::user()->currentTeam->owner->username;

echo "I also have these teams: ";
print_r( Auth::user()->teams );

echo "I am the owner of these teams: ";
print_r( Auth::user()->ownedTeams );

echo "My team has " . Auth::user()->currentTeam->users->count() . " users.";

The Team model has access to these methods:

  • invites() — Returns a many-to-many relation to associated invitations.
  • users() — Returns a many-to-many relation with all users associated to this team.
  • owner() — Returns a one-to-one relation with the User model that owns this team.
  • hasUser(User $user) — Helper function to determine if a user is a teammember

Team owner

If you need to check if the User is a team owner (regardless of the current team) use the isTeamOwner() method on the User model.

if( Auth::user()->isTeamOwner() )
{
    echo "I'm a team owner. Please let me pay more.";
}

Additionally if you need to check if the user is the owner of a specific team, use:

$team = Auth::user()->currentTeam;
if( Auth::user()->isOwnerOfTeam( $team ) )
{
    echo "I'm a specific team owner. Please let me pay even more.";
}

The isOwnerOfTeam method also allows an array or id as team parameter.

Switching the current team

If your Users are members of multiple teams you might want to give them access to a switch team mechanic in some way.

This means that the user has one "active" team, that is currently assigned to the user. All other teams still remain attached to the relation!

Glad we have the UserHasTeams trait.

try {
    Auth::user()->switchTeam( $team_id );
    // Or remove a team association at all
    Auth::user()->switchTeam( null );
} catch( UserNotInTeamException $e )
{
    // Given team is not allowed for the user
}

Just like the isOwnerOfTeam method, switchTeam accepts a Team object, array, id or null as a parameter.

Inviting others

The best team is of no avail if you're the only team member.

To invite other users to your teams, use the Teamwork facade.

Teamwork::inviteToTeam( $email, $team, function( $invite )
{
    // Send email to user / let them know that they got invited
});

You can also send invites by providing an object with an email property like:

$user = Auth::user();

Teamwork::inviteToTeam( $user , $team, function( $invite )
{
    // Send email to user / let them know that they got invited
});

This method will create a TeamInvite model and return it in the callable third parameter.

This model has these attributes:

  • email — The email that was invited.
  • accept_token — Unique token used to accept the invite.
  • deny_token — Unique token used to deny the invite.

In addition to these attributes, the model has these relations:

  • user() — one-to-one relation using the email as a unique identifier on the User model.
  • team() — one-to-one relation return the Team, that invite was aiming for.
  • inviter() — one-to-one relation return the User, that created the invite.

Note: The inviteToTeam method will not check if the given email already has a pending invite. To check for pending invites use the hasPendingInvite method on the Teamwork facade.

Example usage:

if( !Teamwork::hasPendingInvite( $request->email, $request->team) )
{
    Teamwork::inviteToTeam( $request->email, $request->team, function( $invite )
    {
                // Send email to user
    });
} else {
    // Return error - user already invited
}

Accepting invites

Once you invited other users to join your team, in order to accept the invitation use the Teamwork facade once again.

$invite = Teamwork::getInviteFromAcceptToken( $request->token ); // Returns a TeamworkInvite model or null

if( $invite ) // valid token found
{
    Teamwork::acceptInvite( $invite );
}

The acceptInvite method does two thing:

  • Call attachTeam with the invite-team on the currently authenticated user.
  • Delete the invitation afterwards.

Denying invites

Just like accepting invites:

$invite = Teamwork::getInviteFromDenyToken( $request->token ); // Returns a TeamworkInvite model or null

if( $invite ) // valid token found
{
    Teamwork::denyInvite( $invite );
}

The denyInvite method is only responsible for deleting the invitation from the database.

Attaching/Detaching/Invite Events

If you need to run additional processes after attaching/detaching a team from a user or inviting a user, you can Listen for these events:

\Mpociot\Teamwork\Events\UserJoinedTeam

\Mpociot\Teamwork\Events\UserLeftTeam

\Mpociot\Teamwork\Events\UserInvitedToTeam

In your EventServiceProvider add your listener(s):

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    ...
    \Mpociot\Teamwork\Events\UserJoinedTeam::class => [
        App\Listeners\YourJoinedTeamListener::class,
    ],
    \Mpociot\Teamwork\Events\UserLeftTeam::class => [
        App\Listeners\YourLeftTeamListener::class,
    ],
    \Mpociot\Teamwork\Events\UserInvitedToTeam::class => [
        App\Listeners\YourUserInvitedToTeamListener::class,
    ],
];

The UserJoinedTeam and UserLeftTeam event exposes the User and Team's ID. In your listener, you can access them like so:

<?php

namespace App\Listeners;

use Mpociot\Teamwork\Events\UserJoinedTeam;

class YourJoinedTeamListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  UserJoinedTeam  $event
     * @return void
     */
    public function handle(UserJoinedTeam $event)
    {
        // $user = $event->getUser();
        // $teamId = $event->getTeamId();

        // Do something with the user and team ID.
    }
}

The UserInvitedToTeam event contains an invite object which could be accessed like this:

<?php

namespace App\Listeners;

use Mpociot\Teamwork\Events\UserInvitedToTeam;

class YourUserInvitedToTeamListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  UserInvitedToTeam  $event
     * @return void
     */
    public function handle(UserInvitedToTeam $event)
    {
        // $user = $event->getInvite()->user;
        // $teamId = $event->getTeamId();

        // Do something with the user and team ID.
    }
}

Limit Models to current Team

If your models are somehow limited to the current team you will find yourself writing this query over and over again: Model::where('team_id', auth()->user()->currentTeam->id)->get();.

To automate this process, you can let your models use the UsedByTeams trait. This trait will automatically append the current team id of the authenticated user to all queries and will also add it to a field called team_id when saving the models.

Note:

This assumes that the model has a field called team_id

Usage

use Mpociot\Teamwork\Traits\UsedByTeams;

class Task extends Model
{
    use UsedByTeams;
}

When using this trait, all queries will append WHERE team_id=CURRENT_TEAM_ID. If theres a place in your app, where you really want to retrieve all models, no matter what team they belong to, you can use the allTeams scope.

Example:

// gets all tasks for the currently active team of the authenticated user
Task::all();

// gets all tasks from all teams globally
Task::allTeams()->get();

License

Teamwork is free software distributed under the terms of the MIT license.

'Marvel Avengers' image licensed under Creative Commons 2.0 - Photo from W_Minshull

More Repositories

1

chatgpt-vscode

A VSCode extension that allows you to use ChatGPT
TypeScript
3,779
star
2

laravel-apidoc-generator

Laravel API Documentation Generator
PHP
3,386
star
3

whiteboard

Simply write beautiful API documentation.
JavaScript
1,224
star
4

laravel-test-factory-helper

Generate Laravel test factories from your existing models
PHP
930
star
5

versionable

Laravel Model versioning made easy
PHP
687
star
6

laravel-testtools

Chrome extension to generate Laravel integration tests while using your app.
JavaScript
473
star
7

documentarian

Create beautiful API documentation
JavaScript
377
star
8

captainhook

Add Webhooks to your Laravel app, arrr
PHP
335
star
9

reauthenticate

Reauthenticate users by letting them re-enter their passwords for specific parts of your app.
PHP
296
star
10

laravel-firebase-sync

Synchronize your Eloquent models with a Firebase Realtime Database.
PHP
264
star
11

laravel-face-auth

Laravel Face authentication
PHP
157
star
12

TiSideMenu

iOS 7 / 8 style side menu with parallax effect. (Wrapper module for RESideMenu)
Objective-C
147
star
13

pipeline

Simple PHP pipelines
PHP
131
star
14

reanimate

Easily add an "undo" option to your Laravel application
PHP
121
star
15

titanium-facebook-slide-menu

Example of how to implement a facebook like sliding menu in appcelerator's titanium mobile
JavaScript
117
star
16

blacksmith

The unofficial Laravel Forge PHP API
PHP
103
star
17

human-regex

Regular expressions for human beings, not machines
PHP
102
star
18

reflection-docblock

Fork of phpdocumentor/reflection-docblock to work with the api-documentation-generator
PHP
85
star
19

TiMotionEffects

UIMotionEffects for Appcelerator Titanium
Python
59
star
20

TiMWKProgressIndicator

A minimal progress indicator for iOS with status update support. Displays above UINavigationBar and below the Status Bar.
Objective-C
49
star
21

TiCircularSlider

Titanium circular slider module with many customizations.
Objective-C
47
star
22

TiCircularProgress

Circular progress indicator for Appcelerator Titanium
Objective-C
44
star
23

cockpit

Custom widgets for your Laravel app
PHP
38
star
24

titanium-social-modul

iOS6 module for facebook, twitter, sina weibo to use with appcelerator titanium
Python
38
star
25

laravel-slack-inviter

A little Laravel application to invite a user into your Slack team.
PHP
36
star
26

TiImageFromGIF

Create native imageviews from GIFs
Objective-C
35
star
27

TiCustomTab

Create Tabs with custom selected / unselected images.
Objective-C
34
star
28

laravel-composite-key

PHP trait to use composite keys in your Laravel Eloquent models.
PHP
34
star
29

codeception-testtools

Chrome extension to generate Codeception acceptance tests while using your app.
JavaScript
34
star
30

TiAndroidAutofocus

Prevents TextFields in Android to autofocus
Java
31
star
31

titanium-mobile-twitter-module

Basic twitter iOS 5 integration as a titanium module
Objective-C
30
star
32

TiAppirater

Titanium mobile iOS rating reminder
Objective-C
27
star
33

TiFaceRecognizer

CoreImage face detection module to use with the Appcelerator Titanium SDK
Python
27
star
34

titanium-mobile-alasset-module

Titanium module to get access to the iOS ALAsset framework
Objective-C
26
star
35

TiiMMAppSwitcher

iOS Titanium Mobile module - Replace iOS7 app switcher view with your own customized card view.
Objective-C
26
star
36

titanium-mobile-zip-module

zip module for appcelerators titanium mobile
C
25
star
37

chuck-norris-jokes

Create random Chuck Norris jokes.
PHP
25
star
38

TiScreenshotDetection

Detect when someone takes a screenshot in your Appcelerator Titanium iOS app.
Objective-C
20
star
39

TokenCompleteTextView

Java
20
star
40

lastfm-slack

Set your Last.fm tracks as your Slack status
PHP
19
star
41

TiAdvancedSplitWindow

Appcelerator titanium module to make use of the MGSplitView functions, not used by the Titanium SDK
Python
19
star
42

socialite-slack

Slack OAuth2 Provider for Laravel Socialite
PHP
18
star
43

TiTutorialView

Path like tutorial view as a commonJS module for Appcelerator Titanium
JavaScript
18
star
44

TiWebviewFragment

Simple helper class that is a workaround for Webviews Crashing / rendering blank on Android 4.4 in Titanium
Java
17
star
45

laravel-firebase-sync-example

Example project demonstrating the usage of the laravel-firebase-sync package
PHP
17
star
46

TiSplashScreen

Path like splash screen animation
Python
15
star
47

TiSDSegmentedControl

This is a titanium module for Olivier Poitrey's SDSegmentedControl library.
Objective-C
14
star
48

TiDocumentInteraction

Share/Print/Open files with the native activity view controller in your Titanium app
Python
12
star
49

mpociot

10
star
50

TiSMPageControl

Titanium mobile iOS module for some funky ScrollableView customization
Objective-C
7
star
51

llamero

A GUI application to easily try out Facebook's LLaMA models.
JavaScript
6
star
52

botman-spark-demo

BotMan + Cisco Spark demo project
PHP
5
star
53

psd2tss

JavaScript
5
star
54

feature-switch

A feature switcher for PHP
PHP
5
star
55

MagicPie

A Titanium implementation of https://github.com/Sk0rpion/MagicPie
Python
4
star
56

ti-crittercism-hook

A CLI hook for Appcelerator Titanium to automatically upload dSYM files to crittercism.
JavaScript
4
star
57

skeleton-php

PHP
3
star
58

TiIOS8WebviewFix

Prevent iOS8 iPad apps with WebViews from crashing
Python
3
star
59

laracon-eu-2017

My Laracon EU 2017 talk
PHP
3
star
60

php-uk-conference-2018

My PHP UK Conference 2018 Talk
PHP
3
star
61

titanium-twitter-oauth

A Twitter OAuth Module for Titanium Mobile
JavaScript
3
star
62

php-serbia-2018

The talk I gave at PHP Serbia 2018
PHP
2
star
63

ti-taffy

taffyDB wrapper for titanium
JavaScript
2
star
64

botman-workshop

PHP
2
star
65

TiShowcaseView

Native android module for Appcelerator Titanium that tries to wrap the "ShowcaseView" library.
2
star