commit vendor

This commit is contained in:
2025-11-11 14:49:30 +01:00
parent f33121a308
commit 6d03080c00
2436 changed files with 483781 additions and 0 deletions

27
vendor/sabre/event/LICENSE vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (C) 2013-2016 fruux GmbH (https://fruux.com/)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Sabre nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

19
vendor/sabre/event/lib/Emitter.php vendored Normal file
View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* Emitter object.
*
* Instantiate this class, or subclass it for easily creating event emitters.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class Emitter implements EmitterInterface
{
use EmitterTrait;
}

View File

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* Event Emitter Interface.
*
* Anything that accepts listeners and emits events should implement this
* interface.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
interface EmitterInterface
{
/**
* Subscribe to an event.
*/
public function on(string $eventName, callable $callBack, int $priority = 100);
/**
* Subscribe to an event exactly once.
*/
public function once(string $eventName, callable $callBack, int $priority = 100);
/**
* Emits an event.
*
* This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain.
*
* If the continueCallBack is specified, this callback will be called every
* time before the next event handler is called.
*
* If the continueCallback returns false, event propagation stops. This
* allows you to use the eventEmitter as a means for listeners to implement
* functionality in your application, and break the event loop as soon as
* some condition is fulfilled.
*
* Note that returning false from an event subscriber breaks propagation
* and returns false, but if the continue-callback stops propagation, this
* is still considered a 'successful' operation and returns true.
*
* Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times.
*/
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool;
/**
* Returns the list of listeners for an event.
*
* The list is returned as an array, and the list of events are sorted by
* their priority.
*
* @return callable[]
*/
public function listeners(string $eventName): array;
/**
* Removes a specific listener from an event.
*
* If the listener could not be found, this method will return false. If it
* was removed it will return true.
*/
public function removeListener(string $eventName, callable $listener): bool;
/**
* Removes all listeners.
*
* If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is
* removed.
*/
public function removeAllListeners(string $eventName = null);
}

178
vendor/sabre/event/lib/EmitterTrait.php vendored Normal file
View File

@ -0,0 +1,178 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* Event Emitter Trait.
*
* This trait contains all the basic functions to implement an
* EventEmitterInterface.
*
* Using the trait + interface allows you to add EventEmitter capabilities
* without having to change your base-class.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
trait EmitterTrait
{
/**
* Subscribe to an event.
*/
public function on(string $eventName, callable $callBack, int $priority = 100)
{
if (!isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = [
true, // If there's only one item, it's sorted
[$priority],
[$callBack],
];
} else {
$this->listeners[$eventName][0] = false; // marked as unsorted
$this->listeners[$eventName][1][] = $priority;
$this->listeners[$eventName][2][] = $callBack;
}
}
/**
* Subscribe to an event exactly once.
*/
public function once(string $eventName, callable $callBack, int $priority = 100)
{
$wrapper = null;
$wrapper = function () use ($eventName, $callBack, &$wrapper) {
$this->removeListener($eventName, $wrapper);
return \call_user_func_array($callBack, \func_get_args());
};
$this->on($eventName, $wrapper, $priority);
}
/**
* Emits an event.
*
* This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain.
*
* If the continueCallBack is specified, this callback will be called every
* time before the next event handler is called.
*
* If the continueCallback returns false, event propagation stops. This
* allows you to use the eventEmitter as a means for listeners to implement
* functionality in your application, and break the event loop as soon as
* some condition is fulfilled.
*
* Note that returning false from an event subscriber breaks propagation
* and returns false, but if the continue-callback stops propagation, this
* is still considered a 'successful' operation and returns true.
*
* Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times.
*/
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
{
if (\is_null($continueCallBack)) {
foreach ($this->listeners($eventName) as $listener) {
$result = \call_user_func_array($listener, $arguments);
if (false === $result) {
return false;
}
}
} else {
$listeners = $this->listeners($eventName);
$counter = \count($listeners);
foreach ($listeners as $listener) {
--$counter;
$result = \call_user_func_array($listener, $arguments);
if (false === $result) {
return false;
}
if ($counter > 0) {
if (!$continueCallBack()) {
break;
}
}
}
}
return true;
}
/**
* Returns the list of listeners for an event.
*
* The list is returned as an array, and the list of events are sorted by
* their priority.
*
* @return callable[]
*/
public function listeners(string $eventName): array
{
if (!isset($this->listeners[$eventName])) {
return [];
}
// The list is not sorted
if (!$this->listeners[$eventName][0]) {
// Sorting
\array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]);
// Marking the listeners as sorted
$this->listeners[$eventName][0] = true;
}
return $this->listeners[$eventName][2];
}
/**
* Removes a specific listener from an event.
*
* If the listener could not be found, this method will return false. If it
* was removed it will return true.
*/
public function removeListener(string $eventName, callable $listener): bool
{
if (!isset($this->listeners[$eventName])) {
return false;
}
foreach ($this->listeners[$eventName][2] as $index => $check) {
if ($check === $listener) {
unset($this->listeners[$eventName][1][$index]);
unset($this->listeners[$eventName][2][$index]);
return true;
}
}
return false;
}
/**
* Removes all listeners.
*
* If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is
* removed.
*/
public function removeAllListeners(string $eventName = null)
{
if (!\is_null($eventName)) {
unset($this->listeners[$eventName]);
} else {
$this->listeners = [];
}
}
/**
* The list of listeners.
*
* @var array
*/
protected $listeners = [];
}

