orest

Member Since 10 Months Ago

Experience Points
47,120
Total
Experience

2,880 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
417
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

  • Community Pillar

    Earned once your experience points ranks in the top 10 of all Laracasts users.

Level 10
47,120 XP
Jan
05
1 week ago
Activity icon

Replied to Query Using Recursive CTE

i am using MySQL 8.

I ended up using sql functions because for some reason the categories.id was not synchronised and its value was always the same when i used the query above

Jan
03
2 weeks ago
Activity icon

Started a new Conversation Query Using Recursive CTE

I have the following tables

Category

- id
- parent_id
- title

Threads

- id
- category_id
- title

A category have sub-categories and only the "leaf" category can have threads To explain further with an example

Computer -> Mac -> macbook

In this case the category macbook can have threads while the parent categories can't have threads.

What i want to achieve is to find the latest thread of a category, among all sub-categories

Computer -> Mac -> macbook
Computer -> Windows-> HP

In the example above, the categories macbook and HP have threads and i want for the parent category Computer to find the latest thread among the categories macbook and HP

To achieve that i am using recursive CTE and it seems to work when i test it with sqlite but when i use mysql it doesn't work

public function scopeWithLatestThread($query)
{
	return $query->addSelect(DB::raw('(
            SELECT
                id
            FROM
                threads
            WHERE
                threads.category_id in
                    (
                        with recursive recursive_categories (id) as
                        (
                            SELECT id
                            from categories as initial_categories
                            where initial_categories.id=categories.id
                            UNION ALL
                            SELECT remaining_categories.id
                            FROM recursive_categories JOIN categories as remaining_categories
                            on recursive_categories.id=remaining_categories.parent_id
                        )
                        SELECT id FROM recursive_categories
                    )
            ORDER BY
                updated_at DESC
            LIMIT 1) AS latest_thread_id')
        )->with('latestThread');     
}
public function latestThread()
{
    return $this->belongsTo(Thread::class);
}

Category::whereNull('parent_id')->withLatestThread()->get();
Dec
29
2 weeks ago
Activity icon

Replied to Config Db Connection During Testing

no i didn't because i need to change the database connection in a small number of tests within various test files.

changing the settings in phpunit.xml per test seems the same to me which is not very convenient.

i'd rather not setting env variables manually

Activity icon

Started a new Conversation Config Db Connection During Testing

In the phpunit.xml i have the following settings

 <server name="DB_CONNECTION" value="sqlite"/>
  <server name="DB_DATABASE" value=":memory:"/>

However, in some cases i need to use mysql and i set the config in the tests that i need mysql like

config(['database.default' => 'mysql']);
config(['database.connections.mysql.database' => 'dbname')]);

This works for Feature tests but for some reason when i do the same thing for Unit tests it does not work and i can't figure out why.

I have tried to do config:clear and cache:clear but it didn't help

Any ideas ?

Dec
26
3 weeks ago
Activity icon

Started a new Conversation Policy For Polymorphic Model

I have a model named Reply which can be either a

  • Thread reply
  • Comment
  • Message

In each case the policy for deleting a reply is different

Right now i have a ReplyPolicy

class ReplyPolicy
{
	public function deleteReply(User $user, Reply $reply)
	{
		//
	}

	public function deleteComment(User $user, Reply $reply)
	{
		//
	}

	public function deleteMessage(User $user, Reply $reply)
	{
		//
	}

}

And when i need to authorize the user i do

$this->authorize('deleteReply', $reply); 
$this->authorize('deleteComment', $comment); 
$this->authorize('deleteMessage', $message); 

Is there a better approach to handle this case ?

Dec
19
4 weeks ago
Activity icon

Started a new Conversation Set Env Variable In Phpunit At Runtime

by default the database variables in the phpunit.xml are the following:

 <server name="DB_CONNECTION" value="sqlite"/>
 <server name="DB_DATABASE" value=":memory:"/>

In one of my tests, i want to set the DB_CONNECTION to mysql because i test a functionality which uses whereJsonContains which is not supported by sqlite.

Is there a way to change the DB_CONNECTION at runtime ?

  • I have tried to use putenv and config but none of them work
  • I don't want the default connection to be mysql because it is considerably slower than using memory database
Dec
05
1 month ago
Activity icon

Started a new Conversation Difference Between WhereColumn And Where Clause

i have the following table, model and scope

