Dev
Example of how I learn using ChatGPT using an idea from Caleb Porzio, the creator of Livewire and Alpine.js

Caleb post a cool idea about date filters in Laravel. I wasn’t sure the best way to do that with the frame work. I’ve used the framework quite a bit but I’m still learning the nuances of how to extend it and make it even more useful for my projects. I’m excited for the upcoming release of Livewire 3.0 so I’m not going to bug him with my questions so I decided to ask ChatGPT. I wanted to know what some ways to solve this.

Here’s Caleb’s tweet for reference:

Would be rad if Eloquent had these, yeah? pic.twitter.com/qjOD5vv68y

— Caleb Porzio (@calebporzio) April 7, 2023

I pay for ChatGPT so I logged into my account to see if it could help me quickly understand the core concepts involved here and it’s pretty simple. There are two ways that ChatGPT suggested but let’s start with my prompt. Here’s what I asked:

I’m using Laravel 9 and php 8.1 for a project. I would like to create methods that are available on all Models in the application. For example, the calls would look like:

1Model::today()->sum(‘amount’);
2Model::yesterday()->sum(‘amount’);
3Model::monthTodate()->sum(‘amount’);
4Model::quarterToDate()->sum(‘amount’);
5Model::yearToDate()->sum(‘amount’);
6Model::last7days()->sum(‘amount’);
7Model::last30days()->sum(‘amount’);
8Model::lastMonth()->sum(‘amount’);
9Model::lastQuarter()->sum(‘amount’);
10Model::lastYear()->sum(‘amount’);

In this example Model represents whatever model you currently using, eg: Transaction. Also, amount is the field name. What’s the best way to achieve this with Laravel?

Below is what ChatGPT suggested for the first way to do it using class inheritance. I don’t have any issue with this approach but personally like the trait method, but we’ll get to that. Here is CGPT’s reply:

To achieve this in Laravel, you can create a custom base model that extends the default Eloquent model and includes these new methods. Then, make sure all your other models extend this custom base model.

Here’s how you can do it:

  1. Create a new file app/Models/BaseModel.php and define your custom BaseModel class with the required methods:
1<?php namespace App\Models;
2 
3use Illuminate\Database\Eloquent\Model;
4use Carbon\Carbon;
5 
6class BaseModel extends Model
7{
8 public function scopeToday($query)
9 {
10 return $query-?>whereDate('created_at', Carbon::today());
11 }
12 
13 // Define the other methods in a similar manner
14}
  1. Update your existing models to extend the new BaseModel:
1<?php namespace App\Models;
2 
3class Transaction extends BaseModel
4{
5 // Your model code
6}
  1. Now you can use the methods as follows:
1$todayTotal = Transaction::today()->sum('amount');

You can add the other methods (yesterday, monthToDate, etc.) to the BaseModel in a similar manner using Carbon to manipulate dates. Here’s an example for the yesterday() method:

1public function scopeYesterday($query)
2{
3 return $query->whereDate('created_at', Carbon::yesterday());
4}

Repeat this process for all the required methods, making sure to properly manipulate dates using Carbon. Once you’re done, all your models that extend BaseModel will have these methods available for use.

That’s pretty damn good if you ask me. That’s really close to how I would write the code. I would want to test and play around with it to validate it of course. You should never blindly use code copied from anywhere, including and especially ChatGPT.

But I wanted to see how it would suggest doing this with a trait. I like this approach a lot more as it’s easier to combine traits and this just seems more “Laravel” to me than extending classes. So I asked:

Could this also be achieved with a trait and if so, could you provide an example and explain the pros and cons of using model inheritance vs a trait?

And since ChatGPT is aware of your chat history it was easily able to use the previous information and build this out using traits instead of class inheritance. Here is ChatGPT’s suggestions:

Yes, you can achieve this using a trait as well. Here’s an example of how to do it with a trait:

  1. Create a new file app/Traits/DateScopes.php and define your trait with the required methods:
1<?php namespace App\Traits;
2 
3use Carbon\Carbon;
4 
5trait DateScopes
6{
7 public function scopeToday($query)
8 {
9 return $query-?>whereDate('created_at', Carbon::today());
10 }
11 
12 // Define the other methods in a similar manner
13}

Update your existing models to use the DateScopes trait:

1<?php namespace App\Models;
2 
3use Illuminate\Database\Eloquent\Model;
4use App\Traits\DateScopes;
5 
6class Transaction extends Model
7{
8 use DateScopes;
9 
10 // Your model code
11}

Now you can use the methods just like before:

1$todayTotal = Transaction::today()->sum('amount');

Add the other methods (yesterday, monthToDate, etc.) to the DateScopes trait in a similar manner, using Carbon to manipulate dates.

Pros and Cons of Model Inheritance vs. Traits:

Model Inheritance:

  • Pros:
    1. Provides a clear hierarchy and easy-to-understand structure.
    2. Allows the centralization of shared methods and properties in a base model.
  • Cons:
    1. Can lead to deeper inheritance hierarchies, making the code harder to understand and maintain.
    2. Models can inherit unnecessary functionality, which might not be required for all models.

Traits:

  • Pros:
    1. Encourages code reusability and organization without deep inheritance hierarchies.
    2. Allows the sharing of specific methods with only the models that need them.
    3. Models can use multiple traits, enabling better organization and separation of concerns.
  • Cons:
    1. The relationship between the model and the trait is not as explicit as with inheritance, which might make the code harder to understand for some developers.

In your case, using a trait is recommended since it enables better separation of concerns and prevents unnecessary inheritance. You can organize your code more efficiently by using multiple traits for different sets of functionality, and only apply them to the models that need them.

End of chat session with ChatGPT.

Come on, that’s pretty slick, right? The pros and cons are exactly what I would expect.

Do you think ChatGPT got it wrong? Would you do something different?

I decided to ask it to do one more thing and make the date field a variable instead of just being created at. ChatGPT was smart enough to set a sensible default and allow you to override as needed.

Here is what I asked next:

Can you modify the trait example so that you can pass a field name to the ::today() method. For example, ::tododay(‘received_at’)?

And here is the response:

Sure, you can modify the trait to accept a custom field name as a parameter. Here’s the updated DateScopes trait:

1<?php namespace App\Traits;
2 
3use Carbon\Carbon;
4 
5trait DateScopes
6{
7 public function scopeToday($query, $field = 'created_at')
8 {
9 return $query-?>whereDate($field, Carbon::today());
10 }
11 
12 // Define the other methods in a similar manner, allowing a custom field name
13}

With this modification, you can now pass a custom field name to the ::today() method:

1$todayTotal = Transaction::today('received_at')->sum('amount');

If you don’t provide a field name, it will default to ‘created_at’. You can apply the same modification to the other methods as well, allowing them to accept a custom field name.

End of ChatGPT response.

That’s pretty handy. I’ll definitely use this pattern in my code. And it helped me get a better handle on traits in general.

No comments yet…

avatar
You can use Markdown
No results