Skip to content

Commit

Permalink
Published at flag (#17)
Browse files Browse the repository at this point in the history
Add PublishedAt timestamp flag
  • Loading branch information
Pe Ell authored Jan 11, 2017
1 parent dccf78d commit 479564e
Show file tree
Hide file tree
Showing 19 changed files with 529 additions and 23 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to `laravel-eloquent-flag` will be documented in this file.

## 3.1.0 - 2017-01-11

### Added

- `Timestamp` flag types introduced.
- `published_at` classic timestamp flag added.

## 3.0.0 - 2017-01-07

### Added
Expand Down
92 changes: 78 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,46 @@

## Introduction

Eloquent flagged attributes behavior. Enhance eloquent models with commonly used flags like `Active`, `Published`, `Approved` and other in a minutes!
Eloquent boolean & timestamp flagged attributes behavior. Enhance eloquent models with commonly used state flags like `Active`, `Published`, `Approved` and others in a minutes!

## Features

- Designed to work with Laravel Eloquent models
- Each model can has as many flags as required
- Each flag adds global query scopes to models
- 2 logical groups of flags: `Classic`, `Inverse`
- 2 types of flags: `Boolean`, `Timestamp`
- Covered with unit tests

## Available flags list

| Trait name | Logic | Database columns | Flag type |
| ---------- | ----- | ---------------- | --------- |
| `HasAcceptedFlag` | Classic | `is_accepted` | Boolean |
| `HasActiveFlag` | Classic | `is_active` | Boolean |
| `HasApprovedFlag` | Classic | `is_approved` | Boolean |
| `HasClosedFlag` | Inverse | `is_closed` | Boolean |
| `HasExpiredFlag` | Inverse | `is_expired` | Boolean |
| `HasKeptFlag` | Classic | `is_kept` | Boolean |
| `HasPublishedFlag` | Classic | `is_published` | Boolean |
| `HasVerifiedFlag` | Classic | `is_verified` | Boolean |
| Trait name | Logic | Database columns | Flag type | Conflict |
| ---------- | ----- | ---------------- | --------- | -------- |
| `HasAcceptedFlag` | Classic | `is_accepted` | Boolean | - |
| `HasActiveFlag` | Classic | `is_active` | Boolean | - |
| `HasApprovedFlag` | Classic | `is_approved` | Boolean | - |
| `HasClosedFlag` | Inverse | `is_closed` | Boolean | - |
| `HasExpiredFlag` | Inverse | `is_expired` | Boolean | - |
| `HasKeptFlag` | Classic | `is_kept` | Boolean | - |
| `HasPublishedAt` | Classic | `published_at` | Timestamp | `HasPublishedFlag` |
| `HasPublishedFlag` | Classic | `is_published` | Boolean | `HasPublishedAt` |
| `HasVerifiedFlag` | Classic | `is_verified` | Boolean | - |

Any entity can has more than one flag at the same time. If flags can't work for the same entity simultaneously they are listed in `Conflict` column.

## How it works

Eloquent Flag is an easy way to add flagged attributes to eloquent models. All flags has their own trait which adds global scopes to desired entity.

There are 2 types of flags:

- `Boolean` flags are the common ones. Stored in database as `BOOLEAN` or `TINYINT(1)` value.
- `Timestamp` flags represented in database as nullable `TIMESTAMP` column. Useful when you need to know when action was performed.

All flags separated on 2 logical groups:

- `Classic` flags displays only entities with flag setted as `true`.
- `Inverse` flags displays only entities with flag setted as `false`.
- `Classic` flags displays only entities with `true` or `timestamp` flag value.
- `Inverse` flags displays only entities with `false` or `null` flag value.

Omitted entities could be retrieved by using special global scope methods, unique for each flag.

Expand All @@ -62,6 +72,40 @@ And then include the service provider within `app/config/app.php`.

## Usage

### Prepare database

#### Boolean flag

```php
public function up()
{
Schema::create('post', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->boolean('is_published');
$table->timestamps();
});
}
```

*Change `is_published` on any other `Boolean` flag database column name.*

#### Timestamp flag

```php
public function up()
{
Schema::create('post', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
```

*Change `published_at` on any other `Timestamp` flag database column name.*

### Setup an activatable model

```php
Expand Down Expand Up @@ -217,6 +261,8 @@ Post::where('id', 4)->disapprove();

### Setup a publishable model

#### With boolean flag

```php
<?php

Expand All @@ -233,6 +279,24 @@ class Post extends Model

*Model must have boolean `is_published` column in database table.*

#### With timestamp flag

```php
<?php

namespace App\Models;

use Cog\Flag\Traits\Classic\HasPublishedAt;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
use HasPublishedAt;
}
```

*Model must have nullable timestamp `published_at` column in database table.*

### Available functions

#### Get only published models
Expand Down Expand Up @@ -500,7 +564,7 @@ Post::where('id', 4)->close();
#### Remove close flag from model

```php
Post::where('id', 4)->unclose();
Post::where('id', 4)->open();
```

## Testing
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cybercog/laravel-eloquent-flag",
"description": "Laravel Eloquent flagged attributes behavior.",
"description": "Laravel Eloquent boolean & timestamp flagged attributes behavior.",
"type": "library",
"license": "MIT",
"keywords": [
Expand All @@ -10,6 +10,8 @@
"trait",
"scopes",
"flag",
"state",
"status",
"boolean",
"timestamp",
"accepted",
Expand Down
124 changes: 124 additions & 0 deletions src/Scopes/Classic/PublishedAtScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php

/*
* This file is part of Laravel Eloquent Flag.
*
* (c) Anton Komarev <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cog\Flag\Scopes\Classic;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

/**
* Class PublishedAtScope.
*
* @package Cog\Flag\Scopes\Classic
*/
class PublishedAtScope implements Scope
{
/**
* All of the extensions to be added to the builder.
*
* @var array
*/
protected $extensions = ['Publish', 'Unpublish', 'WithUnpublished', 'WithoutUnpublished', 'OnlyUnpublished'];

/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Builder $builder, Model $model)
{
return $builder->whereNotNull('published_at');
}

/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Builder $builder)
{
foreach ($this->extensions as $extension) {
$this->{"add{$extension}"}($builder);
}
}

/**
* Add the `publish` extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addPublish(Builder $builder)
{
$builder->macro('publish', function (Builder $builder) {
$builder->withUnpublished();

return $builder->update(['published_at' => Carbon::now()]);
});
}

/**
* Add the `unpublish` extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addUnpublish(Builder $builder)
{
$builder->macro('unpublish', function (Builder $builder) {
return $builder->update(['published_at' => null]);
});
}

/**
* Add the `withUnpublished` extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addWithUnpublished(Builder $builder)
{
$builder->macro('withUnpublished', function (Builder $builder) {
return $builder->withoutGlobalScope($this);
});
}

/**
* Add the `withoutUnpublished` extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addWithoutUnpublished(Builder $builder)
{
$builder->macro('withoutUnpublished', function (Builder $builder) {
return $builder->withoutGlobalScope($this)->whereNotNull('published_at');
});
}

/**
* Add the `onlyUnpublished` extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addOnlyUnpublished(Builder $builder)
{
$builder->macro('onlyUnpublished', function (Builder $builder) {
return $builder->withoutGlobalScope($this)->whereNull('published_at');
});
}
}
23 changes: 23 additions & 0 deletions src/Traits/Classic/HasPublishedAt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of Laravel Eloquent Flag.
*
* (c) Anton Komarev <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cog\Flag\Traits\Classic;

/**
* Class HasPublishedAt.
*
* @package Cog\Flag\Traits\Classic
*/
trait HasPublishedAt
{
use HasPublishedAtHelpers,
HasPublishedAtScope;
}
22 changes: 22 additions & 0 deletions src/Traits/Classic/HasPublishedAtHelpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of Laravel Eloquent Flag.
*
* (c) Anton Komarev <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cog\Flag\Traits\Classic;

/**
* Class HasPublishedAtHelpers.
*
* @package Cog\Flag\Traits\Classic
*/
trait HasPublishedAtHelpers
{
//
}
32 changes: 32 additions & 0 deletions src/Traits/Classic/HasPublishedAtScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of Laravel Eloquent Flag.
*
* (c) Anton Komarev <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cog\Flag\Traits\Classic;

use Cog\Flag\Scopes\Classic\PublishedAtScope;

/**
* Class HasPublishedAtScope.
*
* @package Cog\Flag\Traits\Classic
*/
trait HasPublishedAtScope
{
/**
* Boot the HasPublishedAtScope trait for a model.
*
* @return void
*/
public static function bootHasPublishedAtScope()
{
static::addGlobalScope(new PublishedAtScope);
}
}
17 changes: 17 additions & 0 deletions tests/database/factories/EntityWithPublishedAtFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

/*
* This file is part of Laravel Eloquent Flag.
*
* (c) Anton Komarev <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

$factory->define(\Cog\Flag\Tests\Stubs\Models\Classic\EntityWithPublishedAt::class, function (\Faker\Generator $faker) {
return [
'name' => $faker->word,
'published_at' => null,
];
});
Loading

0 comments on commit 479564e

Please sign in to comment.