conversations

- id

reads

- id
- readable_id
- readable_type
- user_id
- read_at

users

- id

I have the following scope for the Conversation model

public function scopeWithRead($query)
{
    return $query->addSelect(['read_at' => Read::select('reads.read_at')
                ->whereColumn('reads.readable_id', 'conversations.id')
                ->whereColumn('reads.readable_type', 'App\Conversation')
                ->whereColumn('reads.user_id', auth()->id()),
        ]);
}

when i test this scope i get the correct results but when i actually try to use it from the front end i get 500 error

$conversations = Conversation::withRead()->get();

On the other hand, if i change from whereColumn to where, i get wrong results when i test it and the front end does not give any errors, however the results are wrong

public function scopeWithRead($query)
{
     return $query->addSelect(['read_at' => Read::select('reads.read_at')
                ->where('reads.readable_id', '=', 'conversations.id')
                ->where('reads.readable_type', '=', 'App\Conversation')
                ->where('reads.user_id', '=', auth()->id()),
        ]);
}

Any thoughts on what is wrong ?

Nov
23
1 month ago
Activity icon

Replied to Determine If Model Is Recordable

@wingly thanks for the suggestion

i thought of that but it doesn't depend only on the repliable model. There is a case where it depends on another column of the replies table.

Activity icon

Started a new Conversation Determine If Model Is Recordable

I have a trait that records the activity of a model

RecordsActivityTrait

One of the models is polymorphic and in some cases i don't want to record the activity for that particular case.

The model name is Reply and it has a repliable relationship

For example

if ( $reply->repliable_type == 'SomeName' ){
 // activity should not be recorded    
}

Now i'm wondering if i should create a method isRecordable for all models that i want to record the activity

public function isRecordable()
{
     return true;
}

And for the Reply model it would be

public function isRecordable()
{
    if ( $this->repliable_type == 'SomeName' ){
         return false;
     }
     return true;
}
}

or should i create a class that determines if the model is recordable

For example

class DetermineRecordability
{
     public function handle($model)
      {
               if ( class_basename($model) == 'Reply' && $model->repliable_type == 'SomeName'){
                    return false;
               }
               return true;
       }
}

Which approach do you think is better ?

Nov
20
1 month ago
Activity icon

Replied to Get The Value That Failed The Validation Rule

@automica thanks!

this is what i am doing but in my case

i have an array as input and each value in the array must exist in the database.

If one of the values in the array does not exist, then the validation will fail and

what i am looking for is to grab that value that failed the validation.

For example let's say that the input consists of the array