20
vendor/sabre/event/lib/EventEmitter.php vendored Normal file
View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* This is the old name for the Emitter class.
*
* Instead of of using EventEmitter, please use Emitter. They are identical
* otherwise.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class EventEmitter implements EmitterInterface
{
use EmitterTrait;
}

341
vendor/sabre/event/lib/Loop/Loop.php vendored Normal file
View File

@ -0,0 +1,341 @@
<?php
declare(strict_types=1);
namespace Sabre\Event\Loop;
/**
* A simple eventloop implementation.
*
* This eventloop supports:
* * nextTick
* * setTimeout for delayed functions
* * setInterval for repeating functions
* * stream events using stream_select
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class Loop
{
/**
* Executes a function after x seconds.
*/
public function setTimeout(callable $cb, float $timeout)
{
$triggerTime = microtime(true) + ($timeout);
if (!$this->timers) {
// Special case when the timers array was empty.
$this->timers[] = [$triggerTime, $cb];
return;
}
// We need to insert these values in the timers array, but the timers
// array must be in reverse-order of trigger times.
//
// So here we search the array for the insertion point.
$index = count($this->timers) - 1;
while (true) {
if ($triggerTime < $this->timers[$index][0]) {
array_splice(
$this->timers,
$index + 1,
0,
[[$triggerTime, $cb]]
);
break;
} elseif (0 === $index) {
array_unshift($this->timers, [$triggerTime, $cb]);
break;
}
--$index;
}
}
/**
* Executes a function every x seconds.
*
* The value this function returns can be used to stop the interval with
* clearInterval.
*/
public function setInterval(callable $cb, float $timeout): array
{
$keepGoing = true;
$f = null;
$f = function () use ($cb, &$f, $timeout, &$keepGoing) {
if ($keepGoing) {
$cb();
$this->setTimeout($f, $timeout);
}
};
$this->setTimeout($f, $timeout);
// Really the only thing that matters is returning the $keepGoing
// boolean value.
//
// We need to pack it in an array to allow returning by reference.
// Because I'm worried people will be confused by using a boolean as a
// sort of identifier, I added an extra string.
return ['I\'m an implementation detail', &$keepGoing];
}
/**
* Stops a running interval.
*/
public function clearInterval(array $intervalId)
{
$intervalId[1] = false;
}
/**
* Runs a function immediately at the next iteration of the loop.
*/
public function nextTick(callable $cb)
{
$this->nextTick[] = $cb;
}
/**
* Adds a read stream.
*
* The callback will be called as soon as there is something to read from
* the stream.
*
* You MUST call removeReadStream after you are done with the stream, to
* prevent the eventloop from never stopping.
*
* @param resource $stream
*/
public function addReadStream($stream, callable $cb)
{
$this->readStreams[(int) $stream] = $stream;
$this->readCallbacks[(int) $stream] = $cb;
}
/**
* Adds a write stream.
*
* The callback will be called as soon as the system reports it's ready to
* receive writes on the stream.
*
* You MUST call removeWriteStream after you are done with the stream, to
* prevent the eventloop from never stopping.
*
* @param resource $stream
*/
public function addWriteStream($stream, callable $cb)
{
$this->writeStreams[(int) $stream] = $stream;
$this->writeCallbacks[(int) $stream] = $cb;
}
/**
* Stop watching a stream for reads.
*
* @param resource $stream
*/
public function removeReadStream($stream)
{
unset(
$this->readStreams[(int) $stream],
$this->readCallbacks[(int) $stream]
);
}
/**
* Stop watching a stream for writes.
*
* @param resource $stream
*/
public function removeWriteStream($stream)
{
unset(
$this->writeStreams[(int) $stream],
$this->writeCallbacks[(int) $stream]
);
}
/**
* Runs the loop.
*
* This function will run continuously, until there's no more events to
* handle.
*/
public function run()
{
$this->running = true;
do {
$hasEvents = $this->tick(true);
} while ($this->running && $hasEvents);
$this->running = false;
}
/**
* Executes all pending events.
*
* If $block is turned true, this function will block until any event is
* triggered.
*
* If there are now timeouts, nextTick callbacks or events in the loop at
* all, this function will exit immediately.
*
* This function will return true if there are _any_ events left in the
* loop after the tick.
*/
public function tick(bool $block = false): bool
{
$this->runNextTicks();
$nextTimeout = $this->runTimers();
// Calculating how long runStreams should at most wait.
if (!$block) {
// Don't wait
$streamWait = 0;
} elseif ($this->nextTick) {
// There's a pending 'nextTick'. Don't wait.
$streamWait = 0;
} elseif (is_numeric($nextTimeout)) {
// Wait until the next Timeout should trigger.
$streamWait = $nextTimeout;
} else {
// Wait indefinitely
$streamWait = null;
}
$this->runStreams($streamWait);
return $this->readStreams || $this->writeStreams || $this->nextTick || $this->timers;
}
/**
* Stops a running eventloop.
*/
public function stop()
{
$this->running = false;
}
/**
* Executes all 'nextTick' callbacks.
*
* return void
*/
protected function runNextTicks()
{
$nextTick = $this->nextTick;
$this->nextTick = [];
foreach ($nextTick as $cb) {
$cb();
}
}
/**
* Runs all pending timers.
*
* After running the timer callbacks, this function returns the number of
* seconds until the next timer should be executed.
*
* If there's no more pending timers, this function returns null.
*
* @return float|null
*/
protected function runTimers()
{
$now = microtime(true);
while (($timer = array_pop($this->timers)) && $timer[0] < $now) {
$timer[1]();
}
// Add the last timer back to the array.
if ($timer) {
$this->timers[] = $timer;
return max(0, $timer[0] - microtime(true));
}
}
/**
* Runs all pending stream events.
*
* If $timeout is 0, it will return immediately. If $timeout is null, it
* will wait indefinitely.
*
* @param float|null timeout
*/
protected function runStreams($timeout)
{
if ($this->readStreams || $this->writeStreams) {
$read = $this->readStreams;
$write = $this->writeStreams;
$except = null;
if (stream_select($read, $write, $except, (null === $timeout) ? null : 0, $timeout ? (int) ($timeout * 1000000) : 0)) {
// See PHP Bug https://bugs.php.net/bug.php?id=62452
// Fixed in PHP7
foreach ($read as $readStream) {
$readCb = $this->readCallbacks[(int) $readStream];
$readCb();
}
foreach ($write as $writeStream) {
$writeCb = $this->writeCallbacks[(int) $writeStream];
$writeCb();
}
}
} elseif ($this->running && ($this->nextTick || $this->timers)) {
usleep(null !== $timeout ? intval($timeout * 1000000) : 200000);
}
}
/**
* Is the main loop active.
*
* @var bool
*/
protected $running = false;
/**
* A list of timers, added by setTimeout.
*
* @var array
*/
protected $timers = [];
/**
* A list of 'nextTick' callbacks.
*
* @var callable[]
*/
protected $nextTick = [];
/**
* List of readable streams for stream_select, indexed by stream id.
*
* @var resource[]
*/
protected $readStreams = [];
/**
* List of writable streams for stream_select, indexed by stream id.
*
* @var resource[]
*/
protected $writeStreams = [];
/**
* List of read callbacks, indexed by stream id.
*
* @var callable[]
*/
protected $readCallbacks = [];
/**
* List of write callbacks, indexed by stream id.
*
* @var callable[]
*/
protected $writeCallbacks = [];
}

