Trying to understand how to make a UpdateOrCreate - php

I have a model with the following code:
public static function insertSent($itemId, $currentPackId)
{
$itemHistory = new ItemHistory([
'item_id' => $itemId,
'pack_id' => $currentPackId,
'status' => self::SENT,
'returned_by' => Auth::id()
]);
$itemHistory->save();
}
public static function insertReturned($itemId, $currentPackId)
{
$itemHistory = new ItemHistory([
'item_id' => $itemId,
'pack_id' => $currentPackId,
'status' => self::RETURNED,
'returned_by' => Auth::id()
]);
$itemHistory->save();
}
I just added the insertSent and I want to change the insertReturned to a function where it updates a record if it exists or creates it so UpdateOrCreate.
I'm using laravel php

You can adjust your method to use updateOrCreate pretty easily:
public static function insertReturned($itemId, $currentPackId)
{
ItemHistory::updateOrCreate([
'item_id' => $itemId,
'pack_id' => $currentPackId,
], [
'status' => self::RETURNED,
'returned_by' => Auth::id(),
]);
}
The first array is what you are looking for. If a record is found fill it with the second array and save. If no record is found merge the first and second array and create the new record.
Laravel 6.x Docs - Eloquent - Other Creation MethodsupdateOrCreate

Related

Laravel API Resource not returning correct value with condition

I am new to Laravel API, I want to return a book where recommended === 1
In my resources, I have this
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'about' => $this->about,
'content' => $this->content,
// 'image' => asset('/storage/'.$this->image),
'image' => $this->image_url,
// 'recommended' => $this->recommended,
'recommended' => $this->when($this->recommended === 1, $this->recommended),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'author' => $this->author,
];
I want to return books when recommended === 1
My table is Like this
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('about');
$table->string('image');
$table->string('image_url');
$table->string('epub_url');
$table->integer('author_id');
$table->string('publisher');
$table->year('year');
$table->boolean('recommended')->default(0);
$table->timestamps();
});
I was able to achieve the same thing on web using this
public function index()
{
$data = array();
$data['recommends'] = Book::where('recommended', 1)->take(10)->get();
$data['latests'] = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('welcome', compact("data"));
}
But I don't know how to replicate the same using Laravel API.
UPDATE
I was able to achieve the same thing on web using this
public function index()
{
$data = array();
$data['recommends'] = Book::where('recommended', 1)->take(10)->get();
$data['latests'] = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('welcome', compact("data"));
}
But I don't know how to replicate the same using Laravel API.
Normally I will get all Books or Post like this using API Resource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'about' => $this->about,
'content' => $this->content,
'image' => $this->image_url,
'recommended' => $this->recommended,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'author' => $this->author,
];
and call it like this in my controller
public function indexapi()
{
return BookResource::collection(Book::with('author')->Paginate(16));
}
But there some cases recommended is == 1 and some recommended == 0, in this case, I want to return data only when recommended == 1
I know my question is quite confusing
Thanks.
Thanks.
If I get it right, you want to filter & get only the books with ( recommended attribute == 1 ). If thats the case you shouldn't do it in your Collection file. You should do this filtering process in your Controller before passing any data to Collection.
Here is some code example from one of my project.
In ProductController.php FILE
public function index()
{
return new ProductCollection( Product::where('recommended','1')->get() );
}
As you can see , I'm filtering the products to get only the recommended ones. Then I'm sending this filtered data to the ProductCollection. This way The collection will only return the data I want.
In ProductCollection.php FILE
public function toArray($request)
{
return [
'data' => $this->collection->map( function($data) {
return [
'id' => (integer) $data->id,
'name' => $data->name,
'category_id' => $data->category_id,
'brand_id' => $data->brand_id,
'photos' => json_decode($data->photos),
'gtin' => $data->gtin
];
})
];
}
I don't have to make any changes in Collection. Because in this way , Collection should do the job for every data it gets.

Laravel - Trying to get property "id" of non-object while using POST Method

