Laravel 8 - Calling multiple factory states at once - laravel

Pre Laravel 8 there seems to be an option to line up different states at once
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
(edit: I now realise that this was to apply 2 different states into the same factory record)
whereas I can't seem to find the equivalent of this in Laravel 8, does anybody know how?
Essentially I am trying to call one chain to create multiple records with different states for example:
User::factory()->verified()->unverified()->banned()->create()
Result: 3 different users one verified one unverified one banned
It can be achieved with below code, it just seems a little verbose
User::factory()->verified()->create();
User::factory()->unverified()->create();
User::factory()->banned()->create();

1. Get rid of states and just use sequences
User::factory()
->count(3)
->state(new Sequence(
['status' => 'verified'],
['status' => 'unverified'],
['status' => 'banned'],
))
->create()
2. Use variables as functions
Keep your current states, but dynamically access them from a predefined list.
$states = ['verified', 'unverified', 'banned'];
foreach ($states as $state) {
User::factory()->$state()->create();
}
3. Write each one out by hand.
Similar to number 2, but we don't use a loop.
User::factory()->verified()->create();
User::factory()->unverified()->create();
User::factory()->banned()->create();

Related

Getting Stripe Upcoming Invoice Line Items with Laravel Cashier

I'm attempting to use Laravel Cashier to retrieve line items of the client's upcoming invoice. I'm having difficulty obtaining the invoice in the first place. Though I've found the undocumented public function "upcomingInvoice," I can't get any of its protected properties out.
Even with it, I'm having trouble understanding how to use the poorly documented "asStripe..." functions, presumably asStripeInovice(), to return the line items.
I've tried a whole host of things and it would muddle things up to write them all out, so I figure it might be better just to ask how to go about it.
Thanks!
Try this one liner code in laravel 7 or 8 with cashier.
$user->upcomingInvoice()
And you're good getting all upcoming invoices details.
As up update, I was able to get this to work just using the Stripe client, like so:
$stripe = new StripeClient(env('STRIPE_SECRET'));
$upcomingLineItems = $stripe->invoices
->upcomingLines(['customer' => $customer['stripe_id']]);
I'll still leave this open in case there's a way to do it with Cashier's methods, but it now doesn't seem necessary.
Similarly, I wanted to be able to display the "amount due today" to a user prior to switching subscription plans (which takes into account proration as well as any credit applied to the customer's account). I was able to do this in Laravel using the following:
$stripe_client = new StripeClient(config('stripe.secret'));
$items = [
[
'id' => $user->subscription()->items()->first()->stripe_id,
'price' => $selected_plan, # Switch to new price
],
];
$invoice = $stripe_client->invoices->upcoming([
'customer' => $user->stripe_id,
'subscription' => $user->subscription()->stripe_id,
'subscription_items' => $items,
'subscription_proration_date' => Carbon::now()->timestamp
]);
$amount_due = $invoice->amount_due; // and there it is

Hide API Resource Field / Belongs To Many Through Deep Relationship Problem

It seems as if the tutorial right here doesn't work as intended https://hackernoon.com/hiding-api-fields-dynamically-laravel-5-5-82744f1dd15a
I am aware of how to load relationships only if necessary by making use of "whenLoaded", but for simple field parameters that do not involve a relationship, I am unable to dynamically load these fields.
Below is a snippet of Agency.php
'expected_num_of_b_positive_donors' => $this->getExpectedNumOfDonors("B+"),
'elligible_to_schedule_mbd' => $this->
'donors' => $this->getDonors(),
'contact_persons' => $this->getContactPersons(),
'last_mbd' => $this->getLastMBD(),
'average_number_of_donors_per_day' => $this->getAverageNumberofDonorsPerDay()
This would all have been extremely easy, if Laravel came out of the box with a Belongs To Many Through Deep Relationship, as I could have easily used:
'donors' => $this->whenLoaded("donors")
instead of:
'donors' => $this->getDonors(),
For context, here is a snippet of my getDonors()
$donors = [];
// MBD -> Schedule -> Donation List -> Donor
foreach($this->mbds as $mbd){
foreach($mbd->mbd_schedules as $schedule){
foreach($schedule->donation_list as $donation_list){
if(!in_array($donation_list->donation->donor, $donors)){
array_push($donors, new UserResource($donation_list->donation->donor));
}
}
}
}
return $donors;
Since Belongs To Many Through does not exist, I had to create a custom laravel relationship where I can get All Donors of an Agency. Now, I have 2 Questions.
Is there a way for me to dynamically load the getDonors()?
// I am aware that this is wrong, I'd just like to give context if it's possible to do something like this
'donors' => $this->whenLoaded("donors", $this->getDonors()),
Is there an elegant way for me to make a custom Belongs To Many Relationship? So that I could just simply do
'donors' => $this->whenLoaded("donors")
I am aware that third party packages exist for Belongs To Many Relationships, but I'd like to know which one of these are best in your opinions as I am afraid of using a potentially wrong package and end up screwing my system much more.
Thanks Laracasts!

Comparing laravel collections

I have two collections: "Instructions" and "Known". Basically I am taking a new set of "Instructions" and checking whether anything is different to what is "Known".
So, the quantity is not massive. I retrieve the info:
$Instructions = Instruction::all();
$Knowns = Known::all();
Now, I'm looking for the differences, and I've tried each of these three methods:
$IssuesFound = $Instructions->diff($Knowns);
$IssuesFound = $Instructions->diffKeys($Knowns);
$IssuesFound = $Instructions->diffAssoc($Knowns);
The thing is, an "Instruction" or "Known" is an item with 17 attributes, and anyone of those attributes can be different. I want to compare the attributes of an "Instruction" with the matching attribute of a "Known". (Both items have the same keys, bot items have a Reference attribute to act as a unique identifier.
What I'm finding is that theese methods give me the item that is different, but doesn't tell me which individual attributes are the mismatch.
foreach ($IssuesFound as $issue)
{
dd($issue);
}
So a method like $IssuesFound = $Instructions->diffKeys($Knowns); will come up with item xxx being different, but I can't see how to find out which attribute of the item it is that is different. Not unless I start nesting loops and iterating through all the attributes - which I'm trying to avoid.
How do I do it?
Thanks in advance. (Laravel 5.6)
Straight from laravel docs, diffAssoc will return what you are asking:
$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6
]);
$diff = $collection->diffAssoc([
'color' => 'yellow',
'type' => 'fruit',
'remain' => 3,
'used' => 6
]);
$diff->all();
// ['color' => 'orange', 'remain' => 6]
You get the attribute from the FIRST collection that is different on the SECOND collection, therefore if you get 3 attributes when calling $diff->all() you will know WHICH attributes ARE DIFFERENT, so you could access them or do whatever you want to, if you post more specific results of what you are getting and what you are trying we can help, but I think you are just not thinking how to use these methods

