Single Responsibility Principle and Laravel

  • URIs to access the pages for the posts and actions
  • blade templates for holding the HTML for final rendering
  • A Controller to handle the HTTP requests.
  • index – Displays a list of all posts
  • create – Displays the form to create a post
  • store – Stores a post in the database
  • show – Displays a specific post
  • edit – Displays the form to update a specific post
  • update – Updates a previously stored post in the database
  • publish – sets the deleted_at value to null
  • unpublish – sets the deleted_at value to the current timestamp
  • destroy – permanently deletes a post from the database
Route::group(['middleware' => ['can:create posts']], function () {
Route::get('/blog/post/create',
'PostController@create')->name('post.create');
Route::post('/blog/post/store',
'PostController@store')->name('post.store');
});
Route::get('/blog/post/',
'PostController@index')->name('post.index');
Route::get('/blog/post/{post}',
'PostController@show')->name('post.show');
Route::group(['middleware' => ['can:edit posts']], function () {
Route::get('/blog/post/{post}/edit',
'PostController@edit')->name('post.edit');
Route::post('/blog/post/{post}/update',
'PostController@update')->name('post.update');
});
Route::group(['middleware' => ['can:unpublish posts']], function () {
Route::get('/blog/post/{post}/delete',
'PostController@unpublish')->name('post.delete');
});
Route::group(['middleware' => ['can:publish posts']], function () {
Route::get('/blog/post/{post}/restore',
'PostController@publish')->name('post.restore');
});
Route::group(['middleware' => ['can:destroy posts']], function () {
Route::get('/blog/post/{post}/destroy',
'PostController@destroy')->name('post.destroy');
});
<?phpnamespace App\Http\Controllers;//core
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
//model
use App\Models\Post;
//events
use App\Events\PostCreated;
use App\Events\QueuePostForReview;
use App\Events\UpdatePostSchedule;
use App\Events\PostPublished;
use App\Events\PostUnpublished;
use App\Events\PostDestroyed;
class PostController extends Controller
{
/**
* Display all posts
*
* @return View
*/
public function index(): View
{
return view('posts.index');
}
/**
* Show the form to create a new post
*
* @return View
*/
public function create(): View
{
return view('posts.create');
}
/**
* Store a newly created post in the database
*
* @param Request $request
* @return RedirectResponse
*/
public function store(Request $request): RedirectResponse
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);