View File

@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace Sabre\Event\Loop;
/**
* Executes a function after x seconds.
*/
function setTimeout(callable $cb, float $timeout)
{
instance()->setTimeout($cb, $timeout);
}
/**
* Executes a function every x seconds.
*
* The value this function returns can be used to stop the interval with
* clearInterval.
*/
function setInterval(callable $cb, float $timeout): array
{
return instance()->setInterval($cb, $timeout);
}
/**
* Stops a running interval.
*/
function clearInterval(array $intervalId)
{
instance()->clearInterval($intervalId);
}
/**
* Runs a function immediately at the next iteration of the loop.
*/
function nextTick(callable $cb)
{
instance()->nextTick($cb);
}
/**
* Adds a read stream.
*
* The callback will be called as soon as there is something to read from
* the stream.
*
* You MUST call removeReadStream after you are done with the stream, to
* prevent the eventloop from never stopping.
*
* @param resource $stream
*/
function addReadStream($stream, callable $cb)
{
instance()->addReadStream($stream, $cb);
}
/**
* Adds a write stream.
*
* The callback will be called as soon as the system reports it's ready to
* receive writes on the stream.
*
* You MUST call removeWriteStream after you are done with the stream, to
* prevent the eventloop from never stopping.
*
* @param resource $stream
*/
function addWriteStream($stream, callable $cb)
{
instance()->addWriteStream($stream, $cb);
}
/**
* Stop watching a stream for reads.
*
* @param resource $stream
*/
function removeReadStream($stream)
{
instance()->removeReadStream($stream);
}
/**
* Stop watching a stream for writes.
*
* @param resource $stream
*/
function removeWriteStream($stream)
{
instance()->removeWriteStream($stream);
}
/**
* Runs the loop.
*
* This function will run continuously, until there's no more events to
* handle.
*/
function run()
{
instance()->run();
}
/**
* Executes all pending events.
*
* If $block is turned true, this function will block until any event is
* triggered.
*
* If there are now timeouts, nextTick callbacks or events in the loop at
* all, this function will exit immediately.
*
* This function will return true if there are _any_ events left in the
* loop after the tick.
*/
function tick(bool $block = false): bool
{
return instance()->tick($block);
}
/**
* Stops a running eventloop.
*/
function stop()
{
instance()->stop();
}
/**
* Retrieves or sets the global Loop object.
*/
function instance(Loop $newLoop = null): Loop
{
static $loop;
if ($newLoop) {
$loop = $newLoop;
} elseif (!$loop) {
$loop = new Loop();
}
return $loop;
}

