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

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;
}