Laravel API validation (different rules depending on route) - php

I'm currently using Laravel with Infyom to build a backend, one thing that I'm not understanding is how to have multiple rules for validation depending on the API route, for instance, when I'm creating a user, both fields email and role should be provided to the endpoint, but when updating the user (due to login), only the email and password is required to be present. What I want is to have a different set o rules depending on the endpoint being used, is that possible and how? Currently, the endpoint always returns
{
"message": "The given data was invalid.",
"errors": {
"role": [
"The role field is required."
]
}
}
my routes/api.php looks like this
<?php
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('login', 'TokenAPIController#loginUser');
Route::put('login/updateToken/{id}', 'TokenAPIController#updateToken');
Route::resource('users', 'UserAPIController');
Route::resource('roles', 'RoleAPIController');
Route::resource('roles', 'roleAPIController');
Route::resource('product_variants', 'Product_variantAPIController');
Route::resource('product_images', 'Product_imageAPIController');
Route::resource('product_categories', 'Product_categoryAPIController');
Route::resource('products', 'ProductAPIController');
Route::resource('orders', 'OrderAPIController');
Route::resource('order_products', 'Order_productAPIController');
Route::resource('notifications', 'NotificationAPIController');
Route::resource('factories', 'FactoryAPIController');
Route::resource('statuses', 'StatusAPIController');
My user app/Models/User.php
<?php
namespace App\Models;
use Eloquent as Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
public $table = 'users';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'name',
'role',
'email',
'password',
'remember_token',
'notification_token',
'factory',
'api_token'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'name' => 'string',
'role' => 'integer',
'email' => 'string',
'password' => 'string',
'remember_token' => 'string',
'notification_token' => 'string',
'factory' => 'integer',
'api_token' => 'string'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
'role' => 'required',
'email' => 'required'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function role()
{
return $this->belongsTo(\App\Models\Role::class, 'role');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function factory()
{
return $this->belongsTo(\App\Models\Factory::class, 'factory');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function orders()
{
return $this->hasMany(\App\Models\Order::class, 'customer');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function order1s()
{
return $this->hasMany(\App\Models\Order::class, 'responsible');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function notifications()
{
return $this->hasMany(\App\Models\Notification::class, '"from"');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function notification2s()
{
return $this->hasMany(\App\Models\Notification::class, '"to"');
}
}
And finally, my TokenAPIController.php
<?php
namespace App\Http\Controllers\API;
use App\Http\Requests\API\CreateUserAPIRequest;
use App\Http\Requests\API\UpdateUserAPIRequest;
use App\Models\User;
use App\Repositories\UserRepository;
use Illuminate\Http\Request;
use App\Http\Controllers\AppBaseController;
use Response;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
class TokenAPIController extends AppBaseController
{
/** #var UserRepository */
private $userRepository;
public function __construct(UserRepository $userRepo)
{
$this->userRepository = $userRepo;
}
public function loginUser(UpdateUserAPIRequest $request)
{ /** #var User $user */
$input = $request->all();
if (!isset($input['email'])) {
return $this->sendError('Email is required');
}
if (!isset($input['password'])) {
return $this->sendError('Password is required');
}
$user = User::where('email', $input['email'])
->first();
if (empty($user)) {
return $this->sendError('User not found');
}
$validCredentials = Hash::check($input['password'], $user["password"]);
if ($validCredentials) {
return $this->updateToken($user["id"]);
}
return $this->sendError('No match');
}
public function updateToken($id)
{
// $input = $request->all();
/** #var User $user */
$user = $this->userRepository->find($id);
if (empty($user)) {
return $this->sendError('User not found');
}
$token = Str::random(60);
$user->forceFill([
'api_token' => hash('sha256', $token),
])->save();
return $this->sendResponse($user->toArray(), 'User updated successfully');
}
}

Edit your App\Http\Requests\API\UpdateUserAPIRequest file and adjust the rules it returns from rules.

Related

Access restriction for users that are not admin and landlord

I am working on a laravel project. I want to restrict the api/property/create route so that only admins and landlord users can create property.However i am meeting a challenge in implementing this functionality.
Here is my route to create property
Route::group(['middleware' => ['auth:api', 'adminLandlord']], function() {
Route::post('/property/create', 'App\Http\Controllers\PropertyController#create')->name('createProperty');
});
Below is my AccountType Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AccountType extends Model
{
use HasFactory;
protected $name = [
1 => 'Admin',
2 => 'Landlord',
3 => 'Guest',
4 => 'Tenant',
5 => 'Service Provider',
];
const ADMIN = 1;
const LANDLORD = 2;
const GUEST = 3;
const TENANT = 4;
const SERVICEPROVIDER = 5;
public static function getAccountName($id) {
$name = [
1 => 'Admin',
2 => 'Landlord',
3 => 'Guest',
4 => 'Tenant',
5 => 'Service Provider',
];
return $name[$id];
}
public function user()
{
return $this->hasMany(User::class);
}
}
This is the User model
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name',
'last_name',
'account_type',
'email',
'password',
'phone_number'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
const ADMIN = 'Admin';
const LANDLORD = 'Landlord';
const GUEST = 'Guest';
const TENANT = 'Tenant';
const SERVICEPROVIDER = 'Service Provider';
// Get property(s) under a user
public function properties()
{
return $this->hasMany(Property::class);
}
public function roles()
{
return $this->hasOne(AccountType::class);
}
public function isAdmin()
{
return $this->account_type == 1; // this looks for an account_type column in the users table
}
public function isLandlord()
{
return $this->account_type;
}
public function isGuest()
{
return $this->account_type;
}
public function isTenant()
{
return $this->account_type;
}
public function isServiceProvider()
{
return $this->account_type;
}
}
Here is my adminLandlord middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use App\Models\AccountType;
class AdminLandlordMiddleware
{
/**
* The Guard implementation.
*
* #var Guard
*/
// protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
// public function __construct(Guard $auth)
// {
// $this->auth = $auth;
// }
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if(Auth::check() && !Auth::user()->isLandlord($this->getAccountTypeId('Landlord')) || !Auth::user()->isAdmin($this->getAccountTypeId('Admin'))){
// return $next($request);
return response()->json(['error_message' => 'Unauthorized action'], 403);
}
return $next($request);
}
public function getAccountTypeId($name)
{
$accountType = AccountType::where('name', $name)->first();
return $accountType->id;
}
}
I need to be able to pass the getAccountTypeId() to the isAdmin and isLandlord methods so as to get the accountTypeId which i will then use in the condition in the middleware. I tried it the way shown above but its not working out.
Thank you for the help.

Laravel JWT - Getting Unauthenticated with the valid login token

I am working on a simple JWT authentication system. User will get a token from login and when he passes the token, the user information will be given as the response. I have followed the procedure from: https://jwt-auth.readthedocs.io/en/develop/laravel-installation/ .
When I pass email and password to the login method I am able to get a token. But when I pass the token (to the me function) it returns 'Unauthorized'.
User Model:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
```````
api.php (Route)
`````
Route::group([
'middleware' => 'api',
'prefix' => 'auth'
], function ($router) {
Route::post('login', 'AuthController#login');
Route::post('logout', 'AuthController#logout');
Route::post('refresh', 'AuthController#refresh');
Route::post('me', 'AuthController#me');
});
````
AuthController
```
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\User;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
//return response()->json(User::all());
}
/**
* Get the authenticated User.
*
* #return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth()->user());
//return response()->json("hellllo");
}
/**
* Log the user out (Invalidate the token).
*
* #return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
*
* #return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
/**
* Get the token array structure.
*
* #param string $token
*
* #return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
```

Laravel 5 ResetsPasswords for JWTAuth

I am using JWT Authentication and I am trying to setup a Reset Password api functionality using ResetsPasswords.
I have created my own controller for reseting the password to use ResetsPasswords:
namespace App\Http\Controllers\v1;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Models\PdTlogin;
use App\Models\PdTprofessional;
use App\Models\PdTpatientPainkiller;
use App\Models\PdTprofessionalQualifcation;
use App\Models\PdTprofessionalSpeciality;
use Config;
use LbTtradesman_login;
use Auth;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
public function resetPassword(request $request)
{
return json_encode($this->reset($request));
}
public function __construct()
{
$this->middleware('guest');
}
}
And I am calling the reset function in ResetsPasswords, here is that full controller:
namespace Illuminate\Foundation\Auth;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;
trait ResetsPasswords
{
use RedirectsUsers;
/**
* Reset the given user's password.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function reset(Request $request)
{
//$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
/**
* Get the password reset validation rules.
*
* #return array
*/
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:6',
];
}
/**
* Get the password reset validation error messages.
*
* #return array
*/
protected function validationErrorMessages()
{
return [];
}
/**
* Get the password reset credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only(
'email', 'password', 'password_confirmation', 'token'
);
}
/**
* Reset the given user's password.
*
* #param \Illuminate\Contracts\Auth\CanResetPassword $user
* #param string $password
* #return void
*/
protected function resetPassword($user, $password)
{
$user->forceFill([
'password' => bcrypt($password),
'remember_token' => Str::random(60),
])->save();
$this->guard()->login($user);
}
/**
* Get the response for a successful password reset.
*
* #param string $response
* #return \Illuminate\Http\RedirectResponse
*/
protected function sendResetResponse($response)
{
return trans($response);
}
/**
* Get the response for a failed password reset.
*
* #param \Illuminate\Http\Request
* #param string $response
* #return \Illuminate\Http\RedirectResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{
return ['email' => trans($response)];
}
/**
* Get the broker to be used during password reset.
*
* #return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('pd_tlogin');
}
/**
* Get the guard to be used during password reset.
*
* #return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard();
}
}
But when I run everything, my password does not get updated. Instead I get this error:
Type error: Argument 1 passed to
App\Http\Controllers\v1\ResetPasswordController::resetPassword() must
be an instance of Illuminate\Http\Request, instance of App\User given,
called in
/var/www/html/my_project/vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php
on line 45
I really don't understand this error or what I am doing wrong :( All I know is that my User model is App\Models\PdTlogin with the database table name of pd_tlogin
UPDATE
I have also tried this:
public function resetPassword(request $request)
{
$this->validate($request, [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed',
]);
$credentials = $request->only(
'email', 'password', 'password_confirmation', 'token'
);
$response = $this->passwords->reset($credentials, function($user, $password) {
$user->password = bcrypt($password);
$user->save();
$this->auth->login($user);
});
return json_encode($response);
}
But I got this error:
Undefined property:
App\Http\Controllers\v1\ResetPasswordController::$passwords',
'/var/www/html/my_project/app/Http/Controllers/v1/ResetPasswordController.php
You are invoking resetPassword of the ResetPasswordController instead of invoking resetPassword of the ResetPasswords trait. Change the resetPassword function name in your controller or use an alias for the trait resetPassword function like this:
use ResetsPasswords
{
resetPassword as protected resetUserPassword;
}
Well, It seems you need a json resonse from the reset method. Modify your ResetPasswordController as,
<?php
namespace App\Http\Controllers\v1;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
//...
class ResetPasswordController extends Controller
{
use ResetsPasswords;
protected function sendResetResponse($response)
{
return response()->json(['success' => trans($response)]);
}
protected function sendResetFailedResponse(Request $request, $response)
{
return response()->json(['error' => trans($response)], 401);
}
// removed min:6 validation
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed',
];
}
public function __construct()
{
$this->middleware('guest');
}
}
And point your reset route to ResetPasswordController#reset.
return response()->json(['message'=> __('labels.password_updated')]);

Laravel 5.3 dynamically binding validator to custom form request

I'm developing in a system using Laravel 5.3 and I"m trying to update custom validation rules. The architecture is currently as follows:
ProfileStoreRequest --> ProfileValidator
ClientStoreRequest --> ClientValidator
...
What I'm basically trying to do here is to have only one object named "StoreRequest" which will call the correct validator depending on the route which is being called. Here's what I have so far:
In my routes:
Route::group([
'prefix' => 'manage',
'namespace' => 'Manage',
'validators' => [
'manage.profile.storeAjax' => [
'name' => "required|max:40",
'color' => "integer|digits_between:0,7",
'service' => "integer", //digits_between:3,10
'company_id' => "required|integer|exists:companies,id,deleted_at,NULL",
'site_id' => "integer|siteIdExists"
]
]], function () {
Route::post('/site/storeAjax', 'SiteController#storeAjax')->name('manage.site.storeAjax');
Route::post('/company/storeAjax', 'CompanyController#storeAjax')->name('manage.company.storeAjax');
Route::post('/employee/store', 'EmployeeController#store')->name('manage.employee.store');
Route::post('/employee/addProfile', 'EmployeeController#addProfile')->name('manage.employee.addProfile');
Route::post('/employee/removeProfile', 'EmployeeController#removeProfile')->name('manage.employee.removeProfile');
Route::post('/employee/addSite', 'EmployeeController#addSite')->name('manage.employee.addSite');
Route::post('/employee/removeSite', 'EmployeeController#removeSite')->name('manage.employee.removeSite');
Route::post('/message/storeAjax', 'MessageController#storeAjax')->name('manage.message.storeAjax');
Route::post('/profile/storeAjax', 'ProfileController#storeAjax')->name('manage.profile.storeAjax');
Route::post('/timeEntry/storeAjax', 'TimeEntryController#storeAjax')->name('manage.timeEntry.storeAjax');
});
Next is my StoreRequest:
namespace App\Http\Requests;
use App\Http\Validators\ProfileValidator;
use Auth;
//use App\Model\TimeEntry;
use DateUtil;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
class StoreRequest extends AbstractRequest {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
// prj(__METHOD__);
$authorized = parent::authorize();
if ($authorized) {
$user = Auth::user();
if ($user && $user->can('write')) {
return true;
} else {
return false;
}
}
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
parent::rules();
return $this->route()->getAction()['validators'][$this->route()->getName()];
}
/**
* User messages
*
* #return array
*/
public function messages() {
$messages = array_merge(parent::messages(), [
'exists' => 'The selected :attribute is invalid for this time entry id.'
]);
return $messages;
}
public function validate()
{
parent::validate();
}
}
And of course, all of my custom validators are registered using service providers (here's an example with a profileValidator):
profileServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class ProfileServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
Validator::extend('siteIdExists', 'App\Http\Validators\ProfileValidator#validateSiteIdExists');
}
/**
* Register any application services.
*
* #return void
*/
public function register() {
//
}
}
ProfileValidator.php
namespace App\Http\Validators;
use App\Model\Site;
use Mockery\Exception;
class ProfileValidator
{
public function validateSiteIdExists($attribute, $value, $parameters, $validator)
{
if ($value == -1)
return true;
else
{
return Site::where(
[
['id', '=', $value],
['company_id', '=', $validator->getData()['company_id']]
]
)->whereNull('deleted_at')->exists();
}
}
}
So basically, my StoreRequest is capable of loading its validation rules from the route... however, no matter how hard I try, I can't figure how to bind the validator I want. Can anyone help me?

