mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-06-29 07:59:31 +02:00
213 lines
4.9 KiB
PHP
213 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Core\Manifest;
|
|
|
|
use SilverStripe\Core\Injector\Injectable;
|
|
|
|
/**
|
|
* Sorts an associative array of items given a list of priorities,
|
|
* where priorities are the keys of the items in the order they are desired.
|
|
* Allows user-defined variables, and a "rest" key to symbolise all remaining items.
|
|
* Example:
|
|
*
|
|
* $myItems = [
|
|
* 'product-one' => new Product(...),
|
|
* 'product-two' => new Product(...),
|
|
* 'product-three' => new Product(...),
|
|
* 'product-four' => new Product(...),
|
|
* ];
|
|
*
|
|
* $priorities = [
|
|
* '$featured',
|
|
* 'product-two',
|
|
* '...rest',
|
|
* ];
|
|
*
|
|
* $sorter = new PrioritySorter($items, $priorities);
|
|
* $sorter->setVariable('$featured', 'product-three');
|
|
* $sorter->getSortedList();
|
|
*
|
|
* [
|
|
* 'product-three' => [object] Product,
|
|
* 'product-two' => [object] Product,
|
|
* 'product-one' => [object] Product,
|
|
* 'product-four' => [object] Product
|
|
* ]
|
|
*
|
|
*/
|
|
class PrioritySorter
|
|
{
|
|
use Injectable;
|
|
|
|
/**
|
|
* The key that is used to denote all remaining items that have not
|
|
* been specified in priorities
|
|
* @var string
|
|
*/
|
|
protected $restKey = '...rest';
|
|
|
|
/**
|
|
* A map of variables to their values
|
|
* @var array
|
|
*/
|
|
protected $variables = [];
|
|
|
|
/**
|
|
* An associative array of items, whose keys can be used in the $priorities list
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $items;
|
|
|
|
/**
|
|
* An indexed array of keys in the $items list, reflecting the desired sort
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $priorities;
|
|
|
|
/**
|
|
* The keys of the $items array
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $names;
|
|
|
|
/**
|
|
* PrioritySorter constructor.
|
|
* @param array $items
|
|
* @param array $priorities
|
|
*/
|
|
public function __construct(array $items = [], array $priorities = [])
|
|
{
|
|
$this->setItems($items);
|
|
$this->priorities = $priorities;
|
|
}
|
|
|
|
/**
|
|
* Sorts the items and returns a new version of $this->items
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getSortedList()
|
|
{
|
|
$this->addVariables();
|
|
|
|
// Find all items that don't have their order specified by the config system
|
|
$unspecified = array_diff($this->names, $this->priorities);
|
|
|
|
if (!empty($unspecified)) {
|
|
$this->includeRest($unspecified);
|
|
}
|
|
|
|
$sortedList = [];
|
|
foreach ($this->priorities as $itemName) {
|
|
if (isset($this->items[$itemName])) {
|
|
$sortedList[$itemName] = $this->items[$itemName];
|
|
}
|
|
}
|
|
|
|
return $sortedList;
|
|
}
|
|
|
|
/**
|
|
* Set the priorities for the items
|
|
*
|
|
* @param array $priorities An array of keys used in $this->items
|
|
* @return $this
|
|
*/
|
|
public function setPriorities(array $priorities)
|
|
{
|
|
$this->priorities = $priorities;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Sets the list of all items
|
|
*
|
|
* @param array $items
|
|
* @return $this
|
|
*/
|
|
public function setItems(array $items)
|
|
{
|
|
$this->items = $items;
|
|
$this->names = array_keys($items);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add a variable for replacination, e.g. addVariable->('$project', 'myproject')
|
|
*
|
|
* @param string $name
|
|
* @param $value
|
|
* @return $this
|
|
*/
|
|
public function setVariable($name, $value)
|
|
{
|
|
$this->variables[$name] = $value;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* The key used for "all other items"
|
|
*
|
|
* @param $key
|
|
* @return $this
|
|
*/
|
|
public function setRestKey($key)
|
|
{
|
|
$this->restKey = $key;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* If variables are defined, interpolate their values
|
|
*/
|
|
protected function addVariables()
|
|
{
|
|
// Remove variables from the list
|
|
$varValues = array_values($this->variables);
|
|
$this->names = array_filter($this->names, function ($name) use ($varValues) {
|
|
return !in_array($name, $varValues);
|
|
});
|
|
|
|
// Replace variables with their values
|
|
$this->priorities = array_map(function ($name) {
|
|
return $this->resolveValue($name);
|
|
}, $this->priorities);
|
|
}
|
|
|
|
/**
|
|
* If the "rest" key exists in the order array,
|
|
* replace it by the unspecified items
|
|
*/
|
|
protected function includeRest(array $list)
|
|
{
|
|
$otherItemsIndex = false;
|
|
if ($this->restKey) {
|
|
$otherItemsIndex = array_search($this->restKey, $this->priorities);
|
|
}
|
|
if ($otherItemsIndex !== false) {
|
|
array_splice($this->priorities, $otherItemsIndex, 1, $list);
|
|
} else {
|
|
// Otherwise just jam them on the end
|
|
$this->priorities = array_merge($this->priorities, $list);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ensure variables get converted to their values
|
|
*
|
|
* @param $name
|
|
* @return mixed
|
|
*/
|
|
protected function resolveValue($name)
|
|
{
|
|
return isset($this->variables[$name]) ? $this->variables[$name] : $name;
|
|
}
|
|
}
|