ResourceSorter.php

<?php

namespace Lia\Addon;


class ResourceSorter extends \Lia\Addon {

    public string $fqn = 'lia:server.resourcesorter';

    protected $didSet=false;

    protected $orders=['css'=>[], 'js'=>[]];


    public function init_lia(){
        $this->lia->methods['setResourceOrder'] = [$this,'setResourceOrder'];
    }

    /**
     * Give an array of file names in the order they should be sent to the browser
     *
     * @param $ext the file extension js or css
     * @param $names an array of relative file paths, in the order you want them. There MUST NOT be leading `/`. There MAY be as many `/` as you like
     * @param $prepend TRUE to put these $names BEFORE any previous names set this way. FALSE to put these names at the end. WILL replace any identical names for sorting
     */
    public function setResourceOrder($ext,$names, $prepend=true){
        $ext = strtolower($ext);
        if (!$this->didSet){
            $this->lia->setResourceSorter($ext, [$this, 'getSortedFiles']);
        }

        $names = array_reverse($names);
        foreach ($names as $n){
            if ($index=array_search($n,$this->orders)){
                unset($this->orders[$ext][$index]);
            }
            array_unshift($this->orders[$ext], $n);
        }
        
    }


    public function getSortedFiles($unsortedFiles){
        //@TODO add support for file paths using backslash separators like C:\Whatever\Folder\File.js
        if (count($unsortedFiles)==0)return;
        $f = array_values($unsortedFiles)[0];
        $ext = pathinfo($f, PATHINFO_EXTENSION);
        $ext = strtolower($ext);
        $orders = $this->orders[$ext];

        $counts = [];
        foreach ($orders as $o){
            $c = count(explode('/', $o));
            $counts[$c] = $c;
        }
        ksort($counts);
        $counts = array_reverse($counts, true);

        $filesOrder = array_flip($orders);
        $sorted = [];
        $append = [];
        foreach ($unsortedFiles as $f){
            $parts = explode('/', $f);
            foreach ($counts as $c){
                $bits = array_slice($parts, -$c);
                $piece = implode('/', $bits);
                if (isset($filesOrder[$piece])){
                    $index = $filesOrder[$piece];
                    $sorted[$index] = $f;
                    continue 2;
                }
            }
            $append[] = $f;
        } 
        ksort($sorted);
        $sorted = [...$sorted, ...$append];
        return $sorted;
    }

}