Open aerni opened 3 years ago
I'm not sure but I'd imagine it's probably just something that was just never ported across.
They don't exist because we switched to using query builders. We want to be able to work just like Eloquent. If you swapped to using a database, the syntax would be the same.
Filters worked because you would start with all the entries. Potentially very inefficient. Imagine you have a database with 10,000+ entries.
But, I suppose we could still bring them back. You'd just need to be aware of the drawbacks.
Yeah, I understand your point. There might be a possible middle ground though.
What I'm looking for is a way to filter and transform the collection data. With scopes, you can only apply queries. Would it maybe be possible to also be able to transform data in the scope class and return that? Does that make sense?
Your request makes sense but it won't be doable in its current state. Same with what Erin just linked to.
The scope doesn't manipulate anything. It happens later on in the tag.
$query = Entry::query();
$yourScope->apply($query); // gets sent to your scope where you can add where clauses, etc.
$query->get(); // this is where all the magic happens and it finally returns Entry instances.
We can't just let you filter afterwards either because it would have been limited and paginated by that point too.
Transforming though, sure. That's probably simple enough. Although you could do that now already.
{{ collection:blog as="entries" }}
{{ entries a_modifier_that_transforms_them="true" }}
//
{{ /entries }}
{{ /collection:blog }}
Maybe there could be a step in between. Something like $query->entries()
to get all entries. Do custom magic on there. And then $query->get()
at the end to paginate etc.
Can you give a concrete example of what you plan to do?
Sure thing. This is a recent example of a class that used to be a filter in v2 and had to be refactored to a tag in v3.
If the tag has a lat
and lng
parameter, I need to map through the collection entries and return the transformed result. And apply the limit at the end. Because of the current limitation, I can't easily add pagination.
<?php
namespace App\Tags;
use Illuminate\Support\Collection;
use Statamic\Tags\Collection\Collection as CollectionTag;
class NearbyLibraries extends CollectionTag
{
/**
* The {{ nearby_libraries:* }} tag.
*/
public function __call($method, $args): Collection
{
return $this->outputLibraries();
}
/**
* The {{ nearby_libraries }} tag.
*
* @return Collection
*/
public function index(): Collection
{
return $this->outputLibraries();
}
private function outputLibraries()
{
$this->params->put('from', 'libraries');
$this->limit = $this->params->pull('limit');
$this->lat = $this->params->get('lat');
$this->lng = $this->params->get('lng');
$libraries = parent::index();
if ($as = $this->params->get('as')) {
$libraries = $libraries[$as];
}
return $this->hasCoordinates() ? $this->nearbyLibraries($libraries) : $libraries->limit($this->limit);
}
private function nearbyLibraries($libraries): Collection
{
return $libraries->map(function ($library) {
$distance = $this->haversine($this->lat, $this->lng, $library->get('branch_latitude'), $library->get('branch_longitude'));
$distanceInMiles = intval(round($distance / 1609));
$library->set('distance', $distanceInMiles);
$library->set('distanceLabel', $distanceInMiles . ' mile' . ($distanceInMiles === 1 ? '' : 's'));
return $library;
})
->sortBy(function ($library) {
return $library->get('distance');
})
->limit($this->limit);
}
private function hasCoordinates(): bool
{
if (empty($this->lat)) {
return false;
}
if (empty($this->lng)) {
return false;
}
return true;
}
private function haversine(float $latitudeFrom, float $longitudeFrom, float $latitudeTo, float $longitudeTo, int $earthRadius = 6371000): float
{
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
return $angle * $earthRadius;
}
}
Yup, almost exactly the same tag I've written a few times.
Please bring back the collection filter functionality from v2. I've been running into a few cases, where scopes just don't do it. So I had to write a custom tag that extends from the collection tag class and do the filtering in there. But there are things that don't work properly. Like pagination, limit, etc. It's a real headache to reimplement all this. I really miss filters and it's a step back in many ways.
Any reason filters don't exist anymore?