php - How to stop passing null to `__construct`
I have a Service
which is called inside a Controller
in a Laravel application. Usually these services are implemented using a composition pattern, where the service is injected in the __construct
of the controller; then, whenever it's necessary to use the service, you just call the service and the method you want. If you want to create a new register on the database, you just need to call the service, the method, and pass the necessary parameters to that method.
But let's say I don't want to pass parameters. I want an immutable, zero-parameter object. I have tried to implement this in the code bellow (first there's the service and then the controller where the service is called). Notice I have all the parameters I'd need to pass to each method in the constructor of my service. This produces what I want: an immutable, zero-parameter object.
But there's a problem: it's not in every call of the service that I need all the parameters in the constructor (not every method used needs them), that's why they're typed as a [any type]|null. This seems wrong, because if I don't need all the parameters to construct my object, maybe it should be another object altogether. I don't have a problem with small classes (I like it, actually), but it seems just too much to have a CreateCmsUserService
, UpdateCmsUserService
, DeleteCmsUserService
.
I'd like to know if there's an elegant solution for this constructor with null or if the only way to go is dividing the class.
<?php
namespace App\Services;
use App\Models\User;
use Exception;
use Illuminate\Support\Facades\Hash;
use App\Interfaces\CRUD;
class CmsUsersService implements CRUD
{
private ?int $user_id;
private ?array $data;
private ?string $users_to_be_deleted;
public function __construct(?array $data, ?int $user_id, ?string $users_to_be_deleted)
{
$this->user_id = $user_id;
$this->data = $data;
$this->users_to_be_deleted = $users_to_be_deleted;
}
public function create()
{
$this->data['token'] = Hash::make($this->data['email']);
$this->data['password'] = Hash::make($this->data['password']);
User::create($this->data);
return cms_response(trans('cms.users.success_create'));
}
public function update()
{
try {
if (array_key_exists('password', $this->data)) {
$this->data['password'] = Hash::make($this->data['password']);
}
$user = $this->__findOrFail();
$user->update($this->data);
return cms_response(trans('cms.users.success_update'));
} catch (\Throwable $th) {
return cms_response($th->getMessage(), false, 400);
}
}
public function delete()
{
User::whereIn('id', json_decode($this->users_to_be_deleted))->delete();
return cms_response(trans('cms.users.success_delete'));
}
private function __findOrFail()
{
$user = User::find($this->user_id);
if ($user instanceof User) {
return $user;
}
throw new Exception(trans('cms.users.error_user_not_found'));
}
}
<?php
namespace App\Http\Controllers\Cms;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserRequest;
use App\Services\CmsUsersService;
use Illuminate\Http\Request;
class UsersController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(UserRequest $request)
{
$users_service = new CmsUsersService($request->all(), null, null);
$result = $users_service->create();
return redirect()->back()->with('message', $result);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(UserRequest $request, $id)
{
$users_service = new CmsUsersService($request->all(), $id, null);
$result = $users_service->update();
return redirect()->back()->with('message', $result);
}
/**
* Remove the specified resource from storage.
*
* @param string $users_id
* @return \Illuminate\Http\Response
*/
public function destroy($users_id)
{
$users_service = new CmsUsersService(null, null, $users_id);
$result = $users_service->delete();
return redirect()->back()->with('message', $result);
}
}
Answer
Solution:
You could give parameters a default value, like so:
public function __construct(?array $data = [], ?int $user_id = null, ?string $users_to_be_deleted = null)
{
$this->user_id = $user_id;
$this->data = $data;
$this->users_to_be_deleted = $users_to_be_deleted;
}
Now you can use this:
$users_service = new CmsUsersService();
Source