258
vendor/sabre/event/lib/Promise.php vendored Normal file
View File

@ -0,0 +1,258 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
use Exception;
use Throwable;
/**
* An implementation of the Promise pattern.
*
* A promise represents the result of an asynchronous operation.
* At any given point a promise can be in one of three states:
*
* 1. Pending (the promise does not have a result yet).
* 2. Fulfilled (the asynchronous operation has completed with a result).
* 3. Rejected (the asynchronous operation has completed with an error).
*
* To get a callback when the operation has finished, use the `then` method.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class Promise
{
/**
* The asynchronous operation is pending.
*/
const PENDING = 0;
/**
* The asynchronous operation has completed, and has a result.
*/
const FULFILLED = 1;
/**
* The asynchronous operation has completed with an error.
*/
const REJECTED = 2;
/**
* The current state of this promise.
*
* @var int
*/
public $state = self::PENDING;
/**
* Creates the promise.
*
* The passed argument is the executor. The executor is automatically
* called with two arguments.
*
* Each are callbacks that map to $this->fulfill and $this->reject.
* Using the executor is optional.
*/
public function __construct(callable $executor = null)
{
if ($executor) {
$executor(
[$this, 'fulfill'],
[$this, 'reject']
);
}
}
/**
* This method allows you to specify the callback that will be called after
* the promise has been fulfilled or rejected.
*
* Both arguments are optional.
*
* This method returns a new promise, which can be used for chaining.
* If either the onFulfilled or onRejected callback is called, you may
* return a result from this callback.
*
* If the result of this callback is yet another promise, the result of
* _that_ promise will be used to set the result of the returned promise.
*
* If either of the callbacks return any other value, the returned promise
* is automatically fulfilled with that value.
*
* If either of the callbacks throw an exception, the returned promise will
* be rejected and the exception will be passed back.
*/
public function then(callable $onFulfilled = null, callable $onRejected = null): Promise
{
// This new subPromise will be returned from this function, and will
// be fulfilled with the result of the onFulfilled or onRejected event
// handlers.
$subPromise = new self();
switch ($this->state) {
case self::PENDING:
// The operation is pending, so we keep a reference to the
// event handlers so we can call them later.
$this->subscribers[] = [$subPromise, $onFulfilled, $onRejected];
break;
case self::FULFILLED:
// The async operation is already fulfilled, so we trigger the
// onFulfilled callback asap.
$this->invokeCallback($subPromise, $onFulfilled);
break;
case self::REJECTED:
// The async operation failed, so we call the onRejected
// callback asap.
$this->invokeCallback($subPromise, $onRejected);
break;
}
return $subPromise;
}
/**
* Add a callback for when this promise is rejected.
*
* Its usage is identical to then(). However, the otherwise() function is
* preferred.
*/
public function otherwise(callable $onRejected): Promise
{
return $this->then(null, $onRejected);
}
/**
* Marks this promise as fulfilled and sets its return value.
*
* @param mixed $value
*/
public function fulfill($value = null)
{
if (self::PENDING !== $this->state) {
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
}
$this->state = self::FULFILLED;
$this->value = $value;
foreach ($this->subscribers as $subscriber) {
$this->invokeCallback($subscriber[0], $subscriber[1]);
}
}
/**
* Marks this promise as rejected, and set it's rejection reason.
*/
public function reject(Throwable $reason)
{
if (self::PENDING !== $this->state) {
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
}
$this->state = self::REJECTED;
$this->value = $reason;
foreach ($this->subscribers as $subscriber) {
$this->invokeCallback($subscriber[0], $subscriber[2]);
}
}
/**
* Stops execution until this promise is resolved.
*
* This method stops execution completely. If the promise is successful with
* a value, this method will return this value. If the promise was
* rejected, this method will throw an exception.
*
* This effectively turns the asynchronous operation into a synchronous
* one. In PHP it might be useful to call this on the last promise in a
* chain.
*
* @return mixed
*/
public function wait()
{
$hasEvents = true;
while (self::PENDING === $this->state) {
if (!$hasEvents) {
throw new \LogicException('There were no more events in the loop. This promise will never be fulfilled.');
}
// As long as the promise is not fulfilled, we tell the event loop
// to handle events, and to block.
$hasEvents = Loop\tick(true);
}
if (self::FULFILLED === $this->state) {
// If the state of this promise is fulfilled, we can return the value.
return $this->value;
} else {
// If we got here, it means that the asynchronous operation
// errored. Therefore we need to throw an exception.
throw $this->value;
}
}
/**
* A list of subscribers. Subscribers are the callbacks that want us to let
* them know if the callback was fulfilled or rejected.
*
* @var array
*/
protected $subscribers = [];
/**
* The result of the promise.
*
* If the promise was fulfilled, this will be the result value. If the
* promise was rejected, this property hold the rejection reason.
*
* @var mixed
*/
protected $value = null;
/**
* This method is used to call either an onFulfilled or onRejected callback.
*
* This method makes sure that the result of these callbacks are handled
* correctly, and any chained promises are also correctly fulfilled or
* rejected.
*
* @param callable $callBack
*/
private function invokeCallback(Promise $subPromise, callable $callBack = null)
{
// We use 'nextTick' to ensure that the event handlers are always
// triggered outside of the calling stack in which they were originally
// passed to 'then'.
//
// This makes the order of execution more predictable.
Loop\nextTick(function () use ($callBack, $subPromise) {
if (is_callable($callBack)) {
try {
$result = $callBack($this->value);
if ($result instanceof self) {
// If the callback (onRejected or onFulfilled)
// returned a promise, we only fulfill or reject the
// chained promise once that promise has also been
// resolved.
$result->then([$subPromise, 'fulfill'], [$subPromise, 'reject']);
} else {
// If the callback returned any other value, we
// immediately fulfill the chained promise.
$subPromise->fulfill($result);
}
} catch (Throwable $e) {
// If the event handler threw an exception, we need to make sure that
// the chained promise is rejected as well.
$subPromise->reject($e);
}
} else {
if (self::FULFILLED === $this->state) {
$subPromise->fulfill($this->value);
} else {
$subPromise->reject($this->value);
}
}
});
}
}