// The blog post is valid...
$post = Post::create([
'title' => $validatedData['title'], //the post title
'body' => $validatedData['body'], //the post body
'deleted_at' => Carbon::now() //sets the post to be 'unpublished' by default
'author' => Auth::user()->id, //sets the post author ID
]);
PostCreated::dispatch($post);
QueuePostForReview::dispatch($post);
UpdatePostSchedule::dispatch($post);
return redirect()
->route('posts.index')
->with('success', 'The post was created, but not published!');
}
/**
* Display a specific post
*
* @param Post $post
* @return View
*/
public function show(Post $post): View
{
return view('posts.show', ['post' => $post]);
}
/**
* Show the form to edit a specific post
*
* @param Post $post
* @return View
*/
public function edit(Post $post): View
{
return view('posts.edit', ['post' => $post]);
}
/**
* Update a specific post in the database
*
* @param Request $request
* @param Environment $environment
* @return RedirectResponse
*/
public function update(Request $request, $post): RedirectResponse
{
$postInstance = Post::withTrashed()->find($post);
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid...
$postInstance->title = $validatedData['title']; //the post title
$postInstance->body = $validatedData['body']; //the post body
$postInstance->deleted_at = Carbon::now(); //sets the post to be 'unpublished' by default
$postInstance->author = Auth::user()->id; //sets the post author ID
$postInstance->save();
PostUpdated::dispatch($postInstance);
QueuePostForReview::dispatch($postInstance);
UpdatePostSchedule::dispatch($postInstance);
return redirect()
->route('posts.index')
->with('success', 'The post was updated, but not published!');
}
/**
* SoftDeletes post from Database
*
* @param Post $post
* @return RedirectResponse
*/
public function delete(Post $post): RedirectResponse
{
$environment->delete();
return redirect()->route('posts.index')->with('success', 'The post was successfully unpublished');
}
/**
* Recovers post from SoftDelete
*
* @param $post
* @return RedirectResponse
*/
public function restore($post): RedirectResponse
{
$postInstance = Post::withTrashed()->find($post);
$postInstance->restore();
PostUnpublished::dispatch($postInstance);
QueuePostForReview::dispatch($postInstance);
UpdatePostSchedule::dispatch($postInstance);
PostPublished::dispatch($postInstance); return redirect()->route('posts.index')->with('success', 'The post was successfully published');
}
/**
* Permanently deletes post from the database
*
* @param $post
* @return RedirectResponse
*/
public function destroy($post): RedirectResponse
{
$postInstance = Post::withTrashed()->find($post);
PostDestroyed::dispatch($post); $postInstance->forceDelete();
return redirect()->route('posts.index')->with('success', 'The post was permanantly deleted');
}
}
app
├── Console
├── Events
├── Listeners
├── Exceptions
├── Http
│ ├── Controllers
│ │ ├── Controller.php
│ │ └── PostController.php
│ ├── Middleware
│ └── Requests
│ └── PostFormRequest.php
├── Models
│ └── Post.php
└── Processors
└── Post
├── PostProcessor.php
└── PostEventProcessor.php
<?phpnamespace App\Processors\Post;use App\Models\Post;class PostProcessor
{
/**
* @param $data
* @return Post
*/
public function start($data, $type)
{
switch($type) {
case 'create':
if(Auth::user()->can(['create post'])) {
return self::create($data);
} else {
throw new Exception(__('isAuthorized.false'), 1);
}
break;
case 'update':
if(Auth::user()->can(['edit post'])) {
return self::update($data);
} else {
throw new Exception(__('isAuthorized.false'), 1);
}
break;
case 'publish':
if(Auth::user()->can(['publish post'])) {
return self::publish($data);
} else {
throw new Exception(__('isAuthorized.false'), 1);
}
break;
case 'unpublish':
if(Auth::user()->can(['unpublish post'])) {
return self::unpublish($data);
} else {
throw new Exception(__('isAuthorized.false'), 1);
}
break;
case 'destroy':
if(Auth::user()->can(['destroy post'])) {
return self::destroy($data);
} else {
throw new Exception(__('isAuthorized.false'), 1);
}
break;
default:
throw new Exception(__('processRequest.error'), 1);
}
}
/**
* @param array $requestData
* @return Post
*/
private static function create(Array $requestData): Post
{
$post = Post::create($requestData);
$post->deleted_at = Carbon::now();
$post->save();
return $post;
}
/**
* @param array $requestData
* @return Post
*/
private static function update(Array $requestData): Post
{
$post = Post::withTrashed()->find($requestData['id']);
$post->title = $requestData['title'];
$post->body = $requestData['body'];
$post->deleted_at = Carbon::now();
$post->updated_at = Carbon::now();
$post->save();
return $post;
}
/**
* @param Post $post
* @return void
*/
private static function publish($post)
{
$postInstance = Post::withTrashed()->find($post);
$postInstance->deleted_at = null;
$postInstance->updated_at = Carbon::now();
$postInstance->save();
return $post;
}
/**
* @param Post $post
* @return void
*/
private static function unpublish(Post $post)
{
$post->deleted_at = Carbon::now();
$post->updated_at = Carbon::now();
$post->save();
return $post;
}
/**
* @param $post
* @return void
*/
private static function destroy($post)
{
$postInstance = Post::withTrashed()->find($post);
$postInstance->forceDelete();
}
}
<?phpnamespace App\Http\Requests\Post;use Auth;
use Illuminate\Foundation\Http\FormRequest;
class PostFormRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return Auth::user()->can(['control posts']);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
public function messages(): array
{
return [
'title.required' => 'A post must have a title',
'title.unique' => 'A post with that title already exists',
'title.max' => 'The title is too long, max title is 255 characters',
'body.required' => 'A post body is required',
];
}
}
<?phpnamespace App\Processors\Post;//models
use App\Models\Post;
//events
use App\Events\PostCreated;
use App\Events\QueuePostForReview;
use App\Events\UpdatePostSchedule;
use App\Events\PostPublished;
use App\Events\PostUnpublished;
use App\Events\PostDestroyed;
class PostEventProcessor
{
/**
* @param $post
* @param $type
*/
public function start($post, $type)
{
switch($type) {
case 'create':
PostCreated::dispatch($post);
QueuePostForReview::dispatch($post);
UpdatePostSchedule::dispatch($post);
case 'update':
PostUpdated::dispatch($post);
QueuePostForReview::dispatch($post);
UpdatePostSchedule::dispatch($post);
case 'publish':
PostPublished::dispatch($post);
case 'unpublish':
PostUnpublished::dispatch($post);
QueuePostForReview::dispatch($post);
UpdatePostSchedule::dispatch($post);
case 'destroy':
PostDestroyed::dispatch($post);
default:
throw new Exception(__('processEventRequest.error'), 1);
}
}
}
<?phpnamespace App\Http\Controllers\Post;//core
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
//model
use App\Models\Post;
//requests
use App\Http\Requests\Post\PostFormRequest;
//processor
use App\Processor\Post\PostProcessor;
use App\Processor\Post\PostEventProcessor;
class PostController extends Controller
{
/**
* Display all posts
*
* @return View
*/
public function index(): View
{
return view('post.index');
}
/**
* Show the form to create a new post
*
* @return View
*/
public function create(): View
{
return view('post.create');
}
/**
* Store a newly created post in the database
*
* @param StorePostRequest $request
* @return RedirectResponse
*/
public function store(StorePostRequest $request): RedirectResponse
{
try {
$post = PostProcessor::start($request->validated(), 'create');
PostEventProcessor::start($post, 'create');
return redirect()
->route('posts.show', ['post' => $post])
->with('success', __('post.create.success'));
} catch (\Exception $e) {
return redirect()
->route('posts.index')
->with('error', __('post.create.error'));
}
}
/**
* Display a specific post
*
* @param Post $post
* @return View
*/
public function show(Post $post): View
{
return view('post.show', ['post' => $post]);
}
/**
* Show the form to edit a specific post
*
* @param Post $post
* @return View
*/
public function edit(Post $post): View
{
return view('post.update', ['post' => $post]);
}
/**
* Update a specific post in the database
*
* @param UpdatePostRequest $request
* @param Post $post
* @return RedirectResponse
*/
public function update(PostFormRequest $request, Post $post): RedirectResponse
{
try{
$updatedPost = PostProcessor::start($request->validated(), 'update');
PostEventProcessor::start($updatedPost, 'update');
return redirect()
->route('posts.show', ['post' => $updatedPost->id])
->with('success', __('post.update.success'));
} catch (\Exception $e) {
return redirect()
->route('posts.index')
->with('success', __('post.update.error'));
}
}
/**
* SoftDeletes Post from Database
*
* @param Post $post
* @return RedirectResponse
*/
public function unpublish(Post $post): RedirectResponse
{
try{
PostProcessor::start($post, 'unpublish');
PostEventProcessor::start($post, 'unpublish');
return redirect()
->route('posts.index')
->with('success', __('post.unpublish.success'));
} catch (\Exception $e) {
return redirect()
->route('posts.index')
->with('error', __('post.unpublish.error'));
}

}
/**
* Recovers Post from SoftDelete
*
* @param $post
* @return RedirectResponse
*/
public function publish($post): RedirectResponse
{
$post = Post::withTrashed()->where('id', $post)->first();
try{
PostProcessor::start($post, 'publish');
PostEventProcessor::start($post, 'publish');
return redirect()
->route('posts.index')
->with('success', __('post.publish.success'));
} catch (\Exception $e) {
return redirect()
->route('posts.index')
->with('error', __('post.publish.error'));
}

}
/**
* Permanently deletes post from the database
*
* @param $post
* @return RedirectResponse
*/
public function destroy($post): RedirectResponse
{
$post = Post::withTrashed()->where('id', $post)->first();
try{
PostEventProcessor::start($post, 'destroy');
PostProcessor::start($post, 'destroy');
return redirect()
->route('posts.index')
->with('success', __('post.destroy.success'));
} catch (\Exception $e) {
return redirect()
->route('posts.index')
->with('error', __('post.destroy.error'));
}

}
}

--

--

--

I am a web designer and developer. I like to play the piano, write, and pet dogs. Coffee lover, gaybro, nerd. In no particular order. (garrettmassey.net)

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Nudges, Devops and getting people to do the Right Thing

Two urinals side by side with small fly drawing

Local MS-SQL Server 2019 with Docker, Microsoft SQL Server Management Studio for Data Base Setup

Autonomy, architecture and agile

Multiplayer AR with RealityKit — What Went Wrong??

Ten years of testing htaccess rewrite rules

The Secrets Revealed from ITIL V4

Hey TypeScript, where’s my I-prefixed interface!

7 Tips to Help Startups Hire Developers

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Garrett Massey

Garrett Massey

I am a web designer and developer. I like to play the piano, write, and pet dogs. Coffee lover, gaybro, nerd. In no particular order. (garrettmassey.net)

More from Medium

How To Define Laravel 9 Global or Constant Variables

How To Define Laravel 9 Global or Constant Variables

Laravel 9 One To One Relationship Example

PHP’s RESTful Life

Message Processing in PHP — Symfony Messenger, Laravel Queues and Ecotone