Trying to get property of non-object in Laravel Function

I'm making a function that each time I add a comment to an RMA Ticket it sends an email to the user but I'm getting Trying to get property of non-object when I submit the comment
Below I pasted the code from the CommentController and the Email function
if you want more information just ask and i will post what i could
I'm getting the error on this code - $mailer->sendRmaTicketComments($comment->ticket->user, Auth::user(), $comment->ticket, $comment);
CommentController Code
<?php
namespace App\Http\Controllers\Rma;
use Auth;
use App\User;
use App\Rma\RmaTicket;
use App\Rma\RmaComments;
use App\Mailers\AppMailer;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class RmaCommentController extends Controller
{
public function postComment(Request $request, AppMailer $mailer)
{
$this->validate($request, [
'comment' => 'required',
'user_id' => 'required',
]);
$comment = RmaComments::create([
'rma_ticket_id' => $request->input('ticket_id'),
'user_id' => $request->input('user_id'),
'comment' => $request->input('comment'),
]);
$mailer->sendRmaTicketComments($comment->ticket->user, Auth::user(), $comment->ticket, $comment);
return redirect()->back()->with('successPanel', 'Thank you for your message please allow up to 48 hours for a response.');
}
}
Mail Function Code
<?php
namespace App\Mailers;
use App\Rma\RmaTicket;
use App\Rma\RmaStatus;
use App\SupportTickets\SupportTicket;
use App\SupportTickets\SupportTicketStatus;
use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Support\Facades\Mail;
class AppMailer
{
protected $mailer;
/**
* Get the email address
*
* #var [type]
*/
protected $to;
/**
* Set the subject for the email
*
* #var [type]
*/
protected $subject;
/**
* Set the template for the email
*
* #var [type]
*/
protected $view;
/**
* Set the data for the email
*
* #var array
*/
protected $data = [];
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
/**
* Send RMA Comments/Replies to RMA Owner
*
* #param User $ticketOwner
* #param User $user
* #param rmaTicket $rmaTicket
* #param Comment $comment
*
* #return method delivered()
*/
public function sendRmaTicketComments($ticketOwner, $user, RmaTicket $rmaTicket, $comment)
{
$this->to = $ticketOwner->email;
$this->subject = "RE[RMA Ticket # $rmaTicket->rma_ticket_id]";
$this->view = 'emails.rma.rma_comments';
$this->data = compact('ticketOwner', 'user', 'rmaTicket', 'comment');
return $this->deliver();
}
RmaComments Model
<?php
namespace App\Rma;
use Illuminate\Database\Eloquent\Model;
class RmaComments extends Model
{
protected $table = 'rma_comments';
protected $fillable = [
'rma_ticket_id', 'user_id', 'comment'
];
public function ticket()
{
return $this->belongsTo(RmaTicket::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
RMA Model
<?php
namespace App\Rma;
use Illuminate\Database\Eloquent\Model;
class RmaTicket extends Model
{
protected $table = 'rma_tickets';
protected $fillable = [
'user_id', 'rma_ticket_id', 'first_name', 'last_name',
'email', 'fax', 'company', 'marketplace_id', 'returnTypeId',
'product_name', 'quantity', 'order_number', 'address_one',
'address_two', 'city', 'state', 'zip_code', 'sku', 'model_number', 'comment',
'status_id', 'rma_number', 'refund_number', 'return_tracking_number',
'replacement_number', 'return_label'
];
public function returnType()
{
return $this->belongsTo(RmaReturnType::class);
}
public function marketplace()
{
return $this->belongsTo(RmaMarketplace::class);
}
public function status()
{
return $this->belongsTo(RmaStatus::class);
}
public function comments()
{
return $this->hasMany(RmaComments::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Looking at your code and since you have null if you dd($comment->ticket) i believe it's the naming of your foreign keys.
your belongsTo:
public function ticket()
{
return $this->belongsTo(RmaTicket::class);
}
expects an ticket_id but you named it rma_ticket_id.
You could specify a different foreign key name in the second argument in the belongTo relationship
public function ticket()
{
return $this->belongsTo(RmaTicket::class, 'rma_ticket_id');
}
As per the docs:
. Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with _id. However, if the foreign key on the Phone model is not user_id, you may pass a custom key name as the second argument to the belongsTo method:

Categories