alexcrawford / lexorank-php
PHP Implementation of JIRA's LexoRank algorithm.
Requires
- php: ~8.0 || ~8.1 || ~8.2
- webmozart/assert: ^1.11
Requires (Dev)
- doctrine/coding-standard: ^10.0
- phpunit/phpunit: ^9.5
- psalm/plugin-phpunit: ^0.17.0
- roave/infection-static-analysis-plugin: ^1.23
- vimeo/psalm: ^4.27
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-02 12:38:38 UTC
README
A simple PHP implementation of xissy/lexorank
LexoRank is a ranking system introduced by Atlassian JIRA.
Background
What is the best representation of an ordered list in a database? With a dumb order number based ranking system, re-ordering a row of a list may require updating all rows of the list in a transaction, which is O(n).
- https://stackoverflow.com/questions/9536262/best-representation-of-an-ordered-list-in-a-database/49956113
- https://softwareengineering.stackexchange.com/questions/195308/storing-a-re-orderable-list-in-a-database
LexoRank makes it O(1). All you need to do is updating the re-ordered row's order field.
Installation
composer require alexcrawford/lexorank-php
Requires PHP 8.1 or later.
Usage
use AlexCrawford\LexoRank\Rank; $first = Rank::forEmptySequence(); // 'U' $last = Rank::after($first); // 'V' $top = Rank::before($first); // 'T' $middle = Rank::betweenRanks($first, $last); // 'UU' $rank = Rank::fromString($row->sort); $rank->get(); // the string to store
betweenRanks() throws PrevGreaterThanOrEquals if the first rank
does not sort before the second.
Storing ranks
Ranks are made of the ASCII characters 0 to z, which includes
upper case, lower case and a few punctuation characters. Order by the
column with a binary or case-sensitive collation, or the database will
sort a and A together and the order will be wrong. In MySQL, use
ascii_bin or utf8mb4_bin.
A rank can be up to 1024 characters (Rank::MAX_RANK_LEN), and
anything longer throws MaxRankLength. Ranks get longer as you keep
inserting at the same place, for example appending to the end of one
list many thousands of times. The library doesn't rebalance a list, so
if that happens, rewrite the list's ranks from forEmptySequence()
onwards.
Development
composer install
vendor/bin/phpunit
vendor/bin/psalm
vendor/bin/phpcs
CI also runs Infection mutation tests.