i’m working on a Laravel 9 API project whereby I have the following models:
- Buyer
- BuyerTier
- BuyerTierOption
And each relate to one another, e.g: Buyers have BuyerTiers, and BuyerTiers have BuyerTierOtpions.
I’ve encountered a slight problem with the default Laravel validation whereby my URL already contains the buyer ID that I want to create a new tier for, but I need to make sure this ID not only exists, but belongs to my company.
How I’d get around this is to create a field in my request called buyer_id
and create a custom rule like ValidModelOwnership
which validates the ID and company, but I feel like Laravel should be able to do this as it’s in the URL, what am I missing:
/**
* Store a newly created resource in storage.
*
* @param IlluminateHttpRequest $request
* @return IlluminateHttpResponse
*/
public function store($company_id, $buyer_id, Request $request)
{
$this->authorize('create', BuyerTier::class);
$validator = Validator::make($request->all(), [
'name' => [
'required',
'string',
Rule::unique(BuyerTier::class)
->where('buyer_id', $buyer_id)
->where('company_id', $company_id)
],
'buyer_id' => [
'required',
'numeric|min:50',
new ValidModelOwnership(Buyer::class, [
['company_id', $company_id],
['id', $request->input('buyer_id')]
])
],
'country_id' => [
'required',
'numeric',
new ValidModelOwnership(Country::class, [
['company_id', $company_id],
['id', $request->input('country_id')]
])
],
'product_id' => [
'required',
'numeric',
new ValidModelOwnership(Product::class, [
['company_id', $company_id],
['id', $request->input('product_id')]
])
],
'processing_class' => 'required|string|alpha_num',
'is_default' => [
'required',
'boolean',
new ValidDefaultModel(BuyerTier::class, $buyer_id)
],
'is_enabled' => 'required|boolean'
]);
if ($validator->fails()) {
return response()->json([
'message' => 'One or more fields has been missed or is invalid.',
'errors' => $validator->messages(),
], 400);
}
try {
$tier = new BuyerTier;
$tier->user_id = Auth::id();
$tier->company_id = $company_id;
$tier->buyer_id = $buyer_id;
$tier->country_id = $request->input('country_id');
$tier->product_id = $request->input('product_id');
$tier->name = trim($request->input('name'));
$tier->description = $request->input('description') ?? null;
$tier->processing_class = $request->input('processing_class');
$tier->is_default = $request->boolean('is_default');
$tier->is_enabled = $request->boolean('is_enabled');
$tier->save();
return response()->json([
'message' => 'Buyer tier has been created successfully',
'tier' => $tier
], 201);
} catch (Exception $e) {
return response()->json([
'message' => $e->getMessage()
], 400);
}
}
And I’m making a post request to:
- {{endpoint}}/api/company/1/buyers/1/tiers/
2
Answers
You can do this using
Route-Model Binding
For checking the if the
buyer_id
exists you can useRoute-Model Bindings
:Route
Controller
Your post is a bit confusing and you do not provide data about all models relation mentioned in your post, but I just assume your
buyer
model has a relationship of belongsTocompany
model.And as I understand, you want to validate if the
$buyer_id
exists and owned by$company_id
that you pass as parameters on your route.First option, you could simply query the model and check for thier relation.
2nd options is to just merge the buyer id to your request then perform a rule to validate buyer id existance and related model owner