View File

@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Sabre\Event\Promise;
use Sabre\Event\Promise;
use Throwable;
/**
* This file contains a set of functions that are useful for dealing with the
* Promise object.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
/**
* This function takes an array of Promises, and returns a Promise that
* resolves when all of the given arguments have resolved.
*
* The returned Promise will resolve with a value that's an array of all the
* values the given promises have been resolved with.
*
* This array will be in the exact same order as the array of input promises.
*
* If any of the given Promises fails, the returned promise will immediately
* fail with the first Promise that fails, and its reason.
*
* @param Promise[] $promises
*/
function all(array $promises): Promise
{
return new Promise(function ($success, $fail) use ($promises) {
if (empty($promises)) {
$success([]);
return;
}
$successCount = 0;
$completeResult = [];
foreach ($promises as $promiseIndex => $subPromise) {
$subPromise->then(
function ($result) use ($promiseIndex, &$completeResult, &$successCount, $success, $promises) {
$completeResult[$promiseIndex] = $result;
++$successCount;
if ($successCount === count($promises)) {
$success($completeResult);
}
return $result;
}
)->otherwise(
function ($reason) use ($fail) {
$fail($reason);
}
);
}
});
}
/**
* The race function returns a promise that resolves or rejects as soon as
* one of the promises in the argument resolves or rejects.
*
* The returned promise will resolve or reject with the value or reason of
* that first promise.
*
* @param Promise[] $promises
*/
function race(array $promises): Promise
{
return new Promise(function ($success, $fail) use ($promises) {
$alreadyDone = false;
foreach ($promises as $promise) {
$promise->then(
function ($result) use ($success, &$alreadyDone) {
if ($alreadyDone) {
return;
}
$alreadyDone = true;
$success($result);
},
function ($reason) use ($fail, &$alreadyDone) {
if ($alreadyDone) {
return;
}
$alreadyDone = true;
$fail($reason);
}
);
}
});
}
/**
* Returns a Promise that resolves with the given value.
*
* If the value is a promise, the returned promise will attach itself to that
* promise and eventually get the same state as the followed promise.
*
* @param mixed $value
*/
function resolve($value): Promise
{
if ($value instanceof Promise) {
return $value->then();
} else {
$promise = new Promise();
$promise->fulfill($value);
return $promise;
}
}
/**
* Returns a Promise that will reject with the given reason.
*/
function reject(Throwable $reason): Promise
{
$promise = new Promise();
$promise->reject($reason);
return $promise;
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* This exception is thrown when the user tried to reject or fulfill a promise,
* after either of these actions were already performed.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class PromiseAlreadyResolvedException extends \LogicException
{
}

20
vendor/sabre/event/lib/Version.php vendored Normal file
View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* This class contains the version number for this package.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class Version
{
/**
* Full version number.
*/
const VERSION = '5.1.0';
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* This class is an EventEmitter with support for wildcard event handlers.
*
* What this means is that you can emit events like this:
*
* emit('change:firstName')
*
* and listen to this event like this:
*
* on('change:*')
*
* A few notes:
*
* - Wildcards only work at the end of an event name.
* - Currently you can only use 1 wildcard.
* - Using ":" as a separator is optional, but it's highly recommended to use
* some kind of separator.
*
* The WilcardEmitter is a bit slower than the regular Emitter. If you code
* must be very high performance, it might be better to try to use the other
* emitter. For must usage the difference is negligible though.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class WildcardEmitter implements EmitterInterface
{
use WildcardEmitterTrait;
}

View File

@ -0,0 +1,233 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
/**
* Wildcard Emitter Trait.
*
* This trait provides the implementation for WildCardEmitter
* Refer to that class for the full documentation about this
* trait.
*
* Normally you can just instantiate that class, but if you want to add
* emitter functionality to existing classes, using the trait might be a
* better way to do this.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
trait WildcardEmitterTrait
{
/**
* Subscribe to an event.
*/
public function on(string $eventName, callable $callBack, int $priority = 100)
{
// If it ends with a wildcard, we use the wildcardListeners array
if ('*' === $eventName[\strlen($eventName) - 1]) {
$eventName = \substr($eventName, 0, -1);
$listeners = &$this->wildcardListeners;
} else {
$listeners = &$this->listeners;
}
// Always fully reset the listener index. This is fairly sane for most
// applications, because there's a clear "event registering" and "event
// emitting" phase, but can be slow if there's a lot adding and removing
// of listeners during emitting of events.
$this->listenerIndex = [];
if (!isset($listeners[$eventName])) {
$listeners[$eventName] = [];
}
$listeners[$eventName][] = [$priority, $callBack];
}
/**
* Subscribe to an event exactly once.
*/
public function once(string $eventName, callable $callBack, int $priority = 100)
{
$wrapper = null;
$wrapper = function () use ($eventName, $callBack, &$wrapper) {
$this->removeListener($eventName, $wrapper);
return \call_user_func_array($callBack, \func_get_args());
};
$this->on($eventName, $wrapper, $priority);
}
/**
* Emits an event.
*
* This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain.
*
* If the continueCallBack is specified, this callback will be called every
* time before the next event handler is called.
*
* If the continueCallback returns false, event propagation stops. This
* allows you to use the eventEmitter as a means for listeners to implement
* functionality in your application, and break the event loop as soon as
* some condition is fulfilled.
*
* Note that returning false from an event subscriber breaks propagation
* and returns false, but if the continue-callback stops propagation, this
* is still considered a 'successful' operation and returns true.
*
* Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times.
*/
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
{
if (\is_null($continueCallBack)) {
foreach ($this->listeners($eventName) as $listener) {
$result = \call_user_func_array($listener, $arguments);
if (false === $result) {
return false;
}
}
} else {
$listeners = $this->listeners($eventName);
$counter = \count($listeners);
foreach ($listeners as $listener) {
--$counter;
$result = \call_user_func_array($listener, $arguments);
if (false === $result) {
return false;
}
if ($counter > 0) {
if (!$continueCallBack()) {
break;
}
}
}
}
return true;
}
/**
* Returns the list of listeners for an event.
*
* The list is returned as an array, and the list of events are sorted by
* their priority.
*
* @return callable[]
*/
public function listeners(string $eventName): array
{
if (!\array_key_exists($eventName, $this->listenerIndex)) {
// Create a new index.
$listeners = [];
$listenersPriority = [];
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $listener) {
$listenersPriority[] = $listener[0];
$listeners[] = $listener[1];
}
}
foreach ($this->wildcardListeners as $wcEvent => $wcListeners) {
// Wildcard match
if (\substr($eventName, 0, \strlen($wcEvent)) === $wcEvent) {
foreach ($wcListeners as $listener) {
$listenersPriority[] = $listener[0];
$listeners[] = $listener[1];
}
}
}
// Sorting by priority
\array_multisort($listenersPriority, SORT_NUMERIC, $listeners);
// Creating index
$this->listenerIndex[$eventName] = $listeners;
}
return $this->listenerIndex[$eventName];
}
/**
* Removes a specific listener from an event.
*
* If the listener could not be found, this method will return false. If it
* was removed it will return true.
*/
public function removeListener(string $eventName, callable $listener): bool
{
// If it ends with a wildcard, we use the wildcardListeners array
if ('*' === $eventName[\strlen($eventName) - 1]) {
$eventName = \substr($eventName, 0, -1);
$listeners = &$this->wildcardListeners;
} else {
$listeners = &$this->listeners;
}
if (!isset($listeners[$eventName])) {
return false;
}
foreach ($listeners[$eventName] as $index => $check) {
if ($check[1] === $listener) {
// Remove listener
unset($listeners[$eventName][$index]);
// Reset index
$this->listenerIndex = [];
return true;
}
}
return false;
}
/**
* Removes all listeners.
*
* If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is
* removed.
*/
public function removeAllListeners(string $eventName = null)
{
if (\is_null($eventName)) {
$this->listeners = [];
$this->wildcardListeners = [];
} else {
if ('*' === $eventName[\strlen($eventName) - 1]) {
// Wildcard event
unset($this->wildcardListeners[\substr($eventName, 0, -1)]);
} else {
unset($this->listeners[$eventName]);
}
}
// Reset index
$this->listenerIndex = [];
}
/**
* The list of listeners.
*/
protected $listeners = [];
/**
* The list of "wildcard listeners".
*/
protected $wildcardListeners = [];
/**
* An index of listeners for a specific event name. This helps speeding
* up emitting events after all listeners have been set.
*
* If the list of listeners changes though, the index clears.
*/
protected $listenerIndex = [];
}