Am writing an endpoint with Laravel using using. When I tested on postman using POST Method, I got this error:
ErrorException: Trying to get property 'id' of non-object in file C:\xampp\htdocs\testing-file\testing\app\Http\Controllers\ApiController.php on line 912
Controller
public function storeBilling(Request $request)
{
// $billing = Billing::create($request->all());
// return response()->json(['success' => $billing], $this-> successStatus);
$validator = Validator::make($request->all(), [
'network' => 'required'
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
// Creating a record in a different way
$createBilling = Billing::create([
'user_id' => $request->user()->id,
'network' => $request->network,
'sender' => $request->sender,
'recipient' => $request->recipient,
'message' => $request->message,
'amount' => $request->amount,
'billing_type' => $request->billing_type,
]);
return new BillingResource($createBilling);
}
Model
class Billing extends Model
{
protected $table = 'billing';
protected $fillable = [
'network' ,
'sender',
'recipient',
'message',
'timestamp',
'created_at',
'updated_at',
'amount',
'billing_type',
'user_id',
'service_name',
'package',
'email',
'user_id'
];
public function user() {
return $this->belongsTo('App\User');
}
}
Resource
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Billing;
class BillingResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'network' => $this->network,
'sender' => $this->sender,
'recipient' => $this->recipient,
'message' => $this->message,
'amount' => $this->amount,
'billing_type' => $this->billing_type,
'email' => $this->email,
'user' => $this->user,
'service' => $this->service,
'package' => $this->package,
// Casting objects to string, to avoid receive create_at and update_at as object
'timestamp' => (string) $this->timestamp,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at
];
}
}
If I use this POST Method:
http://localhost/testing-file/stesting/api/storeBilling?network=100
It suppose to post into the database, but I got this error:
ErrorException: Trying to get property 'id' of non-object in file C:\xampp\htdocs\testing-file\testing\app\Http\Controllers\ApiController.php on line 912
'user_id' => $request->user()->id
Your error is saying that $request->user() is not an object, so you cannot access its parameters using object notation, e.g. ->id.
If you dd($request->user) you may see that you are not getting what you thought you were getting - it may be an array, or it may not be the right value at all.
If it is an array, you can access the value like $request['user']['id']. It really depends what you are passing in your POST request.
$request->user()->id is incorrect.
If you want the current user you can use Auth::user().
In the beginning of your question you said you are trying to build an endpoint using Lravel ..
Postman will not have access to the user object unless authenticated, if authenticated then this should work ::
$request->user()->id or Auth::user()->id or $request["user"]["id"]
on you
public function storeBilling(Request $request)
You write $createBilling = Billing::create([
'user_id' => $request->user()->id, and this create error.
Or is preferable to have $createBilling = Billing::create([
'user_id' => Auth::user()->id, to find the id of the user authentificate.
don't forget to add use Auth; at the beginning of the controller
Going through a same Hassle it's happening because relationship finding its relation with billing table but it did not find so giving this error please check your database have related entry's and try again and make sure you have right relationship with table.

Passing a factory into another in Laravel 5

I am trying to generate a test on Laravel.
What I was trying is to create a fictitious position name, then add 10 people for this position.
PositionsFactory.php
$factory->define(App\Position::class, function (Faker $faker) {
return [
'p_id' => $faker->unique()->randomNumber($nbDigits = 8),
'name' => $faker->word,
'org' => $faker->word,
'user_id' => 1
];
});
Here is my EmployeeFactory.php
$factory->define(App\Employee::class, function (Faker $faker) {
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'pid' => $position->p_id,
'org'=> $position->org,
'user_id' => 1,
];
});
Well here is one my my trials but it did not work
for ($i=0; $i < 5; $i++ ){
$position = factory('App\Position')->create();
factory('App\Employee',10)->create(
'pid' => $position->pid,
'org' => $position->org
);
}
I am trying to loop for 5 times and for each loop I want to create 10 employees with the same position Id. But obviously I am missing something.
I tried adding $position in the Employee factory, which works great.
$factory->define(App\Employee::class, function (Faker $faker) {
$position = factory('App\Position')->create();
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'pid' => $position->p_id,
'org'=> $position->org,
'user_id' => 1,
];
});
Is there a way to make something like,
$factory('App\Position',5)->create($factory('App\Employee',10));
Maybe I am missing something with call back but kinda lost. Any help would be appreciated. Thank you!
I think you might be looking for the each method which can be called after create:
// Generate 5 positions and execute a callback
// function for each position created
factory(App\Position::class, 5)->create()->each(function ($position) {
// In the callback, generate 10 employees
// and manually override the foreign key
factory(App\Employee::class, 10)->create([
'pid' => $position->id
]);
});
Further information on each and handling relationships: https://laravel.com/docs/5.6/database-testing#relationships.
Hope it helps!
You can create them separatly and loop through collections.
$positions = factory('App\Position', 3)->make();
foreach ($positions as $position){
$employes = factory('App\Employee', 3)->make();
foreach ($employes as $employee){
$employee->p_id = $position->id;
//etc.. watever you want to connect
}
}
now you have 1 collection of positions and 1 collection of employes devided of the positions
note that the make method does not save to database you need to manually save them
you could also change your factory as is stated in the documentation https://laravel.com/docs/5.6/database-testing#using-factories
yours would look like:
$factory->define(App\Employee::class, function (Faker $faker) {
return [
'FirstName' => $faker->name,
'LastName' => $faker->lastName,
'org'=> $position->org,
'user_id' => 1,
'pid' => function () {
return factory('App\Position')->create()->id;
}
];
});
This will create a position for each user the factory creates.
You could also use existing eloquent models instead if you have existing positions.

FatalThrowableError Call to a member function where() on null for laravel 5.5 API request

Hi I am trying to build the API from laravel. I am using eloquent resources to manage API. I get FatalThrowableError Call to a member function where() on null when passing id that do not exist in database.
Routes :
Route::resource('hotel', 'HotelController',['only'=>['index','show']]);
Resource :
public function toArray($request)
{
return [
'id' => $this->hotel_id,
'name' => $this->name,
'summary' => $this->summary,
'description' => $this->description,
'contactno' => $this->contactno,
'address' => $this->address,
'latitude' => $this->latitude,
'longitude' => $this->longitude,
'star' => $this->star,
'image' => base_resource_url().$this->image,
'facilities' => $this->facility,
];
}
}
Controller :
public function show($id)
{
return new HotelResource(Hotel::find($id)->where(['suspend'=>1,'verify'=>1])->first());
}
When I pass the ID that is present in database I can get the json data but when I pass the ID that is not present in database in show($id) method of controller then I get FatalThrowableError Call to a member function where() on null how can I handle this exception in laravel to throw some readable json error response like :
{error : not data found with accosiated ID}
You need to check that the record exists first. For example:
public function show($id)
{
if ($hotel = Hotel::find($id)) {
// hotel exists
}
abort(404, 'Hotel does not exist');
}
Update
Hotel::find($id) will only return 1 or 0 records. Applying the where clauses followed by first() doesn't make sense.
// is this what you mean?
Hotel::where(['id' => $id, 'suspend' => 1, 'verify' => 1])->first()
Update 2
public function show($id)
{
if ($hotel = Hotel::where(['id' => $id, 'suspend' => 1, 'verify' => 1])->first()) {
return new HotelResource($hotel);
}
abort(404, 'Hotel does not exist');;
}

Using Fractal's $defaultIncludes

I am trying to use a $defaultIncludes() and am getting an exception --
ErrorException in ViewoptionTransformer.php line 8:
Argument 1 passed to App\Transformers\ViewoptionTransformer::transform() must be an instance of App\Viewoption, boolean given
Following the tutorial (http://laravelista.com/build-an-api-with-lumen-and-fractal/) except I am using Laravel 5.1 not Lumen:
in User model, I have the hasOne relationship with Viewoption called viewoptions
In the UsersController, I eager load viewoptions
public function index(Manager $fractal, UserTransformer $userTransformer)
{
$records = User::with(['locations', 'viewoptions'])->get();
$collection = new Collection($records, $userTransformer);
$data = $fractal->createData($collection)->toArray();
return $this->respondWithCORS($data);
}
In the UserTransformer, I have the $defaultInclude and the includes method
protected $defaultIncludes = ['viewoptions'];
`public function transform(User $user)
{
return [
'id' => $user->id,
'name' => $user->name,
'is_active' => (boolean)$user->is_active,
'is_admin' => (boolean)$user->is_admin,
'is_manager' => (boolean)$user->is_manager,
'role_id' => (integer) $user->role_id,
'email' => $user->email,
'phone' => $user->phone,
'full_sidebar' => (boolean)$user->full_sidebar
];
}
public function includeViewoptions(User $user)
{
$viewoptions = $user->viewoptions;
return $this->collection($viewoptions, new ViewoptionTransformer);
}`
Have a ViewoptionTransformer
`
use App\Viewoption;
use League\Fractal\Resource\Collection;
use League\Fractal\TransformerAbstract;
class ViewoptionTransformer extends TransformerAbstract {
public function transform(Viewoption $item)
{
//return $item;
return [
'id' => $item->id,
'user_id' => $item->user_id,
'voAgency' => (boolean)$item->voAgency,
'voBalanceDue' => (boolean)$item->voBalanceDue,
'voCloseDate' => (boolean)$item->voCloseDate,
'voCommitTotal' => (boolean)$item->voCommitTotal,
'voDistributor' => (boolean)$item->voDistributor,
'voDueDate' => (boolean)$item->voDueDate,
'voFeePercentage' => (boolean)$item->voFeePercentage,
'voRegion' => (boolean)$item->voRegion,
'voSeason' => (boolean)$item->voSeason,
];
}
}`
Worked with these and slight variations of these throughout the day yesterday and I can't rid myself of that exception.
Not all of your users.id corresponds to some viewoptions.user_id.
Just check it:
$records = User::with(['locations', 'viewoptions'])->get();
dd($records);
some viewoptions will be null or false or just undefined
Instead of using collection use item like so
public function includeViewoptions(User $user){
$viewoptions = $user->viewoptions;
return $this->item($viewoptions, new ViewoptionTransformer);
}`
I had a similar issue today, all my other uses of transformers had been with hasMany relationships. I was always instantiating the transformer with a collection of objects.
However, when using a transformer with a belongsTo relationship and instantiating the transformer with only one object (similar to how you are passing only one object from a hasOne relationship) I would get the same boolean given error.
In the end I solved the issue by using 'item' instead of 'collection' when instantiating the transformer.
Within your includeViewoptions function
Instead of using
return $this->collection($viewoptions, new ViewoptionTransformer);
try
return $this->item($viewoptions, new ViewoptionTransformer);

Categories