dragon-code/size-sorter
dragon-code/size-sorter is a lightweight Laravel/PHP package for sorting files and directories by size. It supports human-readable size units and flexible ascending or descending ordering, making it easy to organize file collections, reports, and storage cleanup tasks in your applications.
Install it as a normal Composer dependency:
composer require dragon-code/size-sorter
Check the package name first if you are upgrading an existing project. Release 2.1.0 renamed the project from Product Size Sorter to Size Sorter. That rename is the kind of change that moves the Composer package name and/or the repository URL. If you installed it earlier, run composer show | grep size and compare against the require line in composer.json before bumping — a rename usually means you either need to composer remove the old name first, or that the old name is kept as a replace/alias. Also re-check the FQCN in src/ (DragonCode\SizeSorter\…) rather than trusting a namespace copied from an old blog post; the class name may or may not have followed the project rename.
It is a small, single-purpose utility package — expect no service provider to publish, no migrations, no config file unless the README says otherwise (check composer.json under extra.laravel.providers to confirm whether auto-discovery registers anything, and check require for the illuminate/* and php constraints). The whole surface area is one class with one job: take an array of size strings and give it back in a human-meaningful order.
Where to look first, in order:
src/ — find the main sorter class and skim its method names. That is your real API documentation for a package this size. Note whether it exposes a static sort() helper, an instantiable object, or a facade, because the calling convention dictates how you wire it into your app.tests/ — the fixtures are the best specification of supported inputs. If your catalogue uses XXL, 2XL, UK 10, 170-176, 75B, or 120x60x75, grep the tests for those exact strings before assuming support.Laravel version support: 2.1.0 explicitly adds Laravel 13 compatibility. If you are still on 10/11/12 this changes nothing for you, but it does mean the package is actively following the framework — so it is safe to upgrade Laravel without being blocked by this dependency, and conversely you should not need to hold the package back on an L13 migration. Confirm the actual constraint in composer.json rather than assuming a floor.
Your first real use case: a product filter or size dropdown where S, M, L, XL, XXL currently displays in whatever order the database or a distinct() query returned. Sorting that array is a two-line change and immediately visible in the UI — a good smoke test that the package handles your size vocabulary before you commit to it anywhere important.
use DragonCode\SizeSorter\SizeSorter; // confirm exact FQCN in src/
$sizes = ['XL', 'S', 'XXL', 'M', 'L'];
$sorted = SizeSorter::sort($sizes);
// ['S', 'M', 'L', 'XL', 'XXL']
Wrap it behind your own service. With a small star count and no meaningful dependents, treat this as a leaf utility you may need to replace — and 2.1.0 is a good reminder why: a project rename is exactly the kind of change a wrapper absorbs for you. A thin App\Support\SizeOrder class that delegates to the package gives you one place to swap implementations, one place to normalize input, and one place to add caching:
final class SizeOrder
{
public static function sort(array $sizes): array
{
$clean = array_values(array_unique(array_map(
fn ($s) => mb_strtoupper(trim((string) $s)),
$sizes
)));
return SizeSorter::sort($clean);
}
}
The wrapper is also your rename firewall: when the package's namespace or package name moves again, one file changes.
Sorting Eloquent results in PHP, not SQL. There is no SQL equivalent for "S comes before M comes before L". Keep the distinct() / groupBy('size') cheap in the database, then order the resulting collection in PHP:
$sizes = Product::query()
->where('category_id', $category->id)
->whereNotNull('size')
->distinct()
->pluck('size')
->all();
$ordered = SizeOrder::sort($sizes);
For a large facet list, cache the ordered array keyed by category and bust it whenever a product is saved — sorting is cheap, but you don't want it on every pageview of a busy filter panel.
Sort a collection in place when you need the models, not just the values. Build an index map from the sorted order and use sortBy:
$order = array_flip(SizeOrder::sort($variants->pluck('size')->all()));
$variants = $variants->sortBy(
fn ($v) => $order[mb_strtoupper(trim($v->size))] ?? PHP_INT_MAX
)->values();
The ?? PHP_INT_MAX fallback matters: anything the sorter silently dropped or didn't recognize should land at the end, not throw.
Form requests — validate before you sort. The sorter orders; it does not validate. Pair it with a whitelist derived from the same source so the two never disagree:
$allowed = SizeOrder::sort(array_keys(config('shop.sizes')));
$request->validate([
'size' => ['required', 'string', Rule::in($allowed)],
]);
Multi-select and filter UI. When the user submits sizes[]=M&sizes[]=L, normalize the payload through the same SizeOrder::sort() before storing or querying. That keeps the canonical order consistent between what the filter renders and what the API echoes back, which removes a whole class of "the chip order changed after refresh" bugs.
Blade / Inertia boundary. Compute the ordered list in a view composer or controller and pass it down as a plain array. Don't call the sorter from a Blade template — you lose the ability to cache it and to assert on it in tests.
Upgrade path for the rename. When moving to 2.1.0, do it as a deliberate two-step: bump, run your fixture tests, then commit. Don't let the rename land in the same PR as unrelated feature work — if the package name changed and you also need to touch the require line, lock file, and possibly a use statement, you want that diff isolated and easy to revert.
Normalize before you sort. Case and whitespace are the number one source of "it doesn't work": 'xl', 'XL', ' XL', and 'Xl' will not all be matched unless you trim() + uppercase first. If your data comes from supplier feeds, also strip non-breaking spaces and full-width characters.
Verify where unknown values land. Before shipping, write a throwaway test with deliberately bad input (['', 'ONE SIZE', 'M', '???']) and confirm the package's behavior — whether it drops them, keeps them in place, or moves them to the front/back. Then codify that expectation in your own wrapper so a future package upgrade can't silently reorder your UI.
Don't mix categories in one call. Clothing sizes, bra sizes (75B, 80C), heights (170-176), and furniture dimensions (120x60x75) are different orderings over different grammars. Sorting a combined array — or letting a user-facing filter span two categories — will produce nonsense. Branch by category and sort each independently.
Regional sizes need a mapping layer first. If you sell across UK/EU/US, decide on one canonical internal representation and convert at the edges. The sorter knows the sequences it knows; UK 10 vs EU 38 vs M in the same array is a data modeling problem, not a sorting problem.
Hyphenated ranges and + sizes deserve explicit tests. Catalogue strings like 2XL-3XL, 170-176, or XXL+ are exactly where a general-purpose size sorter has the least predictable behavior. Add fixture tests using strings copy-pasted from your real product table, not invented examples.
The 2.1.0 rename breaks your paper trail, not just your imports. Docs, internal wiki pages, PR review comments, and search results all still say Product Size Sorter. If a new team member is asked to "check the size sorter docs", they will land on the old repo name and possibly a stale README. Record the new name in your composer.json comment/README and link to the current repository in one place.
Laravel 13 compatibility is the only functional change in 2.1.0. Everything else is metadata, license year, and README/image churn. So if you are not on L13 and not affected by the rename, the risk of skipping 2.1.0 is essentially zero — and if you are on L13, this is the release that unblocks you. Either way there are no deprecations or BC breaks signalled in the notes beyond the naming.
Pin the version and read the changelog on upgrade. The maintainer ships frequently across a large ecosystem, and this release proves the point: a "minor" version can still change the project's identity. A caret constraint plus a quick scan of the diff before bumping is cheap insurance for something that touches your product listing order.
Extension point is your wrapper, not the package. If you need custom sequences (children's sizes by age, mattress sizes by country), don't fork. Keep the domain-specific map in your own config and only hand the package the subset it understands — or bypass it entirely for that category and sort off your own index.
Testing tip: assert on the full resulting array, not just the first element. Half the failure modes here are "correct at the front, wrong at the tail" where unrecognized values accumulate. After a version bump — especially one with a rename in it — re-run those fixture tests before touching anything else, so you separate "the upgrade broke sorting" from "my refactor broke sorting".
How can I help you explore Laravel packages today?