Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Intervals.php

function Intervals::generateIntervals

@phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}

Parameters

bool $stopOnFirstValidInterval:

3 calls to Intervals::generateIntervals()
Intervals::compactConstraint in vendor/composer/semver/src/Intervals.php
Attempts to optimize a MultiConstraint
Intervals::get in vendor/composer/semver/src/Intervals.php
Creates an array of numeric intervals and branch constraints representing a given constraint
Intervals::haveIntersections in vendor/composer/semver/src/Intervals.php
Checks whether $a and $b have any intersection, equivalent to $a->matches($b)

File

vendor/composer/semver/src/Intervals.php, line 288

Class

Intervals
Helper class generating intervals from constraints

Namespace

Composer\Semver

Code

private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false) {
    if ($constraint instanceof MatchAllConstraint) {
        return array(
            'numeric' => array(
                new Interval(Interval::fromZero(), Interval::untilPositiveInfinity()),
            ),
            'branches' => Interval::anyDev(),
        );
    }
    if ($constraint instanceof MatchNoneConstraint) {
        return array(
            'numeric' => array(),
            'branches' => array(
                'names' => array(),
                'exclude' => false,
            ),
        );
    }
    if ($constraint instanceof Constraint) {
        return self::generateSingleConstraintIntervals($constraint);
    }
    if (!$constraint instanceof MultiConstraint) {
        throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got ' . \get_class($constraint) . '.');
    }
    $constraints = $constraint->getConstraints();
    $numericGroups = array();
    $constraintBranches = array();
    foreach ($constraints as $c) {
        $res = self::get($c);
        $numericGroups[] = $res['numeric'];
        $constraintBranches[] = $res['branches'];
    }
    if ($constraint->isDisjunctive()) {
        $branches = Interval::noDev();
        foreach ($constraintBranches as $b) {
            if ($b['exclude']) {
                if ($branches['exclude']) {
                    // disjunctive constraint, so only exclude what's excluded in all constraints
                    // !=a,!=b || !=b,!=c => !=b
                    $branches['names'] = array_intersect($branches['names'], $b['names']);
                }
                else {
                    // disjunctive constraint so exclude all names which are not explicitly included in the alternative
                    // (==b || ==c) || !=a,!=b => !=a
                    $branches['exclude'] = true;
                    $branches['names'] = array_diff($b['names'], $branches['names']);
                }
            }
            else {
                if ($branches['exclude']) {
                    // disjunctive constraint so exclude all names which are not explicitly included in the alternative
                    // !=a,!=b || (==b || ==c) => !=a
                    $branches['names'] = array_diff($branches['names'], $b['names']);
                }
                else {
                    // disjunctive constraint, so just add all the other branches
                    // (==a || ==b) || ==c => ==a || ==b || ==c
                    $branches['names'] = array_merge($branches['names'], $b['names']);
                }
            }
        }
    }
    else {
        $branches = Interval::anyDev();
        foreach ($constraintBranches as $b) {
            if ($b['exclude']) {
                if ($branches['exclude']) {
                    // conjunctive, so just add all branch names to be excluded
                    // !=a && !=b => !=a,!=b
                    $branches['names'] = array_merge($branches['names'], $b['names']);
                }
                else {
                    // conjunctive, so only keep included names which are not excluded
                    // (==a||==c) && !=a,!=b => ==c
                    $branches['names'] = array_diff($branches['names'], $b['names']);
                }
            }
            else {
                if ($branches['exclude']) {
                    // conjunctive, so only keep included names which are not excluded
                    // !=a,!=b && (==a||==c) => ==c
                    $branches['names'] = array_diff($b['names'], $branches['names']);
                    $branches['exclude'] = false;
                }
                else {
                    // conjunctive, so only keep names that are included in both
                    // (==a||==b) && (==a||==c) => ==a
                    $branches['names'] = array_intersect($branches['names'], $b['names']);
                }
            }
        }
    }
    $branches['names'] = array_unique($branches['names']);
    if (\count($numericGroups) === 1) {
        return array(
            'numeric' => $numericGroups[0],
            'branches' => $branches,
        );
    }
    $borders = array();
    foreach ($numericGroups as $group) {
        foreach ($group as $interval) {
            $borders[] = array(
                'version' => $interval->getStart()
                    ->getVersion(),
                'operator' => $interval->getStart()
                    ->getOperator(),
                'side' => 'start',
            );
            $borders[] = array(
                'version' => $interval->getEnd()
                    ->getVersion(),
                'operator' => $interval->getEnd()
                    ->getOperator(),
                'side' => 'end',
            );
        }
    }
    $opSortOrder = self::$opSortOrder;
    usort($borders, function ($a, $b) use ($opSortOrder) {
        $order = version_compare($a['version'], $b['version']);
        if ($order === 0) {
            return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
        }
        return $order;
    });
    $activeIntervals = 0;
    $intervals = array();
    $index = 0;
    $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
    $start = null;
    foreach ($borders as $border) {
        if ($border['side'] === 'start') {
            $activeIntervals++;
        }
        else {
            $activeIntervals--;
        }
        if (!$start && $activeIntervals >= $activationThreshold) {
            $start = new Constraint($border['operator'], $border['version']);
        }
        elseif ($start && $activeIntervals < $activationThreshold) {
            // filter out invalid intervals like > x - <= x, or >= x - < x
            if (version_compare($start->getVersion(), $border['version'], '=') && ($start->getOperator() === '>' && $border['operator'] === '<=' || $start->getOperator() === '>=' && $border['operator'] === '<')) {
                unset($intervals[$index]);
            }
            else {
                $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
                $index++;
                if ($stopOnFirstValidInterval) {
                    break;
                }
            }
            $start = null;
        }
    }
    return array(
        'numeric' => $intervals,
        'branches' => $branches,
    );
}
RSS feed
Powered by Drupal