I am making a web service in Laravel which is returning JSON.
I have created an Account model like so:
class Account extends Eloquent {
// The database table used by the model.
// (If not defined then lowercase and plural of class name is consider as a table name)
protected $table = "account";
// define which column can be mass assign
protected $fillable = array("user_id", "account_group_id", "generated_by", "image", "name",
"address", "zip", "area_id", "mobile", "email", "phone", "fax",
"website", "pan", "cst", "tin", "ecc", "iesc", "transport",
"other", "outstanding", "cform", "status", "mitp");
// To prevent column from mass assignment.
protected $guarded = array('id');
// Change Variable for CREATED_AT and UPDATED_AT
const CREATED_AT = 'itp';
const UPDATED_AT = 'utp';
}
I am fetching fields from Account using user_id and returning JSON via Response::json() in my controller
$accountData = Account::select('name', 'status', 'id', 'user_id', 'utp')->where('user_id', Auth::id())->first();
$return = array(
'result' => 'success',
'msg' => 'Login Successfully.',
'data' => $accountData
);
return Response::json($return);
In this, utp behaves as expected and returns a date as a string:
{
"result": "success",
"msg": "Login Successfully.",
"data": {
"name": "Demo",
"status": 0,
"id": 143,
"user_id": 207,
"utp": "2015-07-01 18:38:01"
}
}
However if I take each value separately from the account model like so:
$return = array(
'result' => 'success',
'msg' => 'Login Successfully.',
'data' => $accountData['user_id'],
'account_id' => $accountData['id'],
'utp' => $accountData['utp'],
'usertype' => 'account',
'status' => $accountData['status']
);
Then this gives some unexpected behavior from utp
{
"result": "success",
"msg": "Login Successfully.",
"data": 207,
"account_id": 143,
"utp": {
"date": "2015-07-01 18:38:01",
"timezone_type": 3,
"timezone": "Asia\\/Kolkata"
},
"usertype": "account",
"status": 0
}
Why does this happen with my timestamp field?
Because utp is a Carbon\Carbon instance. Model::toJson (actually Model::toArray, but both are used) handles that usually, and serializes a date to it's usual ISO3601-ish format
For expected behavior, you need to format the Carbon instance.
"utp" => $accountData['utp']->format("Y-m-d H:i:s"),
Alternatively, cast it to a string
"utp" => (string) $accountData['utp'],
Related
Role model relation
public function companies()
{
return $this->belongsToMany(Company::class);
}
User model standart role relation
public function roles(): BelongsToMany
{
return $this->morphToMany(
config('permission.models.role'),
'model',
config('permission.table_names.model_has_roles'),
config('permission.column_names.model_morph_key'),
'role_id'
);
}
add to User model
public function roleCompanies()
{
return $this->roles()->with('companies');
}
Now i see in logging data i need
...
"App\\Models\\User": {
...
"role_companies": [
{
"id": 1,
"name": "administrator",
....
},
"companies": [
{
"id": 1,
"name": "Company name"
but how can i output role_companies - companies - name in backpack field like that(this actual doesnt work):
UserCrudController
...
$this->crud->addColumns([
...
[
'type' => 'relationship',
'name' => 'roleCompanies',
'attribute' => 'companies.name',
],
Is there any native method to do that. Or i need to create custom backpack field?
I got a query that gets the data into a collection, problem is that it shows foreign id but i want it to display what i have given in the url parameters.
columnsGiven is the parameter from url. contains column names with child: "language.name". so column=active,title,language.name
For example i get this:
"name": "george",
"active": 1,
"language": 1,
and this is what i want:
"name": "george",
"active": 1,
"language": "Dutch",
this is my code:
public function index(Request $request){
$columnsGiven = explode(',', $request->columns);
$tableName = $request->table_name; //example: 'support_guide_translations'
$modelName = $request->model_name; //example: "App\Models\SupportGuideTranslation";
if($request->search){
$query = $modelName::search($request->search);
} else{
$query = $modelName::query();
if($request->sort){
$sort = explode('?', $request->sort);
$query->orderBy($sort[0], $sort[1]);
}
}
foreach ($request->query() as $key => $value) {
// dd($value);
if(!$value == ""){
if(Schema::hasColumn($tableName, $key)){
$query->where($key, $value);
}
if(in_array($key, $columnsGiven)){
dd('true');
}
// $searchWord = Str::contains('account123',$request->search);
}
}
$guides = $query->get();
return GuideResource::collection($guides);
}
}
this is GuideResource, it sends data to vue by making it json first. Not allowed to make changes here, it has to be done in the function index. :
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'body' => $this->body,
'active' => $this->active,
'language' => $this->language,
'support_guide' => $this->support_guide,
'support_guide_group' => $this->support_guide_group,
];
}
"language": {
"id": 1,
"name": "Dutch",
"code": "NL",
"created_at": "2021-06-14T10:10:32.000000Z",
"updated_at": "2021-06-14T10:10:32.000000Z"
},
I believe "language" has a relationship with another model.
Isn't this what you are looking for?
return [
// your other attributes...
'language' => $this->language->relationshipName->name,
];
where relationshipName is the method name in the Language model.
For testing reasons, I want to make the following Post Request with the Laravel HTTP Client:
$test = Http::post(route('users.leads.store', ['user' => $user->id]), [
"company_name" => "TESTCOMPANY",
"zip" => "49685",
"city" => "BÜHREN",
"street" => "MÜHLENKAMP 3",
"contact_name" => "FABIANLUKASSEN",
"phone1" => "017691443785",
"email" => "FABIANLUKASSEN#TESTEN.DE",
"website" => "www.fabianlukassen.de",
"category" => "Hotel",
"closed_until" => now(),
"appointment_end" => now()->addDays(1),
"appointment_comment" => "HALLO ICH BIN FABIAN",
"additional_contacts" => "",
"phone2" => "",
"sub_category" => "",
"expert_status" => 0
]);
I know that the route is working just fine. However, with debugging in phpStorm, I can see that the $test variable contains a 419 error (unknown status). Does anyone know what's wrong?
(I'm using laravel 8)
I agree with #ElektaKode that the issue is likely due to lack of csrf token.
In order to disable CSRF middleware while testing,
switch off CSRF token for this route at /app/Http/Midddleware/VerifyCsrfToken.php, by updating:
protected $except = [ 'your-route-url' ];
Then you can use api authentication to follow it up.
The simplest way to use api authentication, follow this doc,
The other ways are either using Laravel passport or using jwt for api.(both will consume more time to set up, as you are using for testing using api authentication is your go to method.)
Usually in Laravel, 419 Page Expired error comes from CSRF middleware meaning there was a failure while validating CSRF token. Add your CSRF token to your test request or consider disabling CSRF middleware while testing.
Post Request with Laravels HTTP Client
$test = Http::post(route('users.leads.store', ['user' => $user->id]), [
"company_name" => "TESTCOMPANY",
"place_id" => null,
"street" => "MÜHLENKAMP 3",
"zip" => "49685",
"city" => "BÜHREN",
"title" => null,
"contact_name" => "FABIANLUKASSEN",
"additional_contacts" => null,
"phone1" => "+49 163 3006603",
"phone2" => null,
"email" => "FABIANLUKASSEN#TESTEN.DE",
"category" => "Hotel",
"sub_category" => null,
"website" => "www.fabianlukassen.de",
"status" => 1,
"expert_status" => 0,
"coordinates" => null,
"expert_id" => 1,
"agent_id" => null,
"blocked" => 0,
"important_note" => null,
]);
Route
Route::apiResource('users.leads', UserLeadController::class);
Store Method in the UserLeadController
public function store(User $user, CreateLeadRequest $request)
{
//TODO: Relocate validation to request class
if(!UserLeadController::isPhone("test", $request->phone1)) {
abort(400, "Keine gültige Telefonnummer!");
return;
}
if(!UserLeadController::isPhoneNumberUnique("test", $request->phone1)) {
abort(400, "Die Telefonnummer existiert bereits!");
return;
}
/**
* The logged in User
* #var User $agent
*/
$agent = Auth::user();
$phoneUtil = PhoneNumberUtil::getInstance();
$lead = new Lead();
$lead->fill($request->except(['appointment_end', 'appointment_comment']));
// Leads created by experts will be blocked
if ($user->id === $agent->id) {
$lead->blocked = true;
}
$numberProto = $phoneUtil->parse($lead->phone1, 'DE');
$lead->phone1 = $phoneUtil->format($numberProto, PhoneNumberFormat::INTERNATIONAL);
try {
$lead->save();
} catch (QueryException $e) {
//$message = 'Lead besteht bereits.';
//return Response::json(['errors' => $message], 422);
abort(422, "Lead besteht bereits!");
return;
}
if ($request->closed_until) {
$lead->closed_until = Carbon::create($request->closed_until);
$event_end = $request->appointment_end
? Carbon::parse($request->appointment_end)
: Carbon::parse($request->closed_until)->addMinutes(90);
$lead->calendarEvents()->save(new CalendarEvent([
'body' => $request->appointment_comment ?? "Wurde von {$this->roleDescriptor($agent->roles)}" . $agent->name . " angelegt.",
'type' => CalendarEventType::CALLCENTER_APPOINTMENT,
'event_begin' => $lead->closed_until,
'event_end' => $event_end,
]));
$lead->status = LeadState::APPOINTMENT;
$lead->expert_status = LeadExpertAcceptance::ACCEPTED;
} else {
$lead->status = LeadState::OPEN;
}
if (isset($request->agent)) {
$lead->agent_id = $request->agent;
}
try {
$user->leads()->save($lead);
$lead->comments()->save(new Comment([
'body' => "Wurde von {$this->roleDescriptor($agent->roles)}" . $agent->name . " angelegt.",
'user_id' => $agent->id,
'commentable_type' => 'lead',
'commentable_id' => $lead->id,
'reason' => 'CREATED',
'date' => now('Europe/Berlin'),
]));
if ($request->closed_until) {
$lead->comments()->save(new Comment([
'body' => "Termin wurde von {$this->roleDescriptor($agent->roles)}" . $agent->name . " vereinbart.",
'user_id' => $agent->id,
'commentable_type' => 'lead',
'commentable_id' => $lead->id,
'reason' => 'APPOINTMENT',
'date' => now('Europe/Berlin')->addMinute(),
]));
}
} catch (QueryException $e) {
//not sure if this works
$message = $e->getMessage();
abort(400, $message);
return;
}
if (empty($message)) {
return Response::json(['message' => 'Lead saved', 'lead' => new LeadSingleResource($lead)]);
} else {
return Response::json(compact('message'), 500);
}
}
//TODO: relocate function to rule object
protected static function isPhoneNumberUnique($attribute, $value) {
$withSpace = PhoneFormatter::formatInternational($value);
$withoutSpace = preg_replace('/ /', '', $withSpace);
$protos = [$withSpace, $withoutSpace]; // Necessary because legacy (25.06.2020).
$booleanTest = Company::query()->whereIn('phone', $protos)->doesntExist()
|| Lead::query()->whereIn('phone1', $protos)->orWhereIn('phone2', $protos)->doesntExist();
return $booleanTest;
}
//TODO: relocate function to rule object
protected static function isPhone($attribute, $value) {
if (!$value) {
return false;
}
$phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();
$test = $phoneUtil->isValidNumber($phoneUtil->parse($value, 'DE'));
return $test;
}
fillable variable in the Lead Model
protected $fillable = [
'company_name',
'place_id',
'street',
'zip',
'city',
'title',
'contact_name',
'additional_contacts',
'phone1',
'phone2',
'email',
'category',
'sub_category',
'website',
'status',
'expert_status',
'coordinates',
'expert_id',
'agent_id',
'blocked',
'important_note'
];
As mentioned before, I receive a 200 OK status. Also, in a Vue.js component, I have done the following axios post request, which also just works fine.
axios
.post(`/api/users/${this.user_id}/leads`, {
"company_name": this.companyName,
"zip": this.zipCode,
"city": this.city,
"street": this.streetAndHouseNumber,
"contact_name": this.contactPartner,
"phone1": this.contactPartnerPhoneNumber,
"email": this.contactPartnerEmail,
"website": this.website,
"category": this.category,
"closed_until": this.appointmentStart,
"appointment_end": this.appointmentEnd,
"appointment_comment": this.comment,
//not used but needed (don't know the purpose)
"additional_contacts": "",
"phone2": "",
"sub_category": "",
"expert_status":this.expert_status,
}).then(() => {
window.location.href = this.routeSuccess;
}).catch((error) => {
this.showErrorAlert = true;
this.errorAlertMessage = error.response.data.message;
});
}
Controller function:
public function index () {
// TESTED
// The getAllActiveSuppliers() function just return Supplier::pagniate(10)
$suppliers = $this -> model -> getAllActiveSuppliers();
return new SupplierResource($suppliers);
}
Returned Json:
{
"current_page": 1,
"data": [
{
"id": 23,
"name": "Test Name",
"description": "Test Description",
"created_by": {
"id": 1,
"name": "Test 1",
"email": "admin#admin.com",
"email_verified_at": null,
"active": 1,
"created_at": "2018-10-12 14:17:38",
"updated_at": "2018-10-12 14:17:38"
},
"updated_by": {
"id": 1,
"name": "Test 1",
"email": "admin#admin.com",
"email_verified_at": null,
"active": 1,
"created_at": "2018-10-12 14:17:38",
"updated_at": "2018-10-12 14:17:38"
},
"deleted_at": null,
"created_at": "2018-10-31 01:46:11",
"updated_at": "2018-11-02 22:05:14",
}
],
...
}
What I am trying to do:
In the created_by and updated_by I just want to show name, email nothing else.
What I have tried to do:
I have tried to create an API resource collection
Supplier.php API Resource Collection :
public function toArray($request)
{
return parent::toArray($request);
}
For anyone that may still need this as I was searching for myself in this topic
First create a resource for your relation with name, email fields
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'name' => $this->name,
'email' => $this->email,
];
}
}
Then create SupplierResource with relation created_by to User
class SupplierResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'created_by' => new UserResource($this->created_by)
];
}
}
In the Controller
public function index () {
$suppliers = $this->model->getAllActiveSuppliers();
return SupplierResource::collection($suppliers);
}
You first need to define a structure for a singular JsonResource object:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
...
'created_by' => $this->created_by->only('name', 'email'),
...
];
}
And then tell your ResourceCollection to use the class:
Customizing The Underlying Resource Class
Typically, the
$this->collection property of a resource collection is automatically
populated with the result of mapping each item of the collection to
its singular resource class. The singular resource class is assumed to
be the collection's class name without the trailing Collection
string.
For example, UserCollection will attempt to map the given user
instances into the User resource. To customize this behavior, you may
override the $collects property of your resource collection
(From https://laravel.com/docs/5.7/eloquent-resources#concept-overview)
If your ResourceCollection doesn't do anything extra, you might not need it. Every JsonResource can transform itself for a collection with the collection() method, e.g. JsonResource::collection($models)
Think we can add item to parent::toArray($request)
public function toArray($request)
{
$array = parent::toArray($request);
$array['created_by'] = $this->created_by->only('name', 'email');
return $array;
}
Hi i am trying to get the valid json response but i am not getting what i want my response is:
{
"status": "true",
"message": "Data Found!",
"data": {
"message_id": 25,
"sender_id": 15,
"body": "kaleem",
"subject": "Test",
"senderName": "Tester Techleadz",
"created_at": "2016-06-23 00:46:55"
}
}
we can see the message_id and sender_id are not in quotes as other values are in quotes i want to get the message_id and sender_id in quotes as well
My controller code is:
$id = $request->input('id');
$type = $request->input('type');
if($type == 'trash'){
$trash = MessagesRelationModel::leftjoin('messages','messages.id','=','messages_relation.message_id')
->leftjoin('users','users.id','=','messages.sender_id')
->leftjoin('contacts','users.contacts_id','=','contacts.id')
->where('messages.id' , $id)
->select('messages_relation.message_id','messages.sender_id','messages.body','messages.subject',DB::raw('CONCAT(firstname, " ", lastname) As senderName'),'messages.created_at')
->first();
if(count($trash) > 0)
{
$resultArray = ['status' => 'true', 'message' => 'Data Found!', 'data' => $trash];
return Response::json( $resultArray, 200);
}
}
else{
$resultArray = ['status' => 'false', 'message' => 'No Data Found'];
return Response::json($resultArray, 200);
}
}
how can i solve my problem in controller i used the select clause in controller any help will be highly appreciated!!!
This is a valid json, message_id and sender_id are integers, so that the are not in quoted, You can use them easily...