Laravel - Eloquent multiple delete vs destroy array

I was wondering what's the best way to destroy multiples database entries with ELOQUENT and I don't find a way to determine that.
So I have 3 array of id's (2 with ints, 1 with strings).
Is it better to go with a foreach and ->delete() every entry or destroy the array ?
When I look at the destroy function, it states the following :
We will actually pull the models from the database table and call
delete on each of them individually so that their events get fired
properly with a correct set of attributes in case the developers
wants to check these.
And the code clearly shows :
$key = $instance->getKeyName();
foreach ($instance->whereIn($key, $ids)->get() as $model) {
if ($model->delete()) {
$count++;
}
}
So I guess there's no real difference and the destroy function is just to avoid the use of a foreach. Can anyone confirm or inform and explain ?
Thanks :)
At first you need to know the difference between destroy and delete, destroy is think to be used for removing an entity (object/model) and delete for being used on a query builder.
Both are different ways but they have the same purpose you can do like:
Model::destroy(array(1, 2, 3));
or
$ids = explode(",", [1,2,3]);
$model->find($ids)->each(function ($model, $key) {
//Do things before deleting
$model->delete();
});
But as you can see the first one is just more direct, on the second one you can do custom things before deleting.

Laravel attach pivot to table with multiple values

Background
I'm creating a database revolving around food allergies and I have a many to many relationship between foods and allergies. There is also a pivot value called severity which has a numerical number representing the severity of the allergy for that food item.
This link table looks like this;
food_id|allergy_id|severity
-------|----------|--------
1 | 1 | 3
1 | 4 | 1
2 | 2 | 1
The problem
When trying to update the link table with Eloquent (where $allergy_ids is an array)
$food->allergies()->attach($allergy_ids);
How would I go about adding multiple values to this pivot table at once along with the pivot values?
I can add all the allergy_id's for a particular food item in one go using the above line, but how can I also add in the severity column at the same time with an array of various severity values? Maybe something like
$food->allergies()->attach($allergy_ids, $severity_ids);
Edit: There could be between 0-20 allergies for a specific food item, and a severity rating from 0-4 for each allergy, if this helps at all.
You can.
From this example in Docs (4.2, 5.0):
$user->roles()->sync(array(1 => array('expires' => true)));
Hardcoded version for the first two rows:
$food = Food::find(1);
$food->allergies()->sync([1 => ['severity' => 3], 4 => ['severity' => 1]]);
Dynamically, with your arrays $allergy_ids and $severities in a compatible state (size and sort), you shall prepare your sync data before. Something like:
$sync_data = [];
for($i = 0; $i < count($allergy_ids); $i++))
$sync_data[$allergy_ids[$i]] = ['severity' => $severities[$i]];
$food->allergies()->sync($sync_data);
You can't do it like you' like so I suggest a simple loop:
foreach ($allergy_ids as $key => $id)
{
$food->allergies()->attach($id, array_get($severity_ids, $key));
// should you need a sensible default pass it as a 3rd parameter to the array_get()
}
workaround
However if you wanted to attach multiple allergies with single severity level/id then you could do this:
$food->allergies()->attach($allergy_ids, array('severity' => $singleSeverityValue));
From version 5.1 of Laravel (Currently in Laravel 9.x) onwards it is possible to pass an array as a second argument with all the additional parameters that need to be saved in the intermediate table.
As you can read in the documentation
When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table:
$user->roles()->attach($roleId, ['expires' => $expires]);
For convenience, attach and detach also accept arrays of IDs as input:
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
Then you can simply do
$food->allergies()->attach([1 => ['severity' => 3], 4 => ['severity' => 1]]);
So, on Laravel 9, passing the ids in the array worked for me. Likeso,
$user->roles()->attach([$a->id,$b->id,$c->id]); and so on.
I guess instead of passing the string. We can pass just the id or else convert the string into array.
Easiest indeed is to attach with the extra data, like so:
$retailer->paymentmethods()->attach($paymentmethod, array('currency' => $paymentmethod->currency));
change out the values for food allergy severity, but you get the hint... :-)

Resources