About Sharp for Laravel — Part 3.
Filtering things.
Let’s start today with something really simple, at least if you’re a Laravel developer : validation. Right now, if we try to update or create a Player without typing a name, we got this nasty database error:
Let’s add a validation layer. First, we create a new PlayerSharpValidator class with extends Laravel’s regular FormRequest:
class PlayerSharpValidator extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
"name" => "required"
];
}
}
Standard stuff here: wa can use all the good from Laravel validation system, like custom messages, custom validation rules, … Now we just have to register this validator in sharp config file:
return [
[...]
"entities" => [
"players" => [
"list" => \App\Sharp\PlayerSharpList::class,
"form" => \App\Sharp\PlayerSharpForm::class,
"validator" => \App\Sharp\PlayerSharpValidator::class,
],
[...]
],
Et voilà:
Next task: we need to add the country information in our Team entity. This is mainly to show how filters works, so let’s skip the database migration, form and list update and we’re here:
To create our filter, we first write a Filter class:
class CountryFilter implements EntityListFilter
{
public function values()
{
return Team::select("country")
->orderBy("country")
->pluck("country", "country");
}
}
Our values() code is a little odd here, because we choose a string attribute instead of a foreign key for this example, but why not. We next register this filter in the Team EntityList class:
class TeamSharpList extends SharpEntityList
{
[...]
function buildListConfig()
{
$this->setPaginated()
->addFilter("country", CountryFilter::class);
} [...]
}
And filter is on:
But for now changing its value does nothing... We have to take this new filter into account:
class TeamSharpList extends SharpEntityList
{
[...]
function getListData(EntityListQueryParams $params)
{
$teams = Team::orderBy("name", "asc");
if($country = $params->filterFor("country")) {
$teams->where("country", $country);
}
return $this
->setCustomTransformer("players", function($players, $team) {
return $team->players()->count();
})
->transform(
$teams->paginate(30)
);
}
}
Like always with Sharp, you’ll have to write this code because Sharp won’t presume anything about your data structure, and this is very useful in many trickier cases. The result here is as expected:
Okay, let’s reproduce this quickly in a more realistic case; filter players by teams.
class TeamFilter implements EntityListRequiredFilter
{
public function values()
{
return Team::orderBy("name")
->pluck("name", "id");
}
public function defaultValue()
{
return Team::first()->id;
}
}
Notice we implement EntityListRequiredFilter, and thus we have to define defaultValue() too. The idea is that we decide it’s mandatory to choose a team to list players. More on this required filter and other options (like multiple filter) in the documentation.
class PlayerSharpList extends SharpEntityList
{
[...]
function buildListConfig()
{
$this->setPaginated()
->setSearchable()
->addFilter("team", TeamFilter::class);
}
function getListData(EntityListQueryParams $params)
{
$players = Player::orderBy(
$params->sortedBy(), $params->sortedDir()
)->where("team_id", $params->filterFor("team"));
[...]
}
}
Two minutes to implement, and it’s working:
I promised that we’ll review form lists, but I’d like to keep these posts short: I keep that for Part 4 (EDIT: which is live now).
The Part 3 code is available on github (https://github.com/code16/sharp-handball-sample/tree/part-3), and I tried to organize commits to make it easy to follow.