Let\'s say whenever I do a CRUD operation or modify a relationship in a specific way I also want to do something else. E.g., whenever someone publishes a post I also want to
In my opinion, Laravel already has many options for you to store your business logic.
Short answer:
Request
objects to automatically validate your input, and then persist the data in the request (create the model). Since all of the users input is directly available in the request, I believe it makes sense to perform this here.Job
objects to perform tasks that require individual components, then simply dispatch them. I think Job
's encompass service classes. They perform a task, such as business logic.Long(er) answer:
Use Respositories When Required:
Repositories are bound to be overbloated, and most of the time, are simply used as an accessor
to the model. I feel like they definitely have some use, but unless you're developing a massive application that requires that amount of flexibility for you to be able to ditch laravel entirely, stay away from repositories. You'll thank yourself later and your code will be much more straight forward.
Ask yourself if there's a possibility that you're going to be changing PHP frameworks or to a database type that laravel doesn't support.
If your answer is "Probably not", then don't implement the repository pattern.
In addition to above, please don't slap a pattern on top of a superb ORM like Eloquent. You're just adding complexity that isn't required and it won't benefit you at all.
Utilize Services sparingly: Service classes to me, are just a place to store business logic to perform a specific task with its given dependencies. Laravel has these out of the box, called 'Jobs', and they have much more flexibility than a custom Service class.
I feel like Laravel has a well-rounded solution for the MVC
logic problem. It's just a matter or organization.
Example:
Request:
namespace App\Http\Requests;
use App\Post;
use App\Jobs\PostNotifier;
use App\Events\PostWasCreated;
use App\Http\Requests\Request;
class PostRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required',
'description' => 'required'
];
}
/**
* Save the post.
*
* @param Post $post
*
* @return bool
*/
public function persist(Post $post)
{
if (!$post->exists) {
// If the post doesn't exist, we'll assign the
// post as created by the current user.
$post->user_id = auth()->id();
}
$post->title = $this->title;
$post->description = $this->description;
// Perform other tasks, maybe fire an event, dispatch a job.
if ($post->save()) {
// Maybe we'll fire an event here that we can catch somewhere else that
// needs to know when a post was created.
event(new PostWasCreated($post));
// Maybe we'll notify some users of the new post as well.
dispatch(new PostNotifier($post));
return true;
}
return false;
}
}
Controller:
namespace App\Http\Controllers;
use App\Post;
use App\Http\Requests\PostRequest;
class PostController extends Controller
{
/**
* Creates a new post.
*
* @return string
*/
public function store(PostRequest $request)
{
if ($request->persist(new Post())) {
flash()->success('Successfully created new post!');
} else {
flash()->error('There was an issue creating a post. Please try again.');
}
return redirect()->back();
}
/**
* Updates a post.
*
* @return string
*/
public function update(PostRequest $request, $id)
{
$post = Post::findOrFail($id);
if ($request->persist($post)) {
flash()->success('Successfully updated post!');
} else {
flash()->error('There was an issue updating this post. Please try again.');
}
return redirect()->back();
}
}
In the example above, the request input is automatically validated, and all we need to do is call the persist method and pass in a new Post. I think readability and maintainability should always trump complex and unneeded design patterns.
You can then utilize the exact same persist method for updating posts as well, since we can check whether or not the post already exists and perform alternating logic when needed.