119
vendor/sabre/event/lib/coroutine.php vendored Normal file
View File

@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace Sabre\Event;
use Generator;
use Throwable;
/**
* Turn asynchronous promise-based code into something that looks synchronous
* again, through the use of generators.
*
* Example without coroutines:
*
* $promise = $httpClient->request('GET', '/foo');
* $promise->then(function($value) {
*
* return $httpClient->request('DELETE','/foo');
*
* })->then(function($value) {
*
* return $httpClient->request('PUT', '/foo');
*
* })->error(function($reason) {
*
* echo "Failed because: $reason\n";
*
* });
*
* Example with coroutines:
*
* coroutine(function() {
*
* try {
* yield $httpClient->request('GET', '/foo');
* yield $httpClient->request('DELETE', /foo');
* yield $httpClient->request('PUT', '/foo');
* } catch(\Throwable $reason) {
* echo "Failed because: $reason\n";
* }
*
* });
*
* @return \Sabre\Event\Promise
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
function coroutine(callable $gen): Promise
{
$generator = $gen();
if (!$generator instanceof Generator) {
throw new \InvalidArgumentException('You must pass a generator function');
}
// This is the value we're returning.
$promise = new Promise();
/**
* So tempted to use the mythical y-combinator here, but it's not needed in
* PHP.
*/
$advanceGenerator = function () use (&$advanceGenerator, $generator, $promise) {
while ($generator->valid()) {
$yieldedValue = $generator->current();
if ($yieldedValue instanceof Promise) {
$yieldedValue->then(
function ($value) use ($generator, &$advanceGenerator) {
$generator->send($value);
$advanceGenerator();
},
function (Throwable $reason) use ($generator, $advanceGenerator) {
$generator->throw($reason);
$advanceGenerator();
}
)->otherwise(function (Throwable $reason) use ($promise) {
// This error handler would be called, if something in the
// generator throws an exception, and it's not caught
// locally.
$promise->reject($reason);
});
// We need to break out of the loop, because $advanceGenerator
// will be called asynchronously when the promise has a result.
break;
} else {
// If the value was not a promise, we'll just let it pass through.
$generator->send($yieldedValue);
}
}
// If the generator is at the end, and we didn't run into an exception,
// We're grabbing the "return" value and fulfilling our top-level
// promise with its value.
if (!$generator->valid() && Promise::PENDING === $promise->state) {
$returnValue = $generator->getReturn();
// The return value is a promise.
if ($returnValue instanceof Promise) {
$returnValue->then(function ($value) use ($promise) {
$promise->fulfill($value);
}, function (Throwable $reason) use ($promise) {
$promise->reject($reason);
});
} else {
$promise->fulfill($returnValue);
}
}
};
try {
$advanceGenerator();
} catch (Throwable $e) {
$promise->reject($e);
}
return $promise;
}

2
vendor/sabre/event/phpstan.neon vendored Normal file
View File

@ -0,0 +1,2 @@
parameters:
level: 1