['john', 'doe'] and ```doe`` does not exist in the database

i want to be able to concat the message with the value doe

so the message error that i want is

The following members could not be found: doe

Activity icon

Replied to Get The Value That Failed The Validation Rule

@jlrdw thanks!

What i want is to add the value that failed the validation in the error message and not to display it in the view. ( i want to return it as a json response )

However, the $errors variable displays only the error that occurred and not the value that caused the error.

Nov
18
1 month ago
Activity icon

Started a new Conversation Get The Value That Failed The Validation Rule

I have a FormRequest with the following rule.

It takes an array as input and for each value in the array the following rules are applied.

 public function rules()
    {
        return [
            'participants.*' => ['required', 'string', 'exists:users,name'],
        ];
    }

What i want, is to get the value from the array that failed the validation rule and use it in the error message.

What i have tried is to use the :attribute which returns a string with the name of the array and the index of the value that failed the validation.

So for example if the array participants has the following values

participants = ['john', 'doe']

and the value doe does not exist in the database, then the :attribute will return the string participants.1 And i can use the index from the resulting string to get the value from the input array.

 public function messages()
    {
        return [
            'participants.*.exists' => 'The following recipients could not be found: :attribute ,
        ];
    }

I was wondering if there is a more elegant way to get the value that failed the validation.

Nov
17
2 months ago
Activity icon

Replied to HasMany < - > HasOne Relationship Fail ->What Did I Miss

public function teammates()
{
    return $this->belongsToMany(User::class, ‘user_id’);
}

Make sure that in your team table, you have a user_id

Nov
16
2 months ago
Activity icon

Replied to Repetitive Validation Rules And Messages

the rules required and string are used on several validations and the error message is always the same.

i want to avoid writing the same rule and error message in multiple places

instead i was looking for a solution where the rule and the message are stored in one place ( thus a rule named BodyIsRequired ( but maybe what i'm want to do is "too much" and i can just write the same rule and message since they are quite simple )

I agree that it would be better to read the rules and understand them without reaching another file.

Activity icon

Started a new Conversation Repetitive Validation Rules And Messages

I'm trying to come up with a solution to avoid writing the same validation rules and messages over and over.

For example i have the following rules for the body attribute

 public function rules()
    {
        return [
            'body' => ['string','required'],
        ];
    }

I want the validation message for both rules to be the same.

One approach is to create two custom rules and, string and required and write the message that i want in each rule.

class BodyMustBeString implements Rule
{

    public function passes($attribute, $value)
    {
        if (is_string($value)) {
            return true;
        }
        return false;
    }

    public function message()
    {
        return 'Please enter a valid message.';
    }
}
class BodyIsRequired implements Rule
{

    public function passes($attribute, $value)
    {
        if (empty($value)) {
            return false;
        }
        return true;
    }

    public function message()
    {
        return 'Please enter a valid message.';
    }
}

The other approach is to create one custom rule for the body attribute attribute that consists of both string and required rules.

class BodyRules implements Rule
{

    public function passes($attribute, $value)
    {
        if ( !empty($value) && is_string($value)) {
            return true;
        }
        return false;
    }

    public function message()
    {
        return 'Please enter a valid message.';
    }
}

Do you have any other approach or do you agree with any of my approaches ?

Activity icon

Replied to Errors Are Available In View But Not In Test Assertion

Ok, thanks!

By the way, if could suggest a different approach in case you think that my approach is "wrong" or unusual, please let me know.

Activity icon

Replied to Errors Are Available In View But Not In Test Assertion

Yes that is what i am doing.

And the errors are displayed correctly in the view, i just couldn't assert that the session has errors in my test.

More specifically, in my search endpoint what i do is

  1. Validate the search parameters and if validation fails, then display the errors
  2. If validation passes, then search and display the results
 public function show(Search $search, SearchRequest $searchRequest)
    {
        $validator = $searchRequest
            ->validate($this->request)
            ->getValidator();

        if ($validator->fails()) {
            return view('search.show')
                ->withErrors($validator);
        }

        $results = $search->handle($this->request);
        $query = $this->request->input('q');

        return view('search.show', compact('results', 'query'));
    }

NOTE

The SearchRequest does not extend the FormRequest, it just uses the Validator facade to apply the validation rules that i have defined.

Activity icon

Replied to Errors Are Available In View But Not In Test Assertion

ok that's what i'm doing wrong :)

Is it considered wrong to validate the request parameters when you make a GET request ?

In my case, i make a search request using GET and before i start searching i want to validate the search parameters.

Activity icon

Started a new Conversation Errors Are Available In View But Not In Test Assertion

I'm using a custom validation and if the validation fails i return a view with the errors

validator = Validator::make(
            $request->input(),
            $this->rules($request),
            $this->messages()
        );

  if ($validator->fails()) {
            return view('some-view')
                ->withErrors($validator);
        }

The issue that i have is that even though in the view i do have access to the errors

@if($errors->any())
    @foreach($errors->all() as $error)
        {{ $error }}
    @endforeach
@endif

When i try to assert that the session has errors, it fails.

$this->get('path')->assertSessionHasErrors('error-name');

but if i assert that the error message is being displayed in the view, it works. And indeed the errors are being displayed when i use the browser.

$this->get('path')->assertSee('error message');

Any thoughts on what i might be doing wrong ?

Nov
14
2 months ago
Activity icon

Replied to Return To View With Errors If Form Request Validation Fails

is the only way to make this work to create a new endpoint that only shows the search results or errors ?

class SearchController extends Controller
{
    public function show(Search $search, SearchRequest $searchRequest)
    {
          $results = $search->handle();
          return redirect(route('search-results.show', compact('results'));
    }
}

class SearchRequest extends FormRequest
{
     public function failedValidation(Validator $validator)
    {
        return redirect(route('search-results.show')->withErrors($validator);
    }
}
Activity icon

Started a new Conversation Return To View With Errors If Form Request Validation Fails

I use a form request named SearchRequest to validate the query parameters and in case the validation fails, I want to return to search.show view in order to display the errors.

If the validation does not fail, then execute the search and return to search.show to display the results.

class SearchController extends Controller
{
    public function show(Search $search, SearchRequest $searchRequest)
    {
          $results = $search->handle();
          return view('search.show', compact('results');
    }
}

class SearchRequest extends FormRequest
{
     public function failedValidation(Validator $validator)
    {
        return view('search.show')->withErrors($validator);
    }
}

When the validation fails, it does return the search.show view but the errors are not available

search.show.blade.php

@if($errors->any())
    @foreach($errors->all() as $error)
         <p> {{ $error }} </p>
    @endforeach
@else
    <p> {{  $results  }} <p>
@endif

I have also tried to redirect instead of returning a view in the failedValidation method

 public function failedValidation(Validator $validator)
    {
        return redirect(route('search.show'))->withErrors($validator);
    }

But for some reason the first time that I hit the endpoint, it does not show the errors. I have to refresh to display the errors and I don't get why that happens.

Any thoughts ?

Nov
13
2 months ago
Activity icon

Replied to Return Json Response Or A View

In the case where there is only a search bar ( a single input ) then yes it looks nice to display the results on the same page.

However in the case where of a search form ( multiple inputs ) it does not look very nice to me at least because the search form already takes a lot of space.

You are right it would be better to stick with either Ajax or search form. But i saw this mix on Macrumors and I wanted to create the same thing and I was not sure how to do it.

So the point was to use a search form but in case something goes wrong, to stay on the same page and at the same time give some feedback to the user, which can be achieved using Ajax

Activity icon

Replied to Return Json Response Or A View

@bugsysha

The reason I want to return a view is because the current page is a search form and if I return json data I will have to show in the same page the search form and the results of the search which will be a mess.

That’s why I want to go to a different view to display the search results

Nov
12
2 months ago
Activity icon

Started a new Conversation Return Json Response Or A View

I have a search functionality and i want to return either

  1. A json response which consists of an exception message in case no results are found or an exception is thrown during search

  2. a view with the search results if everything works properly

currently the only way i can think of dealing with this is

  • Send a search request
  • return error message. ( if any error occurs or no results are found )
  • send another search request to view the results ( if results are found and no exceptions are thrown )

Search.vue

search(){
	axios.get('/search/' + queryParameters)
	.then(() => this.showResults())
        .catch((error) => flash(error.message));
},
showResults(){
	location.href = '/search/results' + queryParameters;
}

And in laravel i will have the following routes

First make a search and if any exceptions are thrown ( the exceptions are thrown by the Search class ) then a response message is returned ( the response message is handled in Handler.php )

Route::get('/search', function(Request $request, Search $search){
	
	$search->handle($request);
});

If results are found and no exceptions are thrown then send a request to the following route

Search and return a view with the results ( this route is called by the showResults method in Search.vue

Route::get('/search/results', function(Request $request, Search $search){
	$results = $search->handle($request);
	return view('search.show', compact('results');
})

Is there an alternative to what i'm trying to do ?

Because right now in order to make a search and get results, i have to send 2 requests and search 2 times.

Nov
11
2 months ago
Activity icon

Started a new Conversation Handle Response Message In Front Or Back End ?

When i make a request from the front end to the back end ( post, get etc) with axios for example

I can use then and catch to handle either a successful or a failed request and flash a message in the front end to give feedback to the user.

For example.

axios.get('/apples')
.then((response) => flash("You got the apples"))
.catch((error) => flash("You didn't get the apples"));

Or i can write the messages in the back end and then use them to flash the messages in the front end.

For example

axios.get('/apples')
.then((response) => flash(response.message)
.catch((error) => flash(error.message));

My question is whether there is a reason to prefer either one, or it does not matter ?

Nov
10
2 months ago
Activity icon

Replied to Optimize Query

I think that neither the distinct nor having methods optimize the query. The method distinct as the name indicates, it gets rid off the duplicates and the having method has the same functionality with the where method. Therefore it depends on what results you need.

Nov
09
2 months ago
Activity icon

Replied to Nested Foreach

Where are the buttons ?

What is the structure of the fields ? Probably you see extra buttons because each field has more elements than you expect it to have

Nov
08
2 months ago
Activity icon

Replied to Fetch One Record From One To Many Relationship

@tykus thanks!

wouldn't it be redundant to have the same user_id in both the conversations table and the conversation_participants table for the same conversation record ?

Activity icon

Started a new Conversation Fetch One Record From One To Many Relationship

I have the following tables

users
- id
conversations
- id
conversation_participants
- id
- conversation_id
- user_id

Now each conversation is created by a user.

What i'm looking for, is to create a relationship to get the user who started the conversation.

  • The user who created the relationship can be determined using the conversation_participants table.
  • The first participant of the conversation is always the user who started the conversation.

I've tried to do that using a belongsToMany relationship and fetch only 1 record. But it returns a collection, while i need a model.

class Conversation extends Model
{
    public function starter()
    {
           return $this->belongsToMany(
            User::class,
            'conversation_participants',
            'conversation_id',
            'user_id'
        )->orderBy('created_at','asc')->take(1);
    }
}

Is there a way to create such a relationship ?

Nov
02
2 months ago
Activity icon

Replied to Tailwind Css- How To Arrange Few Items On Same Row?

I think that flex box is what you are looking for. Have a look at the tailwind docs

Activity icon

Replied to Associate Prepare Data For Validation With Rule Error

Now that i'm reading again your suggestion.

  1. I can't validate that the input must be a string and contain a comma symbol

The reason is that the input consists of usernames which must exist in the database. Therefore, i can't validate a string with multiple usernames.

Another reason is that a comma is included only when multiple usernames are passed.

What i did in the prepareForValidation method is


public function prepareForValidation()
{
     if (!is_string($this->names)) {
            return;
        }

        if (str_contains($this->names, ',')) {
            $this->request->merge(
                [$this->attribute => $this->splitNames($this->names)]
            );
        } else {
            $this->request->merge(
                [$this->attribute => [$this->clean($this->names)]]
            );
        }
}

And the validation rules are

public function rules()
    {
        return [
            'title' => ['required', 'string', 'min:3'],
            'message' => ['required', 'string'],
            'participants' => ['required', "array", 'min:1'],
            'participants.*' => ['required', 'string', 'exists:users,name'],
        ];
    }

So i expect the input to be string. If the input is string then check if comma symbol is included and if yes then explode. Otherwise only one username is in the string and therefore create an array with a single username.

The validation rules expect an array. If the input is not a string then prepareForValidation will not create an array and the validation will fail. If the input is a string, then an array will be created as expected and then the validation rules will check if the content of the array are string and if each element ( username ) exists in the database.

Oct
31
2 months ago
Activity icon

Replied to Associate Prepare Data For Validation With Rule Error

I wasn’t sure if it makes sense to assume that it might not be string.

Thanks for the suggestion

Activity icon

Started a new Conversation Associate Prepare Data For Validation With Rule Error

I have a FormRequest with the following rules.

 public function rules()
    {
        return [
            'participants' => ['required', 'array', 'min:1'],
            'participants.*' => ['required', 'string', 'exists:users,name'],
        ];
    }

However the value of the attribute participants comes from an input text and is a string which normally it can be a single name or multiple names separated with comma.

'George'
'George, John'

And before i validate the data i have to manipulate it.

public function prepareForValidation()
{
	request()->merge(['partcipants' => explode(",", request('participants')])
}

Does it make sense to assume that the value of the participants might not be a string ?

So in case an object or an array is passed to participants

Then the prepareForValidation will fail and i can't even associate it with the participants attribute.

One way to solve this would be to create a new rule in order to be able to associate any kind of exceptions with the participants attribute.

However, in my application i assume that i receive an array from the participants ( an array of usernames ) parameter and i don't find a good idea to hide the prepareForValidation ( the functionality that splits the string into an array ) inside the new rule.

Any thoughts on how i can prepareDataForValidation, associate any failure with the rule so i can return the corresponding message, and at the same time avoid hiding the split of string to array inside a rule.

Oct
29
2 months ago
Activity icon

Replied to Manipulate Request Parameters

exactly.

i want to change the value of a request parameter and validate it independently.

thanks again, i will check this out

Activity icon

Replied to Manipulate Request Parameters

thanks for the suggestion.

if i wanted to apply this particular manipulation to different routes though, how should i approach it ?

Because the user can enter comma separated names in different forms where each form consists of different request parameters.

Therefore if i manipulate the request parameter in the prepareForValidation method, i would end up repeating the code for manipulating se same request parameter.

Activity icon

Started a new Conversation Manipulate Request Parameters

I have an input text in which a user can enter a single username or comma separated usernames.

I have a rule that validates whether the usernames exist. In that rule if the string consists of comma separated usernames i create an array of usernames and then validate the array.

class CommaSeparatedUsernames implements Rule
{
 	public function passes($attribute, $value)
    	{
        	if (str_contains($value, ',')) {
            	$this->validateMultipleUsernames($attribute, $value);
       	 }
        return $this->validateUsername($attribute, $value);
    }
}

However, the value in the request parameter remains the same ( a string which consists of comma separated usernames ) and then i have to split again the string into an array in order to use the usernames.

Right now i have this function within the rule

class CommaSeparatedUsernames implements Rule
{
 	public function passes($attribute, $value)
    	{
        	if (str_contains($value, ',')) {
		    $this->validateMultipleUsernames($attribute, $value);
		    $this->replaceParticipantsParameter($value);
            
                 }
                 return $this->validateUsername($attribute, $value);
    	}

	 public function replaceParticipantsParameter($commaSeparatedNames)
    	{
        	request()->merge(
            		['participants' => $this->getNames($commaSeparatedNames)]
        	);
    	}
	
	public function getNames($commaSeparatedNames)
    	{
        	return array_map(
            	    fn($name) => trim($name, ' '),
            	    explode(',', $commaSeparatedNames)
        	    );
         }

}

My question is where should i put the code for manipulation the request parameter

  1. Does it make sense to create a middleware that manipulates the request parameter ?

  2. Should i put that code in the Controller or in the Model that uses the request parameter ?

Oct
22
2 months ago
Activity icon

Started a new Conversation Laravel Controller Methods Naming Convention Alternatives

I have a FollowController and i want to

  1. get list of user that a user follows ( following )
  2. get list of users that a user is followed by ( followers )

However i can't do that in the same controller without breaking the naming convention or without introducing if statements in the controller.

I would like to know your opinion on this.

First Approach

Create separate controllers

class FollowersController extends Controller
{
	public function index(User $user)
	{
		return $user->followedBy;
	}

}

class FollowingController extends Controller
{
	public function index(User $user)
	{
		return $user->follows;
	}

}

Second Approach

Break the naming convention and fit both in the same controller

class FollowController extends Controller
{
	public function followedBy(User $user)
	{
		return $user->followedBy;
	}

	public function follows(User $user)
	{
		return $user->follows;
	}

}

Third Approach

Use a flag to decide whether to return either one or both ( in this case 1 extra request is avoided and you serve both in a single request )

class FollowControllerr extends Controller
{
	public function index(User $user)
	{
		if (request()->boolean('follows'))
		{
			return $user->follows;
		}
		elseif (request()->boolean('followedBy'))
		{
			return $user->followedBy;
		}
		return [
			'follows' => $user->follows, 
			'folllowedBy' => $user->followedBy
 ];
	}

}
Oct
13
3 months ago
Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha that cleaner indeed.

initially what i wanted to do is something like

public function index(ThreadFilters $filters)
{
	$filters->apply($someBuilder);
}

So the controller wouldn't have to know anything except for applying the filters.

But unfortunately since i had to chain Filter in some cases i created the FilterManager and then i couldn't use the aforementioned approach.

However, your suggestions is much better than my final approach. so thank you again

Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha no there are no default filters in FilterManager

The FilterManager exists to find the requested filters that are passed from an HTTP request ( the requested filters correspond to methods in Filter classes ) . I then manually chain the required Filter classes depending on where i need the FilterManager and finally i apply the filters using the FilterManager

Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha oh now i understand your question.

Because in some cases i might need to add 2 different Filter classes

for example

$filterManager->addFilter(new ThreadFilters(());
$filterManager->addFilter(new PostFilters());

Then when i call

$filterManager->apply($someBuilder);

I apply the filters from both Filter classes. In addition to that, in some cases these Filter classes have some methods in common that are inherited from another Filter class and in the FilterManager i prevent applying the same filter twice ( which i don't know if it makes much sense since the filters are actually SQL where statements which i guess are not costly )

Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha it's not quite clear to me what do you mean by "why".

In the ThreadController and more specifically in the method index, i know that i need the ThreadFilters, that's why i add the filter ThreadFilters. In other places i might need a different filter. And in some cases i need two different Filter classes

class ThreadController extends Controller
{
	public function index(FilterManager $filterManager)
	{
	$filterManager->addFilter(new ThreadFilters());
	 // here i know that i need the ThreadFilters
	}
}
Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha thanks again! any suggestions for a better approach are appreciated :)

Activity icon

Replied to Instantiation Of Chained Filters

@bugsysha thanks. Isn't an issue that i have to manually

$filterManager->addFilter(new ThreadFilters());

where ThreadFilters i guess is also a dependency that is hidden.

or it is even better to do the following

class ThreadController(FilterManager $filterManager, ThreadFilters $threadFilters)
{
	$filters = $filterManager->addFilter($threadFilters);
	$filters->apply($someBuilder);
}
Activity icon

Started a new Conversation Instantiation Of Chained Filters

I have different Filter classes and each class has a number of filter methods. There is ( so far ) one case where I need to apply filters from 2 classes. What I did is that I created another class named FilterManager which stores a list of all the Filter classes you need and then it iterates over the list and applies the filters.

class ThreadFilters 
{
	protected $builder;
	protected $supportedFilters = ['newThreads'];
	public function newThreads($userId)
	{
		$this->builder->orderBy('created_at', 'DESC');
	}
}
class FilterManager
{
	protected $filters = [];
	
	public function addFilter($filter)
	{
		$this->filters[] = $filter;
	}

	public function apply($builder)
	{
		foreach($this->filters as $filter)
		{
				$filter->builder = $builder;
				foreach($filter->supportedFilters as $filterMethod)
				{	
					$filter->$filterMethod()
				}
				$builder = $filter->builder;
		}
	
	}
}

Now in the controller I can do something like

First Approach

class ThreadController(FilterManager $filterManager)
{
	$filters = $filterManager->addFilter(new ThreadFilter());
	$filters->apply($someBuilder);
}

On the other hand I could use the app function

app(ThreadFilters::class)

and in the service container basically I could do

$this->app->bind(ThreadFilters::class, function($app){
	$filterManager = new FilterManager();
	$filterManager->addFilter(new ThreadFilters());
	return $filterManager;
});

and therefore my controller would look like

Second Approach

class ThreadController()
{
	$filters = app(ThreadFilters::class);
	$filter->apply($someBuilder);
}

My question is which solution is good/acceptable.

In the First Approach the FilterManager dependency is injected and the controller has to add the ThreadFilters

In the Second Approach no dependencies are injected and the controller has to use the service container to hide the specifics and make the controller has less knowledge about the filters.

Oct
12
3 months ago
Activity icon

Replied to Factory That Depends On Request Parameters

@rodrigo.pedra that's a very nice idea, thank you

Activity icon

Replied to Factory That Depends On Request Parameters

@automica hahaha oh no. is just a simple example to illustrate the question

Activity icon

Replied to Factory That Depends On Request Parameters

i have updated the question ( basically is a question on top of the initial question ).

To make sure that i'm not on the wrong way

Activity icon

Started a new Conversation Factory That Depends On Request Parameters

Given that I have a factory class that create fruits based on a request parameter.

Should the client know the exact parameter that needs to be passed to the factory ( First Approach)

Or it is better to pass a generic parameter to the Factory ( in other words hide the specifics from the client ) and let the Factory know which exact parameter it needs to create an object. ( Second Approach )

First Approach

class FruitFactory
{

    public function create($type)
    {
        if($type == 'Apple')
        {
            return new Apple();
        }
    }
}

$fruitFactory = new FruitFactory();
$type = request('type');
$fruit = $fruitFactory->create($type);

Second Approach

class FruitFactory
{

    public function create(Request $request)
    {
	$type = request('type');

        if($type == 'Apple')
        {
            return new Apple();
        }
    }
}

$fruitFactory = new FruitFactory();
$fruit = $fruitFactory->create();

Updated Question

If the FruitFactory is a factory of factories, does it need to know about all the exact parameters that its children factories need to create an object ?

Or maybe in this case the second approach is better ( Just passing the general $request parameter and let the factory find out which parameter it needs to create an object )

class FruitFactory
{

    public function create($type, $color)
    {
        if($type == 'Apple')
        {
		return app(Apple::class)->create($color);
        }
    }
}


class Apple
{
	public function create($color)
        {
		if($color == 'green') 
		{
			return new GreenApple();
		}
	}

}


$fruitFactory = new FruitFactory();
$type = request('type');
$color = request('color');

$fruitFactory->create($type, $color);