diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100755 index 00000000..ff9174eb --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + array( + __DIR__ . '/autoload_classmap.php', + ), + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/README.md b/vendor/bacon/bacon-qr-code/README.md new file mode 100755 index 00000000..a836bd61 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/README.md @@ -0,0 +1,24 @@ +QR Code generator +================= + +Master: [![Build Status](https://api.travis-ci.org/Bacon/BaconQrCode.png?branch=master)](http://travis-ci.org/Bacon/BaconQrCode) + +Introduction +------------ +BaconQrCode is a port of QR code portion of the ZXing library. It currently +only features the encoder part, but could later receive the decoder part as +well. + +As the Reed Solomon codec implementation of the ZXing library performs quite +slow in PHP, it was exchanged with the implementation by Phil Karn. + + +Example usage +------------- +```php +$renderer = new \BaconQrCode\Renderer\Image\Png(); +$renderer->setHeight(256); +$renderer->setWidth(256); +$writer = new \BaconQrCode\Writer($renderer); +$writer->writeFile('Hello World!', 'qrcode.png'); +``` diff --git a/vendor/bacon/bacon-qr-code/autoload_classmap.php b/vendor/bacon/bacon-qr-code/autoload_classmap.php new file mode 100755 index 00000000..9fbeb35b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/autoload_classmap.php @@ -0,0 +1,43 @@ + __DIR__ . '/src/BaconQrCode/Common/AbstractEnum.php', + 'BaconQrCode\Common\BitArray' => __DIR__ . '/src/BaconQrCode/Common/BitArray.php', + 'BaconQrCode\Common\BitMatrix' => __DIR__ . '/src/BaconQrCode/Common/BitMatrix.php', + 'BaconQrCode\Common\BitUtils' => __DIR__ . '/src/BaconQrCode/Common/BitUtils.php', + 'BaconQrCode\Common\CharacterSetEci' => __DIR__ . '/src/BaconQrCode/Common/CharacterSetEci.php', + 'BaconQrCode\Common\EcBlock' => __DIR__ . '/src/BaconQrCode/Common/EcBlock.php', + 'BaconQrCode\Common\EcBlocks' => __DIR__ . '/src/BaconQrCode/Common/EcBlocks.php', + 'BaconQrCode\Common\ErrorCorrectionLevel' => __DIR__ . '/src/BaconQrCode/Common/ErrorCorrectionLevel.php', + 'BaconQrCode\Common\FormatInformation' => __DIR__ . '/src/BaconQrCode/Common/FormatInformation.php', + 'BaconQrCode\Common\Mode' => __DIR__ . '/src/BaconQrCode/Common/Mode.php', + 'BaconQrCode\Common\ReedSolomonCodec' => __DIR__ . '/src/BaconQrCode/Common/ReedSolomonCodec.php', + 'BaconQrCode\Common\Version' => __DIR__ . '/src/BaconQrCode/Common/Version.php', + 'BaconQrCode\Encoder\BlockPair' => __DIR__ . '/src/BaconQrCode/Encoder/BlockPair.php', + 'BaconQrCode\Encoder\ByteMatrix' => __DIR__ . '/src/BaconQrCode/Encoder/ByteMatrix.php', + 'BaconQrCode\Encoder\Encoder' => __DIR__ . '/src/BaconQrCode/Encoder/Encoder.php', + 'BaconQrCode\Encoder\MaskUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MaskUtil.php', + 'BaconQrCode\Encoder\MatrixUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MatrixUtil.php', + 'BaconQrCode\Encoder\QrCode' => __DIR__ . '/src/BaconQrCode/Encoder/QrCode.php', + 'BaconQrCode\Exception\ExceptionInterface' => __DIR__ . '/src/BaconQrCode/Exception/ExceptionInterface.php', + 'BaconQrCode\Exception\InvalidArgumentException' => __DIR__ . '/src/BaconQrCode/Exception/InvalidArgumentException.php', + 'BaconQrCode\Exception\OutOfBoundsException' => __DIR__ . '/src/BaconQrCode/Exception/OutOfBoundsException.php', + 'BaconQrCode\Exception\RuntimeException' => __DIR__ . '/src/BaconQrCode/Exception/RuntimeException.php', + 'BaconQrCode\Exception\UnexpectedValueException' => __DIR__ . '/src/BaconQrCode/Exception/UnexpectedValueException.php', + 'BaconQrCode\Exception\WriterException' => __DIR__ . '/src/BaconQrCode/Exception/WriterException.php', + 'BaconQrCode\Renderer\Color\Cmyk' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Cmyk.php', + 'BaconQrCode\Renderer\Color\ColorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Color/ColorInterface.php', + 'BaconQrCode\Renderer\Color\Gray' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Gray.php', + 'BaconQrCode\Renderer\Color\Rgb' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Rgb.php', + 'BaconQrCode\Renderer\Image\AbstractRenderer' => __DIR__ . '/src/BaconQrCode/Renderer/Image/AbstractRenderer.php', + 'BaconQrCode\Renderer\Image\Decorator\DecoratorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php', + 'BaconQrCode\Renderer\Image\Decorator\FinderPattern' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php', + 'BaconQrCode\Renderer\Image\Eps' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Eps.php', + 'BaconQrCode\Renderer\Image\Png' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Png.php', + 'BaconQrCode\Renderer\Image\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/RendererInterface.php', + 'BaconQrCode\Renderer\Image\Svg' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Svg.php', + 'BaconQrCode\Renderer\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/RendererInterface.php', + 'BaconQrCode\Renderer\Text\Plain' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Plain.php', + 'BaconQrCode\Renderer\Text\Html' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Html.php', + 'BaconQrCode\Writer' => __DIR__ . '/src/BaconQrCode/Writer.php', +); \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/autoload_function.php b/vendor/bacon/bacon-qr-code/autoload_function.php new file mode 100755 index 00000000..9148da38 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/autoload_function.php @@ -0,0 +1,12 @@ +strict = $strict; + $this->change($initialValue); + } + + /** + * Changes the value of the enum. + * + * @param mixed $value + * @return void + */ + public function change($value) + { + if (!in_array($value, $this->getConstList(), $this->strict)) { + throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this)); + } + + $this->value = $value; + } + + /** + * Gets current value. + * + * @return mixed + */ + public function get() + { + return $this->value; + } + + /** + * Gets all constants (possible values) as an array. + * + * @param boolean $includeDefault + * @return array + */ + public function getConstList($includeDefault = true) + { + if ($this->constants === null) { + $reflection = new ReflectionClass($this); + $this->constants = $reflection->getConstants(); + } + + if ($includeDefault) { + return $this->constants; + } + + $constants = $this->constants; + unset($constants['__default']); + + return $constants; + } + + /** + * Gets the name of the enum. + * + * @return string + */ + public function __toString() + { + return array_search($this->value, $this->getConstList()); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php new file mode 100755 index 00000000..0a99d9a9 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php @@ -0,0 +1,435 @@ +size = $size; + $this->bits = new SplFixedArray(($this->size + 31) >> 3); + } + + /** + * Gets the size in bits. + * + * @return integer + */ + public function getSize() + { + return $this->size; + } + + /** + * Gets the size in bytes. + * + * @return integer + */ + public function getSizeInBytes() + { + return ($this->size + 7) >> 3; + } + + /** + * Ensures that the array has a minimum capacity. + * + * @param integer $size + * @return void + */ + public function ensureCapacity($size) + { + if ($size > count($this->bits) << 5) { + $this->bits->setSize(($size + 31) >> 5); + } + } + + /** + * Gets a specific bit. + * + * @param integer $i + * @return boolean + */ + public function get($i) + { + return ($this->bits[$i >> 5] & (1 << ($i & 0x1f))) !== 0; + } + + /** + * Sets a specific bit. + * + * @param integer $i + * @return void + */ + public function set($i) + { + $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f); + } + + /** + * Flips a specific bit. + * + * @param integer $i + * @return void + */ + public function flip($i) + { + $this->bits[$i >> 5] ^= 1 << ($i & 0x1f); + } + + /** + * Gets the next set bit position from a given position. + * + * @param integer $from + * @return integer + */ + public function getNextSet($from) + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = $this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while ($currentBits === 0) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = $this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + + return $result > $this->size ? $this->size : $result; + } + + /** + * Gets the next unset bit position from a given position. + * + * @param integer $from + * @return integer + */ + public function getNextUnset($from) + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = ~$this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while ($currentBits === 0) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = ~$this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a bulk of bits. + * + * @param integer $i + * @param integer $newBits + * @return void + */ + public function setBulk($i, $newBits) + { + $this->bits[$i >> 5] = $newBits; + } + + /** + * Sets a range of bits. + * + * @param integer $start + * @param integer $end + * @return void + * @throws Exception\InvalidArgumentException + */ + public function setRange($start, $end) + { + if ($end < $start) { + throw new Exception\InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + $end--; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if ($firstBit === 0 && $lastBit === 31) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j < $lastBit; $j++) { + $mask |= 1 << $j; + } + } + + $this->bits[$i] = $this->bits[$i] | $mask; + } + } + + /** + * Clears the bit array, unsetting every bit. + * + * @return void + */ + public function clear() + { + $bitsLength = count($this->bits); + + for ($i = 0; $i < $bitsLength; $i++) { + $this->bits[$i] = 0; + } + } + + /** + * Checks if a range of bits is set or not set. + * + * @param integer $start + * @param integer $end + * @param integer $value + * @return boolean + * @throws Exception\InvalidArgumentException + */ + public function isRange($start, $end, $value) + { + if ($end < $start) { + throw new Exception\InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + $end--; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if ($firstBit === 0 && $lastBit === 31) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j <= $lastBit; $j++) { + $mask |= 1 << $j; + } + } + + if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) { + return false; + } + } + + return true; + } + + /** + * Appends a bit to the array. + * + * @param boolean $bit + * @return void + */ + public function appendBit($bit) + { + $this->ensureCapacity($this->size + 1); + + if ($bit) { + $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f)); + } + + $this->size++; + } + + /** + * Appends a number of bits (up to 32) to the array. + * + * @param integer $value + * @param integer $numBits + * @return void + * @throws Exception\InvalidArgumentException + */ + public function appendBits($value, $numBits) + { + if ($numBits < 0 || $numBits > 32) { + throw new Exception\InvalidArgumentException('Num bits must be between 0 and 32'); + } + + $this->ensureCapacity($this->size + $numBits); + + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1); + } + } + + /** + * Appends another bit array to this array. + * + * @param BitArray $other + * @return void + */ + public function appendBitArray(self $other) + { + $otherSize = $other->getSize(); + $this->ensureCapacity($this->size + $other->getSize()); + + for ($i = 0; $i < $otherSize; $i++) { + $this->appendBit($other->get($i)); + } + } + + /** + * Makes an exclusive-or comparision on the current bit array. + * + * @param BitArray $other + * @return void + * @throws Exception\InvalidArgumentException + */ + public function xorBits(self $other) + { + $bitsLength = count($this->bits); + $otherBits = $other->getBitArray(); + + if ($bitsLength !== count($otherBits)) { + throw new Exception\InvalidArgumentException('Sizes don\'t match'); + } + + for ($i = 0; $i < $bitsLength; $i++) { + $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i]; + } + } + + /** + * Converts the bit array to a byte array. + * + * @param integer $bitOffset + * @param integer $numBytes + * @return SplFixedArray + */ + public function toBytes($bitOffset, $numBytes) + { + $bytes = new SplFixedArray($numBytes); + + for ($i = 0; $i < $numBytes; $i++) { + $byte = 0; + + for ($j = 0; $j < 8; $j++) { + if ($this->get($bitOffset)) { + $byte |= 1 << (7 - $j); + } + + $bitOffset++; + } + + $bytes[$i] = $byte; + } + + return $bytes; + } + + /** + * Gets the internal bit array. + * + * @return SplFixedArray + */ + public function getBitArray() + { + return $this->bits; + } + + /** + * Reverses the array. + * + * @return void + */ + public function reverse() + { + $newBits = new SplFixedArray(count($this->bits)); + + for ($i = 0; $i < $this->size; $i++) { + if ($this->get($this->size - $i - 1)) { + $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f)); + } + } + + $this->bits = newBits; + } + + /** + * Returns a string representation of the bit array. + * + * @return string + */ + public function __toString() + { + $result = ''; + + for ($i = 0; $i < $this->size; $i++) { + if (($i & 0x07) === 0) { + $result .= ' '; + } + + $result .= $this->get($i) ? 'X' : '.'; + } + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php new file mode 100755 index 00000000..b930f88b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php @@ -0,0 +1,350 @@ +width = $width; + $this->height = $height; + $this->rowSize = ($width + 31) >> 5; + $this->bits = new SplFixedArray($this->rowSize * $height); + } + + /** + * Gets the requested bit, where true means black. + * + * @param integer $x + * @param integer $y + * @return boolean + */ + public function get($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + return (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0; + } + + /** + * Sets the given bit to true. + * + * @param integer $x + * @param integer $y + * @return void + */ + public function set($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f)); + } + + /** + * Flips the given bit. + * + * @param integer $x + * @param integer $y + * @return void + */ + public function flip($x, $y) + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f)); + } + + /** + * Clears all bits (set to false). + * + * @return void + */ + public function clear() + { + $max = count($this->bits); + + for ($i = 0; $i < $max; $i++) { + $this->bits[$i] = 0; + } + } + + /** + * Sets a square region of the bit matrix to true. + * + * @param integer $left + * @param integer $top + * @param integer $width + * @param integer $height + * @return void + */ + public function setRegion($left, $top, $width, $height) + { + if ($top < 0 || $left < 0) { + throw new Exception\InvalidArgumentException('Left and top must be non-negative'); + } + + if ($height < 1 || $width < 1) { + throw new Exception\InvalidArgumentException('Width and height must be at least 1'); + } + + $right = $left + $width; + $bottom = $top + $height; + + if ($bottom > $this->height || $right > $this->width) { + throw new Exception\InvalidArgumentException('The region must fit inside the matrix'); + } + + for ($y = $top; $y < $bottom; $y++) { + $offset = $y * $this->rowSize; + + for ($x = $left; $x < $right; $x++) { + $index = $offset + ($x >> 5); + $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + * + * @param integer $y + * @param BitArray $row + * @return BitArray + */ + public function getRow($y, BitArray $row = null) + { + if ($row === null || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } + + $offset = $y * $this->rowSize; + + for ($x = 0; $x < $this->rowSize; $x++) { + $row->setBulk($x << 5, $this->bits[$offset + $x]); + } + + return $row; + } + + /** + * Sets a row of data from a BitArray. + * + * @param integer $y + * @param BitArray $row + * @return void + */ + public function setRow($y, BitArray $row) + { + $bits = $row->getBitArray(); + + for ($i = 0; $i < $this->rowSize; $i++) { + $this->bits[$y * $this->rowSize + $i] = $bits[$i]; + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getEnclosingRectangle() + { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; $y++) { + for ($x32 = 0; $x32 < $this->rowSize; $x32++) { + $bits = $this->bits[$y * $this->rowSize + $x32]; + + if ($bits !== 0) { + if ($y < $top) { + $top = $y; + } + + if ($y > $bottom) { + $bottom = $y; + } + + if ($x32 * 32 < $left) { + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + } + + if ($x32 * 32 + 31 > $right) { + $bit = 31; + + while (BitUtils::unsignedRightShift($bits, $bit) === 0) { + $bit--; + } + + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return SplFixedArray::fromArray(array($left, $top, $width, $height), false); + } + + /** + * Gets the most top left set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getTopLeftOnBit() + { + $bitsOffset = 0; + + while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] === 0) { + $bitsOffset++; + } + + if ($bitsOffset === count($this->bits)) { + return null; + } + + $x = intval($bitsOffset / $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + $x += $bit; + + return SplFixedArray::fromArray(array($x, $y), false); + } + + /** + * Gets the most bottom right set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return SplFixedArray + */ + public function getBottomRightOnBit() + { + $bitsOffset = count($this->bits) - 1; + + while ($bitsOffset >= 0 && $this->bits[$bitsOffset] === 0) { + $bitsOffset--; + } + + if ($bitsOffset < 0) { + return null; + } + + $x = intval($bitsOffset / $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (BitUtils::unsignedRightShift($bits, $bit) === 0) { + $bit--; + } + + $x += $bit; + + return SplFixedArray::fromArray(array($x, $y), false); + } + + /** + * Gets the width of the matrix, + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Gets the height of the matrix. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php new file mode 100755 index 00000000..a6412440 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php @@ -0,0 +1,51 @@ +>>" in other + * languages. + * + * @param integer $a + * @param integer $b + * @return integer + */ + public static function unsignedRightShift($a, $b) + { + return ( + $a >= 0 + ? $a >> $b + : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1)) + ); + } + + /** + * Gets the number of trailing zeros. + * + * @param integer $i + * @return integer + */ + public static function numberOfTrailingZeros($i) + { + $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1'); + + return $lastPos === false ? 32 : 31 - $lastPos; + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php new file mode 100755 index 00000000..77662360 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php @@ -0,0 +1,134 @@ + self::ISO8859_1, + 'ISO-8859-2' => self::ISO8859_2, + 'ISO-8859-3' => self::ISO8859_3, + 'ISO-8859-4' => self::ISO8859_4, + 'ISO-8859-5' => self::ISO8859_5, + 'ISO-8859-6' => self::ISO8859_6, + 'ISO-8859-7' => self::ISO8859_7, + 'ISO-8859-8' => self::ISO8859_8, + 'ISO-8859-9' => self::ISO8859_9, + 'ISO-8859-10' => self::ISO8859_10, + 'ISO-8859-11' => self::ISO8859_11, + 'ISO-8859-12' => self::ISO8859_12, + 'ISO-8859-13' => self::ISO8859_13, + 'ISO-8859-14' => self::ISO8859_14, + 'ISO-8859-15' => self::ISO8859_15, + 'ISO-8859-16' => self::ISO8859_16, + 'SHIFT-JIS' => self::SJIS, + 'WINDOWS-1250' => self::CP1250, + 'WINDOWS-1251' => self::CP1251, + 'WINDOWS-1252' => self::CP1252, + 'WINDOWS-1256' => self::CP1256, + 'UTF-16BE' => self::UNICODE_BIG_UNMARKED, + 'UTF-8' => self::UTF8, + 'ASCII' => self::ASCII, + 'GBK' => self::GB18030, + 'EUC-KR' => self::EUC_KR, + ); + + /** + * Additional possible values for character sets. + * + * @var array + */ + protected $additionalValues = array( + self::CP437 => 2, + self::ASCII => 170, + ); + + /** + * Gets character set ECI by value. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByValue($value) + { + if ($value < 0 || $value >= 900) { + throw new Exception\InvalidArgumentException('Value must be between 0 and 900'); + } + + if (false !== ($key = array_search($value, self::$additionalValues))) { + $value = $key; + } + + try { + return new self($value); + } catch (Exception\UnexpectedValueException $e) { + return null; + } + } + + /** + * Gets character set ECI by name. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByName($name) + { + $name = strtoupper($name); + + if (isset(self::$nameToEci[$name])) { + return new self(self::$nameToEci[$name]); + } + + return null; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php new file mode 100755 index 00000000..cbcc2ba0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php @@ -0,0 +1,65 @@ +count = $count; + $this->dataCodewords = $dataCodewords; + } + + /** + * Returns how many times the block is used. + * + * @return integer + */ + public function getCount() + { + return $this->count; + } + + /** + * Returns the number of data codewords. + * + * @return integer + */ + public function getDataCodewords() + { + return $this->dataCodewords; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php new file mode 100755 index 00000000..87cef5d0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php @@ -0,0 +1,101 @@ +ecCodewordsPerBlock = $ecCodewordsPerBlock; + + $this->ecBlocks = new SplFixedArray($ecb2 === null ? 1 : 2); + $this->ecBlocks[0] = $ecb1; + + if ($ecb2 !== null) { + $this->ecBlocks[1] = $ecb2; + } + } + + /** + * Gets the number of EC codewords per block. + * + * @return integer + */ + public function getEcCodewordsPerBlock() + { + return $this->ecCodewordsPerBlock; + } + + /** + * Gets the total number of EC block appearances. + * + * @return integer + */ + public function getNumBlocks() + { + $total = 0; + + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + + return $total; + } + + /** + * Gets the total count of EC codewords. + * + * @return integer + */ + public function getTotalEcCodewords() + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + /** + * Gets the EC blocks included in this collection. + * + * @return SplFixedArray + */ + public function getEcBlocks() + { + return $this->ecBlocks; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php new file mode 100755 index 00000000..bd0a60a3 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php @@ -0,0 +1,62 @@ +value) { + case self::L: + return 0; + break; + + case self::M: + return 1; + break; + + case self::Q: + return 2; + break; + + case self::H: + return 3; + break; + } + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php new file mode 100755 index 00000000..5ec9ffd4 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php @@ -0,0 +1,236 @@ +ecLevel = new ErrorCorrectionLevel(($formatInfo >> 3) & 0x3); + $this->dataMask = $formatInfo & 0x7; + } + + /** + * Checks how many bits are different between two integers. + * + * @param integer $a + * @param integer $b + * @return integer + */ + public static function numBitsDiffering($a, $b) + { + $a ^= $b; + + return ( + self::$bitsSetInHalfByte[$a & 0xf] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 4) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 8) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 12) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 16) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 20) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 24) & 0xf)] + + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 28) & 0xf)] + ); + } + + /** + * Decodes format information. + * + * @param integer $maskedFormatInfo1 + * @param integer $maskedFormatInfo2 + * @return FormatInformation|null + */ + public static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) + { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + + if ($formatInfo !== null) { + return $formatInfo; + } + + // Should return null, but, some QR codes apparently do not mask this + // info. Try again by actually masking the pattern first. + return self::doDecodeFormatInformation( + $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR + ); + } + + /** + * Internal method for decoding format information. + * + * @param integer $maskedFormatInfo1 + * @param integer $maskedFormatInfo2 + * @return FormatInformation|null + */ + protected static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) + { + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + + foreach (self::$formatInfoDecodeLookup as $decodeInfo) { + $targetInfo = $decodeInfo[0]; + + if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) { + // Found an exact match + return new self($decodeInfo[1]); + } + + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + + if ($maskedFormatInfo1 !== $maskedFormatInfo2) { + // Also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + + // Hamming distance of the 32 masked codes is 7, by construction, so + // <= 3 bits differing means we found a match. + if ($bestDifference <= 3) { + return new self($bestFormatInfo); + } + + return null; + } + + /** + * Gets the error correction level. + * + * @return ErrorCorrectionLevel + */ + public function getErrorCorrectionLevel() + { + return $this->ecLevel; + } + + /** + * Gets the data mask. + * + * @return integer + */ + public function getDataMask() + { + return $this->dataMask; + } + + /** + * Hashes the code of the EC level. + * + * @return integer + */ + public function hashCode() + { + return ($this->ecLevel->get() << 3) | $this->dataMask; + } + + /** + * Verifies if this instance equals another one. + * + * @param mixed $other + * @return boolean + */ + public function equals($other) { + if (!$other instanceof self) { + return false; + } + + return ( + $this->ecLevel->get() === $other->getErrorCorrectionLevel()->get() + && $this->dataMask === $other->getDataMask() + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php new file mode 100755 index 00000000..8faf344e --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php @@ -0,0 +1,70 @@ + array(0, 0, 0), + self::NUMERIC => array(10, 12, 14), + self::ALPHANUMERIC => array(9, 11, 13), + self::STRUCTURED_APPEND => array(0, 0, 0), + self::BYTE => array(8, 16, 16), + self::ECI => array(0, 0, 0), + self::KANJI => array(8, 10, 12), + self::FNC1_FIRST_POSITION => array(0, 0, 0), + self::FNC1_SECOND_POSITION => array(0, 0, 0), + self::HANZI => array(8, 10, 12), + ); + + /** + * Gets the number of bits used in a specific QR code version. + * + * @param Version $version + * @return integer + */ + public function getCharacterCountBits(Version $version) + { + $number = $version->getVersionNumber(); + + if ($number <= 9) { + $offset = 0; + } elseif ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + + return self::$characterCountBitsForVersions[$this->value][$offset]; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php new file mode 100755 index 00000000..e8d45b94 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php @@ -0,0 +1,476 @@ + 8) { + throw new Exception\InvalidArgumentException('Symbol size must be between 0 and 8'); + } + + if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) { + throw new Exception\InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize)); + } + + if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) { + throw new Exception\InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize)); + } + + if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) { + throw new Exception\InvalidArgumentException('Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots)); + } + + $this->symbolSize = $symbolSize; + $this->blockSize = (1 << $symbolSize) - 1; + $this->padding = $padding; + $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + + // Generate galous field lookup table + $this->indexOf[0] = $this->blockSize; + $this->alphaTo[$this->blockSize] = 0; + + $sr = 1; + + for ($i = 0; $i < $this->blockSize; $i++) { + $this->indexOf[$sr] = $i; + $this->alphaTo[$i] = $sr; + + $sr <<= 1; + + if ($sr & (1 << $symbolSize)) { + $sr ^= $gfPoly; + } + + $sr &= $this->blockSize; + } + + if ($sr !== 1) { + throw new Exception\RuntimeException('Field generator polynomial is not primitive'); + } + + // Form RS code generator polynomial from its roots + $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false); + $this->firstRoot = $firstRoot; + $this->primitive = $primitive; + $this->numRoots = $numRoots; + + // Find prim-th root of 1, used in decoding + for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize); + $this->iPrimitive = intval($iPrimitive / $primitive); + + $this->generatorPoly[0] = 1; + + for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; $i++, $root += $primitive) { + $this->generatorPoly[$i + 1] = 1; + + for ($j = $i; $j > 0; $j--) { + if ($this->generatorPoly[$j] !== 0) { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root)]; + } else { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1]; + } + } + + $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)]; + } + + // Convert generator poly to index form for quicker encoding + for ($i = 0; $i <= $numRoots; $i++) { + $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]]; + } + } + + /** + * Encodes data and writes result back into parity array. + * + * @param SplFixedArray $data + * @param SplFixedArray $parity + * @return void + */ + public function encode(SplFixedArray $data, SplFixedArray $parity) + { + for ($i = 0; $i < $this->numRoots; $i++) { + $parity[$i] = 0; + } + + $iterations = $this->blockSize - $this->numRoots - $this->padding; + + for ($i = 0; $i < $iterations; $i++) { + $feedback = $this->indexOf[$data[$i] ^ $parity[0]]; + + if ($feedback !== $this->blockSize) { + // Feedback term is non-zero + $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback); + + for ($j = 1; $j < $this->numRoots; $j++) { + $parity[$j] = $parity[$j] ^ $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j])]; + } + } + + for ($j = 0; $j < $this->numRoots - 1; $j++) { + $parity[$j] = $parity[$j + 1]; + } + + if ($feedback !== $this->blockSize) { + $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])]; + } else { + $parity[$this->numRoots - 1] = 0; + } + } + } + + /** + * Decodes received data. + * + * @param SplFixedArray $data + * @param SplFixedArray|null $erasures + * @return null|integer + */ + public function decode(SplFixedArray $data, SplFixedArray $erasures = null) + { + // This speeds up the initialization a bit. + $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false); + $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false); + + $lambda = clone $numRootsPlusOne; + $b = clone $numRootsPlusOne; + $t = clone $numRootsPlusOne; + $omega = clone $numRootsPlusOne; + $root = clone $numRoots; + $loc = clone $numRoots; + + $numErasures = ($erasures !== null ? count($erasures) : 0); + + // Form the Syndromes; i.e., evaluate data(x) at roots of g(x) + $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false); + + for ($i = 1; $i < $this->blockSize - $this->padding; $i++) { + for ($j = 0; $j < $this->numRoots; $j++) { + if ($syndromes[$j] === 0) { + $syndromes[$j] = $data[$i]; + } else { + $syndromes[$j] = $data[$i] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive) + ]; + } + } + } + + // Convert syndromes to index form, checking for nonzero conditions + $syndromeError = 0; + + for ($i = 0; $i < $this->numRoots; $i++) { + $syndromeError |= $syndromes[$i]; + $syndromes[$i] = $this->indexOf[$syndromes[$i]]; + } + + if (!$syndromeError) { + // If syndrome is zero, data[] is a codeword and there are no errors + // to correct, so return data[] unmodified. + return 0; + } + + $lambda[0] = 1; + + if ($numErasures > 0) { + // Init lambda to be the erasure locator polynomial + $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))]; + + for ($i = 1; $i < $numErasures; $i++) { + $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i])); + + for ($j = $i + 1; $j > 0; $j--) { + $tmp = $this->indexOf[$lambda[$j - 1]]; + + if ($tmp !== $this->blockSize) { + $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)]; + } + } + } + } + + for ($i = 0; $i <= $this->numRoots; $i++) { + $b[$i] = $this->indexOf[$lambda[$i]]; + } + + // Begin Berlekamp-Massey algorithm to determine error+erasure locator + // polynomial + $r = $numErasures; + $el = $numErasures; + + while (++$r <= $this->numRoots) { + // Compute discrepancy at the r-th step in poly form + $discrepancyR = 0; + + for ($i = 0; $i < $r; $i++) { + if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) { + $discrepancyR ^= $this->alphaTo[$this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1])]; + } + } + + $discrepancyR = $this->indexOf[$discrepancyR]; + + if ($discrepancyR === $this->blockSize) { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } else { + $t[0] = $lambda[0]; + + for ($i = 0; $i < $this->numRoots; $i++) { + if ($b[$i] !== $this->blockSize) { + $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])]; + } else { + $t[$i + 1] = $lambda[$i + 1]; + } + } + + if (2 * $el <= $r + $numErasures - 1) { + $el = $r + $numErasures - $el; + + for ($i = 0; $i <= $this->numRoots; $i++) { + $b[$i] = ( + $lambda[$i] === 0 + ? $this->blockSize + : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize) + ); + } + } else { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } + + $lambda = clone $t; + } + } + + // Convert lambda to index form and compute deg(lambda(x)) + $degLambda = 0; + + for ($i = 0; $i <= $this->numRoots; $i++) { + $lambda[$i] = $this->indexOf[$lambda[$i]]; + + if ($lambda[$i] !== $this->blockSize) { + $degLambda = $i; + } + } + + // Find roots of the error+erasure locator polynomial by Chien search. + $reg = clone $lambda; + $reg[0] = 0; + $count = 0; + + for ($i = 1, $k = $this->iPrimitive - 1; $i <= $this->blockSize; $i++, $k = $this->modNn($k + $this->iPrimitive)) { + $q = 1; + + for ($j = $degLambda; $j > 0; $j--) { + if ($reg[$j] !== $this->blockSize) { + $reg[$j] = $this->modNn($reg[$j] + $j); + $q ^= $this->alphaTo[$reg[$j]]; + } + } + + if ($q !== 0) { + // Not a root + continue; + } + + // Store root (index-form) and error location number + $root[$count] = $i; + $loc[$count] = $k; + + if (++$count === $degLambda) { + break; + } + } + + if ($degLambda !== $count) { + // deg(lambda) unequal to number of roots: uncorreactable error + // detected + return null; + } + + // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo + // x**numRoots). In index form. Also find deg(omega). + $degOmega = $degLambda - 1; + + for ($i = 0; $i <= $degOmega; $i++) { + $tmp = 0; + + for ($j = $i; $j >= 0; $j--) { + if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) { + $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])]; + } + } + + $omega[$i] = $this->indexOf[$tmp]; + } + + // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + // inv(X(l))**(firstRoot-1) and den = lambda_pr(inv(X(l))) all in poly + // form. + for ($j = $count - 1; $j >= 0; $j--) { + $num1 = 0; + + for ($i = $degOmega; $i >= 0; $i--) { + if ($omega[$i] !== $this->blockSize) { + $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])]; + } + } + + $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)]; + $den = 0; + + // lambda[i+1] for i even is the formal derivativelambda_pr of + // lambda[i] + for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) { + if ($lambda[$i + 1] !== $this->blockSize) { + $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])]; + } + } + + // Apply error to data + if ($num1 !== 0 && $loc[$j] >= $this->padding) { + $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ ( + $this->alphaTo[ + $this->modNn( + $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den] + ) + ] + ); + } + } + + if ($erasures !== null) { + if (count($erasures) < $count) { + $erasures->setSize($count); + } + + for ($i = 0; $i < $count; $i++) { + $erasures[$i] = $loc[$i]; + } + } + + return $count; + } + + /** + * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow + * divide. + * + * @param itneger $x + * @return integer + */ + protected function modNn($x) + { + while ($x >= $this->blockSize) { + $x -= $this->blockSize; + $x = ($x >> $this->symbolSize) + ($x & $this->blockSize); + } + + return $x; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php new file mode 100755 index 00000000..d6986399 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php @@ -0,0 +1,687 @@ +versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->errorCorrectionBlocks = $ecBlocks; + + $totalCodewords = 0; + $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock(); + + foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) { + $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + + $this->totalCodewords = $totalCodewords; + } + + /** + * Gets the version number. + * + * @return integer + */ + public function getVersionNumber() + { + return $this->versionNumber; + } + + /** + * Gets the alignment pattern centers. + * + * @return SplFixedArray + */ + public function getAlignmentPatternCenters() + { + return $this->alignmentPatternCenters; + } + + /** + * Gets the total number of codewords. + * + * @return integer + */ + public function getTotalCodewords() + { + return $this->totalCodewords; + } + + /** + * Gets the dimension for the current version. + * + * @return integer + */ + public function getDimensionForVersion() + { + return 17 + 4 * $this->versionNumber; + } + + /** + * Gets the number of EC blocks for a specific EC level. + * + * @param ErrorCorrectionLevel $ecLevel + * @return integer + */ + public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) + { + return $this->errorCorrectionBlocks[$ecLevel->getOrdinal()]; + } + + /** + * Gets a provisional version number for a specific dimension. + * + * @param integer $dimension + * @return Version + * @throws Exception\InvalidArgumentException + */ + public static function getProvisionalVersionForDimension($dimension) + { + if ($dimension % 4 !== 1) { + throw new Exception\InvalidArgumentException('Dimension is not 1 mod 4'); + } + + return self::getVersionForNumber(($dimension - 17) >> 2); + } + + /** + * Gets a version instance for a specific version number. + * + * @param integer $versionNumber + * @return Version + * @throws Exception\InvalidArgumentException + */ + public static function getVersionForNumber($versionNumber) + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new Exception\InvalidArgumentException('Version number must be between 1 and 40'); + } + + if (!isset(self::$versions[$versionNumber])) { + self::buildVersion($versionNumber); + } + + return self::$versions[$versionNumber - 1]; + } + + /** + * Decodes version information from an integer and returns the version. + * + * @param integer $versionBits + * @return Version|null + */ + public static function decodeVersionInformation($versionBits) + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + + foreach (self::$versionDecodeInfo as $i => $targetVersion) { + if ($targetVersion === $versionBits) { + return self::getVersionForNumber($i + 7); + } + + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } + + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } + + return null; + } + + /** + * Builds the function pattern for the current version. + * + * @return BitMatrix + */ + public function buildFunctionPattern() + { + $dimension = $this->getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + + // Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + + // Alignment patterns + $max = count($this->alignmentPatternCenters); + + for ($x = 0; $x < $max; $x++) { + $i = $this->alignmentPatternCenters[$x] - 2; + + for ($y = 0; $y < $max; $y++) { + if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) { + // No alignment patterns near the three finder paterns + continue; + } + + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + + // Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); + // Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { + // Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); + // Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + + /** + * Returns a string representation for the version. + * + * @return string + */ + public function __toString() + { + return (string) $this->versionNumber; + } + + /** + * Build and cache a specific version. + * + * See ISO 18004:2006 6.5.1 Table 9. + * + * @param integer $versionNumber + * @return void + */ + protected static function buildVersion($versionNumber) + { + switch ($versionNumber) { + case 1: + $patterns = array(); + $ecBlocks = array( + new EcBlocks(7, new EcBlock(1, 19)), + new EcBlocks(10, new EcBlock(1, 16)), + new EcBlocks(13, new EcBlock(1, 13)), + new EcBlocks(17, new EcBlock(1, 9)), + ); + break; + + case 2: + $patterns = array(6, 18); + $ecBlocks = array( + new EcBlocks(10, new EcBlock(1, 34)), + new EcBlocks(16, new EcBlock(1, 28)), + new EcBlocks(22, new EcBlock(1, 22)), + new EcBlocks(28, new EcBlock(1, 16)), + ); + break; + + case 3: + $patterns = array(6, 22); + $ecBlocks = array( + new EcBlocks(15, new EcBlock(1, 55)), + new EcBlocks(26, new EcBlock(1, 44)), + new EcBlocks(18, new EcBlock(2, 17)), + new EcBlocks(22, new EcBlock(2, 13)), + ); + break; + + case 4: + $patterns = array(6, 26); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(1, 80)), + new EcBlocks(18, new EcBlock(2, 32)), + new EcBlocks(26, new EcBlock(3, 24)), + new EcBlocks(16, new EcBlock(4, 9)), + ); + break; + + case 5: + $patterns = array(6, 30); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(1, 108)), + new EcBlocks(24, new EcBlock(2, 43)), + new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)), + new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)), + ); + break; + + case 6: + $patterns = array(6, 34); + $ecBlocks = array( + new EcBlocks(18, new EcBlock(2, 68)), + new EcBlocks(16, new EcBlock(4, 27)), + new EcBlocks(24, new EcBlock(4, 19)), + new EcBlocks(28, new EcBlock(4, 15)), + ); + break; + + case 7: + $patterns = array(6, 22, 38); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(2, 78)), + new EcBlocks(18, new EcBlock(4, 31)), + new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)), + new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)), + ); + break; + + case 8: + $patterns = array(6, 24, 42); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(2, 97)), + new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)), + new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)), + new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)), + ); + break; + + case 9: + $patterns = array(6, 26, 46); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(2, 116)), + new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)), + new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)), + new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)), + ); + break; + + case 10: + $patterns = array(6, 28, 50); + $ecBlocks = array( + new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)), + new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)), + new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)), + new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)), + ); + break; + + case 11: + $patterns = array(6, 30, 54); + $ecBlocks = array( + new EcBlocks(20, new EcBlock(4, 81)), + new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)), + new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)), + new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)), + ); + break; + + case 12: + $patterns = array(6, 32, 58); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)), + new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)), + new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)), + new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)), + ); + break; + + case 13: + $patterns = array(6, 34, 62); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(4, 107)), + new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)), + new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)), + new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)), + ); + break; + + case 14: + $patterns = array(6, 26, 46, 66); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)), + new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)), + new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)), + ); + break; + + case 15: + $patterns = array(6, 26, 48, 70); + $ecBlocks = array( + new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)), + new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)), + new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)), + ); + break; + + case 16: + $patterns = array(6, 26, 50, 74); + $ecBlocks = array( + new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)), + new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)), + new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)), + new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)), + ); + break; + + case 17: + $patterns = array(6, 30, 54, 78); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)), + new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)), + ); + break; + + case 18: + $patterns = array(6, 30, 56, 82); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)), + new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)), + ); + break; + + case 19: + $patterns = array(6, 30, 58, 86); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)), + new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)), + new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)), + new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)), + ); + break; + + case 20: + $patterns = array(6, 34, 62, 90); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)), + new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)), + new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)), + ); + break; + + case 21: + $patterns = array(6, 28, 50, 72, 94); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)), + new EcBlocks(26, new EcBlock(17, 42)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)), + ); + break; + + case 22: + $patterns = array(6, 26, 50, 74, 98); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)), + new EcBlocks(28, new EcBlock(17, 46)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)), + new EcBlocks(24, new EcBlock(34, 13)), + ); + break; + + case 23: + $patterns = array(6, 30, 54, 78, 102); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)), + new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)), + ); + break; + + case 24: + $patterns = array(6, 28, 54, 80, 106); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)), + new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)), + ); + break; + + case 25: + $patterns = array(6, 32, 58, 84, 110); + $ecBlocks = array( + new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)), + new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)), + ); + break; + + case 26: + $patterns = array(6, 30, 58, 86, 114); + $ecBlocks = array( + new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)), + new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)), + new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)), + ); + break; + + case 27: + $patterns = array(6, 34, 62, 90, 118); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)), + new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)), + new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)), + ); + break; + + case 28: + $patterns = array(6, 26, 50, 74, 98, 122); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)), + new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)), + new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)), + ); + break; + + case 29: + $patterns = array(6, 30, 54, 78, 102, 126); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)), + new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)), + new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)), + ); + break; + + case 30: + $patterns = array(6, 26, 52, 78, 104, 130); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)), + new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)), + ); + break; + + case 31: + $patterns = array(6, 30, 56, 82, 108, 134); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)), + new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)), + new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)), + ); + break; + + case 32: + $patterns = array(6, 34, 60, 86, 112, 138); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 115)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)), + ); + break; + + case 33: + $patterns = array(6, 30, 58, 86, 114, 142); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)), + new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)), + ); + break; + + case 34: + $patterns = array(6, 34, 62, 90, 118, 146); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)), + new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)), + ); + break; + + case 35: + $patterns = array(6, 30, 54, 78, 102, 126, 150); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)), + new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)), + new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)), + ); + break; + + case 36: + $patterns = array(6, 24, 50, 76, 102, 128, 154); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)), + new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)), + new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)), + ); + break; + + case 37: + $patterns = array(6, 28, 54, 80, 106, 132, 158); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)), + new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)), + ); + break; + + case 38: + $patterns = array(6, 32, 58, 84, 110, 136, 162); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)), + new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)), + new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)), + ); + break; + + case 39: + $patterns = array(6, 26, 54, 82, 110, 138, 166); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)), + new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)), + ); + break; + + case 40: + $patterns = array(6, 30, 58, 86, 114, 142, 170); + $ecBlocks = array( + new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)), + new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)), + new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)), + new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)), + ); + break; + } + + self::$versions[$versionNumber - 1] = new self( + $versionNumber, + SplFixedArray::fromArray($patterns, false), + SplFixedArray::fromArray($ecBlocks, false) + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php new file mode 100755 index 00000000..090db297 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php @@ -0,0 +1,64 @@ +dataBytes = $data; + $this->errorCorrectionBytes = $errorCorrection; + } + + /** + * Gets the data bytes. + * + * @return SplFixedArray + */ + public function getDataBytes() + { + return $this->dataBytes; + } + + /** + * Gets the error correction bytes. + * + * @return SplFixedArray + */ + public function getErrorCorrectionBytes() + { + return $this->errorCorrectionBytes; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php new file mode 100755 index 00000000..a378f083 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php @@ -0,0 +1,158 @@ +height = $height; + $this->width = $width; + $this->bytes = new SplFixedArray($height); + + for ($y = 0; $y < $height; $y++) { + $this->bytes[$y] = new SplFixedArray($width); + } + } + + /** + * Gets the width of the matrix. + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Gets the height of the matrix. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * Gets the internal representation of the matrix. + * + * @return SplFixedArray + */ + public function getArray() + { + return $this->bytes; + } + + /** + * Gets the byte for a specific position. + * + * @param integer $x + * @param integer $y + * @return integer + */ + public function get($x, $y) + { + return $this->bytes[$y][$x]; + } + + /** + * Sets the byte for a specific position. + * + * @param integer $x + * @param integer $y + * @param integer $value + * @return void + */ + public function set($x, $y, $value) + { + $this->bytes[$y][$x] = (int) $value; + } + + /** + * Clears the matrix with a specific value. + * + * @param integer $value + * @return void + */ + public function clear($value) + { + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + $this->bytes[$y][$x] = $value; + } + } + } + + /** + * Returns a string representation of the matrix. + * + * @return string + */ + public function __toString() + { + $result = ''; + + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + switch ($this->bytes[$y][$x]) { + case 0: + $result .= ' 0'; + break; + + case 1: + $result .= ' 1'; + break; + + default: + $result .= ' '; + break; + } + } + + $result .= "\n"; + } + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php new file mode 100755 index 00000000..c8efc35d --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php @@ -0,0 +1,687 @@ +get() === Mode::BYTE && $encoding !== self::DEFAULT_BYTE_MODE_ECODING) { + $eci = CharacterSetEci::getCharacterSetEciByName($encoding); + + if ($eci !== null) { + self::appendEci($eci, $headerBits); + } + } + + // (With ECI in place,) Write the mode marker + self::appendModeInfo($mode, $headerBits); + + // Collect data within the main segment, separately, to count its size + // if needed. Don't add it to main payload yet. + $dataBits = new BitArray(); + self::appendBytes($content, $mode, $dataBits, $encoding); + + // Hard part: need to know version to know how many bits length takes. + // But need to know how many bits it takes to know version. First we + // take a guess at version by assuming version will be the minimum, 1: + $provisionalBitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + + $dataBits->getSize(); + $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel); + + // Use that guess to calculate the right version. I am still not sure + // this works in 100% of cases. + $bitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits($provisionalVersion) + + $dataBits->getSize(); + $version = self::chooseVersion($bitsNeeded, $ecLevel); + + $headerAndDataBits = new BitArray(); + $headerAndDataBits->appendBitArray($headerBits); + + // Find "length" of main segment and write it. + $numLetters = ($mode->get() === Mode::BYTE ? $dataBits->getSizeInBytes() : strlen($content)); + self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits); + + // Put data together into the overall payload. + $headerAndDataBits->appendBitArray($dataBits); + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords(); + + // Terminate the bits properly. + self::terminateBits($numDataBytes, $headerAndDataBits); + + // Interleave data bits with error correction code. + $finalBits = self::interleaveWithEcBytes( + $headerAndDataBits, + $version->getTotalCodewords(), + $numDataBytes, + $ecBlocks->getNumBlocks() + ); + + $qrCode = new QrCode(); + $qrCode->setErrorCorrectionLevel($ecLevel); + $qrCode->setMode($mode); + $qrCode->setVersion($version); + + // Choose the mask pattern and set to "qrCode". + $dimension = $version->getDimensionForVersion(); + $matrix = new ByteMatrix($dimension, $dimension); + $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix); + $qrCode->setMaskPattern($maskPattern); + + // Build the matrix and set it to "qrCode". + MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix); + $qrCode->setMatrix($matrix); + + return $qrCode; + } + + /** + * Gets the alphanumeric code for a byte. + * + * @param string|integer $code + * @return integer + */ + protected static function getAlphanumericCode($code) + { + $code = (is_string($code) ? ord($code) : $code); + + if (isset(self::$alphanumericTable[$code])) { + return self::$alphanumericTable[$code]; + } + + return -1; + } + + /** + * Chooses the best mode for a given content. + * + * @param string $content + * @param string $encoding + * @return Mode + */ + protected static function chooseMode($content, $encoding = null) + { + if (strcasecmp($encoding, 'SHIFT-JIS') === 0) { + return self::isOnlyDoubleByteKanji($content) ? new Mode(Mode::KANJI) : new Mode(Mode::BYTE); + } + + $hasNumeric = false; + $hasAlphanumeric = false; + $contentLength = strlen($content); + + for ($i = 0; $i < $contentLength; $i++) { + $char = $content[$i]; + + if (ctype_digit($char)) { + $hasNumeric = true; + } elseif (self::getAlphanumericCode($char) !== -1) { + $hasAlphanumeric = true; + } else { + return new Mode(Mode::BYTE); + } + } + + if ($hasAlphanumeric) { + return new Mode(Mode::ALPHANUMERIC); + } elseif ($hasNumeric) { + return new Mode(Mode::NUMERIC); + } + + return new Mode(Mode::BYTE); + } + + /** + * Calculates the mask penalty for a matrix. + * + * @param ByteMatrix $matrix + * @return integer + */ + protected static function calculateMaskPenalty(ByteMatrix $matrix) + { + return ( + MaskUtil::applyMaskPenaltyRule1($matrix) + + MaskUtil::applyMaskPenaltyRule2($matrix) + + MaskUtil::applyMaskPenaltyRule3($matrix) + + MaskUtil::applyMaskPenaltyRule4($matrix) + ); + } + + /** + * Chooses the best mask pattern for a matrix. + * + * @param BitArray $bits + * @param ErrorCorrectionLevel $ecLevel + * @param Version $version + * @param ByteMatrix $matrix + * @return integer + */ + protected static function chooseMaskPattern( + BitArray $bits, + ErrorCorrectionLevel $ecLevel, + Version $version, + ByteMatrix $matrix + ) { + $minPenality = PHP_INT_MAX; + $bestMaskPattern = -1; + + for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; $maskPattern++) { + MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix); + $penalty = self::calculateMaskPenalty($matrix); + + if ($penalty < $minPenality) { + $minPenality = $penalty; + $bestMaskPattern = $maskPattern; + } + } + + return $bestMaskPattern; + } + + /** + * Chooses the best version for the input. + * + * @param integer $numInputBits + * @param ErrorCorrectionLevel $ecLevel + * @return Version + * @throws Exception\WriterException + */ + protected static function chooseVersion($numInputBits, ErrorCorrectionLevel $ecLevel) + { + for ($versionNum = 1; $versionNum <= 40; $versionNum++) { + $version = Version::getVersionForNumber($versionNum); + $numBytes = $version->getTotalCodewords(); + + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numEcBytes = $ecBlocks->getTotalEcCodewords(); + + $numDataBytes = $numBytes - $numEcBytes; + $totalInputBytes = intval(($numInputBits + 8) / 8); + + if ($numDataBytes >= $totalInputBytes) { + return $version; + } + } + + throw new Exception\WriterException('Data too big'); + } + + /** + * Terminates the bits in a bit array. + * + * @param integer $numDataBytes + * @param BitArray $bits + * @throws Exception\WriterException + */ + protected static function terminateBits($numDataBytes, BitArray $bits) + { + $capacity = $numDataBytes << 3; + + if ($bits->getSize() > $capacity) { + throw new Exception\WriterException('Data bits cannot fit in the QR code'); + } + + for ($i = 0; $i < 4 && $bits->getSize() < $capacity; $i++) { + $bits->appendBit(false); + } + + $numBitsInLastByte = $bits->getSize() & 0x7; + + if ($numBitsInLastByte > 0) { + for ($i = $numBitsInLastByte; $i < 8; $i++) { + $bits->appendBit(false); + } + } + + $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes(); + + for ($i = 0; $i < $numPaddingBytes; $i++) { + $bits->appendBits(($i & 0x1) === 0 ? 0xec : 0x11, 8); + } + + if ($bits->getSize() !== $capacity) { + throw new Exception\WriterException('Bits size does not equal capacity'); + } + } + + /** + * Gets number of data- and EC bytes for a block ID. + * + * @param integer $numTotalBytes + * @param integer $numDataBytes + * @param integer $numRsBlocks + * @param integer $blockId + * @return array + * @throws Exception\WriterException + */ + protected static function getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $blockId + ) { + if ($blockId >= $numRsBlocks) { + throw new Exception\WriterException('Block ID too large'); + } + + $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks; + $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2; + $numTotalBytesInGroup1 = intval($numTotalBytes / $numRsBlocks); + $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1; + $numDataBytesInGroup1 = intval($numDataBytes / $numRsBlocks); + $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1; + $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1; + $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2; + + if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) { + throw new Exception\WriterException('EC bytes mismatch'); + } + + if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) { + throw new Exception\WriterException('RS blocks mismatch'); + } + + if ($numTotalBytes !== + (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1) + + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2) + ) { + throw new Exception\WriterException('Total bytes mismatch'); + } + + if ($blockId < $numRsBlocksInGroup1) { + return array($numDataBytesInGroup1, $numEcBytesInGroup1); + } else { + return array($numDataBytesInGroup2, $numEcBytesInGroup2); + } + } + + /** + * Interleaves data with EC bytes. + * + * @param BitArray $bits + * @param integer $numTotalBytes + * @param integer $numDataBytes + * @param integer $numRsBlocks + * @return BitArray + * @throws Exception\WriterException + */ + protected static function interleaveWithEcBytes(BitArray $bits, $numTotalBytes, $numDataBytes, $numRsBlocks) + { + if ($bits->getSizeInBytes() !== $numDataBytes) { + throw new Exception\WriterException('Number of bits and data bytes does not match'); + } + + $dataBytesOffset = 0; + $maxNumDataBytes = 0; + $maxNumEcBytes = 0; + + $blocks = new SplFixedArray($numRsBlocks); + + for ($i = 0; $i < $numRsBlocks; $i++) { + list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $i + ); + + $size = $numDataBytesInBlock; + $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size); + $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock); + $blocks[$i] = new BlockPair($dataBytes, $ecBytes); + + $maxNumDataBytes = max($maxNumDataBytes, $size); + $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes)); + $dataBytesOffset += $numDataBytesInBlock; + } + + if ($numDataBytes !== $dataBytesOffset) { + throw new Exception\WriterException('Data bytes does not match offset'); + } + + $result = new BitArray(); + + for ($i = 0; $i < $maxNumDataBytes; $i++) { + foreach ($blocks as $block) { + $dataBytes = $block->getDataBytes(); + + if ($i < count($dataBytes)) { + $result->appendBits($dataBytes[$i], 8); + } + } + } + + for ($i = 0; $i < $maxNumEcBytes; $i++) { + foreach ($blocks as $block) { + $ecBytes = $block->getErrorCorrectionBytes(); + + if ($i < count($ecBytes)) { + $result->appendBits($ecBytes[$i], 8); + } + } + } + + if ($numTotalBytes !== $result->getSizeInBytes()) { + throw new Exception\WriterException('Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ'); + } + + return $result; + } + + /** + * Generates EC bytes for given data. + * + * @param SplFixedArray $dataBytes + * @param integer $numEcBytesInBlock + * @return SplFixedArray + */ + protected static function generateEcBytes(SplFixedArray $dataBytes, $numEcBytesInBlock) + { + $numDataBytes = count($dataBytes); + $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock); + + for ($i = 0; $i < $numDataBytes; $i++) { + $toEncode[$i] = $dataBytes[$i] & 0xff; + } + + $ecBytes = new SplFixedArray($numEcBytesInBlock); + $codec = self::getCodec($numDataBytes, $numEcBytesInBlock); + $codec->encode($toEncode, $ecBytes); + + return $ecBytes; + } + + /** + * Gets an RS codec and caches it. + * + * @param integer $numDataBytes + * @param integer $numEcBytesInBlock + * @return ReedSolomonCodec + */ + protected static function getCodec($numDataBytes, $numEcBytesInBlock) + { + $cacheId = $numDataBytes . '-' . $numEcBytesInBlock; + + if (!isset(self::$codecs[$cacheId])) { + self::$codecs[$cacheId] = new ReedSolomonCodec( + 8, + 0x11d, + 0, + 1, + $numEcBytesInBlock, + 255 - $numDataBytes - $numEcBytesInBlock + ); + } + + return self::$codecs[$cacheId]; + } + + /** + * Appends mode information to a bit array. + * + * @param Mode $mode + * @param BitArray $bits + * @return void + */ + protected static function appendModeInfo(Mode $mode, BitArray $bits) + { + $bits->appendBits($mode->get(), 4); + } + + /** + * Appends length information to a bit array. + * + * @param integer $numLetters + * @param Version $version + * @param Mode $mode + * @param BitArray $bits + * @return void + * @throws Exception\WriterException + */ + protected static function appendLengthInfo($numLetters, Version $version, Mode $mode, BitArray $bits) + { + $numBits = $mode->getCharacterCountBits($version); + + if ($numLetters >= (1 << $numBits)) { + throw new Exception\WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1)); + } + + $bits->appendBits($numLetters, $numBits); + } + + /** + * Appends bytes to a bit array in a specific mode. + * + * @param stirng $content + * @param Mode $mode + * @param BitArray $bits + * @param string $encoding + * @return void + * @throws Exception\WriterException + */ + protected static function appendBytes($content, Mode $mode, BitArray $bits, $encoding) + { + switch ($mode->get()) { + case Mode::NUMERIC: + self::appendNumericBytes($content, $bits); + break; + + case Mode::ALPHANUMERIC: + self::appendAlphanumericBytes($content, $bits); + break; + + case Mode::BYTE: + self::append8BitBytes($content, $bits, $encoding); + break; + + case Mode::KANJI: + self::appendKanjiBytes($content, $bits); + break; + + default: + throw new Exception\WriterException('Invalid mode: ' . $mode->get()); + } + } + + /** + * Appends numeric bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendNumericBytes($content, BitArray $bits) + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $num1 = (int) $content[$i]; + + if ($i + 2 < $length) { + // Encode three numeric letters in ten bits. + $num2 = (int) $content[$i + 1]; + $num3 = (int) $content[$i + 2]; + $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10); + $i += 3; + } elseif ($i + 1 < $length) { + // Encode two numeric letters in seven bits. + $num2 = (int) $content[$i + 1]; + $bits->appendBits($num1 * 10 + $num2, 7); + $i += 2; + } else { + // Encode one numeric letter in four bits. + $bits->appendBits($num1, 4); + $i++; + } + } + } + + /** + * Appends alpha-numeric bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendAlphanumericBytes($content, BitArray $bits) + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + if (-1 === ($code1 = self::getAlphanumericCode($content[$i]))) { + throw new Exception\WriterException('Invalid alphanumeric code'); + } + + if ($i + 1 < $length) { + if (-1 === ($code2 = self::getAlphanumericCode($content[$i + 1]))) { + throw new Exception\WriterException('Invalid alphanumeric code'); + } + + // Encode two alphanumeric letters in 11 bits. + $bits->appendBits($code1 * 45 + $code2, 11); + $i += 2; + } else { + // Encode one alphanumeric letter in six bits. + $bits->appendBits($code1, 6); + $i++; + } + } + } + + /** + * Appends regular 8-bit bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function append8BitBytes($content, BitArray $bits, $encoding) + { + if (false === ($bytes = @iconv('utf-8', $encoding, $content))) { + throw new Exception\WriterException('Could not encode content to ' . $encoding); + } + + $length = strlen($bytes); + + for ($i = 0; $i < $length; $i++) { + $bits->appendBits(ord($bytes[$i]), 8); + } + } + + /** + * Appends KANJI bytes to a bit array. + * + * @param string $content + * @param BitArray $bits + * @return void + */ + protected static function appendKanjiBytes($content, BitArray $bits) + { + if (strlen($content) % 2 > 0) { + // We just do a simple length check here. The for loop will check + // individual characters. + throw new Exception\WriterException('Content does not seem to be encoded in SHIFT-JIS'); + } + + $length = strlen($content); + + for ($i = 0; $i < $length; $i += 2) { + $byte1 = ord($content[$i]) & 0xff; + $byte2 = ord($content[$i + 1]) & 0xff; + $code = ($byte1 << 8) | $byte2; + + if ($code >= 0x8140 && $code <= 0x9ffc) { + $subtracted = $code - 0x8140; + } elseif ($code >= 0xe040 && $code <= 0xebbf) { + $subtracted = $code - 0xc140; + } else { + throw new Exception\WriterException('Invalid byte sequence'); + } + + $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff); + + $bits->appendBits($encoded, 13); + } + } + + /** + * Appends ECI information to a bit array. + * + * @param CharacterSetEci $eci + * @param BitArray $bits + * @return void + */ + protected static function appendEci(CharacterSetEci $eci, BitArray $bits) + { + $mode = new Mode(Mode::ECI); + $bits->appendBits($mode->get(), 4); + $bits->appendBits($eci->get(), 8); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php new file mode 100755 index 00000000..c294d557 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php @@ -0,0 +1,291 @@ +getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height - 1; $y++) { + for ($x = 0; $x < $width - 1; $x++) { + $value = $array[$y][$x]; + + if ($value === $array[$y][$x + 1] && $value === $array[$y + 1][$x] && $value === $array[$y + 1][$x + 1]) { + $penalty++; + } + } + } + + return self::N2 * $penalty; + } + + /** + * Applies mask penalty rule 3 and returns the penalty. + * + * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty + * to them. If we find patterns like 000010111010000, we give penalties + * twice (i.e. 40 * 2). + * + * @param ByteMatrix $matrix + * @return integer + */ + public static function applyMaskPenaltyRule3(ByteMatrix $matrix) + { + $penalty = 0; + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; $y++) { + for ($x = 0; $x < $width; $x++) { + if ( + $x + 6 < $width + && $array[$y][$x] === 1 + && $array[$y][$x + 1] === 0 + && $array[$y][$x + 2] === 1 + && $array[$y][$x + 3] === 1 + && $array[$y][$x + 4] === 1 + && $array[$y][$x + 5] === 0 + && $array[$y][$x + 6] === 1 + && ( + ( + $x + 10 < $width + && $array[$y][$x + 7] === 0 + && $array[$y][$x + 8] === 0 + && $array[$y][$x + 9] === 0 + && $array[$y][$x + 10] === 0 + ) + || ( + $x - 4 >= 0 + && $array[$y][$x - 1] === 0 + && $array[$y][$x - 2] === 0 + && $array[$y][$x - 3] === 0 + && $array[$y][$x - 4] === 0 + ) + ) + ) { + $penalty += self::N3; + } + + if ( + $y + 6 < $height + && $array[$y][$x] === 1 + && $array[$y + 1][$x] === 0 + && $array[$y + 2][$x] === 1 + && $array[$y + 3][$x] === 1 + && $array[$y + 4][$x] === 1 + && $array[$y + 5][$x] === 0 + && $array[$y + 6][$x] === 1 + && ( + ( + $y + 10 < $height + && $array[$y + 7][$x] === 0 + && $array[$y + 8][$x] === 0 + && $array[$y + 9][$x] === 0 + && $array[$y + 10][$x] === 0 + ) + || ( + $y - 4 >= 0 + && $array[$y - 1][$x] === 0 + && $array[$y - 2][$x] === 0 + && $array[$y - 3][$x] === 0 + && $array[$y - 4][$x] === 0 + ) + ) + ) { + $penalty += self::N3; + } + } + } + + return $penalty; + } + + /** + * Applies mask penalty rule 4 and returns the penalty. + * + * Calculates the ratio of dark cells and gives penalty if the ratio is far + * from 50%. It gives 10 penalty for 5% distance. + * + * @param ByteMatrix $matrix + * @return integer + */ + public static function applyMaskPenaltyRule4(ByteMatrix $matrix) + { + $numDarkCells = 0; + + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; $y++) { + $arrayY = $array[$y]; + + for ($x = 0; $x < $width; $x++) { + if ($arrayY[$x] === 1) { + $numDarkCells++; + } + } + } + + $numTotalCells = $height * $width; + $darkRatio = $numDarkCells / $numTotalCells; + $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20); + + return $fixedPercentVariances * self::N4; + } + + /** + * Returns the mask bit for "getMaskPattern" at "x" and "y". + * + * See 8.8 of JISX0510:2004 for mask pattern conditions. + * + * @param integer $maskPattern + * @param integer $x + * @param integer $y + * @return integer + * @throws Exception\InvalidArgumentException + */ + public static function getDataMaskBit($maskPattern, $x, $y) + { + switch ($maskPattern) { + case 0: + $intermediate = ($y + $x) & 0x1; + break; + + case 1: + $intermediate = $y & 0x1; + break; + + case 2: + $intermediate = $x % 3; + break; + + case 3: + $intermediate = ($y + $x) % 3; + break; + + case 4: + $intermediate = (BitUtils::unsignedRightShift($y, 1) + ($x / 3)) & 0x1; + break; + + case 5: + $temp = $y * $x; + $intermediate = ($temp & 0x1) + ($temp % 3); + break; + + case 6: + $temp = $y * $x; + $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1; + break; + + case 7: + $temp = $y * $x; + $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1; + break; + + default: + throw new Exception\InvalidArgumentException('Invalid mask pattern: ' . $maskPattern); + } + + return $intermediate === 0; + } + + /** + * Helper function for applyMaskPenaltyRule1. + * + * We need this for doing this calculation in both vertical and horizontal + * orders respectively. + * + * @param ByteMatrix $matrix + * @param boolean $isHorizontal + * @return integer + */ + protected static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, $isHorizontal) + { + $penalty = 0; + $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth(); + $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight(); + $array = $matrix->getArray(); + + for ($i = 0; $i < $iLimit; $i++) { + $numSameBitCells = 0; + $prevBit = -1; + + for ($j = 0; $j < $jLimit; $j++) { + $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i]; + + if ($bit === $prevBit) { + $numSameBitCells++; + } else { + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; + $prevBit = $bit; + } + } + + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + } + + return $penalty; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php new file mode 100755 index 00000000..83273818 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php @@ -0,0 +1,580 @@ +clear(-1); + } + + /** + * Builds a complete matrix. + * + * @param BitArray $dataBits + * @param ErrorCorrectionLevel $level + * @param Version $version + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + */ + public static function buildMatrix( + BitArray $dataBits, + ErrorCorrectionLevel $level, + Version $version, + $maskPattern, + ByteMatrix $matrix + ) { + self::clearMatrix($matrix); + self::embedBasicPatterns($version, $matrix); + self::embedTypeInfo($level, $maskPattern, $matrix); + self::maybeEmbedVersionInfo($version, $matrix); + self::embedDataBits($dataBits, $maskPattern, $matrix); + } + + /** + * Embeds type information into a matrix. + * + * @param ErrorCorrectionLevel $level + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedTypeInfo(ErrorCorrectionLevel $level, $maskPattern, ByteMatrix $matrix) + { + $typeInfoBits = new BitArray(); + self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits); + + $typeInfoBitsSize = $typeInfoBits->getSize(); + + for ($i = 0; $i < $typeInfoBitsSize; $i++) { + $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i); + + $x1 = self::$typeInfoCoordinates[$i][0]; + $y1 = self::$typeInfoCoordinates[$i][1]; + + $matrix->set($x1, $y1, $bit); + + if ($i < 8) { + $x2 = $matrix->getWidth() - $i - 1; + $y2 = 8; + } else { + $x2 = 8; + $y2 = $matrix->getHeight() - 7 + ($i - 8); + } + + $matrix->set($x2, $y2, $bit); + } + } + + /** + * Generates type information bits and appends them to a bit array. + * + * @param ErrorCorrectionLevel $level + * @param integer $maskPattern + * @param BitArray $bits + * @return void + * @throws Exception\RuntimeException + */ + protected static function makeTypeInfoBits(ErrorCorrectionLevel $level, $maskPattern, BitArray $bits) + { + $typeInfo = ($level->get() << 3) | $maskPattern; + $bits->appendBits($typeInfo, 5); + + $bchCode = self::calculateBchCode($typeInfo, self::$typeInfoPoly); + $bits->appendBits($bchCode, 10); + + $maskBits = new BitArray(); + $maskBits->appendBits(self::$typeInfoMaskPattern, 15); + $bits->xorBits($maskBits); + + if ($bits->getSize() !== 15) { + throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Embeds version information if required. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix) + { + if ($version->getVersionNumber() < 7) { + return; + } + + $versionInfoBits = new BitArray(); + self::makeVersionInfoBits($version, $versionInfoBits); + + $bitIndex = 6 * 3 - 1; + + for ($i = 0; $i < 6; $i++) { + for ($j = 0; $j < 3; $j++) { + $bit = $versionInfoBits->get($bitIndex); + $bitIndex--; + + $matrix->set($i, $matrix->getHeight() - 11 + $j, $bit); + $matrix->set($matrix->getHeight() - 11 + $j, $i, $bit); + } + } + } + + /** + * Generates version information bits and appends them to a bit array. + * + * @param Version $version + * @param BitArray $bits + * @return void + * @throws Exception\RuntimeException + */ + protected static function makeVersionInfoBits(Version $version, BitArray $bits) + { + $bits->appendBits($version->getVersionNumber(), 6); + + $bchCode = self::calculateBchCode($version->getVersionNumber(), self::$versionInfoPoly); + $bits->appendBits($bchCode, 12); + + if ($bits->getSize() !== 18) { + throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Calculates the BHC code for a value and a polynomial. + * + * @param integer $value + * @param integer $poly + * @return integer + */ + protected static function calculateBchCode($value, $poly) + { + $msbSetInPoly = self::findMsbSet($poly); + $value <<= $msbSetInPoly - 1; + + while (self::findMsbSet($value) >= $msbSetInPoly) { + $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly); + } + + return $value; + } + + /** + * Finds and MSB set. + * + * @param integer $value + * @return integer + */ + protected static function findMsbSet($value) + { + $numDigits = 0; + + while ($value !== 0) { + $value >>= 1; + $numDigits++; + } + + return $numDigits; + } + + /** + * Embeds basic patterns into a matrix. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedBasicPatterns(Version $version, ByteMatrix $matrix) + { + self::embedPositionDetectionPatternsAndSeparators($matrix); + self::embedDarkDotAtLeftBottomCorner($matrix); + self::maybeEmbedPositionAdjustmentPatterns($version, $matrix); + self::embedTimingPatterns($matrix); + } + + /** + * Embeds position detection patterns and separators into a byte matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix) + { + $pdpWidth = count(self::$positionDetectionPattern[0]); + + self::embedPositionDetectionPattern(0, 0, $matrix); + self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + + $hspWidth = 8; + + self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix); + + $vspSize = 7; + + self::embedVerticalSeparationPattern($vspSize, 0, $matrix); + self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix); + self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix); + } + + /** + * Embeds a single position detection pattern into a byte matrix. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionDetectionPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 7; $y++) { + for ($x = 0; $x < 7; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::$positionDetectionPattern[$y][$x]); + } + } + } + + /** + * Embeds a single horizontal separation pattern. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedHorizontalSeparationPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($x = 0; $x < 8; $x++) { + if ($matrix->get($xStart + $x, $yStart) !== -1) { + throw new Exception\RuntimeException('Byte already set'); + } + + $matrix->set($xStart + $x, $yStart, 0); + } + } + + /** + * Embeds a single vertical separation pattern. + * + * @param integer $xStart + * @param integer $yStart + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedVerticalSeparationPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 7; $y++) { + if ($matrix->get($xStart, $yStart + $y) !== -1) { + throw new Exception\RuntimeException('Byte already set'); + } + + $matrix->set($xStart, $yStart + $y, 0); + } + } + + /** + * Embeds a dot at the left bottom corner. + * + * @param ByteMatrix $matrix + * @return void + * @throws Exception\RuntimeException + */ + protected static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix) + { + if ($matrix->get(8, $matrix->getHeight() - 8) === 0) { + throw new Exception\RuntimeException('Byte already set to 0'); + } + + $matrix->set(8, $matrix->getHeight() - 8, 1); + } + + /** + * Embeds position adjustment patterns if required. + * + * @param Version $version + * @param ByteMatrix $matrix + * @return void + */ + protected static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix) + { + if ($version->getVersionNumber() < 2) { + return; + } + + $index = $version->getVersionNumber() - 1; + + $coordinates = self::$positionAdjustmentPatternCoordinateTable[$index]; + $numCoordinates = count($coordinates); + + for ($i = 0; $i < $numCoordinates; $i++) { + for ($j = 0; $j < $numCoordinates; $j++) { + $y = $coordinates[$i]; + $x = $coordinates[$j]; + + if ($x === null || $y === null) { + continue; + } + + if ($matrix->get($x, $y) === -1) { + self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix); + } + } + } + } + + /** + * Embeds a single position adjustment pattern. + * + * @param integer $xStart + * @param intger $yStart + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedPositionAdjustmentPattern($xStart, $yStart, ByteMatrix $matrix) + { + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::$positionAdjustmentPattern[$y][$x]); + } + } + } + + /** + * Embeds timing patterns into a matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + protected static function embedTimingPatterns(ByteMatrix $matrix) + { + $matrixWidth = $matrix->getWidth(); + + for ($i = 8; $i < $matrixWidth - 8; $i++) { + $bit = ($i + 1) % 2; + + if ($matrix->get($i, 6) === -1) { + $matrix->set($i, 6, $bit); + } + + if ($matrix->get(6, $i) === -1) { + $matrix->set(6, $i, $bit); + } + } + } + + /** + * Embeds "dataBits" using "getMaskPattern". + * + * For debugging purposes, it skips masking process if "getMaskPattern" is + * -1. See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. + * + * @param BitArray $dataBits + * @param integer $maskPattern + * @param ByteMatrix $matrix + * @return void + * @throws Exception\WriterException + */ + protected static function embedDataBits(BitArray $dataBits, $maskPattern, ByteMatrix $matrix) + { + $bitIndex = 0; + $direction = -1; + + // Start from the right bottom cell. + $x = $matrix->getWidth() - 1; + $y = $matrix->getHeight() - 1; + + while ($x > 0) { + // Skip vertical timing pattern. + if ($x === 6) { + $x--; + } + + while ($y >= 0 && $y < $matrix->getHeight()) { + for ($i = 0; $i < 2; $i++) { + $xx = $x - $i; + + // Skip the cell if it's not empty. + if ($matrix->get($xx, $y) !== -1) { + continue; + } + + if ($bitIndex < $dataBits->getSize()) { + $bit = $dataBits->get($bitIndex); + $bitIndex++; + } else { + // Padding bit. If there is no bit left, we'll fill the + // left cells with 0, as described in 8.4.9 of + // JISX0510:2004 (p. 24). + $bit = false; + } + + // Skip masking if maskPattern is -1. + if ($maskPattern !== -1 && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) { + $bit = !$bit; + } + + $matrix->set($xx, $y, $bit); + } + + $y += $direction; + } + + $direction = -$direction; + $y += $direction; + $x -= 2; + } + + // All bits should be consumed + if ($bitIndex !== $dataBits->getSize()) { + throw new Exception\WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')'); + } + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php new file mode 100755 index 00000000..07e1c385 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php @@ -0,0 +1,201 @@ +mode; + } + + /** + * Sets the mode. + * + * @param Mode $mode + * @return void + */ + public function setMode(Mode $mode) + { + $this->mode = $mode; + } + + /** + * Gets the EC level. + * + * @return ErrorCorrectionLevel + */ + public function getErrorCorrectionLevel() + { + return $this->errorCorrectionLevel; + } + + /** + * Sets the EC level. + * + * @param ErrorCorrectionLevel $errorCorrectionLevel + * @return void + */ + public function setErrorCorrectionLevel(ErrorCorrectionLevel $errorCorrectionLevel) + { + $this->errorCorrectionLevel = $errorCorrectionLevel; + } + + /** + * Gets the version. + * + * @return Version + */ + public function getVersion() + { + return $this->version; + } + + /** + * Sets the version. + * + * @param Version $version + * @return void + */ + public function setVersion(Version $version) + { + $this->version = $version; + } + + /** + * Gets the mask pattern. + * + * @return integer + */ + public function getMaskPattern() + { + return $this->maskPattern; + } + + /** + * Sets the mask pattern. + * + * @param integer $maskPattern + * @return void + */ + public function setMaskPattern($maskPattern) + { + $this->maskPattern = $maskPattern; + } + + /** + * Gets the matrix. + * + * @return ByteMatrix + */ + public function getMatrix() + { + return $this->matrix; + } + + /** + * Sets the matrix. + * + * @param ByteMatrix $matrix + * @return void + */ + public function setMatrix(ByteMatrix $matrix) + { + $this->matrix = $matrix; + } + + /** + * Validates whether a mask pattern is valid. + * + * @param integer $maskPattern + * @return boolean + */ + public static function isValidMaskPattern($maskPattern) + { + return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS; + } + + /** + * Returns a string representation of the QR code. + * + * @return string + */ + public function __toString() + { + $result = "<<\n" + . " mode: " . $this->mode . "\n" + . " ecLevel: " . $this->errorCorrectionLevel . "\n" + . " version: " . $this->version . "\n" + . " maskPattern: " . $this->maskPattern . "\n"; + + if ($this->matrix === null) { + $result .= " matrix: null\n"; + } else { + $result .= " matrix:\n"; + $result .= $this->matrix; + } + + $result .= ">>\n"; + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php new file mode 100755 index 00000000..5c58fc51 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php @@ -0,0 +1,14 @@ + 100) { + throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100'); + } + + if ($magenta < 0 || $magenta > 100) { + throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100'); + } + + if ($yellow < 0 || $yellow > 100) { + throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100'); + } + + if ($black < 0 || $black > 100) { + throw new Exception\InvalidArgumentException('Black must be between 0 and 100'); + } + + $this->cyan = (int) $cyan; + $this->magenta = (int) $magenta; + $this->yellow = (int) $yellow; + $this->black = (int) $black; + } + + /** + * Returns the cyan value. + * + * @return integer + */ + public function getCyan() + { + return $this->cyan; + } + + /** + * Returns the magenta value. + * + * @return integer + */ + public function getMagenta() + { + return $this->magenta; + } + + /** + * Returns the yellow value. + * + * @return integer + */ + public function getYellow() + { + return $this->yellow; + } + + /** + * Returns the black value. + * + * @return integer + */ + public function getBlack() + { + return $this->black; + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + $k = $this->black / 100; + $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100; + $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100; + $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100; + + return new Rgb( + -$c * 255 + 255, + -$m * 255 + 255, + -$y * 255 + 255 + ); + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + return $this; + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return $this->toRgb()->toGray(); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php new file mode 100755 index 00000000..747accc1 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php @@ -0,0 +1,37 @@ + 100) { + throw new Exception\InvalidArgumentException('Gray must be between 0 and 100'); + } + + $this->gray = (int) $gray; + } + + /** + * Returns the gray value. + * + * @return integer + */ + public function getGray() + { + return $this->gray; + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + return new Rgb($this->gray * 2.55, $this->gray * 2.55, $this->gray * 2.55); + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + return new Cmyk(0, 0, 0, 100 - $this->gray); + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return $this; + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php new file mode 100755 index 00000000..44e4060c --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php @@ -0,0 +1,148 @@ + 255) { + throw new Exception\InvalidArgumentException('Red must be between 0 and 255'); + } + + if ($green < 0 || $green > 255) { + throw new Exception\InvalidArgumentException('Green must be between 0 and 255'); + } + + if ($blue < 0 || $blue > 255) { + throw new Exception\InvalidArgumentException('Blue must be between 0 and 255'); + } + + $this->red = (int) $red; + $this->green = (int) $green; + $this->blue = (int) $blue; + } + + /** + * Returns the red value. + * + * @return integer + */ + public function getRed() + { + return $this->red; + } + + /** + * Returns the green value. + * + * @return integer + */ + public function getGreen() + { + return $this->green; + } + + /** + * Returns the blue value. + * + * @return integer + */ + public function getBlue() + { + return $this->blue; + } + + /** + * Returns a hexadecimal string representation of the RGB value. + * + * @return string + */ + public function __toString() + { + return sprintf('%02x%02x%02x', $this->red, $this->green, $this->blue); + } + + /** + * toRgb(): defined by ColorInterface. + * + * @see ColorInterface::toRgb() + * @return Rgb + */ + public function toRgb() + { + return $this; + } + + /** + * toCmyk(): defined by ColorInterface. + * + * @see ColorInterface::toCmyk() + * @return Cmyk + */ + public function toCmyk() + { + $c = 1 - ($this->red / 255); + $m = 1 - ($this->green / 255); + $y = 1 - ($this->blue / 255); + $k = min($c, $m, $y); + + return new Cmyk( + 100 * ($c - $k) / (1 - $k), + 100 * ($m - $k) / (1 - $k), + 100 * ($y - $k) / (1 - $k), + 100 * $k + ); + } + + /** + * toGray(): defined by ColorInterface. + * + * @see ColorInterface::toGray() + * @return Gray + */ + public function toGray() + { + return new Gray(($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php new file mode 100755 index 00000000..b0bb02ac --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php @@ -0,0 +1,338 @@ +margin = (int) $margin; + return $this; + } + + /** + * Gets the margin around the QR code. + * + * @return integer + */ + public function getMargin() + { + return $this->margin; + } + + /** + * Sets the height around the renderd image. + * + * If the width is smaller than the matrix width plus padding, the renderer + * will automatically use that as the width instead of the specified one. + * + * @param integer $width + * @return AbstractRenderer + */ + public function setWidth($width) + { + $this->width = (int) $width; + return $this; + } + + /** + * Gets the width of the rendered image. + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Sets the height around the renderd image. + * + * If the height is smaller than the matrix height plus padding, the + * renderer will automatically use that as the height instead of the + * specified one. + * + * @param integer $height + * @return AbstractRenderer + */ + public function setHeight($height) + { + $this->height = (int) $height; + return $this; + } + + /** + * Gets the height around the rendered image. + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * Sets whether dimensions should be rounded down. + * + * @param boolean $flag + * @return AbstractRenderer + */ + public function setRoundDimensions($flag) + { + $this->floorToClosestDimension = $flag; + return $this; + } + + /** + * Gets whether dimensions should be rounded down. + * + * @return boolean + */ + public function shouldRoundDimensions() + { + return $this->floorToClosestDimension; + } + + /** + * Sets background color. + * + * @param Color\ColorInterface $color + * @return AbstractRenderer + */ + public function setBackgroundColor(Color\ColorInterface $color) + { + $this->backgroundColor = $color; + return $this; + } + + /** + * Gets background color. + * + * @return Color\ColorInterface + */ + public function getBackgroundColor() + { + if ($this->backgroundColor === null) { + $this->backgroundColor = new Color\Gray(100); + } + + return $this->backgroundColor; + } + + /** + * Sets foreground color. + * + * @param Color\ColorInterface $color + * @return AbstractRenderer + */ + public function setForegroundColor(Color\ColorInterface $color) + { + $this->foregroundColor = $color; + return $this; + } + + /** + * Gets foreground color. + * + * @return Color\ColorInterface + */ + public function getForegroundColor() + { + if ($this->foregroundColor === null) { + $this->foregroundColor = new Color\Gray(0); + } + + return $this->foregroundColor; + } + + /** + * Adds a decorator to the renderer. + * + * @param DecoratorInterface $decorator + * @return AbstractRenderer + */ + public function addDecorator(DecoratorInterface $decorator) + { + $this->decorators[] = $decorator; + return $this; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $input = $qrCode->getMatrix(); + $inputWidth = $input->getWidth(); + $inputHeight = $input->getHeight(); + $qrWidth = $inputWidth + ($this->getMargin() << 1); + $qrHeight = $inputHeight + ($this->getMargin() << 1); + $outputWidth = max($this->getWidth(), $qrWidth); + $outputHeight = max($this->getHeight(), $qrHeight); + $multiple = (int) min($outputWidth / $qrWidth, $outputHeight / $qrHeight); + + if ($this->shouldRoundDimensions()) { + $outputWidth -= $outputWidth % $multiple; + $outputHeight -= $outputHeight % $multiple; + } + + // Padding includes both the quiet zone and the extra white pixels to + // accommodate the requested dimensions. For example, if input is 25x25 + // the QR will be 33x33 including the quiet zone. If the requested size + // is 200x160, the multiple will be 4, for a QR of 132x132. These will + // handle all the padding from 100x100 (the actual QR) up to 200x160. + $leftPadding = (int) (($outputWidth - ($inputWidth * $multiple)) / 2); + $topPadding = (int) (($outputHeight - ($inputHeight * $multiple)) / 2); + + // Store calculated parameters + $this->finalWidth = $outputWidth; + $this->finalHeight = $outputHeight; + $this->blockSize = $multiple; + + $this->init(); + $this->addColor('background', $this->getBackgroundColor()); + $this->addColor('foreground', $this->getForegroundColor()); + $this->drawBackground('background'); + + foreach ($this->decorators as $decorator) { + $decorator->preProcess( + $qrCode, + $this, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ); + } + + for ($inputY = 0, $outputY = $topPadding; $inputY < $inputHeight; $inputY++, $outputY += $multiple) { + for ($inputX = 0, $outputX = $leftPadding; $inputX < $inputWidth; $inputX++, $outputX += $multiple) { + if ($input->get($inputX, $inputY) === 1) { + $this->drawBlock($outputX, $outputY, 'foreground'); + } + } + } + + foreach ($this->decorators as $decorator) { + $decorator->postProcess( + $qrCode, + $this, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ); + } + + return $this->getByteStream(); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php new file mode 100755 index 00000000..e67268b5 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php @@ -0,0 +1,63 @@ +outerColor = $color; + return $this; + } + + /** + * Gets outer color. + * + * @return Color\ColorInterface + */ + public function getOuterColor() + { + if ($this->outerColor === null) { + $this->outerColor = new Color\Gray(100); + } + + return $this->outerColor; + } + + /** + * Sets inner color. + * + * @param Color\ColorInterface $color + * @return FinderPattern + */ + public function setInnerColor(Color\ColorInterface $color) + { + $this->innerColor = $color; + return $this; + } + + /** + * Gets inner color. + * + * @return Color\ColorInterface + */ + public function getInnerColor() + { + if ($this->innerColor === null) { + $this->innerColor = new Color\Gray(0); + } + + return $this->innerColor; + } + + /** + * preProcess(): defined by DecoratorInterface. + * + * @see DecoratorInterface::preProcess() + * @param QrCode $qrCode + * @param RendererInterface $renderer + * @param integer $outputWidth + * @param integer $outputHeight + * @param integer $leftPadding + * @param integer $topPadding + * @param integer $multiple + * @return void + */ + public function preProcess( + QrCode $qrCode, + RendererInterface $renderer, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ) { + $matrix = $qrCode->getMatrix(); + $positions = array( + array(0, 0), + array($matrix->getWidth() - 7, 0), + array(0, $matrix->getHeight() - 7), + ); + + foreach (self::$outerPositionDetectionPattern as $y => $row) { + foreach ($row as $x => $isSet) { + foreach ($positions as $position) { + $matrix->set($x + $position[0], $y + $position[1], 0); + } + } + } + } + + /** + * postProcess(): defined by DecoratorInterface. + * + * @see DecoratorInterface::postProcess() + * + * @param QrCode $qrCode + * @param RendererInterface $renderer + * @param integer $outputWidth + * @param integer $outputHeight + * @param integer $leftPadding + * @param integer $topPadding + * @param integer $multiple + * @return void + */ + public function postProcess( + QrCode $qrCode, + RendererInterface $renderer, + $outputWidth, + $outputHeight, + $leftPadding, + $topPadding, + $multiple + ) { + $matrix = $qrCode->getMatrix(); + $positions = array( + array(0, 0), + array($matrix->getWidth() - 7, 0), + array(0, $matrix->getHeight() - 7), + ); + + $renderer->addColor('finder-outer', $this->getOuterColor()); + $renderer->addColor('finder-inner', $this->getInnerColor()); + + foreach (self::$outerPositionDetectionPattern as $y => $row) { + foreach ($row as $x => $isOuterSet) { + $isInnerSet = self::$innerPositionDetectionPattern[$y][$x]; + + if ($isOuterSet) { + foreach ($positions as $position) { + $renderer->drawBlock( + $leftPadding + $x * $multiple + $position[0] * $multiple, + $topPadding + $y * $multiple + $position[1] * $multiple, + 'finder-outer' + ); + } + } + + if ($isInnerSet) { + foreach ($positions as $position) { + $renderer->drawBlock( + $leftPadding + $x * $multiple + $position[0] * $multiple, + $topPadding + $y * $multiple + $position[1] * $multiple, + 'finder-inner' + ); + } + } + } + } + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php new file mode 100755 index 00000000..97661951 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php @@ -0,0 +1,152 @@ +eps = "%!PS-Adobe-3.0 EPSF-3.0\n" + . "%%BoundingBox: 0 0 " . $this->finalWidth . " " . $this->finalHeight . "\n" + . "/F { rectfill } def\n"; + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + */ + public function addColor($id, ColorInterface $color) + { + if ( + !$color instanceof Rgb + && !$color instanceof Cmyk + && !$color instanceof Gray + ) { + $color = $color->toCmyk(); + } + + $this->colors[$id] = $color; + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + $this->setColor($colorId); + $this->eps .= "0 0 " . $this->finalWidth . " " . $this->finalHeight . " F\n"; + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + $this->setColor($colorId); + $this->eps .= $x . " " . ($this->finalHeight - $y - $this->blockSize) . " " . $this->blockSize . " " . $this->blockSize . " F\n"; + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + return $this->eps; + } + + /** + * Sets color to use. + * + * @param string $colorId + * @return void + */ + protected function setColor($colorId) + { + if ($colorId !== $this->currentColor) { + $color = $this->colors[$colorId]; + + if ($color instanceof Rgb) { + $this->eps .= sprintf( + "%F %F %F setrgbcolor\n", + $color->getRed() / 100, + $color->getGreen() / 100, + $color->getBlue() / 100 + ); + } elseif ($color instanceof Cmyk) { + $this->eps .= sprintf( + "%F %F %F %F setcmykcolor\n", + $color->getCyan() / 100, + $color->getMagenta() / 100, + $color->getYellow() / 100, + $color->getBlack() / 100 + ); + } elseif ($color instanceof Gray) { + $this->eps .= sprintf( + "%F setgray\n", + $color->getGray() / 100 + ); + } + + $this->currentColor = $colorId; + } + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php new file mode 100755 index 00000000..dd593a8b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php @@ -0,0 +1,115 @@ +image = imagecreatetruecolor($this->finalWidth, $this->finalHeight); + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + * @throws Exception\RuntimeException + */ + public function addColor($id, ColorInterface $color) + { + if ($this->image === null) { + throw new Exception\RuntimeException('Colors can only be added after init'); + } + + $color = $color->toRgb(); + + $this->colors[$id] = imagecolorallocate( + $this->image, + $color->getRed(), + $color->getGreen(), + $color->getBlue() + ); + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + imagefill($this->image, 0, 0, $this->colors[$colorId]); + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + imagefilledrectangle( + $this->image, + $x, + $y, + $x + $this->blockSize - 1, + $y + $this->blockSize - 1, + $this->colors[$colorId] + ); + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + ob_start(); + imagepng($this->image); + return ob_get_clean(); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php new file mode 100755 index 00000000..52101a65 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php @@ -0,0 +1,61 @@ +svg = new SimpleXMLElement( + '' + . '' + ); + $this->svg->addAttribute('version', '1.1'); + $this->svg->addAttribute('width', $this->finalWidth . 'px'); + $this->svg->addAttribute('height', $this->finalHeight . 'px'); + $this->svg->addAttribute('viewBox', '0 0 ' . $this->finalWidth . ' ' . $this->finalHeight); + $this->svg->addChild('defs'); + } + + /** + * addColor(): defined by RendererInterface. + * + * @see ImageRendererInterface::addColor() + * @param string $id + * @param ColorInterface $color + * @return void + * @throws Exception\InvalidArgumentException + */ + public function addColor($id, ColorInterface $color) + { + $this->colors[$id] = (string) $color->toRgb(); + } + + /** + * drawBackground(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBackground() + * @param string $colorId + * @return void + */ + public function drawBackground($colorId) + { + $rect = $this->svg->addChild('rect'); + $rect->addAttribute('x', 0); + $rect->addAttribute('y', 0); + $rect->addAttribute('width', $this->finalWidth); + $rect->addAttribute('height', $this->finalHeight); + $rect->addAttribute('fill', '#' . $this->colors[$colorId]); + } + + /** + * drawBlock(): defined by RendererInterface. + * + * @see ImageRendererInterface::drawBlock() + * @param integer $x + * @param integer $y + * @param string $colorId + * @return void + */ + public function drawBlock($x, $y, $colorId) + { + $use = $this->svg->addChild('use'); + $use->addAttribute('x', $x); + $use->addAttribute('y', $y); + $use->addAttribute( + 'xlink:href', + $this->getRectPrototypeId($colorId), + 'http://www.w3.org/1999/xlink' + ); + } + + /** + * getByteStream(): defined by RendererInterface. + * + * @see ImageRendererInterface::getByteStream() + * @return string + */ + public function getByteStream() + { + return $this->svg->asXML(); + } + + /** + * Get the prototype ID for a color. + * + * @param integer $colorId + * @return string + */ + protected function getRectPrototypeId($colorId) + { + if (!isset($this->prototypeIds[$colorId])) { + $id = 'r' . dechex(count($this->prototypeIds)); + + $rect = $this->svg->defs->addChild('rect'); + $rect->addAttribute('id', $id); + $rect->addAttribute('width', $this->blockSize); + $rect->addAttribute('height', $this->blockSize); + $rect->addAttribute('fill', '#' . $this->colors[$colorId]); + + $this->prototypeIds[$colorId] = '#' . $id; + } + + return $this->prototypeIds[$colorId]; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php new file mode 100755 index 00000000..554e1d88 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php @@ -0,0 +1,26 @@ +class = $class; + } + + /** + * Get CSS class name. + * + * @return string + */ + public function getClass() + { + return $this->class; + } + + /** + * Set CSS style value. + * + * @param string $style + */ + public function setStyle($style) + { + $this->style = $style; + } + + /** + * Get CSS style value. + * + * @return string + */ + public function getStyle() + { + return $this->style; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $textCode = parent::render($qrCode); + + $result = '' . $textCode . ''; + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php new file mode 100755 index 00000000..a7e4cfb7 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php @@ -0,0 +1,150 @@ +fullBlock = $fullBlock; + } + + /** + * Get char used as full block (occupied space, "black"). + * + * @return string + */ + public function getFullBlock() + { + return $this->fullBlock; + } + + /** + * Set char used as empty block (empty space, "white"). + * + * @param string $emptyBlock + */ + public function setEmptyBlock($emptyBlock) + { + $this->emptyBlock = $emptyBlock; + } + + /** + * Get char used as empty block (empty space, "white"). + * + * @return string + */ + public function getEmptyBlock() + { + return $this->emptyBlock; + } + + /** + * Sets the margin around the QR code. + * + * @param integer $margin + * @return AbstractRenderer + * @throws Exception\InvalidArgumentException + */ + public function setMargin($margin) + { + if ($margin < 0) { + throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0'); + } + + $this->margin = (int) $margin; + + return $this; + } + + /** + * Gets the margin around the QR code. + * + * @return integer + */ + public function getMargin() + { + return $this->margin; + } + + /** + * render(): defined by RendererInterface. + * + * @see RendererInterface::render() + * @param QrCode $qrCode + * @return string + */ + public function render(QrCode $qrCode) + { + $result = ''; + $matrix = $qrCode->getMatrix(); + $width = $matrix->getWidth(); + + // Top margin + for ($x = 0; $x < $this->margin; $x++) { + $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n"; + } + + // Body + $array = $matrix->getArray(); + + foreach ($array as $row) { + $result .= str_repeat($this->emptyBlock, $this->margin); // left margin + foreach ($row as $byte) { + $result .= $byte ? $this->fullBlock : $this->emptyBlock; + } + $result .= str_repeat($this->emptyBlock, $this->margin); // right margin + $result .= "\n"; + } + + // Bottom margin + for ($x = 0; $x < $this->margin; $x++) { + $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n"; + } + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php new file mode 100755 index 00000000..0f803138 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php @@ -0,0 +1,105 @@ +renderer = $renderer; + } + + /** + * Sets the renderer used to create a byte stream. + * + * @param RendererInterface $renderer + * @return Writer + */ + public function setRenderer(RendererInterface $renderer) + { + $this->renderer = $renderer; + return $this; + } + + /** + * Gets the renderer used to create a byte stream. + * + * @return RendererInterface + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Writes QR code and returns it as string. + * + * Content is a string which *should* be encoded in UTF-8, in case there are + * non ASCII-characters present. + * + * @param string $content + * @param string $encoding + * @param integer $ecLevel + * @return string + * @throws Exception\InvalidArgumentException + */ + public function writeString( + $content, + $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + $ecLevel = ErrorCorrectionLevel::L + ) { + if (strlen($content) === 0) { + throw new Exception\InvalidArgumentException('Found empty contents'); + } + + $qrCode = Encoder::encode($content, new ErrorCorrectionLevel($ecLevel), $encoding); + + return $this->getRenderer()->render($qrCode); + } + + /** + * Writes QR code to a file. + * + * @see Writer::writeString() + * @param string $content + * @param string $filename + * @param string $encoding + * @param integer $ecLevel + * @return void + */ + public function writeFile( + $content, + $filename, + $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + $ecLevel = ErrorCorrectionLevel::L + ) { + file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel)); + } +} diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php new file mode 100755 index 00000000..81bcbce6 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php @@ -0,0 +1,201 @@ +assertFalse($array->get($i)); + $array->set($i); + $this->assertTrue($array->get($i)); + } + } + + public function testGetNextSet1() + { + $array = new BitArray(32); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 33, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet2() + { + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i)); + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); $i++) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet3() + { + $array = new BitArray(63); + $array->set(31); + $array->set(32); + + for ($i = 0; $i < $array->getSize(); $i++) { + if ($i <= 31) { + $expected = 31; + } elseif ($i <= 32) { + $expected = 32; + } else { + $expected = 63; + } + + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet4() + { + $array = new BitArray(63); + $array->set(33); + $array->set(40); + + for ($i = 0; $i < $array->getSize(); $i++) { + if ($i <= 33) { + $expected = 33; + } elseif ($i <= 40) { + $expected = 40; + } else { + $expected = 63; + } + + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } + } + + public function testGetNextSet5() + { + if (defined('MT_RAND_PHP')) { + mt_srand(0xdeadbeef, MT_RAND_PHP); + } else { + mt_srand(0xdeadbeef); + } + + for ($i = 0; $i < 10; $i++) { + $array = new BitArray(mt_rand(1, 100)); + $numSet = mt_rand(0, 19); + + for ($j = 0; $j < $numSet; $j++) { + $array->set(mt_rand(0, $array->getSize() - 1)); + } + + $numQueries = mt_rand(0, 19); + + for ($j = 0; $j < $numQueries; $j++) { + $query = mt_rand(0, $array->getSize() - 1); + $expected = $query; + + while ($expected < $array->getSize() && !$array->get($expected)) { + $expected++; + } + + $actual = $array->getNextSet($query); + + if ($actual !== $expected) { + $array->getNextSet($query); + } + + $this->assertEquals($expected, $actual); + } + } + } + + public function testSetBulk() + { + $array = new BitArray(64); + $array->setBulk(32, 0xFFFF0000); + + for ($i = 0; $i < 48; $i++) { + $this->assertFalse($array->get($i)); + } + + for ($i = 48; $i < 64; $i++) { + $this->assertTrue($array->get($i)); + } + } + + public function testClear() + { + $array = new BitArray(32); + + for ($i = 0; $i < 32; $i++) { + $array->set($i); + } + + $array->clear(); + + for ($i = 0; $i < 32; $i++) { + $this->assertFalse($array->get($i)); + } + } + + public function testGetArray() + { + $array = new BitArray(64); + $array->set(0); + $array->set(63); + + $ints = $array->getBitArray(); + + $this->assertEquals(1, $ints[0]); + $this->assertEquals(0x80000000, $ints[1]); + } + + public function testIsRange() + { + $array = new BitArray(64); + $this->assertTrue($array->isRange(0, 64, false)); + $this->assertFalse($array->isRange(0, 64, true)); + + $array->set(32); + $this->assertTrue($array->isRange(32, 33, true)); + + $array->set(31); + $this->assertTrue($array->isRange(31, 33, true)); + + $array->set(34); + $this->assertFalse($array->isRange(31, 35, true)); + + for ($i = 0; $i < 31; $i++) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 33, true)); + + for ($i = 33; $i < 64; $i++) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 64, true)); + $this->assertFalse($array->isRange(0, 64, false)); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php new file mode 100755 index 00000000..89a58812 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php @@ -0,0 +1,119 @@ +assertEquals(33, $matrix->getHeight()); + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; $x++) { + if ($y * $x % 3 === 0) { + $matrix->set($x, $y); + } + } + } + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; $x++) { + $this->assertEquals($x * $y % 3 === 0, $matrix->get($x, $y)); + } + } + } + + public function testSetRegion() + { + $matrix = new BitMatrix(5); + $matrix->setRegion(1, 1, 3, 3); + + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $this->assertEquals($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y)); + } + } + } + + public function testRectangularMatrix() + { + $matrix = new BitMatrix(75, 20); + $this->assertEquals(75, $matrix->getWidth()); + $this->assertEquals(20, $matrix->getHeight()); + + $matrix->set(10, 0); + $matrix->set(11, 1); + $matrix->set(50, 2); + $matrix->set(51, 3); + $matrix->flip(74, 4); + $matrix->flip(0, 5); + + $this->assertTrue($matrix->get(10, 0)); + $this->assertTrue($matrix->get(11, 1)); + $this->assertTrue($matrix->get(50, 2)); + $this->assertTrue($matrix->get(51, 3)); + $this->assertTrue($matrix->get(74, 4)); + $this->assertTrue($matrix->get(0, 5)); + + $matrix->flip(50, 2); + $matrix->flip(51, 3); + + $this->assertFalse($matrix->get(50, 2)); + $this->assertFalse($matrix->get(51, 3)); + } + + public function testRectangularSetRegion() + { + $matrix = new BitMatrix(320, 240); + $this->assertEquals(320, $matrix->getWidth()); + $this->assertEquals(240, $matrix->getHeight()); + + $matrix->setRegion(105, 22, 80, 12); + + for ($y = 0; $y < 240; $y++) { + for ($x = 0; $x < 320; $x++) { + $this->assertEquals($y >= 22 && $y < 34 && $x >= 105 && $x < 185, $matrix->get($x, $y)); + } + } + } + + public function testGetRow() + { + $matrix = new BitMatrix(102, 5); + + for ($x = 0; $x < 102; $x++) { + if ($x & 3 === 0) { + $matrix->set($x, 2); + } + } + + $array1 = $matrix->getRow(2, null); + $this->assertEquals(102, $array1->getSize()); + + $array2 = new BitArray(60); + $array2 = $matrix->getRow(2, $array2); + $this->assertEquals(102, $array2->getSize()); + + $array3 = new BitArray(200); + $array3 = $matrix->getRow(2, $array3); + $this->assertEquals(200, $array3->getSize()); + + for ($x = 0; $x < 102; $x++) { + $on = ($x & 3 === 0); + + $this->assertEquals($on, $array1->get($x)); + $this->assertEquals($on, $array2->get($x)); + $this->assertEquals($on, $array3->get($x)); + } + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php new file mode 100755 index 00000000..b80ff7df --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php @@ -0,0 +1,30 @@ +assertEquals(1, BitUtils::unsignedRightShift(1, 0)); + $this->assertEquals(1, BitUtils::unsignedRightShift(10, 3)); + $this->assertEquals(536870910, BitUtils::unsignedRightShift(-10, 3)); + } + + public function testNumberOfTrailingZeros() + { + $this->assertEquals(32, BitUtils::numberOfTrailingZeros(0)); + $this->assertEquals(1, BitUtils::numberOfTrailingZeros(10)); + $this->assertEquals(0, BitUtils::numberOfTrailingZeros(15)); + $this->assertEquals(2, BitUtils::numberOfTrailingZeros(20)); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php new file mode 100755 index 00000000..736e995d --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php @@ -0,0 +1,40 @@ +assertEquals(0x0, ErrorCorrectionLevel::M); + $this->assertEquals(0x1, ErrorCorrectionLevel::L); + $this->assertEquals(0x2, ErrorCorrectionLevel::H); + $this->assertEquals(0x3, ErrorCorrectionLevel::Q); + } + + public function testInvalidErrorCorrectionLevelThrowsException() + { + $this->setExpectedException( + 'BaconQrCode\Exception\UnexpectedValueException', + 'Value not a const in enum BaconQrCode\Common\ErrorCorrectionLevel' + ); + new ErrorCorrectionLevel(4); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php new file mode 100755 index 00000000..5f6ee58c --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php @@ -0,0 +1,104 @@ +unmaskedTestFormatInfo = $this->maskedTestFormatInfo ^ 0x5412; + } + + + public function testBitsDiffering() + { + $this->assertEquals(0, FormatInformation::numBitsDiffering(1, 1)); + $this->assertEquals(1, FormatInformation::numBitsDiffering(0, 2)); + $this->assertEquals(2, FormatInformation::numBitsDiffering(1, 2)); + $this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0)); + } + + public function testDecode() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertNotNull($expected); + $this->assertEquals(7, $expected->getDataMask()); + $this->assertEquals(ErrorCorrectionLevel::Q, $expected->getErrorCorrectionLevel()->get()); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->unmaskedTestFormatInfo, + $this->maskedTestFormatInfo + ) + ); + } + + public function testDecodeWithBitDifference() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x1, + $this->maskedTestFormatInfo ^ 0x1 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x3, + $this->maskedTestFormatInfo ^ 0x3 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x7, + $this->maskedTestFormatInfo ^ 0x7 + ) + ); + $this->assertNull( + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0xf, + $this->maskedTestFormatInfo ^ 0xf + ) + ); + } + + public function testDecodeWithMisRead() + { + $expected = FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo, + $this->maskedTestFormatInfo + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + $this->maskedTestFormatInfo ^ 0x3, + $this->maskedTestFormatInfo ^ 0xf + ) + ); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php new file mode 100755 index 00000000..4daab7c3 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php @@ -0,0 +1,42 @@ +assertEquals(0x0, Mode::TERMINATOR); + $this->assertEquals(0x1, Mode::NUMERIC); + $this->assertEquals(0x2, Mode::ALPHANUMERIC); + $this->assertEquals(0x4, Mode::BYTE); + $this->assertEquals(0x8, Mode::KANJI); + } + + public function testInvalidModeThrowsException() + { + $this->setExpectedException( + 'BaconQrCode\Exception\UnexpectedValueException', + 'Value not a const in enum BaconQrCode\Common\Mode' + ); + new Mode(10); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php new file mode 100755 index 00000000..604641a0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php @@ -0,0 +1,111 @@ +encode($block, $parity); + + // Copy parity into test blocks + for ($i = 0; $i < $numRoots; $i++) { + $block[$i + $dataSize] = $parity[$i]; + $tBlock[$i + $dataSize] = $parity[$i]; + } + + // Seed with errors + for ($i = 0; $i < $errors; $i++) { + $errorValue = mt_rand(1, $blockSize); + + do { + $errorLocation = mt_rand(0, $blockSize); + } while ($errorLocations[$errorLocation] !== 0); + + $errorLocations[$errorLocation] = 1; + + if (mt_rand(0, 1)) { + $erasures[] = $errorLocation; + } + + $tBlock[$errorLocation] ^= $errorValue; + } + + $erasures = SplFixedArray::fromArray($erasures, false); + + // Decode the errored block + $foundErrors = $codec->decode($tBlock, $erasures); + + if ($errors > 0 && $foundErrors === null) { + $this->assertEquals($block, $tBlock, 'Decoder failed to correct errors'); + } + + $this->assertEquals($errors, $foundErrors, 'Found errors do not equal expected errors'); + + for ($i = 0; $i < $foundErrors; $i++) { + if ($errorLocations[$erasures[$i]] === 0) { + $this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i])); + } + } + + $this->assertEquals($block, $tBlock, 'Decoder did not correct errors'); + } + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php new file mode 100755 index 00000000..8b3fc01f --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php @@ -0,0 +1,88 @@ +assertNotNull($version); + $this->assertEquals($versionNumber, $version->getVersionNumber()); + $this->assertNotNull($version->getAlignmentPatternCenters()); + + if ($versionNumber > 1) { + $this->assertTrue(count($version->getAlignmentPatternCenters()) > 0); + } + + $this->assertEquals($dimension, $version->getDimensionForVersion()); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::H))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::L))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::M))); + $this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::Q))); + $this->assertNotNull($version->buildFunctionPattern()); + } + + /** + * @dataProvider versionProvider + * @param integer $versionNumber + * @param integer $dimension + */ + public function testGetProvisionalVersionForDimension($versionNumber, $dimension) + { + $this->assertEquals( + $versionNumber, + Version::getProvisionalVersionForDimension($dimension)->getVersionNumber() + ); + } + + /** + * @dataProvider decodeInformationProvider + * @param integer $expectedVersion + * @param integer $mask + */ + public function testDecodeVersionInformation($expectedVersion, $mask) + { + $version = Version::decodeVersionInformation($mask); + $this->assertNotNull($version); + $this->assertEquals($expectedVersion, $version->getVersionNumber()); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php new file mode 100755 index 00000000..31cdaa4e --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php @@ -0,0 +1,468 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testGetAlphanumericCode() + { + // The first ten code points are numbers. + for ($i = 0; $i < 10; $i++) { + $this->assertEquals($i, $this->methods['getAlphanumericCode']->invoke(null, ord('0') + $i)); + } + + // The next 26 code points are capital alphabet letters. + for ($i = 10; $i < 36; $i++) { + // The first ten code points are numbers + $this->assertEquals($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10)); + } + + // Others are symbol letters. + $this->assertEquals(36, $this->methods['getAlphanumericCode']->invoke(null, ' ')); + $this->assertEquals(37, $this->methods['getAlphanumericCode']->invoke(null, '$')); + $this->assertEquals(38, $this->methods['getAlphanumericCode']->invoke(null, '%')); + $this->assertEquals(39, $this->methods['getAlphanumericCode']->invoke(null, '*')); + $this->assertEquals(40, $this->methods['getAlphanumericCode']->invoke(null, '+')); + $this->assertEquals(41, $this->methods['getAlphanumericCode']->invoke(null, '-')); + $this->assertEquals(42, $this->methods['getAlphanumericCode']->invoke(null, '.')); + $this->assertEquals(43, $this->methods['getAlphanumericCode']->invoke(null, '/')); + $this->assertEquals(44, $this->methods['getAlphanumericCode']->invoke(null, ':')); + + // Should return -1 for other letters. + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, 'a')); + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, '#')); + $this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, "\0")); + } + + public function testChooseMode() + { + // Numeric mode + $this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0')->get()); + $this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789')->get()); + + // Alphanumeric mode + $this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, 'A')->get()); + $this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')->get()); + + // 8-bit byte mode + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, 'a')->get()); + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '#')->get()); + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '')->get()); + + // AIUE in Hiragana in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6")->get()); + + // Nihon in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b")->get()); + + // Sou-Utso-Byou in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61")->get()); + } + + public function testEncode() + { + $qrCode = Encoder::encode('ABCDEF', new ErrorCorrectionLevel(ErrorCorrectionLevel::H)); + $expected = "<<\n" + . " mode: ALPHANUMERIC\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 0\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" + . " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" + . " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" + . " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" + . " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" + . " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" + . ">>\n"; + + $this->assertEquals($expected, $qrCode->__toString()); + } + + public function testSimpleUtf8Eci() + { + $qrCode = Encoder::encode('hello', new ErrorCorrectionLevel(ErrorCorrectionLevel::H), 'utf-8'); + $expected = "<<\n" + . " mode: BYTE\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 3\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n" + . " 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n" + . " 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n" + . " 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n" + . " 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n" + . " 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n" + . " 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n" + . ">>\n"; + + $this->assertEquals($expected, $qrCode->__toString()); + } + + public function testAppendModeInfo() + { + $bits = new BitArray(); + $this->methods['appendModeInfo']->invoke(null, new Mode(Mode::NUMERIC), $bits); + $this->assertEquals(' ...X', $bits->__toString()); + } + + public function testAppendLengthInfo() + { + // 1 letter (1/1), 10 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 1, + Version::getVersionForNumber(1), + new Mode(Mode::NUMERIC), + $bits + ); + $this->assertEquals(' ........ .X', $bits->__toString()); + + // 2 letters (2/1), 11 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 2, + Version::getVersionForNumber(10), + new Mode(Mode::ALPHANUMERIC), + $bits + ); + $this->assertEquals(' ........ .X.', $bits->__toString()); + + // 255 letters (255/1), 16 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 255, + Version::getVersionForNumber(27), + new Mode(Mode::BYTE), + $bits + ); + $this->assertEquals(' ........ XXXXXXXX', $bits->__toString()); + + // 512 letters (1024/2), 12 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 512, + Version::getVersionForNumber(40), + new Mode(Mode::KANJI), + $bits + ); + $this->assertEquals(' ..X..... ....', $bits->__toString()); + } + + public function testAppendBytes() + { + // Should use appendNumericBytes. + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + '1', + new Mode(Mode::NUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' ...X', $bits->__toString()); + + // Should use appendAlphaNumericBytes. + // A = 10 = 0xa = 001010 in 6 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'A', + new Mode(Mode::ALPHANUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' ..X.X.', $bits->__toString()); + + // Should use append8BitBytes. + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'abc', + new Mode(Mode::BYTE), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString()); + + // Should use appendKanjiBytes. + // 0x93, 0x5f + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + "\x93\x5f", + new Mode(Mode::KANJI), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString()); + + // Lower letters such as 'a' cannot be encoded in alphanumeric mode. + $this->setExpectedException( + 'BaconQrCode\Exception\WriterException', + 'Invalid alphanumeric code' + ); + $this->methods['appendBytes']->invoke( + null, + "a", + new Mode(Mode::ALPHANUMERIC), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + } + + public function testTerminateBits() + { + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 0, $bits); + $this->assertEquals('', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 3); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 5); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 8); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertEquals(' ........', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 2, $bits); + $this->assertEquals(' ........ XXX.XX..', $bits->__toString()); + + $bits = new BitArray(); + $bits->appendBits(0, 1); + $this->methods['terminateBits']->invoke(null, 3, $bits); + $this->assertEquals(' ........ XXX.XX.. ...X...X', $bits->__toString()); + } + + public function testGetNumDataBytesAndNumEcBytesForBlockId() + { + // Version 1-H. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 26, 9, 1, 0); + $this->assertEquals(9, $numDataBytes); + $this->assertEquals(17, $numEcBytes); + + // Version 3-H. 2 blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 0); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(22, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 1); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(22, $numEcBytes); + + // Version 7-H. (4 + 1) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 0); + $this->assertEquals(13, $numDataBytes); + $this->assertEquals(26, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 4); + $this->assertEquals(14, $numDataBytes); + $this->assertEquals(26, $numEcBytes); + + // Version 40-H. (20 + 61) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 0); + $this->assertEquals(15, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 20); + $this->assertEquals(16, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 80); + $this->assertEquals(16, $numDataBytes); + $this->assertEquals(30, $numEcBytes); + } + + public function testInterleaveWithEcBytes() + { + $dataBytes = SplFixedArray::fromArray(array(32, 65, 205, 69, 41, 220, 46, 128, 236), false); + $in = new BitArray(); + + foreach ($dataBytes as $dataByte) { + $in->appendBits($dataByte, 8); + } + + $outBits = $this->methods['interleaveWithEcBytes']->invoke(null, $in, 26, 9, 1); + $expected = SplFixedArray::fromArray(array( + // Data bytes. + 32, 65, 205, 69, 41, 220, 46, 128, 236, + // Error correction bytes. + 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61, + ), false); + + $out = $outBits->toBytes(0, count($expected)); + + $this->assertEquals($expected, $out); + } + + public function testAppendNumericBytes() + { + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1', $bits); + $this->assertEquals(' ...X', $bits->__toString()); + + // 12 = 0xc = 0001100 in 7 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '12', $bits); + $this->assertEquals(' ...XX..', $bits->__toString()); + + // 123 = 0x7b = 0001111011 in 10 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '123', $bits); + $this->assertEquals(' ...XXXX. XX', $bits->__toString()); + + // 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1234', $bits); + $this->assertEquals(' ...XXXX. XX.X..', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '', $bits); + $this->assertEquals('', $bits->__toString()); + } + + public function testAppendAlphanumericBytes() + { + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits); + $this->assertEquals(' ..X.X.', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits); + $this->assertEquals(' ..XXX..X X.X', $bits->__toString()); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits); + $this->assertEquals(' ..XXX..X X.X..XX. .', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, '', $bits); + $this->assertEquals('', $bits->__toString()); + + // Invalid data + $this->setExpectedException('BaconQrCode\Exception\WriterException', 'Invalid alphanumeric code'); + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits); + } + + public function testAppend8BitBytes() + { + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString()); + + // Empty + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertEquals('', $bits->__toString()); + } + + public function testAppendKanjiBytes() + { + // Numbers are from page 21 of JISX0510:2004 + $bits = new BitArray(); + $this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits); + $this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString()); + + $this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits); + $this->assertEquals(' .XX.XX.. XXXXXXX. X.X.X.X. X.', $bits->__toString()); + } + + public function testGenerateEcBytes() + { + // Numbers are from http://www.swetake.com/qr/qr3.html and + // http://www.swetake.com/qr/qr9.html + $dataBytes = SplFixedArray::fromArray(array(32, 65, 205, 69, 41, 220, 46, 128, 236), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray(array(42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61), false); + $this->assertEquals($expected, $ecBytes); + + $dataBytes = SplFixedArray::fromArray(array(67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 18); + $expected = SplFixedArray::fromArray(array(175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187), false); + $this->assertEquals($expected, $ecBytes); + + // High-order zero coefficient case. + $dataBytes = SplFixedArray::fromArray(array(32, 49, 205, 69, 42, 20, 0, 236, 17), false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray(array(0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213), false); + $this->assertEquals($expected, $ecBytes); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php new file mode 100755 index 00000000..a5c38656 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php @@ -0,0 +1,281 @@ +fail('Data mask bit did not match'); + } + } + } + } + + public function testApplyMaskPenaltyRule1() + { + $matrix = new ByteMatrix(4, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Horizontal + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 0); + $matrix->set(5, 0, 1); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(5, 0, 0); + $this->assertEquals(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Vertical + $matrix = new ByteMatrix(1, 6); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 0); + $matrix->set(0, 5, 1); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(0, 5, 0); + $this->assertEquals(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + } + + public function testApplyMaskPenaltyRule2() + { + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 1); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $this->assertEquals(3, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(1, 2, 0); + $matrix->set(2, 2, 0); + $this->assertEquals(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix)); + } + + public function testApplyMaskPenalty3() + { + // Horizontal 00001011101 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 1); + $matrix->set(8, 0, 1); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 1); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Horizontal 10111010000 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 1); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 0); + $matrix->set(8, 0, 0); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 0); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 00001011101 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 1); + $matrix->set(0, 8, 1); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 1); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 10111010000 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 1); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 1); + $matrix->set(0, 3, 1); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 0); + $matrix->set(0, 8, 0); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 0); + $this->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + } + + public function testApplyMaskPenaltyRule4() + { + // Dark cell ratio = 0% + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertEquals(100, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 5% + $matrix = new ByteMatrix(2, 1); + $matrix->set(0, 0, 0); + $matrix->set(0, 0, 1); + $this->assertEquals(0, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 66.67% + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $this->assertEquals(30, MaskUtil::applyMaskPenaltyRule4($matrix)); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php new file mode 100755 index 00000000..bf3544f0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php @@ -0,0 +1,336 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testToString() + { + $matrix= new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 1); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 1); + $matrix->set(0, 2, -1); + $matrix->set(1, 2, -1); + $matrix->set(2, 2, -1); + + $expected = " 0 1 0\n 1 0 1\n \n"; + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testClearMatrix() + { + $matrix = new ByteMatrix(2, 2); + MatrixUtil::clearMatrix($matrix); + + $this->assertEquals(-1, $matrix->get(0, 0)); + $this->assertEquals(-1, $matrix->get(1, 0)); + $this->assertEquals(-1, $matrix->get(0, 1)); + $this->assertEquals(-1, $matrix->get(1, 1)); + } + + public function testEmbedBasicPatterns1() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 0 0 0 0 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedBasicPatterns2() + { + $matrix = new ByteMatrix(25, 25); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(2), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 1 1 1 1 1 \n" + . " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n" + . " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedTypeInfo() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedTypeInfo']->invoke( + null, + new ErrorCorrectionLevel(ErrorCorrectionLevel::M), + 5, + $matrix + ); + $expected = " 0 \n" + . " 1 \n" + . " 1 \n" + . " 1 \n" + . " 0 \n" + . " 0 \n" + . " \n" + . " 1 \n" + . " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 1 \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedVersionInfo() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['maybeEmbedVersionInfo']->invoke( + null, + Version::getVersionForNumber(7), + $matrix + ); + $expected = " 0 0 1 \n" + . " 0 1 0 \n" + . " 0 1 0 \n" + . " 0 1 1 \n" + . " 1 1 1 \n" + . " 0 0 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 0 0 0 1 0 \n" + . " 0 1 1 1 1 0 \n" + . " 1 0 0 1 1 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testEmbedDataBits() + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + + $bits = new BitArray(); + $this->methods['embedDataBits']->invoke( + null, + $bits, + -1, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testBuildMatrix() + { + $bytes = array( + 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169, + 239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61 + ); + $bits = new BitArray(); + + foreach ($bytes as $byte) { + $bits->appendBits($byte, 8); + } + + $matrix = new ByteMatrix(21, 21); + MatrixUtil::buildMatrix( + $bits, + new ErrorCorrectionLevel(ErrorCorrectionLevel::H), + Version::getVersionForNumber(1), + 3, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" + . " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" + . " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" + . " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" + . " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n"; + + $this->assertEquals($expected, $matrix->__toString()); + } + + public function testFindMsbSet() + { + $this->assertEquals(0, $this->methods['findMsbSet']->invoke(null, 0)); + $this->assertEquals(1, $this->methods['findMsbSet']->invoke(null, 1)); + $this->assertEquals(8, $this->methods['findMsbSet']->invoke(null, 0x80)); + $this->assertEquals(32, $this->methods['findMsbSet']->invoke(null, 0x80000000)); + } + + public function testCalculateBchCode() + { + // Encoding of type information. + // From Appendix C in JISX0510:2004 (p 65) + $this->assertEquals(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537)); + // From http://www.swetake.com/qr/qr6.html + $this->assertEquals(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537)); + // From http://www.swetake.com/qr/qr11.html + $this->assertEquals(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537)); + + // Encoding of version information. + // From Appendix D in JISX0510:2004 (p 68) + $this->assertEquals(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25)); + $this->assertEquals(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25)); + $this->assertEquals(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25)); + $this->assertEquals(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25)); + $this->assertEquals(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25)); + $this->assertEquals(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25)); + $this->assertEquals(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25)); + } + + public function testMakeVersionInfoBits() + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits); + $this->assertEquals(' ...XXXXX ..X..X.X ..', $bits->__toString()); + } + + public function testMakeTypeInfoBits() + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeTypeInfoBits']->invoke(null, new ErrorCorrectionLevel(ErrorCorrectionLevel::M), 5, $bits); + $this->assertEquals(' X......X X..XXX.', $bits->__toString()); + } +} \ No newline at end of file diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php new file mode 100755 index 00000000..0c69dd2e --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php @@ -0,0 +1,99 @@ +renderer = new Html(); + $this->writer = new Writer($this->renderer); + } + + public function testBasicRender() + { + $content = 'foobar'; + $expected = + '
' .
+            "                       \n" .
+            " ███████ █████ ███████ \n" .
+            " █     █  █ █  █     █ \n" .
+            " █ ███ █  ██   █ ███ █ \n" .
+            " █ ███ █  ███  █ ███ █ \n" .
+            " █ ███ █   █ █ █ ███ █ \n" .
+            " █     █    ██ █     █ \n" .
+            " ███████ █ █ █ ███████ \n" .
+            "         █████         \n" .
+            " ██ ██ █  ██ █ █     █ \n" .
+            "    ██    ██ █ █ ██    \n" .
+            "  ████████ █  ██ █  ██ \n" .
+            "           ██      █ █ \n" .
+            "  ██  ███  █   █  █  █ \n" .
+            "         █ ███    █ █  \n" .
+            " ███████  ██ ██████    \n" .
+            " █     █   ████   ██   \n" .
+            " █ ███ █ ██ ██ ██ █ ██ \n" .
+            " █ ███ █ ██ ██  █ ██   \n" .
+            " █ ███ █   █   █ ██ ██ \n" .
+            " █     █ ███  ███ ████ \n" .
+            " ███████ ████   ██     \n" .
+            "                       \n" .
+            '
' + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testSetStyle() + { + $content = 'foobar'; + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setStyle('bar'); + $this->assertEquals('bar', $this->renderer->getStyle()); + $this->assertStringMatchesFormat('%astyle="bar"%a', $this->renderer->render($qrCode)); + } + + public function testSetClass() + { + $content = 'foobar'; + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setClass('bar'); + $this->assertEquals('bar', $this->renderer->getClass()); + $this->assertStringMatchesFormat('%aclass="bar"%a', $this->renderer->render($qrCode)); + } +} diff --git a/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php new file mode 100755 index 00000000..d94e8e5d --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php @@ -0,0 +1,149 @@ +renderer = new Plain(); + $this->writer = new Writer($this->renderer); + } + + public function testBasicRender() + { + $content = 'foobar'; + $expected = + " \n" . + " ███████ █████ ███████ \n" . + " █ █ █ █ █ █ \n" . + " █ ███ █ ██ █ ███ █ \n" . + " █ ███ █ ███ █ ███ █ \n" . + " █ ███ █ █ █ █ ███ █ \n" . + " █ █ ██ █ █ \n" . + " ███████ █ █ █ ███████ \n" . + " █████ \n" . + " ██ ██ █ ██ █ █ █ \n" . + " ██ ██ █ █ ██ \n" . + " ████████ █ ██ █ ██ \n" . + " ██ █ █ \n" . + " ██ ███ █ █ █ █ \n" . + " █ ███ █ █ \n" . + " ███████ ██ ██████ \n" . + " █ █ ████ ██ \n" . + " █ ███ █ ██ ██ ██ █ ██ \n" . + " █ ███ █ ██ ██ █ ██ \n" . + " █ ███ █ █ █ ██ ██ \n" . + " █ █ ███ ███ ████ \n" . + " ███████ ████ ██ \n" . + " \n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testBasicRenderNoMargins() + { + $content = 'foobar'; + $expected = + "███████ █████ ███████\n" . + "█ █ █ █ █ █\n" . + "█ ███ █ ██ █ ███ █\n" . + "█ ███ █ ███ █ ███ █\n" . + "█ ███ █ █ █ █ ███ █\n" . + "█ █ ██ █ █\n" . + "███████ █ █ █ ███████\n" . + " █████ \n" . + "██ ██ █ ██ █ █ █\n" . + " ██ ██ █ █ ██ \n" . + " ████████ █ ██ █ ██\n" . + " ██ █ █\n" . + " ██ ███ █ █ █ █\n" . + " █ ███ █ █ \n" . + "███████ ██ ██████ \n" . + "█ █ ████ ██ \n" . + "█ ███ █ ██ ██ ██ █ ██\n" . + "█ ███ █ ██ ██ █ ██ \n" . + "█ ███ █ █ █ ██ ██\n" . + "█ █ ███ ███ ████\n" . + "███████ ████ ██ \n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setMargin(0); + $this->assertEquals(0, $this->renderer->getMargin()); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } + + public function testBasicRenderCustomChar() + { + $content = 'foobar'; + $expected = + "-----------------------\n" . + "-#######-#####-#######-\n" . + "-#-----#--#-#--#-----#-\n" . + "-#-###-#--##---#-###-#-\n" . + "-#-###-#--###--#-###-#-\n" . + "-#-###-#---#-#-#-###-#-\n" . + "-#-----#----##-#-----#-\n" . + "-#######-#-#-#-#######-\n" . + "---------#####---------\n" . + "-##-##-#--##-#-#-----#-\n" . + "----##----##-#-#-##----\n" . + "--########-#--##-#--##-\n" . + "-----------##------#-#-\n" . + "--##--###--#---#--#--#-\n" . + "---------#-###----#-#--\n" . + "-#######--##-######----\n" . + "-#-----#---####---##---\n" . + "-#-###-#-##-##-##-#-##-\n" . + "-#-###-#-##-##--#-##---\n" . + "-#-###-#---#---#-##-##-\n" . + "-#-----#-###--###-####-\n" . + "-#######-####---##-----\n" . + "-----------------------\n" + ; + + $qrCode = Encoder::encode( + $content, + new ErrorCorrectionLevel(ErrorCorrectionLevel::L), + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->renderer->setFullBlock('#'); + $this->renderer->setEmptyBlock('-'); + $this->assertEquals('#', $this->renderer->getFullBlock()); + $this->assertEquals('-', $this->renderer->getEmptyBlock()); + $this->assertEquals($expected, $this->renderer->render($qrCode)); + } +} diff --git a/vendor/bacon/bacon-qr-code/tests/bootstrap.php b/vendor/bacon/bacon-qr-code/tests/bootstrap.php new file mode 100755 index 00000000..05a49415 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/tests/bootstrap.php @@ -0,0 +1,10 @@ + + + + . + + + + ../src/ + + + diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100755 index 00000000..6d0c3f2d --- /dev/null +++ b/vendor/composer/ClassLoader.php @@ -0,0 +1,481 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000..b3a4e161 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,337 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require it's presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + private static $installed; + private static $canGetVendors; + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100755 index 00000000..f27399a0 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100755 index 00000000..22de020d --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,69 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'QrReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php', + 'Zxing\\Binarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php', + 'Zxing\\BinaryBitmap' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php', + 'Zxing\\ChecksumException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php', + 'Zxing\\Common\\BitArray' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php', + 'Zxing\\Common\\BitMatrix' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php', + 'Zxing\\Common\\BitSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php', + 'Zxing\\Common\\CharacterSetECI' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php', + 'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php', + 'Zxing\\Common\\DecoderResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php', + 'Zxing\\Common\\DefaultGridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php', + 'Zxing\\Common\\DetectorResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php', + 'Zxing\\Common\\Detector\\MathUtils' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php', + 'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php', + 'Zxing\\Common\\GlobalHistogramBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php', + 'Zxing\\Common\\GridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php', + 'Zxing\\Common\\HybridBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php', + 'Zxing\\Common\\PerspectiveTransform' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php', + 'Zxing\\Common\\Reedsolomon\\GenericGF' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php', + 'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php', + 'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php', + 'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php', + 'Zxing\\FormatException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php', + 'Zxing\\GDLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php', + 'Zxing\\IMagickLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php', + 'Zxing\\LuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php', + 'Zxing\\NotFoundException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php', + 'Zxing\\PlanarYUVLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php', + 'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php', + 'Zxing\\Qrcode\\Decoder\\DataBlock' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php', + 'Zxing\\Qrcode\\Decoder\\DataMask' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask000' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask001' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask010' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask011' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask100' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask101' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask110' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask111' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php', + 'Zxing\\Qrcode\\Decoder\\Decoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php', + 'Zxing\\Qrcode\\Decoder\\ECB' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Decoder\\ECBlocks' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php', + 'Zxing\\Qrcode\\Decoder\\FormatInformation' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php', + 'Zxing\\Qrcode\\Decoder\\Mode' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php', + 'Zxing\\Qrcode\\Decoder\\Version' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Detector\\AlignmentPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php', + 'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php', + 'Zxing\\Qrcode\\Detector\\Detector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php', + 'Zxing\\Qrcode\\Detector\\FinderPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php', + 'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php', + 'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php', + 'Zxing\\Qrcode\\QRCodeReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php', + 'Zxing\\RGBLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php', + 'Zxing\\Reader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php', + 'Zxing\\ReaderException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php', + 'Zxing\\Result' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Result.php', + 'Zxing\\ResultPoint' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100755 index 00000000..95a15f57 --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,12 @@ + $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '626dcc41390ebdaa619faa02d99943b0' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php', + '3a37ebac017bc098e9a86b35401e7a68' => $vendorDir . '/mongodb/mongodb/src/functions.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100755 index 00000000..30bced12 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,11 @@ + array($vendorDir . '/mikey179/vfsStream/src/main/php'), + 'BaconQrCode' => array($vendorDir . '/bacon/bacon-qr-code/src'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100755 index 00000000..7403e235 --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,16 @@ + array($vendorDir . '/symfony/polyfill-ctype'), + 'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'), + 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'), + 'Picqer\\Barcode\\' => array($vendorDir . '/picqer/php-barcode-generator/src'), + 'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'), + 'MongoDB\\' => array($vendorDir . '/mongodb/mongodb/src'), + 'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qrcode/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100755 index 00000000..e5aa564c --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,75 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire801fbe69b9c17eeb5f87ba0125931956($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire801fbe69b9c17eeb5f87ba0125931956($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 00000000..d404536f --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,158 @@ + __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '626dcc41390ebdaa619faa02d99943b0' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php', + '3a37ebac017bc098e9a86b35401e7a68' => __DIR__ . '/..' . '/mongodb/mongodb/src/functions.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'S' => + array ( + 'Symfony\\Polyfill\\Ctype\\' => 23, + 'Symfony\\Component\\PropertyAccess\\' => 33, + 'Symfony\\Component\\OptionsResolver\\' => 34, + ), + 'P' => + array ( + 'Picqer\\Barcode\\' => 15, + ), + 'M' => + array ( + 'MyCLabs\\Enum\\' => 13, + 'MongoDB\\' => 8, + ), + 'E' => + array ( + 'Endroid\\QrCode\\' => 15, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Symfony\\Component\\PropertyAccess\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/property-access', + ), + 'Symfony\\Component\\OptionsResolver\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/options-resolver', + ), + 'Picqer\\Barcode\\' => + array ( + 0 => __DIR__ . '/..' . '/picqer/php-barcode-generator/src', + ), + 'MyCLabs\\Enum\\' => + array ( + 0 => __DIR__ . '/..' . '/myclabs/php-enum/src', + ), + 'MongoDB\\' => + array ( + 0 => __DIR__ . '/..' . '/mongodb/mongodb/src', + ), + 'Endroid\\QrCode\\' => + array ( + 0 => __DIR__ . '/..' . '/endroid/qrcode/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'o' => + array ( + 'org\\bovigo\\vfs' => + array ( + 0 => __DIR__ . '/..' . '/mikey179/vfsStream/src/main/php', + ), + ), + 'B' => + array ( + 'BaconQrCode' => + array ( + 0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src', + ), + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'QrReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php', + 'Zxing\\Binarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php', + 'Zxing\\BinaryBitmap' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php', + 'Zxing\\ChecksumException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php', + 'Zxing\\Common\\BitArray' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php', + 'Zxing\\Common\\BitMatrix' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php', + 'Zxing\\Common\\BitSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php', + 'Zxing\\Common\\CharacterSetECI' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php', + 'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php', + 'Zxing\\Common\\DecoderResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php', + 'Zxing\\Common\\DefaultGridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php', + 'Zxing\\Common\\DetectorResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php', + 'Zxing\\Common\\Detector\\MathUtils' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php', + 'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php', + 'Zxing\\Common\\GlobalHistogramBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php', + 'Zxing\\Common\\GridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php', + 'Zxing\\Common\\HybridBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php', + 'Zxing\\Common\\PerspectiveTransform' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php', + 'Zxing\\Common\\Reedsolomon\\GenericGF' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php', + 'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php', + 'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php', + 'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php', + 'Zxing\\FormatException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php', + 'Zxing\\GDLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php', + 'Zxing\\IMagickLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php', + 'Zxing\\LuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php', + 'Zxing\\NotFoundException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php', + 'Zxing\\PlanarYUVLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php', + 'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php', + 'Zxing\\Qrcode\\Decoder\\DataBlock' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php', + 'Zxing\\Qrcode\\Decoder\\DataMask' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask000' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask001' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask010' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask011' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask100' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask101' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask110' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DataMask111' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php', + 'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php', + 'Zxing\\Qrcode\\Decoder\\Decoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php', + 'Zxing\\Qrcode\\Decoder\\ECB' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Decoder\\ECBlocks' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php', + 'Zxing\\Qrcode\\Decoder\\FormatInformation' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php', + 'Zxing\\Qrcode\\Decoder\\Mode' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php', + 'Zxing\\Qrcode\\Decoder\\Version' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php', + 'Zxing\\Qrcode\\Detector\\AlignmentPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php', + 'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php', + 'Zxing\\Qrcode\\Detector\\Detector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php', + 'Zxing\\Qrcode\\Detector\\FinderPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php', + 'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php', + 'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php', + 'Zxing\\Qrcode\\QRCodeReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php', + 'Zxing\\RGBLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php', + 'Zxing\\Reader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php', + 'Zxing\\ReaderException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php', + 'Zxing\\Result' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Result.php', + 'Zxing\\ResultPoint' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixesPsr0; + $loader->classMap = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100755 index 00000000..aeaece3d --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,585 @@ +{ + "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee", + "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "suggest": { + "ext-gd": "to generate QR code images" + }, + "time": "2017-10-17T09:59:25+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "BaconQrCode": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "http://www.dasprids.de", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "install-path": "../bacon/bacon-qr-code" + }, + { + "name": "endroid/qrcode", + "version": "2.5.1", + "version_normalized": "2.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "6062677d3404e0ded40647b8f62ec55ff9722eb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/6062677d3404e0ded40647b8f62ec55ff9722eb7", + "reference": "6062677d3404e0ded40647b8f62ec55ff9722eb7", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^1.0.3", + "ext-gd": "*", + "khanamiryan/qrcode-detector-decoder": "1", + "myclabs/php-enum": "^1.5", + "php": ">=5.6", + "symfony/options-resolver": "^2.7", + "symfony/property-access": "^2.7" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "symfony/asset": "^2.7", + "symfony/browser-kit": "^2.7", + "symfony/finder": "^2.7", + "symfony/framework-bundle": "^2.7", + "symfony/http-kernel": "^2.7", + "symfony/templating": "^2.7", + "symfony/twig-bundle": "^2.7", + "symfony/yaml": "^2.7" + }, + "time": "2018-05-09T20:26:30+00:00", + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl", + "homepage": "http://endroid.nl/" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/QrCode", + "keywords": [ + "bundle", + "code", + "endroid", + "flex", + "qr", + "qrcode", + "symfony" + ], + "abandoned": "endroid/qr-code", + "install-path": "../endroid/qrcode" + }, + { + "name": "khanamiryan/qrcode-detector-decoder", + "version": "1", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git", + "reference": "96d5f80680b04803c4f1b69d6e01735e876b80c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/96d5f80680b04803c4f1b69d6e01735e876b80c7", + "reference": "96d5f80680b04803c4f1b69d6e01735e876b80c7", + "shasum": "" + }, + "require": { + "php": "^5.6|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "time": "2017-01-13T09:11:46+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "lib/" + ], + "files": [ + "lib/common/customFunctions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ashot Khanamiryan", + "email": "a.khanamiryan@gmail.com", + "homepage": "https://github.com/khanamiryan", + "role": "Developer" + } + ], + "description": "QR code decoder / reader", + "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder", + "keywords": [ + "barcode", + "qr", + "zxing" + ], + "install-path": "../khanamiryan/qrcode-detector-decoder" + }, + { + "name": "mikey179/vfsStream", + "version": "v1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/bovigo/vfsStream.git", + "reference": "fc0fe8f4d0b527254a2dc45f0c265567c881d07e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/fc0fe8f4d0b527254a2dc45f0c265567c881d07e", + "reference": "fc0fe8f4d0b527254a2dc45f0c265567c881d07e", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2012-08-25T12:49:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "org\\bovigo\\vfs": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "homepage": "http://vfs.bovigo.org/", + "install-path": "../mikey179/vfsStream" + }, + { + "name": "mongodb/mongodb", + "version": "1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "5cffeb33b893b6bb04195b99ddc3955a29252339" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/5cffeb33b893b6bb04195b99ddc3955a29252339", + "reference": "5cffeb33b893b6bb04195b99ddc3955a29252339", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.3.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "time": "2017-10-27T19:42:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MongoDB\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + }, + { + "name": "Hannes Magnusson", + "email": "bjori@mongodb.com" + }, + { + "name": "Derick Rethans", + "email": "github@derickrethans.nl" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "support": { + "issues": "https://github.com/mongodb/mongo-php-library/issues", + "source": "https://github.com/mongodb/mongo-php-library/tree/master" + }, + "install-path": "../mongodb/mongodb" + }, + { + "name": "myclabs/php-enum", + "version": "1.6.6", + "version_normalized": "1.6.6.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "32c4202886c51fbe5cc3a7c34ec5c9a4a790345e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/32c4202886c51fbe5cc3a7c34ec5c9a4a790345e", + "reference": "32c4202886c51fbe5cc3a7c34ec5c9a4a790345e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.7|^6.0", + "squizlabs/php_codesniffer": "1.*" + }, + "time": "2019-02-04T21:18:49+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "install-path": "../myclabs/php-enum" + }, + { + "name": "picqer/php-barcode-generator", + "version": "v0.3", + "version_normalized": "0.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/picqer/php-barcode-generator.git", + "reference": "2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/picqer/php-barcode-generator/zipball/2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c", + "reference": "2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.3" + }, + "time": "2019-01-12T09:29:34+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Picqer\\Barcode\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPLv3" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + }, + { + "name": "Casper Bakker", + "email": "info@picqer.com" + } + ], + "description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", + "homepage": "http://github.com/picqer/php-barcode-generator", + "keywords": [ + "CODABAR", + "Code11", + "Code93", + "EAN13", + "KIX", + "KIXCODE", + "MSI", + "POSTNET", + "Pharma", + "Standard 2 of 5", + "barcode", + "barcode generator", + "code128", + "code39", + "ean", + "html", + "jpeg", + "jpg", + "php", + "png", + "svg", + "upc" + ], + "install-path": "../picqer/php-barcode-generator" + }, + { + "name": "symfony/options-resolver", + "version": "v2.8.49", + "version_normalized": "2.8.49.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "7aaab725bb58f0e18aa12c61bdadd4793ab4c32b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7aaab725bb58f0e18aa12c61bdadd4793ab4c32b", + "reference": "7aaab725bb58f0e18aa12c61bdadd4793ab4c32b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "time": "2018-11-11T11:18:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony OptionsResolver Component", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "install-path": "../symfony/options-resolver" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "82ebae02209c21113908c229e9883c419720738a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", + "reference": "82ebae02209c21113908c229e9883c419720738a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2019-02-06T07:57:58+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "backendtea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/property-access", + "version": "v2.8.49", + "version_normalized": "2.8.49.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "c8f10191183be9bb0d5a1b8364d3891f1bde07b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/c8f10191183be9bb0d5a1b8364d3891f1bde07b6", + "reference": "c8f10191183be9bb0d5a1b8364d3891f1bde07b6", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-ctype": "~1.8" + }, + "time": "2018-11-11T11:18:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony PropertyAccess Component", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "install-path": "../symfony/property-access" + } + ], + "dev": true, + "dev-package-names": [ + "mikey179/vfsstream" + ] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 00000000..adc4d945 --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,113 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => 'codeigniter/framework', + 'dev' => true, + ), + 'versions' => array( + 'bacon/bacon-qr-code' => array( + 'pretty_version' => '1.0.3', + 'version' => '1.0.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../bacon/bacon-qr-code', + 'aliases' => array(), + 'reference' => '5a91b62b9d37cee635bbf8d553f4546057250bee', + 'dev_requirement' => false, + ), + 'codeigniter/framework' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'endroid/qrcode' => array( + 'pretty_version' => '2.5.1', + 'version' => '2.5.1.0', + 'type' => 'symfony-bundle', + 'install_path' => __DIR__ . '/../endroid/qrcode', + 'aliases' => array(), + 'reference' => '6062677d3404e0ded40647b8f62ec55ff9722eb7', + 'dev_requirement' => false, + ), + 'khanamiryan/qrcode-detector-decoder' => array( + 'pretty_version' => '1', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../khanamiryan/qrcode-detector-decoder', + 'aliases' => array(), + 'reference' => '96d5f80680b04803c4f1b69d6e01735e876b80c7', + 'dev_requirement' => false, + ), + 'mikey179/vfsstream' => array( + 'pretty_version' => 'v1.1.0', + 'version' => '1.1.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mikey179/vfsStream', + 'aliases' => array(), + 'reference' => 'fc0fe8f4d0b527254a2dc45f0c265567c881d07e', + 'dev_requirement' => true, + ), + 'mongodb/mongodb' => array( + 'pretty_version' => '1.2.0', + 'version' => '1.2.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mongodb/mongodb', + 'aliases' => array(), + 'reference' => '5cffeb33b893b6bb04195b99ddc3955a29252339', + 'dev_requirement' => false, + ), + 'myclabs/php-enum' => array( + 'pretty_version' => '1.6.6', + 'version' => '1.6.6.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../myclabs/php-enum', + 'aliases' => array(), + 'reference' => '32c4202886c51fbe5cc3a7c34ec5c9a4a790345e', + 'dev_requirement' => false, + ), + 'picqer/php-barcode-generator' => array( + 'pretty_version' => 'v0.3', + 'version' => '0.3.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../picqer/php-barcode-generator', + 'aliases' => array(), + 'reference' => '2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c', + 'dev_requirement' => false, + ), + 'symfony/options-resolver' => array( + 'pretty_version' => 'v2.8.49', + 'version' => '2.8.49.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/options-resolver', + 'aliases' => array(), + 'reference' => '7aaab725bb58f0e18aa12c61bdadd4793ab4c32b', + 'dev_requirement' => false, + ), + 'symfony/polyfill-ctype' => array( + 'pretty_version' => 'v1.11.0', + 'version' => '1.11.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', + 'aliases' => array(), + 'reference' => '82ebae02209c21113908c229e9883c419720738a', + 'dev_requirement' => false, + ), + 'symfony/property-access' => array( + 'pretty_version' => 'v2.8.49', + 'version' => '2.8.49.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/property-access', + 'aliases' => array(), + 'reference' => 'c8f10191183be9bb0d5a1b8364d3891f1bde07b6', + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 00000000..8b379f44 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50600)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/.gitignore b/vendor/khanamiryan/qrcode-detector-decoder/.gitignore new file mode 100755 index 00000000..ff72e2d0 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/.gitignore @@ -0,0 +1,2 @@ +/composer.lock +/vendor diff --git a/vendor/khanamiryan/qrcode-detector-decoder/README.md b/vendor/khanamiryan/qrcode-detector-decoder/README.md new file mode 100755 index 00000000..f4eda03d --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/README.md @@ -0,0 +1,37 @@ +# QR code decoder / reader for PHP +This is a PHP library to detect and decode QR-codes.
This is first and only QR code reader that works without extensions.
+Ported from [ZXing library](https://github.com/zxing/zxing) + + +## Installation +The recommended method of installing this library is via [Composer](https://getcomposer.org/). + +Run the following command from your project root: + +```bash +$ composer require khanamiryan/qrcode-detector-decoder +``` + + +## Usage +```php +require __DIR__ . "/vendor/autoload.php"; +$qrcode = new QrReader('path/to_image'); +$text = $qrcode->text(); //return decoded text from QR Code +``` + +## Requirements +* PHP >= 5.6 +* GD Library + + +## Contributing + +You can help the project by adding features, cleaning the code, adding composer and other. + + +1. Fork it +2. Create your feature branch: `git checkout -b my-new-feature` +3. Commit your changes: `git commit -am 'Add some feature'` +4. Push to the branch: `git push origin my-new-feature` +5. Submit a pull request diff --git a/vendor/khanamiryan/qrcode-detector-decoder/composer.json b/vendor/khanamiryan/qrcode-detector-decoder/composer.json new file mode 100755 index 00000000..53267b89 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/composer.json @@ -0,0 +1,24 @@ +{ + "name": "khanamiryan/qrcode-detector-decoder", + "type": "library", + "description": "QR code decoder / reader", + "keywords": ["qr", "zxing", "barcode"], + "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder", + "license": "MIT", + "authors": [{ + "name": "Ashot Khanamiryan", + "email": "a.khanamiryan@gmail.com", + "homepage": "https://github.com/khanamiryan", + "role": "Developer" + }], + "require": { + "php": "^5.6|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "autoload": { + "classmap": ["lib/"], + "files": ["lib/common/customFunctions.php"] + } +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php new file mode 100755 index 00000000..462113be --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php @@ -0,0 +1,89 @@ +source = $source; + } + + public final function getLuminanceSource() { + return $this->source; + } + + /** + * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + * cached data. Callers should assume this method is expensive and call it as seldom as possible. + * This method is intended for decoding 1D barcodes and may choose to apply sharpening. + * For callers which only examine one row of pixels at a time, the same BitArray should be reused + * and passed in with each call for performance. However it is legal to keep more than one row + * at a time if needed. + * + * @param y The row to fetch, which must be in [0, bitmap height) + * @param row An optional preallocated array. If null or too small, it will be ignored. + * If used, the Binarizer will call BitArray.clear(). Always use the returned object. + * @return The array of bits for this row (true means black). + * @throws NotFoundException if row can't be binarized + */ + public abstract function getBlackRow($y, $row); + + /** + * Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive + * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or + * may not apply sharpening. Therefore, a row from this matrix may not be identical to one + * fetched using getBlackRow(), so don't mix and match between them. + * + * @return The 2D array of bits for the image (true means black). + * @throws NotFoundException if image can't be binarized to make a matrix + */ + public abstract function getBlackMatrix(); + + /** + * Creates a new object with the same type as this Binarizer implementation, but with pristine + * state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache + * of 1 bit data. See Effective Java for why we can't use Java's clone() method. + * + * @param source The LuminanceSource this Binarizer will operate on. + * @return A new concrete Binarizer implementation object. + */ + public abstract function createBinarizer($source); + + public final function getWidth() { + return $this->source->getWidth(); + } + + public final function getHeight() { + return $this->source->getHeight(); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php new file mode 100755 index 00000000..5b19b431 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php @@ -0,0 +1,152 @@ +binarizer = $binarizer; + } + + /** + * @return The width of the bitmap. + */ + public function getWidth() { + return $this->binarizer->getWidth(); + } + + /** + * @return The height of the bitmap. + */ + public function getHeight() { + return $this->binarizer->getHeight(); + } + + /** + * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + * cached data. Callers should assume this method is expensive and call it as seldom as possible. + * This method is intended for decoding 1D barcodes and may choose to apply sharpening. + * + * @param y The row to fetch, which must be in [0, bitmap height) + * @param row An optional preallocated array. If null or too small, it will be ignored. + * If used, the Binarizer will call BitArray.clear(). Always use the returned object. + * @return The array of bits for this row (true means black). + * @throws NotFoundException if row can't be binarized + */ + public function getBlackRow($y, $row) { + return $this->binarizer->getBlackRow($y, $row); + } + + /** + * Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive + * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or + * may not apply sharpening. Therefore, a row from this matrix may not be identical to one + * fetched using getBlackRow(), so don't mix and match between them. + * + * @return The 2D array of bits for the image (true means black). + * @throws NotFoundException if image can't be binarized to make a matrix + */ + public function getBlackMatrix(){ +// The matrix is created on demand the first time it is requested, then cached. There are two +// reasons for this: +// 1. This work will never be done if the caller only installs 1D Reader objects, or if a +// 1D Reader finds a barcode before the 2D Readers run. +// 2. This work will only be done once even if the caller installs multiple 2D Readers. + if ($this->matrix == null) { + $this->matrix = $this->binarizer->getBlackMatrix(); + } + return $this->matrix; + } + + /** + * @return Whether this bitmap can be cropped. + */ + public function isCropSupported() { + return $this->binarizer->getLuminanceSource()->isCropSupported(); + } + + /** + * Returns a new object with cropped image data. Implementations may keep a reference to the + * original data rather than a copy. Only callable if isCropSupported() is true. + * + * @param left The left coordinate, which must be in [0,getWidth()) + * @param top The top coordinate, which must be in [0,getHeight()) + * @param width The width of the rectangle to crop. + * @param height The height of the rectangle to crop. + * @return A cropped version of this object. + */ + public function crop($left, $top, $width, $height) { + $newSource = $this->binarizer->getLuminanceSource()->crop($left, $top, $width, $height); + return new BinaryBitmap($this->binarizer->createBinarizer($newSource)); + } + + /** + * @return Whether this bitmap supports counter-clockwise rotation. + */ + public function isRotateSupported() { + return $this->binarizer->getLuminanceSource()->isRotateSupported(); + } + + /** + * Returns a new object with rotated image data by 90 degrees counterclockwise. + * Only callable if {@link #isRotateSupported()} is true. + * + * @return A rotated version of this object. + */ + public function rotateCounterClockwise() { + $newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise(); + return new BinaryBitmap($this->binarizer->createBinarizer($newSource)); + } + + /** + * Returns a new object with rotated image data by 45 degrees counterclockwise. + * Only callable if {@link #isRotateSupported()} is true. + * + * @return A rotated version of this object. + */ + public function rotateCounterClockwise45() { + $newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise45(); + return new BinaryBitmap($this->binarizer->createBinarizer($newSource)); + } + +//@Override + public function toString() { + try { + return $this->getBlackMatrix()->toString(); + } catch (NotFoundException $e) { + return ""; + } + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php new file mode 100755 index 00000000..72446e1a --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php @@ -0,0 +1,44 @@ +GDLuminanceSource($gdImage,$dataWidth,$dataHeight); + return; + } + parent::__construct($width, $height); + if ($left + $width > $dataWidth || $top + $height > $dataHeight) { + throw new \InvalidArgumentException("Crop rectangle does not fit within image data."); + } + $this->luminances = $gdImage; + $this->dataWidth = $dataWidth; + $this->dataHeight = $dataHeight; + $this->left = $left; + $this->top = $top; + } + + public function GDLuminanceSource($gdImage, $width, $height) + { + parent::__construct($width, $height); + + $this->dataWidth = $width; + $this->dataHeight = $height; + $this->left = 0; + $this->top = 0; + $this->$gdImage = $gdImage; + + +// In order to measure pure decoding speed, we convert the entire image to a greyscale array +// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + $this->luminances = array(); + //$this->luminances = $this->grayScaleToBitmap($this->grayscale()); + + $array = array(); + $rgb = array(); + +for($j=0;$j<$height;$j++){ + for($i=0;$i<$width;$i++){ + $argb = imagecolorat($this->$gdImage, $i, $j); + $pixel = imagecolorsforindex($this->$gdImage, $argb); + $r = $pixel['red']; + $g = $pixel['green']; + $b = $pixel['blue']; + if ($r == $g && $g == $b) { +// Image is already greyscale, so pick any channel. + + $this->luminances[] = $r;//(($r + 128) % 256) - 128; + } else { +// Calculate luminance cheaply, favoring green. + $this->luminances[] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128; + } + } +} + + + + /* + + for ($y = 0; $y < $height; $y++) { + $offset = $y * $width; + for ($x = 0; $x < $width; $x++) { + $pixel = $pixels[$offset + $x]; + $r = ($pixel >> 16) & 0xff; + $g = ($pixel >> 8) & 0xff; + $b = $pixel & 0xff; + if ($r == $g && $g == $b) { +// Image is already greyscale, so pick any channel. + + $this->luminances[intval($offset + $x)] = (($r+128) % 256) - 128; + } else { +// Calculate luminance cheaply, favoring green. + $this->luminances[intval($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128; + } + + + + } + */ + //} + // $this->luminances = $this->grayScaleToBitmap($this->luminances); + + } + +//@Override + public function getRow($y, $row=null) { + if ($y < 0 || $y >= $this->getHeight()) { + throw new \InvalidArgumentException("Requested row is outside the image: " + y); + } + $width = $this->getWidth(); + if ($row == null || count($row) < $width) { + $row = array(); + } + $offset = ($y + $this->top) * $this->dataWidth + $this->left; + $row = arraycopy($this->luminances,$offset, $row, 0, $width); + return $row; + } + +//@Override + public function getMatrix() { + $width = $this->getWidth(); + $height = $this->getHeight(); + +// If the caller asks for the entire underlying image, save the copy and give them the +// original data. The docs specifically warn that result.length must be ignored. + if ($width == $this->dataWidth && $height == $this->dataHeight) { + return $this->luminances; + } + + $area = $width * $height; + $matrix = array(); + $inputOffset = $this->top * $this->dataWidth + $this->left; + +// If the width matches the full width of the underlying data, perform a single copy. + if ($width == $this->dataWidth) { + $matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area); + return $matrix; + } + +// Otherwise copy one cropped row at a time. + $rgb = $this->luminances; + for ($y = 0; $y < $height; $y++) { + $outputOffset = $y * $width; + $matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width); + $inputOffset += $this->dataWidth; + } + return $matrix; + } + +//@Override + public function isCropSupported() { + return true; + } + +//@Override + public function crop($left, $top, $width, $height) { + return new GDLuminanceSource($this->luminances, + $this->dataWidth, + $this->dataHeight, + $this->left + $left, + $this->top + $top, + $width, + $height); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php new file mode 100755 index 00000000..3f0a26ea --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php @@ -0,0 +1,149 @@ +_IMagickLuminanceSource($image,$dataWidth,$dataHeight); + return; + } + parent::__construct($width, $height); + if ($left + $width > $dataWidth || $top + $height > $dataHeight) { + throw new \InvalidArgumentException("Crop rectangle does not fit within image data."); + } + $this->luminances = $image; + $this->dataWidth = $dataWidth; + $this->dataHeight = $dataHeight; + $this->left = $left; + $this->top = $top; + } + + public function _IMagickLuminanceSource($image, $width, $height) + { + parent::__construct($width, $height); + + $this->dataWidth = $width; + $this->dataHeight = $height; + $this->left = 0; + $this->top = 0; + $this->image = $image; + + +// In order to measure pure decoding speed, we convert the entire image to a greyscale array +// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + $this->luminances = array(); + + $image->setImageColorspace (\Imagick::COLORSPACE_GRAY); + // $image->newPseudoImage(0, 0, "magick:rose"); + $pixels = $image->exportImagePixels(1, 1, $width, $height, "RGB", \Imagick::COLORSPACE_RGB); + + $array = array(); + $rgb = array(); + + + for($i=0;$iluminances[] = $r;//(($r + 128) % 256) - 128; + } else { +// Calculate luminance cheaply, favoring green. + $this->luminances[] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128; + } + } + + + + } + +//@Override + public function getRow($y, $row=null) { + if ($y < 0 || $y >= $this->getHeight()) { + throw new \InvalidArgumentException("Requested row is outside the image: " + y); + } + $width = $this->getWidth(); + if ($row == null || count($row) < $width) { + $row = array(); + } + $offset = ($y + $this->top) * $this->dataWidth + $this->left; + $row = arraycopy($this->luminances,$offset, $row, 0, $width); + return $row; + } + +//@Override + public function getMatrix() { + $width = $this->getWidth(); + $height = $this->getHeight(); + +// If the caller asks for the entire underlying image, save the copy and give them the +// original data. The docs specifically warn that result.length must be ignored. + if ($width == $this->dataWidth && $height == $this->dataHeight) { + return $this->luminances; + } + + $area = $width * $height; + $matrix = array(); + $inputOffset = $this->top * $this->dataWidth + $this->left; + +// If the width matches the full width of the underlying data, perform a single copy. + if ($width == $this->dataWidth) { + $matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area); + return $matrix; + } + +// Otherwise copy one cropped row at a time. + $rgb = $this->luminances; + for ($y = 0; $y < $height; $y++) { + $outputOffset = $y * $width; + $matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width); + $inputOffset += $this->dataWidth; + } + return $matrix; + } + +//@Override + public function isCropSupported() { + return true; + } + +//@Override + public function crop($left, $top, $width, $height) { + return new GDLuminanceSource($this->luminances, + $this->dataWidth, + $this->dataHeight, + $this->left + $left, + $this->top + $top, + $width, + $height); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php new file mode 100755 index 00000000..ebe99c79 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php @@ -0,0 +1,159 @@ +width = $width; + $this->height = $height; + } + + /** + * Fetches one row of luminance data from the underlying platform's bitmap. Values range from + * 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have + * to bitwise and with 0xff for each value. It is preferable for implementations of this method + * to only fetch this row rather than the whole image, since no 2D Readers may be installed and + * getMatrix() may never be called. + * + * @param $y; The row to fetch, which must be in [0,getHeight()) + * @param $row; An optional preallocated array. If null or too small, it will be ignored. + * Always use the returned object, and ignore the .length of the array. + * @return array + * An array containing the luminance data. + */ + public abstract function getRow($y, $row); + + /** + * Fetches luminance data for the underlying bitmap. Values should be fetched using: + * {@code int luminance = array[y * width + x] & 0xff} + * + * @return A row-major 2D array of luminance values. Do not use result.length as it may be + * larger than width * height bytes on some platforms. Do not modify the contents + * of the result. + */ + public abstract function getMatrix(); + + /** + * @return The width of the bitmap. + */ + public final function getWidth() { + return $this->width; + } + + /** + * @return The height of the bitmap. + */ + public final function getHeight() { + return $this->height; + } + + /** + * @return Whether this subclass supports cropping. + */ + public function isCropSupported() { + return false; + } + + /** + * Returns a new object with cropped image data. Implementations may keep a reference to the + * original data rather than a copy. Only callable if isCropSupported() is true. + * + * @param left The left coordinate, which must be in [0,getWidth()) + * @param top The top coordinate, which must be in [0,getHeight()) + * @param width The width of the rectangle to crop. + * @param height The height of the rectangle to crop. + * @return A cropped version of this object. + */ + public function crop($left, $top, $width, $height) { + throw new \Exception("This luminance source does not support cropping."); + } + + /** + * @return Whether this subclass supports counter-clockwise rotation. + */ + public function isRotateSupported() { + return false; + } + + /** + * @return a wrapper of this {@code LuminanceSource} which inverts the luminances it returns -- black becomes + * white and vice versa, and each value becomes (255-value). + */ + public function invert() { + return new InvertedLuminanceSource($this); + } + + /** + * Returns a new object with rotated image data by 90 degrees counterclockwise. + * Only callable if {@link #isRotateSupported()} is true. + * + * @return A rotated version of this object. + */ + public function rotateCounterClockwise() { + throw new \Exception("This luminance source does not support rotation by 90 degrees."); + } + + /** + * Returns a new object with rotated image data by 45 degrees counterclockwise. + * Only callable if {@link #isRotateSupported()} is true. + * + * @return A rotated version of this object. + */ + public function rotateCounterClockwise45() { + throw new \Exception("This luminance source does not support rotation by 45 degrees."); + } + +//@Override + public final function toString() { + $row = array(); + $result = ''; + for ($y = 0;$y < $this->height; $y++) { + $row = $this->getRow($y, $row); + for ($x = 0; $x < $this->width; $x++) { + $luminance = $row[$x] & 0xFF; + $c=''; + if ($luminance < 0x40) { + $c = '#'; + } else if ($luminance < 0x80) { + $c = '+'; + } else if ($luminance < 0xC0) { + $c = '.'; + } else { + $c = ' '; + } + $result.=($c); + } + $result.=('\n'); + } + return $result; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php new file mode 100755 index 00000000..572b4dc7 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php @@ -0,0 +1,38 @@ + $dataWidth || $top + $height > $dataHeight) { +throw new IllegalArgumentException("Crop rectangle does not fit within image data."); +} + + $this->yuvData = $yuvData; + $this->dataWidth = $dataWidth; + $this->dataHeight = $dataHeight; + $this->left = $left; + $this->top = $top; + if ($reverseHorizontal) { + $this->reverseHorizontal($width, $height); + } + } + + //@Override + public function getRow($y, $row=null) { + if ($y < 0 || $y >= getHeight()) { + throw new IllegalArgumentException("Requested row is outside the image: " + y); + } + $width = $this->getWidth(); + if ($row == null || count($row) < $width) { + $row = array();//new byte[width]; + } + $offset = ($y + $this->top) * $this->dataWidth + $this->left; + $row = arraycopy($this->yuvData, $offset, $row, 0, $width); + return $row; + } + + //@Override + public function getMatrix() { + $width = $this->getWidth(); + $height = $this->getHeight(); + + // If the caller asks for the entire underlying image, save the copy and give them the + // original data. The docs specifically warn that result.length must be ignored. + if ($width == $this->dataWidth && $height == $this->dataHeight) { + return $this->yuvData; + } + + $area = $width * $height; + $matrix = array();//new byte[area]; + $inputOffset = $this->top * $this->dataWidth + $this->left; + + // If the width matches the full width of the underlying data, perform a single copy. + if ($width == $this->dataWidth) { + $matrix = arraycopy($this->yuvData, $inputOffset, $matrix, 0, $area); + return $matrix; + } + + // Otherwise copy one cropped row at a time. + $yuv = $this->yuvData; + for ($y = 0; $y < $height; $y++) { + $outputOffset = $y * $width; + $matrix = arraycopy($this->yuvData, $inputOffset, $matrix, $outputOffset, $width); + $inputOffset += $this->dataWidth; + } + return $matrix; + } + + // @Override + public function isCropSupported() { + return true; + } + + // @Override + public function crop($left, $top, $width, $height) { + return new PlanarYUVLuminanceSource($this->yuvData, + $this->dataWidth, + $this->dataHeight, + $this->left + $left, + $this->top + $top, + $width, + $height, + false); +} + + public function renderThumbnail() { +$width = intval($this->getWidth() / self::$THUMBNAIL_SCALE_FACTOR); + $height = intval($this->getHeight() / self::$THUMBNAIL_SCALE_FACTOR); + $pixels = array();//new int[width * height]; + $yuv = $this->yuvData; + $inputOffset = $this->top * $this->dataWidth + $this->left; + + for ($y = 0; $y < $height; $y++) { + $outputOffset = $y * $width; + for ($x = 0; $x < $width; $x++) { + $grey = intval32bits($yuv[$inputOffset + $x * self::$THUMBNAIL_SCALE_FACTOR] & 0xff); + $pixels[$outputOffset + $x] = intval32bits(0xFF000000 | ($grey * 0x00010101)); + } + $inputOffset += $this->dataWidth * self::$THUMBNAIL_SCALE_FACTOR; + } + return $pixels; + } + + /** + * @return width of image from {@link #renderThumbnail()} + */ + /* + public int getThumbnailWidth() { + return getWidth() / THUMBNAIL_SCALE_FACTOR; + }*/ + + /** + * @return height of image from {@link #renderThumbnail()} + */ + /* + public int getThumbnailHeight() { + return getHeight() / THUMBNAIL_SCALE_FACTOR; + } + + private void reverseHorizontal(int width, int height) { + byte[] yuvData = this.yuvData; + for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) { + int middle = rowStart + width / 2; + for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { + byte temp = yuvData[x1]; + yuvData[x1] = yuvData[x2]; + yuvData[x2] = temp; + } + } + } +*/ +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/QrReader.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/QrReader.php new file mode 100755 index 00000000..c6c80526 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/QrReader.php @@ -0,0 +1,84 @@ +readImage($imgsource); + }else { + $image = file_get_contents($imgsource); + $im = imagecreatefromstring($image); + } + + break; + + case QrReader::SOURCE_TYPE_BLOB: + if($isUseImagickIfAvailable && extension_loaded('imagick')) { + $im = new Imagick(); + $im->readimageblob($imgsource); + }else { + $im = imagecreatefromstring($imgsource); + } + + break; + + case QrReader::SOURCE_TYPE_RESOURCE: + $im = $imgsource; + if($isUseImagickIfAvailable && extension_loaded('imagick')) { + $isUseImagickIfAvailable = true; + }else { + $isUseImagickIfAvailable = false; + } + + break; + } + + if($isUseImagickIfAvailable && extension_loaded('imagick')) { + $width = $im->getImageWidth(); + $height = $im->getImageHeight(); + $source = new \Zxing\IMagickLuminanceSource($im, $width, $height); + }else { + $width = imagesx($im); + $height = imagesy($im); + $source = new \Zxing\GDLuminanceSource($im, $width, $height); + } + $histo = new \Zxing\Common\HybridBinarizer($source); + $bitmap = new \Zxing\BinaryBitmap($histo); + $reader = new \Zxing\Qrcode\QRCodeReader(); + + $this->result = $reader->decode($bitmap); + }catch (\Zxing\NotFoundException $er){ + $this->result = false; + }catch( \Zxing\FormatException $er){ + $this->result = false; + }catch( \Zxing\ChecksumException $er){ + $this->result = false; + } + } + + public function text() + { + if(method_exists($this->result,'toString')) { + return ($this->result->toString()); + }else{ + return $this->result; + } + } + + public function decode() + { + return $this->text(); + } +} + diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php new file mode 100755 index 00000000..7c09952d --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php @@ -0,0 +1,310 @@ +RGBLuminanceSource_($pixels,$dataWidth,$dataHeight); + return; + } + parent::__construct($width, $height); + if ($left + $width > $dataWidth || $top + $height > $dataHeight) { + throw new \InvalidArgumentException("Crop rectangle does not fit within image data."); + } + $this->luminances = $pixels; + $this->dataWidth = $dataWidth; + $this->dataHeight = $dataHeight; + $this->left = $left; + $this->top = $top; + } + + public function RGBLuminanceSource_($width, $height, $pixels) + { + parent::__construct($width, $height); + + $this->dataWidth = $width; + $this->dataHeight = $height; + $this->left = 0; + $this->top = 0; + $this->pixels = $pixels; + + +// In order to measure pure decoding speed, we convert the entire image to a greyscale array +// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + $this->luminances = array(); + //$this->luminances = $this->grayScaleToBitmap($this->grayscale()); + + foreach ($pixels as $key => $pixel) { + $r = $pixel['red']; + $g = $pixel['green']; + $b = $pixel['blue']; + + /* if (($pixel & 0xFF000000) == 0) { + $pixel = 0xFFFFFFFF; // = white + } + + // .229R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC) + + $this->luminances[$key] = + (306 * (($pixel >> 16) & 0xFF) + + 601 * (($pixel >> 8) & 0xFF) + + 117 * ($pixel & 0xFF) + + 0x200) >> 10; + + */ + //$r = ($pixel >> 16) & 0xff; + //$g = ($pixel >> 8) & 0xff; + //$b = $pixel & 0xff; + if ($r == $g && $g == $b) { +// Image is already greyscale, so pick any channel. + + $this->luminances[$key] = $r;//(($r + 128) % 256) - 128; + } else { +// Calculate luminance cheaply, favoring green. + $this->luminances[$key] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128; + } + + } + + /* + + for ($y = 0; $y < $height; $y++) { + $offset = $y * $width; + for ($x = 0; $x < $width; $x++) { + $pixel = $pixels[$offset + $x]; + $r = ($pixel >> 16) & 0xff; + $g = ($pixel >> 8) & 0xff; + $b = $pixel & 0xff; + if ($r == $g && $g == $b) { +// Image is already greyscale, so pick any channel. + + $this->luminances[intval($offset + $x)] = (($r+128) % 256) - 128; + } else { +// Calculate luminance cheaply, favoring green. + $this->luminances[intval($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128; + } + + + + } + */ + //} + // $this->luminances = $this->grayScaleToBitmap($this->luminances); + + } + function grayscale(){ + $width = $this->dataWidth; + $height = $this->dataHeight; + + $ret = fill_array(0, $width*$height,0); + for ($y = 0; $y < $height; $y++) + { + for ($x = 0; $x < $width; $x++) + { + $gray = $this->getPixel($x, $y,$width,$height); + + $ret[$x+$y*$width] = $gray; + } + } + return $ret; + } + function getPixel($x,$y,$width,$height){ + $image = $this->pixels; + if ($width < $x) { + die('error'); + } + if ($height < $y) { + die('error'); + } + $point = ($x) + ($y * $width); + + $r = $image[$point]['red'];//($image[$point] >> 16) & 0xff; + $g = $image[$point]['green'];//($image[$point] >> 8) & 0xff; + $b = $image[$point]['blue'];//$image[$point] & 0xff; + + $p = intval(($r*33 +$g*34 + $b*33)/100); + + + return $p; + + } + + +function getMiddleBrightnessPerArea($image) +{ + $numSqrtArea = 4; + //obtain middle brightness((min + max) / 2) per area + $areaWidth = floor($this->dataWidth / $numSqrtArea); + $areaHeight = floor($this->dataHeight / $numSqrtArea); + $minmax = fill_array(0,$numSqrtArea,0); + for ($i = 0; $i < $numSqrtArea; $i++) + { + $minmax[$i] = fill_array(0,$numSqrtArea,0); + for ($i2 = 0; $i2 < $numSqrtArea; $i2++) + { + $minmax[$i][$i2] = array(0,0); + } + } + for ($ay = 0; $ay < $numSqrtArea; $ay++) + { + for ($ax = 0; $ax < $numSqrtArea; $ax++) + { + $minmax[$ax][$ay][0] = 0xFF; + for ($dy = 0; $dy < $areaHeight; $dy++) + { + for ($dx = 0; $dx < $areaWidth; $dx++) + { + $target = $image[intval($areaWidth * $ax + $dx+($areaHeight * $ay + $dy)*$this->dataWidth)]; + if ($target < $minmax[$ax][$ay][0]) + $minmax[$ax][$ay][0] = $target; + if ($target > $minmax[$ax][$ay][1]) + $minmax[$ax][$ay][1] = $target; + } + } + //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2; + } + } + $middle = array(); + for ($i3 = 0; $i3 < $numSqrtArea; $i3++) + { + $middle[$i3] = array(); + } + for ($ay = 0; $ay < $numSqrtArea; $ay++) + { + for ($ax = 0; $ax < $numSqrtArea; $ax++) + { + $middle[$ax][$ay] = floor(($minmax[$ax][$ay][0] + $minmax[$ax][$ay][1]) / 2); + //Console.out.print(middle[ax][ay] + ","); + } + //Console.out.println(""); + } + //Console.out.println(""); + + return $middle; +} + +function grayScaleToBitmap ($grayScale) +{ + $middle = $this->getMiddleBrightnessPerArea($grayScale); + $sqrtNumArea = count($middle); + $areaWidth = floor($this->dataWidth/ $sqrtNumArea); + $areaHeight = floor($this->dataHeight / $sqrtNumArea); + $bitmap = fill_array(0,$this->dataWidth*$this->dataHeight,0); + + for ($ay = 0; $ay < $sqrtNumArea; $ay++) + { + for ($ax = 0; $ax < $sqrtNumArea; $ax++) + { + for ($dy = 0; $dy < $areaHeight; $dy++) + { + for ($dx = 0; $dx < $areaWidth; $dx++) + { + $bitmap[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] = ($grayScale[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] < $middle[$ax][$ay])?0:255; + } + } + } + } + return $bitmap; +} + +//@Override + public function getRow($y, $row=null) { + if ($y < 0 || $y >= $this->getHeight()) { + throw new \InvalidArgumentException("Requested row is outside the image: " + y); + } + $width = $this->getWidth(); + if ($row == null || count($row) < $width) { + $row = array(); + } + $offset = ($y + $this->top) * $this->dataWidth + $this->left; + $row = arraycopy($this->luminances,$offset, $row, 0, $width); + return $row; + } + +//@Override + public function getMatrix() { + $width = $this->getWidth(); + $height = $this->getHeight(); + +// If the caller asks for the entire underlying image, save the copy and give them the +// original data. The docs specifically warn that result.length must be ignored. + if ($width == $this->dataWidth && $height == $this->dataHeight) { + return $this->luminances; + } + + $area = $width * $height; + $matrix = array(); + $inputOffset = $this->top * $this->dataWidth + $this->left; + +// If the width matches the full width of the underlying data, perform a single copy. + if ($width == $this->dataWidth) { + $matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area); + return $matrix; + } + +// Otherwise copy one cropped row at a time. + $rgb = $this->luminances; + for ($y = 0; $y < $height; $y++) { + $outputOffset = $y * $width; + $matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width); + $inputOffset += $this->dataWidth; + } + return $matrix; + } + +//@Override + public function isCropSupported() { + return true; + } + +//@Override + public function crop($left, $top, $width, $height) { + return new RGBLuminanceSource($this->luminances, + $this->dataWidth, + $this->dataHeight, + $this->left + $left, + $this->top + $top, + $width, + $height); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/Reader.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/Reader.php new file mode 100755 index 00000000..9d700c87 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/Reader.php @@ -0,0 +1,13 @@ +Encapsulates the result of decoding a barcode within an image.

+ * + * @author Sean Owen + */ +final class Result { + +private $text; +private $rawBytes; +private $resultPoints; +private $format; +private $resultMetadata; +private $timestamp; + + + +public function __construct($text, + $rawBytes, + $resultPoints, + $format, + $timestamp = '') { + + $this->text = $text; + $this->rawBytes = $rawBytes; + $this->resultPoints = $resultPoints; + $this->format = $format; + $this->resultMetadata = null; + $this->timestamp = $timestamp?$timestamp:time(); +} + + /** + * @return raw text encoded by the barcode + */ + public function getText() { + return $this->text; + } + + /** + * @return raw bytes encoded by the barcode, if applicable, otherwise {@code null} + */ + public function getRawBytes() { + return $this->rawBytes; + } + + /** + * @return points related to the barcode in the image. These are typically points + * identifying finder patterns or the corners of the barcode. The exact meaning is + * specific to the type of barcode that was decoded. + */ + public function getResultPoints() { + return $this->resultPoints; + } + + /** + * @return {@link BarcodeFormat} representing the format of the barcode that was decoded + */ + public function getBarcodeFormat() { + return $this->format; + } + + /** + * @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be + * {@code null}. This contains optional metadata about what was detected about the barcode, + * like orientation. + */ + public function getResultMetadata() { + return $this->resultMetadata; + } + + public function putMetadata($type, $value) { + if ($this->resultMetadata == null) { + $this->resultMetadata = array(); + } + $resultMetadata[$type] = $value; +} + + public function putAllMetadata($metadata) { + if ($metadata != null) { + if ($this->resultMetadata == null) { + $this->resultMetadata = $metadata; + } else { + $this->resultMetadata = array_merge($this->resultMetadata, $metadata); + } + } + } + + public function addResultPoints($newPoints) { + $oldPoints = $this->resultPoints; + if ($oldPoints == null) { + $this->resultPoints = $newPoints; + } else if ($newPoints != null && count($newPoints) > 0) { + $allPoints = fill_array(0,count($oldPoints)+count($newPoints),0); + $allPoints = arraycopy($oldPoints, 0, $allPoints, 0, count($oldPoints)); + $allPoints = arraycopy($newPoints, 0, $allPoints, count($oldPoints), count($newPoints)); + $this->resultPoints = $allPoints; + } + } + + public function getTimestamp() { + return $this->timestamp; + } + + //@Override + public function toString() { + return $this->text; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php new file mode 100755 index 00000000..0702004b --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php @@ -0,0 +1,140 @@ +Encapsulates a point of interest in an image containing a barcode. Typically, this + * would be the location of a finder pattern or the corner of the barcode, for example.

+ * + * @author Sean Owen + */ +class ResultPoint { + + private $x; + private $y; + + public function __construct($x, $y) { + $this->x = (float)($x); + $this->y = (float)($y); + } + + public final function getX() { + return (float)($this->x); + } + + public final function getY() { + return (float)($this->y); + } + +//@Override + public final function equals($other) { + if ($other instanceof ResultPoint) { + $otherPoint = $other; + return $this->x == $otherPoint->x && $this->y == $otherPoint->y; + } + return false; + } + +//@Override + public final function hashCode() { + return 31 * floatToIntBits($this->x) + floatToIntBits($this->y); + } + +//@Override + public final function toString() { + $result = ''; + $result.= ('('); + $result.=($this->x); + $result.=(','); + $result.=($this->y); + $result.=(')'); + return $result; + } + + /** + * Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC + * and BC is less than AC, and the angle between BC and BA is less than 180 degrees. + * + * @param patterns array of three {@code ResultPoint} to order + */ + public static function orderBestPatterns($patterns) { + +// Find distances between pattern centers + $zeroOneDistance = self::distance($patterns[0], $patterns[1]); + $oneTwoDistance = self::distance($patterns[1], $patterns[2]); + $zeroTwoDistance = self::distance($patterns[0], $patterns[2]); + + $pointA=''; + $pointB=''; + $pointC=''; +// Assume one closest to other two is B; A and C will just be guesses at first + if ($oneTwoDistance >= $zeroOneDistance && $oneTwoDistance >= $zeroTwoDistance) { + $pointB = $patterns[0]; + $pointA = $patterns[1]; + $pointC = $patterns[2]; + } else if ($zeroTwoDistance >= $oneTwoDistance && $zeroTwoDistance >= $zeroOneDistance) { + $pointB = $patterns[1]; + $pointA = $patterns[0]; + $pointC = $patterns[2]; + } else { + $pointB = $patterns[2]; + $pointA = $patterns[0]; + $pointC = $patterns[1]; + } + +// Use cross product to figure out whether A and C are correct or flipped. +// This asks whether BC x BA has a positive z component, which is the arrangement +// we want for A, B, C. If it's negative, then we've got it flipped around and +// should swap A and C. + if (self::crossProductZ($pointA, $pointB, $pointC) < 0.0) { + $temp = $pointA; + $pointA = $pointC; + $pointC = $temp; + } + + $patterns[0] = $pointA; + $patterns[1] = $pointB; + $patterns[2] = $pointC; + return $patterns; + } + + + /** + * @param pattern1 first pattern + * @param pattern2 second pattern + * @return distance between two points + */ + public static function distance($pattern1, $pattern2) { + return MathUtils::distance($pattern1->x, $pattern1->y, $pattern2->x, $pattern2->y); + } + + /** + * Returns the z component of the cross product between vectors BC and BA. + */ + private static function crossProductZ($pointA, + $pointB, + $pointC) { + $bX = $pointB->x; + $bY = $pointB->y; + return (($pointC->x - $bX) * ($pointA->y - $bY)) - (($pointC->y - $bY) * ($pointA->x - $bX)); + } + + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php new file mode 100755 index 00000000..b6e81b94 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php @@ -0,0 +1,95 @@ +strict = $strict; + $this->change($initialValue); + } + /** + * Changes the value of the enum. + * + * @param mixed $value + * @return void + */ + public function change($value) + { + if (!in_array($value, $this->getConstList(), $this->strict)) { + throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this)); + } + $this->value = $value; + } + /** + * Gets current value. + * + * @return mixed + */ + public function get() + { + return $this->value; + } + /** + * Gets all constants (possible values) as an array. + * + * @param boolean $includeDefault + * @return array + */ + public function getConstList($includeDefault = true) + { + if ($this->constants === null) { + $reflection = new ReflectionClass($this); + $this->constants = $reflection->getConstants(); + } + if ($includeDefault) { + return $this->constants; + } + $constants = $this->constants; + unset($constants['__default']); + return $constants; + } + /** + * Gets the name of the enum. + * + * @return string + */ + public function __toString() + { + return array_search($this->value, $this->getConstList()); + } +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php new file mode 100755 index 00000000..45af51e0 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php @@ -0,0 +1,394 @@ +A simple, fast array of bits, represented compactly by an array of ints internally.

+ * + * @author Sean Owen + */ + +final class BitArray { + + private $bits; + private $size; + + + + public function __construct($bits=array(),$size=0) { + + if(!$bits&&!$size){ + $this->$size = 0; + $this->bits = array(); + }elseif($bits&&!$size){ + $this->size = $bits; + $this->bits = $this->makeArray($bits); + }else{ + $this->bits = $bits; + $this->size = $size; + } + + } + + + + + public function getSize() { + return $this->size; + } + + public function getSizeInBytes() { + return ($this->size + 7) / 8; + } + + private function ensureCapacity($size) { + if ($size > count($this->bits) * 32) { + $newBits = $this->makeArray($size); + $newBits = arraycopy($this->bits, 0, $newBits, 0, count($this->bits)); + $this->bits = $newBits; + } + } + + /** + * @param $i; bit to get + * @return true iff bit i is set + */ + public function get($i) { + $key = intval($i / 32); + return intval32bits($this->bits[$key] & (1 << ($i & 0x1F))) != 0; + } + + /** + * Sets bit i. + * + * @param i bit to set + */ + public function set($i) { + $this->bits[intval($i / 32)] |= 1 << ($i & 0x1F); + $this->bits[intval($i / 32)] = overflow($this->bits[intval($i / 32)]); + } + + /** + * Flips bit i. + * + * @param i bit to set + */ + public function flip($i) { + $this->bits[intval($i / 32)] ^= 1 << ($i & 0x1F); + $this->bits[intval($i / 32)] = overflow32($this->bits[intval($i / 32)]); + } + + /** + * @param from first bit to check + * @return index of first bit that is set, starting from the given index, or size if none are set + * at or beyond this given index + * @see #getNextUnset(int) + */ + public function getNextSet($from) { + if ($from >= $this->size) { + return $this->size; + } + $bitsOffset = intval($from / 32); + $currentBits = (int)$this->bits[$bitsOffset]; + // mask off lesser bits first + $currentBits &= ~((1 << ($from & 0x1F)) - 1); + while ($currentBits == 0) { + if (++$bitsOffset == count($this->bits)) { + return $this->size; + } + $currentBits = $this->bits[$bitsOffset]; + } + $result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits); //numberOfTrailingZeros + return $result > $this->size ? $this->size : $result; + } + + /** + * @param from index to start looking for unset bit + * @return index of next unset bit, or {@code size} if none are unset until the end + * @see #getNextSet(int) + */ + public function getNextUnset($from) { + if ($from >= $this->size) { + return $this->size; + } + $bitsOffset = intval($from / 32); + $currentBits = ~$this->bits[$bitsOffset]; + // mask off lesser bits first + $currentBits &= ~((1 << ($from & 0x1F)) - 1); + while ($currentBits == 0) { + if (++$bitsOffset == count($this->bits)) { + return $this->size; + } + $currentBits = overflow32(~$this->bits[$bitsOffset]); + } + $result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a block of 32 bits, starting at bit i. + * + * @param i first bit to set + * @param newBits the new value of the next 32 bits. Note again that the least-significant bit + * corresponds to bit i, the next-least-significant to i+1, and so on. + */ + public function setBulk($i, $newBits) { + $this->bits[intval($i / 32)] = $newBits; + } + + /** + * Sets a range of bits. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + */ + public function setRange($start, $end) { + if ($end < $start) { + throw new \InvalidArgumentException(); + } + if ($end == $start) { + return; + } + $end--; // will be easier to treat this as the last actually set bit -- inclusive + $firstInt = intval($start / 32); + $lastInt = intval($end / 32); + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1F; + $lastBit = $i < $lastInt ? 31 : $end & 0x1F; + $mask = 0; + if ($firstBit == 0 && $lastBit == 31) { + $mask = -1; + } else { + $mask = 0; + for ($j = $firstBit; $j <= $lastBit; $j++) { + $mask |= 1 << $j; + } + } + $this->bits[$i] = overflow32($this->bits[$i]|$mask); + } + } + + /** + * Clears all bits (sets to false). + */ + public function clear() { + $max = count($this->bits); + for ($i = 0; $i < $max; $i++) { + $this->bits[$i] = 0; + } + } + + /** + * Efficient method to check if a range of bits is set, or not set. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + * @param value if true, checks that bits in range are set, otherwise checks that they are not set + * @return true iff all bits are set or not set in range, according to value argument + * @throws InvalidArgumentException if end is less than or equal to start + */ + public function isRange($start, $end, $value) { + if ($end < $start) { + throw new \InvalidArgumentException(); + } + if ($end == $start) { + return true; // empty range matches + } + $end--; // will be easier to treat this as the last actually set bit -- inclusive + $firstInt = intval($start / 32); + $lastInt = intval($end / 32); + for ($i = $firstInt; $i <= $lastInt; $i++) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1F; + $lastBit = $i < $lastInt ? 31 :$end & 0x1F; + $mask = 0; + if ($firstBit == 0 && $lastBit == 31) { + $mask = -1; + } else { + $mask = 0; + for ($j = $firstBit; $j <= $lastBit; $j++) { + $mask = overflow32($mask|(1 << $j)); + } + } + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if (($this->bits[$i] & $mask) != ($value ? $mask : 0)) { + return false; + } + } + return true; + } + + public function appendBit($bit) { + $this->ensureCapacity($this->size + 1); + if ($bit) { + $this->bits[intval($this->size / 32)] |= 1 << ($this->size & 0x1F); + } + $this->size++; + } + + /** + * Appends the least-significant bits, from value, in order from most-significant to + * least-significant. For example, appending 6 bits from 0x000001E will append the bits + * 0, 1, 1, 1, 1, 0 in that order. + * + * @param value {@code int} containing bits to append + * @param numBits bits from value to append + */ + public function appendBits($value, $numBits) { + if ($numBits < 0 || $numBits > 32) { + throw new \InvalidArgumentException("Num bits must be between 0 and 32"); + } + $this->ensureCapacity($this->size + $numBits); + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) == 1); + } + } + + public function appendBitArray($other) { + $otherSize = $other->size; + $this->ensureCapacity($this->size + $otherSize); + for ($i = 0; $i < $otherSize; $i++) { + $this->appendBit($other->get($i)); + } + } + + public function _xor($other) { + if (count($this->bits) != count($other->bits)) { + throw new \InvalidArgumentException("Sizes don't match"); + } + for ($i = 0; $i < count($this->bits); $i++) { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + $this->bits[$i] ^= $other->bits[$i]; + } + } + + /** + * + * @param bitOffset first bit to start writing + * @param array array to write into. Bytes are written most-significant byte first. This is the opposite + * of the internal representation, which is exposed by {@link #getBitArray()} + * @param offset position in array to start writing + * @param numBytes how many bytes to write + */ + public function toBytes($bitOffset, &$array, $offset, $numBytes) { + for ($i = 0; $i < $numBytes; $i++) { + $theByte = 0; + for ($j = 0; $j < 8; $j++) { + if ($this->get($bitOffset)) { + $theByte |= 1 << (7 - $j); + } + $bitOffset++; + } + $array[(int)($offset + $i)] = $theByte; + } + } + + /** + * @return underlying array of ints. The first element holds the first 32 bits, and the least + * significant bit is bit 0. + */ + public function getBitArray() { + return $this->bits; + } + + /** + * Reverses all bits in the array. + */ + public function reverse() { + $newBits = array(); + // reverse all int's first + $len = (($this->size-1) / 32); + $oldBitsLen = $len + 1; + for ($i = 0; $i < $oldBitsLen; $i++) { + $x = $this->bits[$i];/* + $x = (($x >> 1) & 0x55555555L) | (($x & 0x55555555L) << 1); + $x = (($x >> 2) & 0x33333333L) | (($x & 0x33333333L) << 2); + $x = (($x >> 4) & 0x0f0f0f0fL) | (($x & 0x0f0f0f0fL) << 4); + $x = (($x >> 8) & 0x00ff00ffL) | (($x & 0x00ff00ffL) << 8); + $x = (($x >> 16) & 0x0000ffffL) | (($x & 0x0000ffffL) << 16);*/ + $x = (($x >> 1) & 0x55555555) | (($x & 0x55555555) << 1); + $x = (($x >> 2) & 0x33333333) | (($x & 0x33333333) << 2); + $x = (($x >> 4) & 0x0f0f0f0f) | (($x & 0x0f0f0f0f) << 4); + $x = (($x >> 8) & 0x00ff00ff) | (($x & 0x00ff00ff) << 8); + $x = (($x >> 16) & 0x0000ffff) | (($x & 0x0000ffff) << 16); + $newBits[(int)$len - $i] = (int) $x; + } + // now correct the int's if the bit size isn't a multiple of 32 + if ($this->size != $oldBitsLen * 32) { + $leftOffset = $oldBitsLen * 32 - $this->size; + $mask = 1; + for ($i = 0; $i < 31 - $leftOffset; $i++) { + $mask = ($mask << 1) | 1; + } + $currentInt = ($newBits[0] >> $leftOffset) & $mask; + for ($i = 1; $i < $oldBitsLen; $i++) { + $nextInt = $newBits[$i]; + $currentInt |= $nextInt << (32 - $leftOffset); + $newBits[intval($i) - 1] = $currentInt; + $currentInt = ($nextInt >> $leftOffset) & $mask; + } + $newBits[intval($oldBitsLen) - 1] = $currentInt; + } + $bits = $newBits; + } + + private static function makeArray($size) { + return array(); + } + + // @Override + public function equals($o) { + if (!($o instanceof BitArray)) { + return false; + } + $other = $o; + return $this->size == $other->size && $this->bits===$other->bits; + } + + //@Override + public function hashCode() { + return 31 * $this->size +hashCode($this->bits); + } + + // @Override + public function toString() { + $result = ''; + for ($i = 0; $i < $this->size; $i++) { + if (($i & 0x07) == 0) { + $result.=' '; + } + $result.= ($this->get($i) ? 'X' : '.'); + } + return (string) $result; + } + + // @Override + public function _clone() { + return new BitArray($this->bits, $this->size); + } + +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php new file mode 100755 index 00000000..bde9f49d --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php @@ -0,0 +1,424 @@ +width = $width; + $this->height = $height; + $this->rowSize = $rowSize; + $this->bits = $bits; + } + public static function parse($stringRepresentation, $setString, $unsetString){ + if (!$stringRepresentation) { + throw new \InvalidArgumentException(); + } + $bits = array(); + $bitsPos = 0; + $rowStartPos = 0; + $rowLength = -1; + $nRows = 0; + $pos = 0; + while ($pos < strlen($stringRepresentation)) { + if ($stringRepresentation{$pos} == '\n' || + $stringRepresentation->{$pos} == '\r') { + if ($bitsPos > $rowStartPos) { + if($rowLength == -1) { + $rowLength = $bitsPos - $rowStartPos; + } + else if ($bitsPos - $rowStartPos != $rowLength) { + throw new \InvalidArgumentException("row lengths do not match"); + } + $rowStartPos = $bitsPos; + $nRows++; + } + $pos++; + } + else if (substr($stringRepresentation,$pos, strlen($setString))==$setString) { + $pos += strlen($setString); + $bits[$bitsPos] = true; + $bitsPos++; + } + else if (substr($stringRepresentation, $pos + strlen($unsetString))==$unsetString) { + $pos += strlen($unsetString); + $bits[$bitsPos] = false; + $bitsPos++; + } else { + throw new \InvalidArgumentException( + "illegal character encountered: " . substr($stringRepresentation,$pos)); + } + } + + // no EOL at end? + if ($bitsPos > $rowStartPos) { + if($rowLength == -1) { + $rowLength = $bitsPos - $rowStartPos; + } else if ($bitsPos - $rowStartPos != $rowLength) { + throw new \InvalidArgumentException("row lengths do not match"); + } + $nRows++; + } + + $matrix = new BitMatrix($rowLength, $nRows); + for ($i = 0; $i < $bitsPos; $i++) { + if ($bits[$i]) { + $matrix->set($i % $rowLength, $i / $rowLength); + } + } + return $matrix; + } + + /** + *

Gets the requested bit, where true means black.

+ * + * @param $x; The horizontal component (i.e. which column) + * @param $y; The vertical component (i.e. which row) + * @return value of given bit in matrix + */ + public function get($x, $y) { + + $offset = intval($y * $this->rowSize + ($x / 32)); + if(!isset($this->bits[$offset])){ + $this->bits[$offset] = 0; + } + + // return (($this->bits[$offset] >> ($x & 0x1f)) & 1) != 0; + return (uRShift($this->bits[$offset],($x & 0x1f)) & 1) != 0;//было >>> вместо >>, не знаю как эмулировать беззнаковый сдвиг + } + + /** + *

Sets the given bit to true.

+ * + * @param $x; The horizontal component (i.e. which column) + * @param $y; The vertical component (i.e. which row) + */ + public function set($x, $y) { + $offset = intval($y * $this->rowSize + ($x / 32)); + if(!isset($this->bits[$offset])){ + $this->bits[$offset] = 0; + } + //$this->bits[$offset] = $this->bits[$offset]; + + // if($this->bits[$offset]>200748364){ + //$this->bits= array(0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-1090519040,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,1056964608,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-1358954496,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,117440512,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,50331648,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,33554432,-1,-1,536870911,-4096,65279,0,0,0,0,0,0,0,0,-1,-1,65535,-4096,65535,0,0,0,0,0,0,0,0,-193,536870911,0,-4096,65279,0,0,0,0,0,0,0,0,-254,32767,0,-4096,61951,0,0,0,0,0,0,0,0,20913920,0,0,-4096,50175,0,0,0,0,0,0,0,0,0,0,0,-4096,60159,0,0,0,0,0,0,0,0,0,0,0,-4096,64255,0,0,0,0,0,0,0,0,0,0,0,-8192,56319,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,251658240,0,0,0,-4096,-1,255,0,256,0,0,0,0,117440512,0,0,0,-4096,-1,255,0,512,0,0,0,0,117440512,0,0,0,-4096,-1,255,0,1024,0,0,0,0,117440512,0,0,0,-4096,-1,223,0,256,0,0,0,0,117440512,0,0,33030144,-4096,-1,191,0,256,0,0,0,0,117440512,0,0,33554428,-4096,-1,255,0,768,0,0,0,0,117440512,0,402849792,67108862,-8192,-1,255,0,768,0,0,0,0,117440512,0,470278396,63045630,-8192,-1,255,0,256,0,0,0,0,251658240,-8388608,470278399,58720286,-8192,-1,2686975,0,3842,0,0,0,0,251658240,-131072,1007149567,58720286,-8192,-1,2031615,0,3879,0,0,0,0,251658240,536739840,1007092192,58720286,-8192,-1,851967,0,3840,0,0,0,0,251658240,917504,1007092192,58720284,-8192,-1,2031615,0,3968,0,0,0,0,251658240,917504,1007092160,59244060,-8192,-1,65535,0,7936,0,0,0,0,251658240,917504,1009779136,59244060,-8192,-1,9371647,0,1792,0,0,0,0,251658240,917504,946921920,59244060,-8192,-1,8585215,0,1792,0,0,0,0,117440512,-15859712,477159875,59244060,-8192,-1,65535,0,12032,0,0,0,0,251658240,-15859712,52490691,59244060,-8192,-1,-1,0,65408,0,0,0,0,251658240,-15859712,58778051,59244060,-8192,-1,-1,0,65473,0,0,0,0,251658240,-15859712,125886915,59244060,-8192,-1,-1,0,65472,0,0,0,0,251658240,-15859712,58778051,59244060,-8192,-1,-1,0,65408,0,0,0,0,251658240,-15859712,8380867,59244060,-8192,-1,-1,0,65473,0,0,0,0,251658240,-15859712,8380867,59244060,-8192,-1,-1,0,131011,0,0,0,0,251658240,-15859712,8380867,58720284,-8192,-1,-1,0,130947,0,0,0,0,251658240,-15859712,2089411,58720284,-8192,-1,-1,0,130947,0,0,0,0,251658240,-32636928,449,58720284,-8192,-1,-1,33554431,131015,0,0,0,0,251658240,786432,448,62914588,-8192,-1,-1,16777215,131015,0,0,0,0,251658240,786432,448,67108860,-8192,-1,-1,553648127,131015,0,0,0,0,251658240,786432,946864576,67108860,-8192,-1,-1,32505855,131015,0,0,0,0,251658240,786432,946921976,8388604,-8192,-1,-1,8191999,131015,0,0,0,0,251658240,-262144,946921983,248,-8192,-1,-1,8126463,196551,0,0,0,0,251658240,-262144,7397887,0,-8192,-1,-1,16777215,262087,0,0,0,0,251658240,-262144,8257543,0,-8192,-1,-1,-2121269249,262095,0,0,0,0,520093696,0,8257536,0,-8192,-1,-1,-201326593,262095,0,0,0,0,520290304,0,8257536,117963776,-8192,-1,-1,-201326593,262095,0,0,0,0,520093696,0,-2140143616,118488579,-8192,-1,-1,-201326593,131023,0,0,0,0,520093696,0,-2131697280,118488579,-8192,-1,-1,-503316481,131023,0,0,0,0,520093696,2145386496,-2131631232,118484995,-16384,-1,-1,-469762049,262095,0,0,0,0,520093696,2147221504,552649600,118481344,-16384,-1,-1,-469762049,131023,0,0,0,0,520290304,2147221504,2029002240,118481344,-16384,-1,-1,-469762049,262031,0,0,0,0,520290304,-266600448,2029001791,125952960,-16384,-1,-1,-469762049,262031,0,0,0,0,1057423360,-266600448,2027953215,133177312,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,-266600448,-119531393,133177343,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,-2145648640,-253754369,66068479,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,236716032,-253754369,15729663,-16384,-1,-1,-134217729,262095,0,0,0,0,1057947648,236716032,-253754369,6348807,-16384,-1,-1,-134217729,262095,0,0,0,0,524222464,236716032,-253690305,6348803,-16384,-1,-1,-134217729,262111,0,0,0,0,521076736,2115764224,-253625344,14737411,-16384,-1,-1,-134217729,262095,0,0,0,0,522125312,2115764224,-253625344,14743555,-16384,-1,-1,-134217729,262111,0,0,16772608,0,1073676288,-31719424,-2014283776,14810115,-16384,-1,-1,-1,262143,0,0,16776704,0,1065287680,-1642594304,-1879178880,14810115,-16384,-1,-1,-1,524287,0,0,16776192,0,2139029504,264241152,-2013396089,14809091,-16384,-1,-1,-1,262095,0,0,16776192,0,2139029504,264241152,-2080636025,14803335,-16384,-1,-1,-1,262087,0,0,16776192,0,2147418112,264241152,-2132803581,14803847,-16384,-1,-1,-402653185,524259,0,0,8386048,0,2147418112,0,-2132688896,123783,-16384,-1,-1,1207959551,262112,0,0,16775168,0,2147418112,0,14794752,1046535,-16384,-1,-1,268435455,262128,0,0,16775168,0,2147418112,0,14712832,1047615,-16384,-1,-1,536870911,524284,0,0,16776705,0,2147418112,0,14680832,1047615,-16384,-1,-1,-1,524287,0,0,16776704,0,2147418112,-1048576,14681087,1046591,-32768,-1,-1,-1,524287,0,0,16776704,0,2147418112,-524288,-2132802561,2080831,-32768,-1,-1,-1,524287,0,0,16776705,0,2147418112,-524288,-31718401,2080831,-32768,-1,-1,-1,1048575,0,0,16776193,0,2147418112,3670016,-31718528,2080831,-32768,-1,-1,-1,524287,0,0,16776195,0,2147418112,3670016,-31718528,134086719,-32768,-1,-1,-1,524287,0,0,16776195,0,2147418112,3670016,253494144,268173368,-32768,-1,-1,-1,524287,0,0,16775171,0,2147418112,3670016,268174208,268173368,-32768,-1,-1,-1,1048575,0,0,16771072,0,2147418112,-63438848,268174223,31457328,-32768,-1,-1,-1,1048575,0,0,10418176,0,-65536,-63438848,133957519,14807040,-32768,-1,-1,-1,2097151,0,0,15923200,0,2147418112,-63438848,1968015,14809095,-32768,-1,-1,-1,1048575,0,0,12808192,0,2147418112,-63438848,2082703,12711943,-32768,-1,-1,-1,2097151,0,0,6420480,0,2147418112,-63438848,2082703,14343,-32768,-1,-1,-1,2097151,0,0,15202304,0,-65536,-63438848,2082703,1849351,-32768,-1,-1,-1,2097151,0,0,15464448,0,-65536,-63438848,264472335,1849351,-32768,-1,-1,-1,4194303,0,0,16371712,0,-65536,-63438848,264472335,14343,-32768,-1,-1,-1,8388607,0,0,0,0,-65536,-63438848,532907791,235010048,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-63438848,-1603833,235010160,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-30976,67238000,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-30976,48,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-29391104,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-29391104,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-524287,-65042433,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-524287,2082441215,0,-65536,-1,-1,-1,16777215,0,0,0,0,-13697024,-524287,511,0,-65536,-1,-1,-1,16777215,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,14680063,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,16777215,0,0,0,0,-65536,1,0,0,-65536,-1,-1,-1,14680063,0,0,0,0,-8454144,1,0,0,-65536,-1,-1,-1,12582911,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,2097151,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,-14745600,1,0,0,-65536,-1,-1,-1,3145727,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,50331648,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,117440512,1,0,-268435456,-1,-1,-1,-1,524287,0,0,0,0,251658240,1,0,-320,-1,-1,-1,-1,262143,0,0,0,0,520093696,1,-2048,-1,-1,-1,-1,-1,262143,0,0,0,0,1056964608,-16777213,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-121,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,65535,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,65535,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,262143,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,524287,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,524287,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,589823,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,8179,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-1,4080,0,0,0,0,117440512,-1,-1,-1,-1,-1,-1,-1,1016,0,0,0,0,251658240,-1,-1,-1,-1,-1,-1,1073741823,1020,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,536870911,254,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,536870911,255,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-1879048193,127,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-469762049,63,0,0,0,0,1191182336,-1,-1,-1,-1,1023999,0,-520093712,15,0,0,0,0,-218103808,-1,-1,-1,-1,0,-8454144,-260046849,7,0,0,0,0,0,-193,-1,-1,-1057947649,-2147483648,-1,-58720257,1,0,0,0,0,0,-251,-1,-1,-1057423361,-2074,-1,-1,0,0,0,0,0,0,-59648,-1,-1,-1,-1,-1,1073741823,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,268435455,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,67108863,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,8388607,0,0,0,0,0,0,0,-403603456,-1,-1,-1,-1,262143,0,0,0,8388656,0,0,0,-1891434496,-1,-1,-1,-1,16383,0,0,0,8388608,0,0,0,-1612513280,-1,-1,-1,-1,63,0,0,0,0,0,0,0,-24320,-1,-1,-1,8388607,0,0,0,0,0,0,0,0,-256,-1,-1,1073741823,1,0,0,0,0,0,0,0,1610612736,-15,-1,-1,16383,0,0,0,0,0,0,0,0,-16646144,-1,-1,251658239,0,0,0,0,0,0,0,0,0,-51200,-1,-1,40959,0,0,0,0,0,0,268419584,103809024,-12713984,-1,-2147483137,4194303,0,0,0,0,0,0,0,402620416,-2144010240,-13631487,-32513,3,20480,0,0,0,0,0,0,0,419299328,0,-262144,-1,0,0,0,0,0,0,0,0,0,0,0,-5832704,268049407,0,0,0,0,0,0,0,0,0,0,0,0,33030144,0,0,0,0,0,0,0,0,0,0,0,0,3670016,0,0,0,0,0,0,0,0,0,0,0,0,1572864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,458752,0,0,0,0,0,0,0,0,0,0,0,0,229376,0,0,0,0,0,0,0,0,0,0,0,0,32768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31744,0,0,0,0,0,0,0,0,0,0,0,0,31744,0,0,0,0,0,0,0,0,0,0,0,0,64512,0,0,0,0,0,0,0,0,0,0,0,0,15872,0,0,0,0,0,0,0,0,0,0,0,0,3584,0,0,0,0,0,0,0,0,0,0,0,0,7680,0,0,0,0,0,0,0,0,0,0,0,0,512,0,0,0,0,0,0,0,0,0,0,0,0,3968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3840,0,0,0,0,0,0,0,0,0,0,0,0,1855,0,0,0,0,0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134217728,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,-260046848,63,0,0,0,0,0,0,0,0,0,0,0,-17301504,127,0,0,0,0,0,0,0,0,0,0,0,-524288,127,0,0,0,0,0,0,0,0,0,0,0,-262144,127,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,31,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,3,0,0,0,0,0,0,-262144,63,0,0,0,0,7,0,0,0,0,0,0,-262144,63,0,0,0,0,63,0,0,0,0,0,0,-262144,63,0,0,0,0,511,0,0,0,0,0,0,-524288,31,0,0,0,0,8191,0,0,0,0,0,0,-1048576,63,0,0,0,0,131071,0,0,0,0,0,0,-524288,63,0,0,0,0,262143,0,0,0,0,0,0,-524288,63,0,0,0,0,131071,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-2097152,127,0,0,0,0,262143,0,0,0,0,0,0,-2097152,127,0,0,0,0,262143,0,0,0,0,0,0,-1048576,127,0,0,0,0,262143,0,0,0,0,0,0,-1048576,127,0,0,0,0,262143,0,0,0,0,0,0,-2097152,255,0,0,0,0,262143,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262140,0,0,0,0,0,0,-2097152,255,0,0,0,0,131068,0,0,0,0,0,0,-4194304,255,0,0,0,0,131068,0,0,0,0,0,0,-4194304,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,32760,0,0,0,0,0,0,-8388608,255,0,0,0,0,32760,0,0,0,0,0,0,-16777216,255,0,0,-2147483648,255,16368,0,0,0,0,0,0,-16777216,255,0,0,-536870912,1023,16368,0,0,0,0,0,0,-33554432,255,0,0,-16777216,4095,16352,0,0,0,0,0,0,-33554432,255,0,0,-8388608,262143,16352,0,0,0,0,0,0,-33554432,255,0,0,-1048576,2097151,16352,0,0,0,0,0,0,-67108864,255,0,0,-524288,8388607,16352,0,0,0,0,0,0,-67108864,255,0,0,-262144,16777215,16320,0,0,0,0,0,0,-67108864,255,0,0,-131072,16777215,100679648,0,0,0,0,0,0,-67108864,255,0,0,-16384,16776959,125861824,0,0,0,0,0,0,-134217728,255,0,0,-4096,16773121,62930880,0,0,0,0,0,0,-134217728,127,0,0,2147482624,16252928,32704,0,0,0,0,0,0,-134217728,127,0,0,268435200,14680064,16320,0,0,0,0,0,0,-134217728,127,0,0,134217600,0,32704,0,0,0,0,0,0,-33554432,127,0,1056964608,67108736,0,32704,0,0,0,0,0,0,-33554432,127,0,2130706432,33554368,0,65408,0,0,0,0,0,0,-33554432,127,0,-16777216,8388576,0,32640,0,0,0,0,0,0,-134217728,127,0,-16777216,2097136,0,32640,0,0,0,0,0,0,-134217728,63,0,-16776960,1048573,0,32640,0,0,0,0,0,0,-536870912,63,0,-16776448,1048575,0,32640,0,0,0,0,0,0,-536870912,63,0,-33553664,6291455,66752,32640,0,0,0,0,0,0,-536870912,63,0,2013266688,2097148,229376,32640,0,0,0,0,0,0,-536870912,63,0,256,4194300,229376,32640,0,0,0,0,0,0,-536870912,63,0,0,524280,196608,32512,0,0,8,0,0,0,-1073741824,63,0,0,-200,15,65280,0,0,24,0,0,0,-1073741824,63,0,0,-1867768,127,32512,0,0,56,0,0,0,-1073741824,63,0,0,-1056768,4095,32512,0,0,124,0,0,0,-1073741824,63,0,0,-1050624,8191,32512,0,0,508,0,0,0,-2147483648,31,0,0,-7866368,8191,32512,0,0,1020,0,0,0,-2147483648,31,0,0,-33030656,8095,32512,0,0,2046,0,0,0,-2147483648,63,0,0,-66586624,771,32512,0,0,4094,0,0,0,0,63,0,0,-134184960,1,32256,0,0,8190,0,0,0,0,63,0,0,1610612736,0,32256,0,0,16382,0,0,0,-2147483648,63,0,0,0,0,15872,0,0,32767,0,0,0,-2147483648,31,0,0,0,0,15872,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,0,65535,0,0,0,-2147483648,31,0,0,134217728,0,7680,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,3072,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,3072,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,0,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,31,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,31,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,30,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,30,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,30,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,24,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,0,0,0,0,0,0,0,-536870912,65535);//[$offset] |= intval32bits(1 << ($x & 0x1f)); + $bob = $this->bits[$offset]; + $bob |= 1 << ($x & 0x1f); + $this->bits[$offset] |= overflow32($bob); + //$this->bits[$offset] = intval32bits($this->bits[$offset]); + + //} +//16777216 + } + + public function _unset($x, $y) {//было unset, php не позволяет использовать unset + $offset = intval($y * $this->rowSize + ($x / 32)); + $this->bits[$offset] &= ~(1 << ($x & 0x1f)); + } + + + /**1 << (249 & 0x1f) + *

Flips the given bit.

+ * + * @param $x; The horizontal component (i.e. which column) + * @param $y; The vertical component (i.e. which row) + */ + public function flip($x, $y) { + $offset = $y * $this->rowSize + intval($x / 32); + + $this->bits[$offset] = overflow32($this->bits[$offset]^(1 << ($x & 0x1f))); + } + + /** + * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding + * mask bit is set. + * + * @param $mask; XOR mask + */ + public function _xor($mask) {//было xor, php не позволяет использовать xor + if ($this->width != $mask->getWidth() || $this->height != $mask->getHeight() + || $this->rowSize != $mask->getRowSize()) { + throw new \InvalidArgumentException("input matrix dimensions do not match"); + } + $rowArray = new BitArray($this->width / 32 + 1); + for ($y = 0; $y < $this->height; $y++) { + $offset = $y * $this->rowSize; + $row = $mask->getRow($y, $rowArray)->getBitArray(); + for ($x = 0; $x < $this->rowSize; $x++) { + $this->bits[$offset + $x] ^= $row[$x]; + } + } + } + + /** + * Clears all bits (sets to false). + */ + public function clear() { + $max = count($this->bits); + for ($i = 0; $i < $max; $i++) { + $this->bits[$i] = 0; + } + } + + /** + *

Sets a square region of the bit matrix to true.

+ * + * @param $left; The horizontal position to begin at (inclusive) + * @param $top; The vertical position to begin at (inclusive) + * @param $width; The width of the region + * @param $height; The height of the region + */ + public function setRegion($left, $top, $width, $height) { + if ($top < 0 || $left < 0) { + throw new \InvalidArgumentException("Left and top must be nonnegative"); + } + if ($height < 1 || $width < 1) { + throw new \InvalidArgumentException("Height and width must be at least 1"); + } + $right = $left + $width; + $bottom = $top + $height; + if ($bottom > $this->height || $right > $this->width) { //> this.height || right > this.width + throw new \InvalidArgumentException("The region must fit inside the matrix"); + } + for ($y = $top; $y < $bottom; $y++) { + $offset = $y * $this->rowSize; + for ($x = $left; $x < $right; $x++) { + $this->bits[$offset + intval($x / 32)] = overflow32($this->bits[$offset + intval($x / 32)]|= 1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + * + * @param $y; The row to retrieve + * @param $row; An optional caller-allocated BitArray, will be allocated if null or too small + * @return The resulting BitArray - this reference should always be used even when passing + * your own row + */ + public function getRow($y, $row) { + if ($row == null || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } else { + $row->clear(); + } + $offset = $y * $this->rowSize; + for ($x = 0; $x < $this->rowSize; $x++) { + $row->setBulk($x * 32, $this->bits[$offset + $x]); + } + return $row; + } + + /** + * @param $y; row to set + * @param $row; {@link BitArray} to copy from + */ + public function setRow($y, $row) { + $this->bits = arraycopy($row->getBitArray(), 0, $this->bits, $y * $this->rowSize, $this->rowSize); + } + + /** + * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees + */ + public function rotate180() { + $width = $this->getWidth(); + $height = $this-getHeight(); + $topRow = new BitArray($width); + $bottomRow = new BitArray($width); + for ($i = 0; $i < ($height+1) / 2; $i++) { + $topRow = $this->getRow($i, $topRow); + $bottomRow = $this->getRow($height - 1 - $i, $bottomRow); + $topRow->reverse(); + $bottomRow->reverse(); + $this->setRow($i, $bottomRow); + $this->setRow($height - 1 - $i, $topRow); + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white + */ + public function getEnclosingRectangle() { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; $y++) { + for ($x32 = 0; $x32 < $this->rowSize; $x32++) { + $theBits = $this->bits[$y * $this->rowSize + $x32]; + if ($theBits != 0) { + if ($y < $top) { + $top = $y; + } + if ($y > $bottom) { + $bottom = $y; + } + if ($x32 * 32 < $left) { + $bit = 0; + while (($theBits << (31 - $bit)) == 0) { + $bit++; + } + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + if ($x32 * 32 + 31 > $right) { + $bit = 31; + while ((sdvig3($theBits, $bit)) == 0) {//>>> + $bit--; + } + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return array($left, $top, $width, $height); + } + + /** + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white + */ + public function getTopLeftOnBit() { + $bitsOffset = 0; + while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] == 0) { + $bitsOffset++; + } + if ($bitsOffset == count($this->bits)) { + return null; + } + $y = $bitsOffset / $this->rowSize; + $x = ($bitsOffset % $this->rowSize) * 32; + + $theBits = $this->bits[$bitsOffset]; + $bit = 0; + while (($theBits << (31-$bit)) == 0) { + $bit++; + } + $x += $bit; + return array($x, $y); + } + + public function getBottomRightOnBit() { + $bitsOffset = count($this->bits) - 1; + while ($bitsOffset >= 0 && $this->bits[$bitsOffset] == 0) { + $bitsOffset--; + } + if ($bitsOffset < 0) { + return null; + } + + $y = $bitsOffset / $this->rowSize; + $x = ($bitsOffset % $this->rowSize) * 32; + + $theBits = $this->bits[$bitsOffset]; + $bit = 31; + while ((sdvig3($theBits, $bit)) == 0) {//>>> + $bit--; + } + $x += $bit; + + return array($x, $y); + } + + /** + * @return The width of the matrix + */ + public function getWidth() { + return $this->width; + } + + /** + * @return The height of the matrix + */ + public function getHeight() { + return $this->height; + } + + /** + * @return The row size of the matrix + */ + public function getRowSize() { + return $this->rowSize; + } + + //@Override + public function equals($o) { + if (!($o instanceof BitMatrix)) { + return false; + } + $other = $o; + return $this->width == $other->width && $this->height == $other->height && $this->rowSize == $other->rowSize && + $this->bits===$other->bits; + } + + //@Override + public function hashCode() { + $hash = $this->width; + $hash = 31 * $hash + $this->width; + $hash = 31 * $hash + $this->height; + $hash = 31 * $hash + $this->rowSize; + $hash = 31 * $hash + hashCode($this->bits); + return $hash; + } + + //@Override + public function toString($setString='', $unsetString='',$lineSeparator='') { + if(!$setString||!$unsetString){ + return (string)"X "." "; + } + if($lineSeparator&&$lineSeparator!=="\n"){ + return $this->toString_($setString, $unsetString, $lineSeparator); + } + return (string)($setString. $unsetString. "\n"); + } + + /** + * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always + */ + // @Deprecated + public function toString_($setString, $unsetString, $lineSeparator) { + //$result = new StringBuilder(height * (width + 1)); + $result = ''; + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + $result .= ($this->get($x, $y) ? $setString : $unsetString); + } + $result .= ($lineSeparator); + } + return (string)$result; + } + +// @Override + public function _clone() {//clone() + return new BitMatrix($this->width, $this->height, $this->rowSize, $this->bits); + } + +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php new file mode 100755 index 00000000..05855069 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php @@ -0,0 +1,112 @@ +This provides an easy abstraction to read bits at a time from a sequence of bytes, where the + * number of bits read is not often a multiple of 8.

+ * + *

This class is thread-safe but not reentrant -- unless the caller modifies the bytes array + * it passed in, in which case all bets are off.

+ * + * @author Sean Owen + */ +final class BitSource { + + private $bytes; + private $byteOffset = 0; + private $bitOffset = 0; + + /** + * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. + * Bits are read within a byte from most-significant to least-significant bit. + */ + public function __construct($bytes) { + $this->bytes = $bytes; + } + + /** + * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}. + */ + public function getBitOffset() { + return $this->bitOffset; + } + + /** + * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}. + */ + public function getByteOffset() { + return $this->byteOffset; + } + + /** + * @param numBits number of bits to read + * @return int representing the bits read. The bits will appear as the least-significant + * bits of the int + * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available + */ + public function readBits($numBits) { + if ($numBits < 1 || $numBits > 32 || $numBits > $this->available()) { + throw new \InvalidArgumentException(strval($numBits)); + } + + $result = 0; + + // First, read remainder from current byte + if ($this->bitOffset > 0) { + $bitsLeft = 8 - $this->bitOffset; + $toRead = $numBits < $bitsLeft ? $numBits : $bitsLeft; + $bitsToNotRead = $bitsLeft - $toRead; + $mask = (0xFF >> (8 - $toRead)) << $bitsToNotRead; + $result = ($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead; + $numBits -= $toRead; + $this->bitOffset += $toRead; + if ($this->bitOffset == 8) { + $this->bitOffset = 0; + $this->byteOffset++; + } + } + + // Next read whole bytes + if ($numBits > 0) { + while ($numBits >= 8) { + $result = ($result << 8) | ($this->bytes[$this->byteOffset] & 0xFF); + $this->byteOffset++; + $numBits -= 8; + } + + // Finally read a partial byte + if ($numBits > 0) { + $bitsToNotRead = 8 - $numBits; + $mask = (0xFF >> $bitsToNotRead) << $bitsToNotRead; + $result = ($result << $numBits) | (($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead); + $this->bitOffset += $numBits; + } + } + + return $result; + } + + /** + * @return number of bits that can be read successfully + */ + public function available() { + return 8 * (count($this->bytes) - $this->byteOffset) - $this->bitOffset; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php new file mode 100755 index 00000000..b4407470 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php @@ -0,0 +1,154 @@ + self::ISO8859_1, + 'ISO-8859-2' => self::ISO8859_2, + 'ISO-8859-3' => self::ISO8859_3, + 'ISO-8859-4' => self::ISO8859_4, + 'ISO-8859-5' => self::ISO8859_5, + 'ISO-8859-6' => self::ISO8859_6, + 'ISO-8859-7' => self::ISO8859_7, + 'ISO-8859-8' => self::ISO8859_8, + 'ISO-8859-9' => self::ISO8859_9, + 'ISO-8859-10' => self::ISO8859_10, + 'ISO-8859-11' => self::ISO8859_11, + 'ISO-8859-12' => self::ISO8859_12, + 'ISO-8859-13' => self::ISO8859_13, + 'ISO-8859-14' => self::ISO8859_14, + 'ISO-8859-15' => self::ISO8859_15, + 'ISO-8859-16' => self::ISO8859_16, + 'SHIFT-JIS' => self::SJIS, + 'WINDOWS-1250' => self::CP1250, + 'WINDOWS-1251' => self::CP1251, + 'WINDOWS-1252' => self::CP1252, + 'WINDOWS-1256' => self::CP1256, + 'UTF-16BE' => self::UNICODE_BIG_UNMARKED, + 'UTF-8' => self::UTF8, + 'ASCII' => self::ASCII, + 'GBK' => self::GB18030, + 'EUC-KR' => self::EUC_KR, + ); + /** + * Additional possible values for character sets. + * + * @var array + */ + protected static $additionalValues = array( + self::CP437 => 2, + self::ASCII => 170, + ); + /** + * Gets character set ECI by value. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByValue($value) + { + if ($value < 0 || $value >= 900) { + throw new Exception\InvalidArgumentException('Value must be between 0 and 900'); + } + if (false !== ($key = array_search($value, self::$additionalValues))) { + $value = $key; + } + array_search($value, self::$nameToEci); + try + { + self::setName($value); + return new self($value); + } catch (Exception\UnexpectedValueException $e) { + return null; + } + } + + private static function setName($value) + { + foreach (self::$nameToEci as $name => $key) { + if($key == $value) + { + self::$name = $name; + return true; + } + } + if(self::$name == null) + { + foreach (self::$additionalValues as $name => $key) { + if($key == $value) + { + self::$name = $name; + return true; + } + } + } + } + /** + * Gets character set ECI name. + * + * @return character set ECI name|null + */ + public static function name() + { + return self::$name; + } + /** + * Gets character set ECI by name. + * + * @param string $name + * @return CharacterSetEci|null + */ + public static function getCharacterSetECIByName($name) + { + $name = strtoupper($name); + if (isset(self::$nameToEci[$name])) { + return new self(self::$nameToEci[$name]); + } + return null; + } +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php new file mode 100755 index 00000000..5568f901 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php @@ -0,0 +1,109 @@ +Encapsulates the result of decoding a matrix of bits. This typically + * applies to 2D barcode formats. For now it contains the raw bytes obtained, + * as well as a String interpretation of those bytes, if applicable.

+ * + * @author Sean Owen + */ +final class DecoderResult { + + private $rawBytes; + private $text; + private $byteSegments; + private $ecLevel; + private $errorsCorrected; + private $erasures; + private $other; + private $structuredAppendParity; + private $structuredAppendSequenceNumber; + + + + public function __construct($rawBytes, + $text, + $byteSegments, + $ecLevel, + $saSequence = -1, + $saParity = -1) { + $this->rawBytes = $rawBytes; + $this->text = $text; + $this->byteSegments = $byteSegments; + $this->ecLevel = $ecLevel; + $this->structuredAppendParity = $saParity; + $this->structuredAppendSequenceNumber = $saSequence; + } + + public function getRawBytes() { + return $this->rawBytes; + } + + public function getText() { + return $this->text; + } + + public function getByteSegments() { + return $this->byteSegments; + } + + public function getECLevel() { + return $this->ecLevel; + } + + public function getErrorsCorrected() { + return $this->errorsCorrected; + } + + public function setErrorsCorrected($errorsCorrected) { + $this->errorsCorrected = $errorsCorrected; + } + + public function getErasures() { + return $this->erasures; + } + + public function setErasures($erasures) { + $this->erasures = $erasures; + } + + public function getOther() { + return $this->other; + } + + public function setOther($other) { + $this->other = $other; + } + + public function hasStructuredAppend() { + return $this->structuredAppendParity >= 0 && $this->structuredAppendSequenceNumber >= 0; + } + + public function getStructuredAppendParity() { + return $this->structuredAppendParity; + } + + public function getStructuredAppendSequenceNumber() { + return $this->structuredAppendSequenceNumber; + } + +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php new file mode 100755 index 00000000..1e790a8f --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php @@ -0,0 +1,89 @@ +sampleGrid_($image, $dimensionX, $dimensionY, $transform); + } + +//@Override + public function sampleGrid_($image, + $dimensionX, + $dimensionY, + $transform) { + if ($dimensionX <= 0 || $dimensionY <= 0) { + throw NotFoundException::getNotFoundInstance(); + } + $bits = new BitMatrix($dimensionX, $dimensionY); + $points = fill_array(0,2 * $dimensionX,0.0); + for ($y = 0; $y < $dimensionY; $y++) { + $max = count($points); + $iValue = (float) $y + 0.5; + for ($x = 0; $x < $max; $x += 2) { + $points[$x] = (float) ($x / 2) + 0.5; + $points[$x + 1] = $iValue; + } + $transform->transformPoints($points); +// Quick check to see if points transformed to something inside the image; +// sufficient to check the endpoints + $this->checkAndNudgePoints($image, $points); + try { + for ($x = 0; $x < $max; $x += 2) { + if ($image->get((int) $points[$x], (int) $points[$x + 1])) { +// Black(-ish) pixel + $bits->set($x / 2, $y); + } + } + } catch (\Exception $aioobe) {//ArrayIndexOutOfBoundsException +// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting +// transform gets "twisted" such that it maps a straight line of points to a set of points +// whose endpoints are in bounds, but others are not. There is probably some mathematical +// way to detect this about the transformation that I don't know yet. +// This results in an ugly runtime exception despite our clever checks above -- can't have +// that. We could check each point's coordinates but that feels duplicative. We settle for +// catching and wrapping ArrayIndexOutOfBoundsException. + throw NotFoundException::getNotFoundInstance(); + } + } + return $bits; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php new file mode 100755 index 00000000..97f05678 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php @@ -0,0 +1,47 @@ +Encapsulates the result of detecting a barcode in an image. This includes the raw + * matrix of black/white pixels corresponding to the barcode, and possibly points of interest + * in the image, like the location of finder patterns or corners of the barcode in the image.

+ * + * @author Sean Owen + */ +class DetectorResult { + + private $bits; + private $points; + + public function __construct($bits, $points) { + $this->bits = $bits; + $this->points = $points; + } + + public final function getBits() { + return $this->bits; + } + + public final function getPoints() { + return $this->points; + } + +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php new file mode 100755 index 00000000..2df580f4 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php @@ -0,0 +1,206 @@ +luminances = self::$EMPTY; + $this->buckets = fill_array(0, self::$LUMINANCE_BUCKETS,0); + $this->source = $source; + } + +// Applies simple sharpening to the row data to improve performance of the 1D Readers. +//@Override + public function getBlackRow($y, $row=null) { + $this->source = $this->getLuminanceSource(); + $width = $this->source->getWidth(); + if ($row == null || $row->getSize() < $width) { + $row = new BitArray($width); + } else { + $row->clear(); + } + + $this->initArrays($width); + $localLuminances = $this->source->getRow($y, $this->luminances); + $localBuckets = $this->buckets; + for ($x = 0; $x < $width; $x++) { + $pixel = $localLuminances[$x] & 0xff; + $localBuckets[$pixel >> self::$LUMINANCE_SHIFT]++; + } + $blackPoint = $this->estimateBlackPoint($localBuckets); + + $left = $localLuminances[0] & 0xff; + $center = $localLuminances[1] & 0xff; + for ($x = 1; $x < $width - 1; $x++) { + $right = $localLuminances[$x + 1] & 0xff; +// A simple -1 4 -1 box filter with a weight of 2. + $luminance = (($center * 4) - $left - $right) / 2; + if ($luminance < $blackPoint) { + $row->set($x); + } + $left = $center; + $center = $right; + } + return $row; + } + +// Does not sharpen the data, as this call is intended to only be used by 2D Readers. +//@Override + public function getBlackMatrix(){ + $source = $this->getLuminanceSource(); + $width = $source->getWidth(); + $height = $source->getHeight(); + $matrix = new BitMatrix($width, $height); + +// Quickly calculates the histogram by sampling four rows from the image. This proved to be +// more robust on the blackbox tests than sampling a diagonal as we used to do. + $this->initArrays($width); + $localBuckets = $this->buckets; + for ($y = 1; $y < 5; $y++) { + $row = intval($height * $y / 5); + $localLuminances = $source->getRow($row, $this->luminances); + $right = intval(($width * 4) / 5); + for ($x = intval($width / 5); $x < $right; $x++) { + $pixel = intval32bits($localLuminances[intval($x)] & 0xff); + $localBuckets[intval32bits($pixel >> self::$LUMINANCE_SHIFT)]++; + } + } + $blackPoint = $this->estimateBlackPoint($localBuckets); + +// We delay reading the entire image luminance until the black point estimation succeeds. +// Although we end up reading four rows twice, it is consistent with our motto of +// "fail quickly" which is necessary for continuous scanning. + $localLuminances = $source->getMatrix(); + for ($y = 0; $y < $height; $y++) { + $offset = $y * $width; + for ($x = 0; $x< $width; $x++) { + $pixel = intval($localLuminances[$offset + $x] & 0xff); + if ($pixel < $blackPoint) { + $matrix->set($x, $y); + } + } + } + + return $matrix; + } + +//@Override + public function createBinarizer($source) { + return new GlobalHistogramBinarizer($source); + } + + private function initArrays($luminanceSize) { + if (count($this->luminances) < $luminanceSize) { + $this->luminances = array(); + } + for ($x = 0; $x < self::$LUMINANCE_BUCKETS; $x++) { + $this->buckets[$x] = 0; + } + } + + private static function estimateBlackPoint($buckets){ +// Find the tallest peak in the histogram. + $numBuckets = count($buckets); + $maxBucketCount = 0; + $firstPeak = 0; + $firstPeakSize = 0; + for ($x = 0; $x < $numBuckets; $x++) { + if ($buckets[$x] > $firstPeakSize) { + $firstPeak = $x; + $firstPeakSize = $buckets[$x]; + } + if ($buckets[$x] > $maxBucketCount) { + $maxBucketCount = $buckets[$x]; + } + } + +// Find the second-tallest peak which is somewhat far from the tallest peak. + $secondPeak = 0; + $secondPeakScore = 0; + for ($x = 0; $x < $numBuckets; $x++) { + $distanceToBiggest = $x - $firstPeak; +// Encourage more distant second peaks by multiplying by square of distance. + $score = $buckets[$x] * $distanceToBiggest * $distanceToBiggest; + if ($score > $secondPeakScore) { + $secondPeak = $x; + $secondPeakScore = $score; + } + } + +// Make sure firstPeak corresponds to the black peak. + if ($firstPeak > $secondPeak) { + $temp = $firstPeak; + $firstPeak = $secondPeak; + $secondPeak = $temp; + } + +// If there is too little contrast in the image to pick a meaningful black point, throw rather +// than waste time trying to decode the image, and risk false positives. + if ($secondPeak - $firstPeak <= $numBuckets / 16) { + throw NotFoundException::getNotFoundInstance(); + } + +// Find a valley between them that is low and closer to the white peak. + $bestValley = $secondPeak - 1; + $bestValleyScore = -1; + for ($x = $secondPeak - 1; $x > $firstPeak; $x--) { + $fromFirst = $x - $firstPeak; + $score = $fromFirst * $fromFirst * ($secondPeak - $x) * ($maxBucketCount - $buckets[$x]); + if ($score > $bestValleyScore) { + $bestValley = $x; + $bestValleyScore = $score; + } + } + + return intval32bits($bestValley << self::$LUMINANCE_SHIFT); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php new file mode 100755 index 00000000..30c3aee2 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php @@ -0,0 +1,177 @@ +Checks a set of points that have been transformed to sample points on an image against + * the image's dimensions to see if the point are even within the image.

+ * + *

This method will actually "nudge" the endpoints back onto the image if they are found to be + * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder + * patterns in an image where the QR Code runs all the way to the image border.

+ * + *

For efficiency, the method will check points from either end of the line until one is found + * to be within the image. Because the set of points are assumed to be linear, this is valid.

+ * + * @param image image into which the points should map + * @param points actual points in x1,y1,...,xn,yn form + * @throws NotFoundException if an endpoint is lies outside the image boundaries + */ + protected static function checkAndNudgePoints($image, + $points) { + $width = $image->getWidth(); + $height = $image->getHeight(); +// Check and nudge points from start until we see some that are OK: + $nudged = true; + for ($offset = 0; $offset < count($points) && $nudged; $offset += 2) { + $x = (int) $points[$offset]; + $y = (int) $points[$offset + 1]; + if ($x < -1 || $x > $width || $y < -1 || $y > $height) { + throw NotFoundException::getNotFoundInstance(); + } + $nudged = false; + if ($x == -1) { + $points[$offset] = 0.0; + $nudged = true; + } else if ($x == $width) { + $points[$offset] = $width - 1; + $nudged = true; + } + if ($y == -1) { + $points[$offset + 1] = 0.0; + $nudged = true; + } else if ($y == $height) { + $points[$offset + 1] = $height - 1; + $nudged = true; + } + } +// Check and nudge points from end: + $nudged = true; + for ($offset = count($points) - 2; $offset >= 0 && $nudged; $offset -= 2) { + $x = (int) $points[$offset]; + $y = (int) $points[$offset + 1]; + if ($x < -1 || $x > $width || $y < -1 || $y > $height) { + throw NotFoundException::getNotFoundInstance(); + } + $nudged = false; + if ($x == -1) { + $points[$offset] = 0.0; + $nudged = true; + } else if ($x == $width) { + $points[$offset] = $width - 1; + $nudged = true; + } + if ($y == -1) { + $points[$offset + 1] = 0.0; + $nudged = true; + } else if ($y == $height) { + $points[$offset + 1] = $height - 1; + $nudged = true; + } + } + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php new file mode 100755 index 00000000..670562c3 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php @@ -0,0 +1,259 @@ +matrix != null) { + return $this->matrix; + } + $source = $this->getLuminanceSource(); + $width = $source->getWidth(); + $height = $source->getHeight(); + if ($width >= self::$MINIMUM_DIMENSION && $height >= self::$MINIMUM_DIMENSION) { + $luminances = $source->getMatrix(); + $subWidth = $width >> self::$BLOCK_SIZE_POWER; + if (($width & self::$BLOCK_SIZE_MASK) != 0) { + $subWidth++; + } + $subHeight = $height >> self::$BLOCK_SIZE_POWER; + if (($height & self::$BLOCK_SIZE_MASK) != 0) { + $subHeight++; + } + $blackPoints = $this->calculateBlackPoints($luminances, $subWidth, $subHeight, $width, $height); + + $newMatrix = new BitMatrix($width, $height); + $this->calculateThresholdForBlock($luminances, $subWidth, $subHeight, $width, $height, $blackPoints, $newMatrix); + $this->matrix = $newMatrix; + } else { +// If the image is too small, fall back to the global histogram approach. + $this->matrix = parent::getBlackMatrix(); + } + return $this->matrix; + } + +//@Override + public function createBinarizer($source) { + return new HybridBinarizer($source); + } + + /** + * For each block in the image, calculate the average black point using a 5x5 grid + * of the blocks around it. Also handles the corner cases (fractional blocks are computed based + * on the last pixels in the row/column which are also used in the previous block). + */ + private static function calculateThresholdForBlock($luminances, + $subWidth, + $subHeight, + $width, + $height, + $blackPoints, + $matrix) { + for ($y = 0; $y < $subHeight; $y++) { + $yoffset = intval32bits($y << self::$BLOCK_SIZE_POWER); + $maxYOffset = $height - self::$BLOCK_SIZE; + if ($yoffset > $maxYOffset) { + $yoffset = $maxYOffset; + } + for ($x = 0; $x < $subWidth; $x++) { + $xoffset = intval32bits($x << self::$BLOCK_SIZE_POWER); + $maxXOffset = $width - self::$BLOCK_SIZE; + if ($xoffset > $maxXOffset) { + $xoffset = $maxXOffset; + } + $left = self::cap($x, 2, $subWidth - 3); + $top = self::cap($y, 2, $subHeight - 3); + $sum = 0; + for ($z = -2; $z <= 2; $z++) { + $blackRow = $blackPoints[$top + $z]; + $sum += $blackRow[$left - 2] + $blackRow[$left - 1] + $blackRow[$left] + $blackRow[$left + 1] + $blackRow[$left + 2]; + } + $average = intval($sum / 25); + + self::thresholdBlock($luminances, $xoffset, $yoffset, $average, $width, $matrix); + } + } + } + + private static function cap($value, $min, $max) { + if($value<$min){ + return $min; + }elseif($value>$max){ + return $max; + }else{ + return $value; + } + + + + } + + /** + * Applies a single threshold to a block of pixels. + */ + private static function thresholdBlock($luminances, + $xoffset, + $yoffset, + $threshold, + $stride, + $matrix) { + + for ($y = 0, $offset = $yoffset * $stride + $xoffset; $y < self::$BLOCK_SIZE; $y++, $offset += $stride) { + for ($x = 0; $x < self::$BLOCK_SIZE; $x++) { +// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0. + if (($luminances[$offset + $x] & 0xFF) <= $threshold) { + $matrix->set($xoffset + $x, $yoffset + $y); + } + } + } + } + + /** + * Calculates a single black point for each block of pixels and saves it away. + * See the following thread for a discussion of this algorithm: + * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 + */ + private static function calculateBlackPoints($luminances, + $subWidth, + $subHeight, + $width, + $height) { + $blackPoints = fill_array(0,$subHeight,0); + foreach($blackPoints as $key=>$point){ + $blackPoints[$key] = fill_array(0,$subWidth,0); + } + for ($y = 0; $y < $subHeight; $y++) { + $yoffset = intval32bits($y << self::$BLOCK_SIZE_POWER); + $maxYOffset = $height - self::$BLOCK_SIZE; + if ($yoffset > $maxYOffset) { + $yoffset = $maxYOffset; + } + for ($x = 0; $x < $subWidth; $x++) { + $xoffset = intval32bits($x << self::$BLOCK_SIZE_POWER); + $maxXOffset = $width - self::$BLOCK_SIZE; + if ($xoffset > $maxXOffset) { + $xoffset = $maxXOffset; + } + $sum = 0; + $min = 0xFF; + $max = 0; + for ($yy = 0, $offset = $yoffset * $width + $xoffset; $yy < self::$BLOCK_SIZE; $yy++, $offset += $width) { + for ($xx = 0; $xx < self::$BLOCK_SIZE; $xx++) { + $pixel = intval32bits(intval($luminances[intval($offset +$xx)]) & 0xFF); + $sum += $pixel; +// still looking for good contrast + if ($pixel < $min) { + $min = $pixel; + } + if ($pixel > $max) { + $max = $pixel; + } + } +// short-circuit min/max tests once dynamic range is met + if ($max - $min > self::$MIN_DYNAMIC_RANGE) { +// finish the rest of the rows quickly + for ($yy++, $offset += $width; $yy < self::$BLOCK_SIZE; $yy++, $offset += $width) { + for ($xx = 0; $xx < self::$BLOCK_SIZE; $xx++) { + $sum += intval32bits($luminances[$offset +$xx] & 0xFF); + } + } + } + } + +// The default estimate is the average of the values in the block. + $average = intval32bits($sum >> (self::$BLOCK_SIZE_POWER * 2)); + if ($max - $min <= self::$MIN_DYNAMIC_RANGE) { +// If variation within the block is low, assume this is a block with only light or only +// dark pixels. In that case we do not want to use the average, as it would divide this +// low contrast area into black and white pixels, essentially creating data out of noise. +// +// The default assumption is that the block is light/background. Since no estimate for +// the level of dark pixels exists locally, use half the min for the block. + $average = intval($min / 2); + + if ($y > 0 && $x > 0) { +// Correct the "white background" assumption for blocks that have neighbors by comparing +// the pixels in this block to the previously calculated black points. This is based on +// the fact that dark barcode symbology is always surrounded by some amount of light +// background for which reasonable black point estimates were made. The bp estimated at +// the boundaries is used for the interior. + +// The (min < bp) is arbitrary but works better than other heuristics that were tried. + $averageNeighborBlackPoint = + intval(($blackPoints[$y - 1][$x] + (2 * $blackPoints[$y][$x - 1]) + $blackPoints[$y - 1][$x - 1]) / 4); + if ($min < $averageNeighborBlackPoint) { + $average = $averageNeighborBlackPoint; + } + } + } + $blackPoints[$y][$x] = intval($average); + } + } + return $blackPoints; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php new file mode 100755 index 00000000..7c046a8b --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php @@ -0,0 +1,161 @@ +This class implements a perspective transform in two dimensions. Given four source and four + * destination points, it will compute the transformation implied between them. The code is based + * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.

+ * + * @author Sean Owen + */ +final class PerspectiveTransform { + + private $a11; + private $a12; + private $a13; + private $a21; + private $a22; + private $a23; + private $a31; + private $a32; + private $a33; + + private function __construct($a11, $a21, $a31, + $a12, $a22, $a32, + $a13, $a23, $a33) { + $this->a11 = $a11; + $this->a12 = $a12; + $this->a13 = $a13; + $this->a21 = $a21; + $this->a22 = $a22; + $this->a23 = $a23; + $this->a31 = $a31; + $this->a32 = $a32; + $this->a33 = $a33; + } + + public static function quadrilateralToQuadrilateral($x0, $y0, + $x1, $y1, + $x2, $y2, + $x3, $y3, + $x0p, $y0p, + $x1p, $y1p, + $x2p, $y2p, + $x3p, $y3p) { + + $qToS = self::quadrilateralToSquare($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3); + $sToQ = self::squareToQuadrilateral($x0p, $y0p, $x1p, $y1p, $x2p, $y2p, $x3p, $y3p); + return $sToQ->times($qToS); + } + + public function transformPoints(&$points,&$yValues=0) { + if($yValues) { + $this->transformPoints_($points,$yValues); + return; + } + $max =count($points); + $a11 = $this->a11; + $a12 = $this->a12; + $a13 = $this->a13; + $a21 = $this->a21; + $a22 = $this->a22; + $a23 = $this->a23; + $a31 = $this->a31; + $a32 = $this->a32; + $a33 = $this->a33; + for ($i = 0; $i < $max; $i += 2) { + $x = $points[$i]; + $y = $points[$i + 1]; + $denominator = $a13 * $x + $a23 * $y + $a33; + $points[$i] = ($a11 * $x + $a21 * $y + $a31) / $denominator; + $points[$i + 1] = ($a12 * $x + $a22 * $y +$a32) / $denominator; + } + } + + public function transformPoints_(&$xValues, &$yValues) { + $n = count($xValues); + for ($i = 0; $i < $n; $i ++) { + $x = $xValues[$i]; + $y = $yValues[$i]; + $denominator = $this->a13 * $x + $this->a23 * $y + $this->a33; + $xValues[$i] = ($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator; + $yValues[$i] = ($this->a12 * $x + $this->a22 *$y + $this->a32) / $denominator; + } + } + + public static function squareToQuadrilateral($x0, $y0, + $x1, $y1, + $x2, $y2, + $x3, $y3) { + $dx3 = $x0 - $x1 + $x2 - $x3; + $dy3 = $y0 - $y1 + $y2 - $y3; + if ($dx3 == 0.0 && $dy3 == 0.0) { +// Affine + return new PerspectiveTransform($x1 - $x0, $x2 - $x1, $x0, + $y1 - $y0, $y2 - $y1, $y0, + 0.0, 0.0, 1.0); + } else { + $dx1 = $x1 - $x2; + $dx2 = $x3 - $x2; + $dy1 = $y1 - $y2; + $dy2 = $y3 - $y2; + $denominator = $dx1 * $dy2 - $dx2 * $dy1; + $a13 = ($dx3 * $dy2 - $dx2 * $dy3) / $denominator; + $a23 = ($dx1 * $dy3 - $dx3 * $dy1) / $denominator; + return new PerspectiveTransform($x1 - $x0 + $a13 * $x1, $x3 - $x0 + $a23 * $x3, $x0, + $y1 - $y0 + $a13 * $y1, $y3 - $y0 + $a23 * $y3, $y0, + $a13, $a23, 1.0); + } + } + + public static function quadrilateralToSquare($x0, $y0, + $x1, $y1, + $x2, $y2, + $x3, $y3) { +// Here, the adjoint serves as the inverse: + return self::squareToQuadrilateral($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)->buildAdjoint(); + } + + function buildAdjoint() { +// Adjoint is the transpose of the cofactor matrix: + return new PerspectiveTransform($this->a22 * $this->a33 - $this->a23 * $this->a32, + $this->a23 * $this->a31 - $this->a21 * $this->a33, + $this->a21 * $this->a32 - $this->a22 * $this->a31, + $this->a13 * $this->a32 - $this->a12 * $this->a33, + $this->a11 * $this->a33 - $this->a13 * $this->a31, + $this->a12 * $this->a31 - $this->a11 * $this->a32, + $this->a12 * $this->a23 - $this->a13 * $this->a22, + $this->a13 * $this->a21 - $this->a11 * $this->a23, + $this->a11 * $this->a22 - $this->a12 * $this->a21); + } + + function times($other) { + return new PerspectiveTransform($this->a11 * $other->a11 + $this->a21 * $other->a12 + $this->a31 * $other->a13, + $this->a11 * $other->a21 + $this->a21 * $other->a22 + $this->a31 * $other->a23, + $this->a11 * $other->a31 + $this->a21 * $other->a32 + $this->a31 * $other->a33, + $this->a12 * $other->a11 + $this->a22 * $other->a12 + $this->a32 * $other->a13, + $this->a12 * $other->a21 + $this->a22 * $other->a22 + $this->a32 * $other->a23, + $this->a12 * $other->a31 + $this->a22 * $other->a32 + $this->a32 * $other->a33, + $this->a13 * $other->a11 + $this->a23 * $other->a12 + $this->a33 * $other->a13, + $this->a13 * $other->a21 + $this->a23 * $other->a22 + $this->a33 * $other->a23, + $this->a13 * $other->a31 + $this->a23 * $other->a32 + $this->a33 * $other->a33); + + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php new file mode 100755 index 00000000..6ae71cc0 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php @@ -0,0 +1,93 @@ +>= 1; + $num++; + } + return $num; +} +function intval32bits($value) +{ + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) + $value = -((~$value & 0xFFFFFFFF) + 1); + + return $value; +} + +function uRShift($a, $b) +{ + + if($b == 0) return $a; + return ($a >> $b) & ~(1<<(8*PHP_INT_SIZE-1)>>($b-1)); +} +/* +function sdvig3($num,$count=1){//>>> 32 bit + $s = decbin($num); + + $sarray = str_split($s,1); + $sarray = array_slice($sarray,-32);//32bit + + for($i=0;$i<=1;$i++) { + array_pop($sarray); + array_unshift($sarray, '0'); + } + return bindec(implode($sarray)); +} +*/ + +function sdvig3($a,$b) { + + if ($a >= 0) { + return bindec(decbin($a>>$b)); //simply right shift for positive number + } + + $bin = decbin($a>>$b); + + $bin = substr($bin, $b); // zero fill on the left side + + $o = bindec($bin); + return $o; +} + +function floatToIntBits($float_val) +{ + $int = unpack('i', pack('f', $float_val)); + return $int[1]; +} + +function fill_array($index,$count,$value){ + if($count<=0){ + return array(0); + }else { + return array_fill($index, $count, $value); + } +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php new file mode 100755 index 00000000..1d3de23d --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php @@ -0,0 +1,46 @@ +A somewhat generic detector that looks for a barcode-like rectangular region within an image. + * It looks within a mostly white region of an image for a region of black and white, but mostly + * black. It returns the four corners of the region, as best it can determine.

+ * + * @author Sean Owen + * @port Ashot Khanamiryan + */ +class MonochromeRectangleDetector { + private static $MAX_MODULES = 32; + private $image; + function __construct($image){ + $this->image = $image; + + } + + /** + *

Detects a rectangular region of black and white -- mostly black -- with a region of mostly + * white, in an image.

+ * + * @return {@link ResultPoint}[] describing the corners of the rectangular region. The first and + * last points are opposed on the diagonal, as are the second and third. The first point will be + * the topmost point and the last, the bottommost. The second point will be leftmost and the + * third, the rightmost + * @throws NotFoundException if no Data Matrix Code can be found + */ + public function detect(){ + + $height = $this->image->getHeight(); + $width = $this->image->getWidth(); + $halfHeight = $height / 2; + $halfWidth = $width / 2; + + $deltaY = max(1, $height / (self::$MAX_MODULES * 8)); + $deltaX = max(1, $width / (self::$MAX_MODULES * 8)); + + + $top = 0; + $bottom = $height; + $left = 0; + $right = $width; + $pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right, + $halfHeight, -$deltaY, $top, $bottom, $halfWidth / 2); + $top = (int) $pointA->getY() - 1; + $pointB = $this->findCornerFromCenter($halfWidth, -$deltaX, $left,$right, + $halfHeight, 0, $top, $bottom, $halfHeight / 2); + $left = (int) $pointB->getX() - 1; + $pointC = $this->findCornerFromCenter($halfWidth, $deltaX, $left, $right, + $halfHeight, 0, $top, $bottom, $halfHeight / 2); + $right = (int) $pointC->getX() + 1; + $pointD = $this->findCornerFromCenter($halfWidth, 0, $left, $right, + $halfHeight, $deltaY, $top, $bottom, $halfWidth / 2); + $bottom = (int) $pointD->getY() + 1; + + // Go try to find po$A again with better information -- might have been off at first. + $pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right, + $halfHeight, -$deltaY, $top, $bottom, $halfWidth / 4); + + return new ResultPoint( $pointA, $pointB, $pointC, $pointD ); + + } + + + + /** + * Attempts to locate a corner of the barcode by scanning up, down, left or right from a center + * point which should be within the barcode. + * + * @param centerX center's x component (horizontal) + * @param deltaX same as deltaY but change in x per step instead + * @param left minimum value of x + * @param right maximum value of x + * @param centerY center's y component (vertical) + * @param deltaY change in y per step. If scanning up this is negative; down, positive; + * left or right, 0 + * @param top minimum value of y to search through (meaningless when di == 0) + * @param bottom maximum value of y + * @param maxWhiteRun maximum run of white pixels that can still be considered to be within + * the barcode + * @return a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found + * @throws NotFoundException if such a point cannot be found + */ + private function findCornerFromCenter($centerX, + $deltaX, + $left, + $right, + $centerY, + $deltaY, + $top, + $bottom, + $maxWhiteRun){ + $lastRange = null; + for ($y = $centerY, $x = $centerX; + $y < $bottom && $y >= $top && $x < $right && $x >= $left; + $y += $deltaY, $x += $deltaX) { + $range = 0; + if ($deltaX == 0) { + // horizontal slices, up and down + $range = $this->blackWhiteRange($y, $maxWhiteRun, $left, $right, true); + } else { + // vertical slices, left and right + $range = $this->blackWhiteRange($x, $maxWhiteRun, $top, $bottom, false); + } + if ($range == null) { + if ($lastRange == null) { + throw NotFoundException::getNotFoundInstance(); + } + // lastRange was found + if ($deltaX == 0) { + $lastY = $y - $deltaY; + if ($lastRange[0] < $centerX) { + if ($lastRange[1] > $centerX) { + // straddle, choose one or the other based on direction + return new ResultPoint($deltaY > 0 ? $lastRange[0] : $lastRange[1], $lastY); + } + return new ResultPoint($lastRange[0], $lastY); + } else { + return new ResultPoint($lastRange[1], $lastY); + } + } else { + $lastX = $x - $deltaX; + if ($lastRange[0] < $centerY) { + if ($lastRange[1] > $centerY) { + return new ResultPoint($lastX, $deltaX < 0 ? $lastRange[0] : $lastRange[1]); + } + return new ResultPoint($lastX, $lastRange[0]); + } else { + return new ResultPoint($lastX, $lastRange[1]); + } + } + } + $lastRange = $range; + } + throw NotFoundException::getNotFoundInstance(); + } + + + + /** + * Computes the start and end of a region of pixels, either horizontally or vertically, that could + * be part of a Data Matrix barcode. + * + * @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location) + * where we are scanning. If scanning vertically it's the column, the fixed horizontal location + * @param maxWhiteRun largest run of white pixels that can still be considered part of the + * barcode region + * @param minDim minimum pixel location, horizontally or vertically, to consider + * @param maxDim maximum pixel location, horizontally or vertically, to consider + * @param horizontal if true, we're scanning left-right, instead of up-down + * @return int[] with start and end of found range, or null if no such range is found + * (e.g. only white was found) + */ + + private function blackWhiteRange($fixedDimension, $maxWhiteRun, $minDim, $maxDim, $horizontal){ + $center = ($minDim + $maxDim) / 2; + + // Scan left/up first + $start = $center; + while ($start >= $minDim) { + if ($horizontal ? $this->image->get($start, $fixedDimension) : $this->image->get($fixedDimension, $start)) { + $start--; + } else { + $whiteRunStart = $start; + do { + $start--; + } while ($start >= $minDim && !($horizontal ? $this->image->get($start, $fixedDimension) : + $this->image->get($fixedDimension, $start))); + $whiteRunSize = $whiteRunStart - $start; + if ($start < $minDim || $whiteRunSize > $maxWhiteRun) { + $start = $whiteRunStart; + break; + } + } + } + $start++; + + // Then try right/down + $end = $center; + while ($end < $maxDim) { + if ($horizontal ? $this->image->get($end, $fixedDimension) : $this->image->get($fixedDimension, $end)) { + $end++; + } else { + $whiteRunStart = $end; + do { + $end++; + } while ($end < $maxDim && !($horizontal ? $this->image->get($end, $fixedDimension) : + $this->image->get($fixedDimension, $end))); + $whiteRunSize = $end - $whiteRunStart; + if ($end >= $maxDim || $whiteRunSize > $maxWhiteRun) { + $end = $whiteRunStart; + break; + } + } + } + $end--; + + return $end > $start ? array($start, $end) : null; + } +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php new file mode 100755 index 00000000..ea9d7b9d --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php @@ -0,0 +1,181 @@ +This class contains utility methods for performing mathematical operations over + * the Galois Fields. Operations use a given primitive polynomial in calculations.

+ * + *

Throughout this package, elements of the GF are represented as an {@code int} + * for convenience and speed (but at the cost of memory). + *

+ * + * @author Sean Owen + * @author David Olivier + */ +final class GenericGF { + + public static $AZTEC_DATA_12; + public static $AZTEC_DATA_10; + public static $AZTEC_DATA_6; + public static $AZTEC_PARAM; + public static $QR_CODE_FIELD_256; + public static $DATA_MATRIX_FIELD_256; + public static $AZTEC_DATA_8; + public static $MAXICODE_FIELD_64; + + private $expTable; + private $logTable; + private $zero; + private $one; + private $size; + private $primitive; + private $generatorBase; + + + public static function Init(){ + self::$AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1 + self::$AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1 + self::$AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1 + self::$AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1 + self::$QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 + self::$DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1 + self::$AZTEC_DATA_8 = self::$DATA_MATRIX_FIELD_256; + self::$MAXICODE_FIELD_64 = self::$AZTEC_DATA_6; + } + + + /** + * Create a representation of GF(size) using the given primitive polynomial. + * + * @param primitive irreducible polynomial whose coefficients are represented by + * the bits of an int, where the least-significant bit represents the constant + * coefficient + * @param size the size of the field + * @param b the factor b in the generator polynomial can be 0- or 1-based + * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))). + * In most cases it should be 1, but for QR code it is 0. + */ + public function __construct($primitive, $size, $b) { + $this->primitive = $primitive; + $this->size = $size; + $this->generatorBase = $b; + + $this->expTable = array(); + $this->logTable =array(); + $x = 1; + for ($i = 0; $i < $size; $i++) { + $this->expTable[$i] = $x; + $x *= 2; // we're assuming the generator alpha is 2 + if ($x >= $size) { + $x ^= $primitive; + $x &= $size-1; + } + } + for ($i = 0; $i < $size-1; $i++) { + $this->logTable[$this->expTable[$i]] = $i; + } + // logTable[0] == 0 but this should never be used + $this->zero = new GenericGFPoly($this, array(0)); + $this->one = new GenericGFPoly($this, array(1)); + } + + function getZero() { + return $this->zero; + } + + function getOne() { + return $this->one; + } + + /** + * @return the monomial representing coefficient * x^degree + */ + function buildMonomial($degree, $coefficient) { + if ($degree < 0) { + throw new \InvalidArgumentException(); + } + if ($coefficient == 0) { + return $this->zero; + } + $coefficients = fill_array(0,$degree+1,0);//new int[degree + 1]; + $coefficients[0] = $coefficient; + return new GenericGFPoly($this, $coefficients); + } + + /** + * Implements both addition and subtraction -- they are the same in GF(size). + * + * @return sum/difference of a and b + */ + static function addOrSubtract($a, $b) { + return $a ^ $b; + } + + /** + * @return 2 to the power of a in GF(size) + */ + function exp($a) { + return $this->expTable[$a]; + } + + /** + * @return base 2 log of a in GF(size) + */ + function log($a) { + if ($a == 0) { + throw new \InvalidArgumentException(); + } + return $this->logTable[$a]; + } + + /** + * @return multiplicative inverse of a + */ + function inverse($a) { + if ($a == 0) { + throw new Exception(); + } + return $this->expTable[$this->size - $this->logTable[$a] - 1]; + } + + /** + * @return product of a and b in GF(size) + */ + function multiply($a, $b) { + if ($a == 0 || $b == 0) { + return 0; + } + return $this->expTable[($this->logTable[$a] + $this->logTable[$b]) % ($this->size - 1)]; + } + + public function getSize() { + return $this->size; + } + + public function getGeneratorBase() { + return $this->generatorBase; + } + + // @Override + public function toString() { + return "GF(0x" . dechex(intval($this->primitive)) . ',' . $this->size . ')'; + } + +} +GenericGF::Init(); \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php new file mode 100755 index 00000000..9e9aa333 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php @@ -0,0 +1,268 @@ +Represents a polynomial whose coefficients are elements of a GF. + * Instances of this class are immutable.

+ * + *

Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation.

+ * + * @author Sean Owen + */ +final class GenericGFPoly { + + private $field; + private $coefficients; + + /** + * @param field the {@link GenericGF} instance representing the field to use + * to perform computations + * @param coefficients array coefficients as ints representing elements of GF(size), arranged + * from most significant (highest-power term) coefficient to least significant + * @throws IllegalArgumentException if argument is null or empty, + * or if leading coefficient is 0 and this is not a + * constant polynomial (that is, it is not the monomial "0") + */ + function __construct($field, $coefficients) { + if (count($coefficients) == 0) { + throw new \InvalidArgumentException(); + } + $this->field = $field; + $coefficientsLength = count($coefficients); + if ($coefficientsLength > 1 && $coefficients[0] == 0) { + // Leading term must be non-zero for anything except the constant polynomial "0" + $firstNonZero = 1; + while ($firstNonZero < $coefficientsLength && $coefficients[$firstNonZero] == 0) { + $firstNonZero++; + } + if ($firstNonZero == $coefficientsLength) { + $this->coefficients = array(0); + } else { + $this->coefficients = fill_array(0,$coefficientsLength - $firstNonZero,0); + $this->coefficients = arraycopy($coefficients, + $firstNonZero, + $this->coefficients, + 0, + count($this->coefficients)); + } + } else { + $this->coefficients = $coefficients; + } + } + + function getCoefficients() { + return $this->coefficients; + } + + /** + * @return degree of this polynomial + */ + function getDegree() { + return count($this->coefficients) - 1; + } + + /** + * @return true iff this polynomial is the monomial "0" + */ + function isZero() { + return $this->coefficients[0] == 0; + } + + /** + * @return coefficient of x^degree term in this polynomial + */ + function getCoefficient($degree) { + return $this->coefficients[count($this->coefficients) - 1 - $degree]; + } + + /** + * @return evaluation of this polynomial at a given point + */ + function evaluateAt($a) { + if ($a == 0) { + // Just return the x^0 coefficient + return $this->getCoefficient(0); + } + $size = count($this->coefficients); + if ($a == 1) { + // Just the sum of the coefficients + $result = 0; + foreach ($this->coefficients as $coefficient ) { + $result = GenericGF::addOrSubtract($result, $coefficient); + } + return $result; + } + $result = $this->coefficients[0]; + for ($i = 1; $i < $size; $i++) { + $result = GenericGF::addOrSubtract($this->field->multiply($a, $result), $this->coefficients[$i]); + } + return $result; + } + + function addOrSubtract($other) { + if ($this->field !== $other->field) { + throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field"); + } + if ($this->isZero()) { + return $other; + } + if ($other->isZero()) { + return $this; + } + + $smallerCoefficients = $this->coefficients; + $largerCoefficients = $other->coefficients; + if (count($smallerCoefficients) > count($largerCoefficients)) { + $temp = $smallerCoefficients; + $smallerCoefficients = $largerCoefficients; + $largerCoefficients = $temp; + } + $sumDiff = fill_array(0,count($largerCoefficients),0); + $lengthDiff = count($largerCoefficients) - count($smallerCoefficients); + // Copy high-order terms only found in higher-degree polynomial's coefficients + $sumDiff = arraycopy($largerCoefficients, 0, $sumDiff, 0, $lengthDiff); + + for ($i = $lengthDiff; $i < count($largerCoefficients); $i++) { + $sumDiff[$i] = GenericGF::addOrSubtract($smallerCoefficients[$i - $lengthDiff], $largerCoefficients[$i]); + } + + return new GenericGFPoly($this->field, $sumDiff); + } + + function multiply($other) { + if(is_int($other)){ + return $this->multiply_($other); + } + if ($this->field !== $other->field) { + throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field"); + } + if ($this->isZero() || $other->isZero()) { + return $this->field->getZero(); + } + $aCoefficients = $this->coefficients; + $aLength = count($aCoefficients); + $bCoefficients = $other->coefficients; + $bLength = count($bCoefficients); + $product = fill_array(0,$aLength + $bLength - 1,0); + for ($i = 0; $i < $aLength; $i++) { + $aCoeff = $aCoefficients[$i]; + for ($j = 0; $j < $bLength; $j++) { + $product[$i + $j] = GenericGF::addOrSubtract($product[$i + $j], + $this->field->multiply($aCoeff, $bCoefficients[$j])); + } + } + return new GenericGFPoly($this->field, $product); + } + + function multiply_($scalar) { + if ($scalar == 0) { + return $this->field->getZero(); + } + if ($scalar == 1) { + return $this; + } + $size = count($this->coefficients); + $product = fill_array(0,$size,0); + for ($i = 0; $i < $size; $i++) { + $product[$i] = $this->field->multiply($this->coefficients[$i], $scalar); + } + return new GenericGFPoly($this->field, $product); + } + + function multiplyByMonomial($degree, $coefficient) { + if ($degree < 0) { + throw new \InvalidArgumentException(); + } + if ($coefficient == 0) { + return $this->field->getZero(); + } + $size = count($this->coefficients); + $product = fill_array(0,$size + $degree,0); + for ($i = 0; $i < $size; $i++) { + $product[$i] = $this->field->multiply($this->coefficients[$i], $coefficient); + } + return new GenericGFPoly($this->field, $product); + } + + function divide($other) { + if ($this->field !==$other->field) { + throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field"); + } + if ($other->isZero()) { + throw new \InvalidArgumentException("Divide by 0"); + } + + $quotient = $this->field->getZero(); + $remainder = $this; + + $denominatorLeadingTerm = $other->getCoefficient($other->getDegree()); + $inverseDenominatorLeadingTerm = $this->field->inverse($denominatorLeadingTerm); + + while ($remainder->getDegree() >= $other->getDegree() && !$remainder->isZero()) { + $degreeDifference = $remainder->getDegree() - $other->getDegree(); + $scale = $this->field->multiply($remainder->getCoefficient($remainder->getDegree()), $inverseDenominatorLeadingTerm); + $term = $other->multiplyByMonomial($degreeDifference, $scale); + $iterationQuotient = $this->field->buildMonomial($degreeDifference, $scale); + $quotient = $quotient->addOrSubtract($iterationQuotient); + $remainder = $remainder->addOrSubtract($term); + } + + return array($quotient, $remainder ); + } + + //@Override + public function toString() { + $result = ''; + for ($degree = $this->getDegree(); $degree >= 0; $degree--) { + $coefficient = $this->getCoefficient($degree); + if ($coefficient != 0) { + if ($coefficient < 0) { + $result.=" - "; + $coefficient = -$coefficient; + } else { + if (strlen($result) > 0) { + $result .= " + "; + } + } + if ($degree == 0 || $coefficient != 1) { + $alphaPower = $this->field->log($coefficient); + if ($alphaPower == 0) { + $result.='1'; + } else if ($alphaPower == 1) { + $result.='a'; + } else { + $result.="a^"; + $result.=($alphaPower); + } + } + if ($degree != 0) { + if ($degree == 1) { + $result.='x'; + } else { + $result.="x^"; + $result.= $degree; + } + } + } + } + return $result; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php new file mode 100755 index 00000000..3fb1c2ef --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php @@ -0,0 +1,192 @@ +Implements Reed-Solomon decoding, as the name implies.

+ * + *

The algorithm will not be explained here, but the following references were helpful + * in creating this implementation:

+ * + * + * + *

Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation.

+ * + * @author Sean Owen + * @author William Rucklidge + * @author sanfordsquires + */ +final class ReedSolomonDecoder { + + private $field; + + public function __construct($field) { + $this->field = $field; + } + + /** + *

Decodes given set of received codewords, which include both data and error-correction + * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, + * in the input.

+ * + * @param received data and error-correction codewords + * @param twoS number of error-correction codewords available + * @throws ReedSolomonException if decoding fails for any reason + */ + public function decode(&$received, $twoS) { + $poly = new GenericGFPoly($this->field, $received); + $syndromeCoefficients = fill_array(0,$twoS,0); + $noError = true; + for ($i = 0; $i < $twoS; $i++) { + $eval = $poly->evaluateAt($this->field->exp($i + $this->field->getGeneratorBase())); + $syndromeCoefficients[count($syndromeCoefficients) - 1 - $i] = $eval; + if ($eval != 0) { + $noError = false; + } + } + if ($noError) { + return; + } + $syndrome = new GenericGFPoly($this->field, $syndromeCoefficients); + $sigmaOmega = + $this->runEuclideanAlgorithm($this->field->buildMonomial($twoS, 1), $syndrome, $twoS); + $sigma = $sigmaOmega[0]; + $omega = $sigmaOmega[1]; + $errorLocations = $this->findErrorLocations($sigma); + $errorMagnitudes = $this->findErrorMagnitudes($omega, $errorLocations); + for ($i = 0; $i < count($errorLocations); $i++) { + $position = count($received) - 1 - $this->field->log($errorLocations[$i]); + if ($position < 0) { + throw new ReedSolomonException("Bad error location"); + } + $received[$position] = GenericGF::addOrSubtract($received[$position], $errorMagnitudes[$i]); + } + + } + + private function runEuclideanAlgorithm($a, $b, $R) + { + // Assume a's degree is >= b's + if ($a->getDegree() < $b->getDegree()) { + $temp = $a; + $a = $b; + $b = $temp; + } + + $rLast = $a; + $r = $b; + $tLast = $this->field->getZero(); + $t = $this->field->getOne(); + + // Run Euclidean algorithm until r's degree is less than R/2 + while ($r->getDegree() >= $R / 2) { + $rLastLast = $rLast; + $tLastLast = $tLast; + $rLast = $r; + $tLast = $t; + + // Divide rLastLast by rLast, with quotient in q and remainder in r + if ($rLast->isZero()) { + // Oops, Euclidean algorithm already terminated? + throw new ReedSolomonException("r_{i-1} was zero"); + } + $r = $rLastLast; + $q = $this->field->getZero(); + $denominatorLeadingTerm = $rLast->getCoefficient($rLast->getDegree()); + $dltInverse = $this->field->inverse($denominatorLeadingTerm); + while ($r->getDegree() >= $rLast->getDegree() && !$r->isZero()) { + $degreeDiff = $r->getDegree() - $rLast->getDegree(); + $scale = $this->field->multiply($r->getCoefficient($r->getDegree()), $dltInverse); + $q = $q->addOrSubtract($this->field->buildMonomial($degreeDiff, $scale)); + $r = $r->addOrSubtract($rLast->multiplyByMonomial($degreeDiff, $scale)); + } + + $t = $q->multiply($tLast)->addOrSubtract($tLastLast); + + if ($r->getDegree() >= $rLast->getDegree()) { + throw new IllegalStateException("Division algorithm failed to reduce polynomial?"); + } + } + + $sigmaTildeAtZero = $t->getCoefficient(0); + if ($sigmaTildeAtZero == 0) { + throw new ReedSolomonException("sigmaTilde(0) was zero"); + } + + $inverse = $this->field->inverse($sigmaTildeAtZero); + $sigma = $t->multiply($inverse); + $omega = $r->multiply($inverse); + return array($sigma, $omega); + } + + private function findErrorLocations($errorLocator) { + // This is a direct application of Chien's search + $numErrors = $errorLocator->getDegree(); + if ($numErrors == 1) { // shortcut + return array($errorLocator->getCoefficient(1) ); + } + $result = fill_array(0,$numErrors,0); + $e = 0; + for ($i = 1; $i < $this->field->getSize() && $e < $numErrors; $i++) { + if ($errorLocator->evaluateAt($i) == 0) { + $result[$e] = $this->field->inverse($i); + $e++; + } + } + if ($e != $numErrors) { + throw new ReedSolomonException("Error locator degree does not match number of roots"); + } + return $result; + } + + private function findErrorMagnitudes($errorEvaluator, $errorLocations) { + // This is directly applying Forney's Formula + $s = count($errorLocations); + $result = fill_array(0,$s,0); + for ($i = 0; $i < $s; $i++) { + $xiInverse = $this->field->inverse($errorLocations[$i]); + $denominator = 1; + for ($j = 0; $j < $s; $j++) { + if ($i != $j) { + //denominator = field.multiply(denominator, + // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); + // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. + // Below is a funny-looking workaround from Steven Parkes + $term = $this->field->multiply($errorLocations[$j], $xiInverse); + $termPlus1 = ($term & 0x1) == 0 ? $term | 1 : $term & ~1; + $denominator = $this->field->multiply($denominator, $termPlus1); + } + } + $result[$i] = $this->field->multiply($errorEvaluator->evaluateAt($xiInverse), + $this->field->inverse($denominator)); + if ($this->field->getGeneratorBase() != 0) { + $result[$i] = $this->field->multiply($result[$i], $xiInverse); + } + } + return $result; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php new file mode 100755 index 00000000..10ac55ed --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php @@ -0,0 +1,31 @@ +Thrown when an exception occurs during Reed-Solomon decoding, such as when + * there are too many errors to correct.

+* +* @author Sean Owen +*/ +final class ReedSolomonException extends \Exception { + + +} + +?> \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php new file mode 100755 index 00000000..dafdbd4f --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php @@ -0,0 +1,222 @@ +decoder = new Decoder(); + + } + + protected final function getDecoder() { + return $this->decoder; + } + + /** + * Locates and decodes a QR code in an image. + * + * @return a String representing the content encoded by the QR code + * @throws NotFoundException if a QR code cannot be found + * @throws FormatException if a QR code cannot be decoded + * @throws ChecksumException if error correction fails + */ + //@Override + + + // @Override + public function decode($image, $hints=null){/* Map hints*/ + $decoderResult = null; + $points = array(); + if ($hints != null && $hints['PURE_BARCODE']) {//hints.containsKey(DecodeHintType.PURE_BARCODE)) { + $bits = $this->extractPureBits($image->getBlackMatrix()); + $decoderResult = $this->decoder->decode($bits, $hints); + $points = self::$NO_POINTS; + } else { + $detector = new Detector($image->getBlackMatrix()); + $detectorResult = $detector->detect($hints); + + $decoderResult = $this->decoder->decode($detectorResult->getBits(), $hints); + $points = $detectorResult->getPoints(); + } + + // If the code was mirrored: swap the bottom-left and the top-right points. + if ($decoderResult->getOther() instanceof QRCodeDecoderMetaData) { + $decoderResult->getOther()->applyMirroredCorrection($points); + } + + $result = new Result($decoderResult->getText(), $decoderResult->getRawBytes(), $points, 'QR_CODE');//BarcodeFormat.QR_CODE + $byteSegments = $decoderResult->getByteSegments(); + if ($byteSegments != null) { + $result->putMetadata('BYTE_SEGMENTS', $byteSegments);//ResultMetadataType.BYTE_SEGMENTS + } + $ecLevel = $decoderResult->getECLevel(); + if ($ecLevel != null) { + $result->putMetadata('ERROR_CORRECTION_LEVEL', $ecLevel);//ResultMetadataType.ERROR_CORRECTION_LEVEL + } + if ($decoderResult->hasStructuredAppend()) { + $result->putMetadata('STRUCTURED_APPEND_SEQUENCE',//ResultMetadataType.STRUCTURED_APPEND_SEQUENCE + $decoderResult->getStructuredAppendSequenceNumber()); + $result->putMetadata('STRUCTURED_APPEND_PARITY',//ResultMetadataType.STRUCTURED_APPEND_PARITY + $decoderResult->getStructuredAppendParity()); + } + return $result; + } + + //@Override + public function reset() { + // do nothing + } + + /** + * This method detects a code in a "pure" image -- that is, pure monochrome image + * which contains only an unrotated, unskewed, image of a code, with some white border + * around it. This is a specialized method that works exceptionally fast in this special + * case. + * + * @see com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix) + */ + private static function extractPureBits($image) { + + $leftTopBlack = $image->getTopLeftOnBit(); + $rightBottomBlack = $image->getBottomRightOnBit(); + if ($leftTopBlack == null || $rightBottomBlack == null) { + throw NotFoundException::getNotFoundInstance(); + } + + $moduleSize = self::moduleSize($leftTopBlack, $image); + + $top = $leftTopBlack[1]; + $bottom = $rightBottomBlack[1]; + $left = $leftTopBlack[0]; + $right = $rightBottomBlack[0]; + + // Sanity check! + if ($left >= $right || $top >= $bottom) { + throw NotFoundException::getNotFoundInstance(); + } + + if ($bottom - $top != $right - $left) { + // Special case, where bottom-right module wasn't black so we found something else in the last row + // Assume it's a square, so use height as the width + $right = $left + ($bottom - $top); + } + + $matrixWidth = round(($right - $left + 1) / $moduleSize); + $matrixHeight = round(($bottom - $top + 1) / $moduleSize); + if ($matrixWidth <= 0 || $matrixHeight <= 0) { + throw NotFoundException::getNotFoundInstance(); + } + if ($matrixHeight != $matrixWidth) { + // Only possibly decode square regions + throw NotFoundException::getNotFoundInstance(); + } + + // Push in the "border" by half the module width so that we start + // sampling in the middle of the module. Just in case the image is a + // little off, this will help recover. + $nudge = (int) ($moduleSize / 2.0);// $nudge = (int) ($moduleSize / 2.0f); + $top += $nudge; + $left += $nudge; + + // But careful that this does not sample off the edge + // "right" is the farthest-right valid pixel location -- right+1 is not necessarily + // This is positive by how much the inner x loop below would be too large + $nudgedTooFarRight = $left + (int) (($matrixWidth - 1) * $moduleSize) - $right; + if ($nudgedTooFarRight > 0) { + if ($nudgedTooFarRight > $nudge) { + // Neither way fits; abort + throw NotFoundException::getNotFoundInstance(); + } + $left -= $nudgedTooFarRight; + } + // See logic above + $nudgedTooFarDown = $top + (int) (($matrixHeight - 1) * $moduleSize) - $bottom; + if ($nudgedTooFarDown > 0) { + if ($nudgedTooFarDown > $nudge) { + // Neither way fits; abort + throw NotFoundException::getNotFoundInstance(); + } + $top -= $nudgedTooFarDown; + } + + // Now just read off the bits + $bits = new BitMatrix($matrixWidth, $matrixHeight); + for ($y = 0; $y < $matrixHeight; $y++) { + $iOffset = $top + (int) ($y * $moduleSize); + for ($x = 0; $x < $matrixWidth; $x++) { + if ($image->get($left + (int) ($x * $moduleSize), $iOffset)) { + $bits->set($x, $y); + } + } + } + return $bits; + } + + private static function moduleSize($leftTopBlack, $image) { + $height = $image->getHeight(); + $width = $image->getWidth(); + $x = $leftTopBlack[0]; + $y = $leftTopBlack[1]; + $inBlack = true; + $transitions = 0; + while ($x < $width && $y < $height) { + if ($inBlack != $image->get($x, $y)) { + if (++$transitions == 5) { + break; + } + $inBlack = !$inBlack; + } + $x++; + $y++; + } + if ($x == $width || $y == $height) { + throw NotFoundException::getNotFoundInstance(); + } + return ($x - $leftTopBlack[0]) / 7.0; //return ($x - $leftTopBlack[0]) / 7.0f; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php new file mode 100755 index 00000000..510cfa8b --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php @@ -0,0 +1,250 @@ += 21 and 1 mod 4 + */ + function __construct($bitMatrix) { + $dimension = $bitMatrix->getHeight(); + if ($dimension < 21 || ($dimension & 0x03) != 1) { + throw FormatException::getFormatInstance(); + } + $this->bitMatrix = $bitMatrix; + } + + /** + *

Reads format information from one of its two locations within the QR Code.

+ * + * @return {@link FormatInformation} encapsulating the QR Code's format info + * @throws FormatException if both format information locations cannot be parsed as + * the valid encoding of format information + */ + function readFormatInformation() { + + if ($this->parsedFormatInfo != null) { + return $this->parsedFormatInfo; + } + + // Read top-left format info bits + $formatInfoBits1 = 0; + for ($i = 0; $i < 6; $i++) { + $formatInfoBits1 = $this->copyBit($i, 8, $formatInfoBits1); + } + // .. and skip a bit in the timing pattern ... + $formatInfoBits1 = $this->copyBit(7, 8, $formatInfoBits1); + $formatInfoBits1 = $this->copyBit(8, 8, $formatInfoBits1); + $formatInfoBits1 = $this->copyBit(8, 7, $formatInfoBits1); + // .. and skip a bit in the timing pattern ... + for ($j = 5; $j >= 0; $j--) { + $formatInfoBits1 = $this->copyBit(8, $j, $formatInfoBits1); + } + + // Read the top-right/bottom-left pattern too + $dimension = $this->bitMatrix->getHeight(); + $formatInfoBits2 = 0; + $jMin = $dimension - 7; + for ($j = $dimension - 1; $j >= $jMin; $j--) { + $formatInfoBits2 = $this->copyBit(8, $j, $formatInfoBits2); + } + for ($i = $dimension - 8; $i < $dimension; $i++) { + $formatInfoBits2 = $this->copyBit($i, 8, $formatInfoBits2); + } + + $parsedFormatInfo = FormatInformation::decodeFormatInformation($formatInfoBits1, $formatInfoBits2); + if ($parsedFormatInfo != null) { + return $parsedFormatInfo; + } + throw FormatException::getFormatInstance(); + } + + /** + *

Reads version information from one of its two locations within the QR Code.

+ * + * @return {@link Version} encapsulating the QR Code's version + * @throws FormatException if both version information locations cannot be parsed as + * the valid encoding of version information + */ + function readVersion(){ + + if ($this->parsedVersion != null) { + return $this->parsedVersion; + } + + $dimension = $this->bitMatrix->getHeight(); + + $provisionalVersion = ($dimension - 17) / 4; + if ($provisionalVersion <= 6) { + return Version::getVersionForNumber($provisionalVersion); + } + + // Read top-right version info: 3 wide by 6 tall + $versionBits = 0; + $ijMin = $dimension - 11; + for ($j = 5; $j >= 0; $j--) { + for ($i = $dimension - 9; $i >= $ijMin; $i--) { + $versionBits = $this->copyBit($i, $j, $versionBits); + } + } + + $theParsedVersion = Version::decodeVersionInformation($versionBits); + if ($theParsedVersion != null && $theParsedVersion->getDimensionForVersion() == $dimension) { + $this->parsedVersion = $theParsedVersion; + return $theParsedVersion; + } + + // Hmm, failed. Try bottom left: 6 wide by 3 tall + $versionBits = 0; + for ($i = 5; $i >= 0; $i--) { + for ($j = $dimension - 9; $j >=$ijMin; $j--) { + $versionBits = $this->copyBit($i, $j, $versionBits); + } + } + + $theParsedVersion = Version::decodeVersionInformation($versionBits); + if ($theParsedVersion != null && $theParsedVersion->getDimensionForVersion() == $dimension) { + $this->parsedVersion = $theParsedVersion; + return $theParsedVersion; + } + throw FormatException::getFormatInstance(); + } + + private function copyBit($i, $j, $versionBits) { + $bit = $this->mirror ? $this->bitMatrix->get($j, $i) : $this->bitMatrix->get($i, $j); + return $bit ? ($versionBits << 1) | 0x1 : $versionBits << 1; + } + + /** + *

Reads the bits in the {@link BitMatrix} representing the finder pattern in the + * correct order in order to reconstruct the codewords bytes contained within the + * QR Code.

+ * + * @return bytes encoded within the QR Code + * @throws FormatException if the exact number of bytes expected is not read + */ + function readCodewords(){ + + $formatInfo = $this->readFormatInformation(); + $version = $this->readVersion(); + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + $dataMask = DataMask::forReference($formatInfo->getDataMask()); + $dimension = $this->bitMatrix->getHeight(); + $dataMask->unmaskBitMatrix($this->bitMatrix, $dimension); + + $functionPattern = $version->buildFunctionPattern(); + + $readingUp = true; + if($version->getTotalCodewords()) { + $result = fill_array(0, $version->getTotalCodewords(), 0); + }else{ + $result = array(); + } + $resultOffset = 0; + $currentByte = 0; + $bitsRead = 0; + // Read columns in pairs, from right to left + for ($j = $dimension - 1; $j > 0; $j -= 2) { + if ($j == 6) { + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + $j--; + } + // Read alternatingly from bottom to top then top to bottom + for ($count = 0; $count < $dimension; $count++) { + $i = $readingUp ? $dimension - 1 - $count : $count; + for ($col = 0; $col < 2; $col++) { + // Ignore bits covered by the function pattern + if (!$functionPattern->get($j - $col, $i)) { + // Read a bit + $bitsRead++; + $currentByte <<= 1; + if ($this->bitMatrix->get($j - $col, $i)) { + $currentByte |= 1; + } + // If we've made a whole byte, save it off + if ($bitsRead == 8) { + $result[$resultOffset++] = $currentByte; //(byte) + $bitsRead = 0; + $currentByte = 0; + } + } + } + } + $readingUp ^= true; // readingUp = !readingUp; // switch directions + } + if ($resultOffset != $version->getTotalCodewords()) { + throw FormatException::getFormatInstance(); + } + return $result; + } + + /** + * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state. + */ + function remask() { + if ($this->parsedFormatInfo == null) { + return; // We have no format information, and have no data mask + } + $dataMask = DataMask::forReference($this->parsedFormatInfo->getDataMask()); + $dimension = $this->bitMatrix->getHeight(); + $dataMask->unmaskBitMatrix($this->bitMatrix, $dimension); + } + + /** + * Prepare the parser for a mirrored operation. + * This flag has effect only on the {@link #readFormatInformation()} and the + * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the + * {@link #mirror()} method should be called. + * + * @param mirror Whether to read version and format information mirrored. + */ + function setMirror($mirror) { + $parsedVersion = null; + $parsedFormatInfo = null; + $this->mirror = $mirror; + } + + /** Mirror the bit matrix in order to attempt a second reading. */ + function mirror() { + for ($x = 0; $x < $this->bitMatrix->getWidth(); $x++) { + for ($y = $x + 1; $y < $this->bitMatrix->getHeight(); $y++) { + if ($this->bitMatrix->get($x, $y) != $this->bitMatrix->get($y, $x)) { + $this->bitMatrix->flip($y, $x); + $this->bitMatrix->flip($x, $y); + } + } + } + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php new file mode 100755 index 00000000..803c14f9 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php @@ -0,0 +1,123 @@ +Encapsulates a block of data within a QR Code. QR Codes may split their data into + * multiple blocks, each of which is a unit of data and error-correction codewords. Each + * is represented by an instance of this class.

+ * + * @author Sean Owen + */ +final class DataBlock { + + private $numDataCodewords; + private $codewords; //byte[] + + private function __construct($numDataCodewords, $codewords) { + $this->numDataCodewords = $numDataCodewords; + $this->codewords = $codewords; + } + + /** + *

When QR Codes use multiple data blocks, they are actually interleaved. + * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This + * method will separate the data into original blocks.

+ * + * @param rawCodewords bytes as read directly from the QR Code + * @param version version of the QR Code + * @param ecLevel error-correction level of the QR Code + * @return DataBlocks containing original bytes, "de-interleaved" from representation in the + * QR Code + */ + static function getDataBlocks($rawCodewords, + $version, + $ecLevel) { + + if (count($rawCodewords) != $version->getTotalCodewords()) { + throw new \InvalidArgumentException(); + } + + // Figure out the number and size of data blocks used by this version and + // error correction level + $ecBlocks = $version->getECBlocksForLevel($ecLevel); + + // First count the total number of data blocks + $totalBlocks = 0; + $ecBlockArray = $ecBlocks->getECBlocks(); + foreach ($ecBlockArray as $ecBlock) { + $totalBlocks += $ecBlock->getCount(); + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + $result = array();//new DataBlock[$totalBlocks]; + $numResultBlocks = 0; + foreach ($ecBlockArray as $ecBlock) { + for ($i = 0; $i < $ecBlock->getCount(); $i++) { + $numDataCodewords = $ecBlock->getDataCodewords(); + $numBlockCodewords = $ecBlocks->getECCodewordsPerBlock() + $numDataCodewords; + $result[$numResultBlocks++] = new DataBlock($numDataCodewords, fill_array(0,$numBlockCodewords,0)); + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + $shorterBlocksTotalCodewords = count($result[0]->codewords); + $longerBlocksStartAt = count($result) - 1; + while ($longerBlocksStartAt >= 0) { + $numCodewords = count($result[$longerBlocksStartAt]->codewords); + if ($numCodewords == $shorterBlocksTotalCodewords) { + break; + } + $longerBlocksStartAt--; + } + $longerBlocksStartAt++; + + $shorterBlocksNumDataCodewords = $shorterBlocksTotalCodewords - $ecBlocks->getECCodewordsPerBlock(); + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + $rawCodewordsOffset = 0; + for ($i = 0; $i < $shorterBlocksNumDataCodewords; $i++) { + for ($j = 0; $j < $numResultBlocks; $j++) { + $result[$j]->codewords[$i] = $rawCodewords[$rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for ($j = $longerBlocksStartAt; $j < $numResultBlocks; $j++) { + $result[$j]->codewords[$shorterBlocksNumDataCodewords] = $rawCodewords[$rawCodewordsOffset++]; + } + // Now add in error correction blocks + $max = count($result[0]->codewords); + for ($i = $shorterBlocksNumDataCodewords; $i < $max; $i++) { + for ($j = 0; $j < $numResultBlocks; $j++) { + $iOffset = $j < $longerBlocksStartAt ? $i : $i + 1; + $result[$j]->codewords[$iOffset] = $rawCodewords[$rawCodewordsOffset++]; + } + } + return $result; + } + + function getNumDataCodewords() { + return $this->numDataCodewords; + } + + function getCodewords() { + return $this->codewords; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php new file mode 100755 index 00000000..852aab77 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php @@ -0,0 +1,175 @@ +Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations + * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, + * including areas used for finder patterns, timing patterns, etc. These areas should be unused + * after the point they are unmasked anyway.

+ * + *

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position + * and j is row position. In fact, as the text says, i is row position and j is column position.

+ * + * @author Sean Owen + */ +abstract class DataMask +{ + + /** + * See ISO 18004:2006 6.8.1 + */ + private static $DATA_MASKS = array(); + + static function Init() + { + self::$DATA_MASKS = array( + new DataMask000(), + new DataMask001(), + new DataMask010(), + new DataMask011(), + new DataMask100(), + new DataMask101(), + new DataMask110(), + new DataMask111(), + ); + } + + function __construct() + { + + } + + /** + *

Implementations of this method reverse the data masking process applied to a QR Code and + * make its bits ready to read.

+ * + * @param bits representation of QR Code bits + * @param dimension dimension of QR Code, represented by bits, being unmasked + */ + final function unmaskBitMatrix($bits, $dimension) + { + for ($i = 0; $i < $dimension; $i++) { + for ($j = 0; $j < $dimension; $j++) { + if ($this->isMasked($i, $j)) { + $bits->flip($j, $i); + } + } + } + } + + abstract function isMasked($i, $j); + + /** + * @param reference a value between 0 and 7 indicating one of the eight possible + * data mask patterns a QR Code may use + * @return DataMask encapsulating the data mask pattern + */ + static function forReference($reference) + { + if ($reference < 0 || $reference > 7) { + throw new \InvalidArgumentException(); + } + return self::$DATA_MASKS[$reference]; + } +} +DataMask::Init(); +/** + * 000: mask bits for which (x + y) mod 2 == 0 + */ +final class DataMask000 extends DataMask { + // @Override + function isMasked($i, $j) { + return (($i + $j) & 0x01) == 0; + } +} + +/** + * 001: mask bits for which x mod 2 == 0 + */ +final class DataMask001 extends DataMask { + //@Override + function isMasked($i, $j) { + return ($i & 0x01) == 0; + } +} + +/** + * 010: mask bits for which y mod 3 == 0 + */ +final class DataMask010 extends DataMask { + //@Override + function isMasked($i, $j) { + return $j % 3 == 0; + } +} + +/** + * 011: mask bits for which (x + y) mod 3 == 0 + */ +final class DataMask011 extends DataMask { + //@Override + function isMasked($i, $j) { + return ($i + $j) % 3 == 0; + } +} + +/** + * 100: mask bits for which (x/2 + y/3) mod 2 == 0 + */ +final class DataMask100 extends DataMask { + //@Override + function isMasked($i, $j) { + return intval((intval($i / 2) + intval($j /3)) & 0x01) == 0; + } +} + +/** + * 101: mask bits for which xy mod 2 + xy mod 3 == 0 + */ +final class DataMask101 extends DataMask { + //@Override + function isMasked($i, $j) { + $temp = $i * $j; + return ($temp & 0x01) + ($temp % 3) == 0; + } +} + +/** + * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + */ +final class DataMask110 extends DataMask { + //@Override + function isMasked($i, $j) { + $temp = $i * $j; + return ((($temp & 0x01) + ($temp % 3)) & 0x01) == 0; + } +} + +/** + * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + */ +final class DataMask111 extends DataMask { + //@Override + function isMasked($i, $j) { + return (((($i + $j) & 0x01) + (($i * $j) % 3)) & 0x01) == 0; + } +} + diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php new file mode 100755 index 00000000..ec4e6673 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php @@ -0,0 +1,359 @@ +QR Codes can encode text as bits in one of several modes, and can use multiple modes + * in one QR Code. This class decodes the bits back into text.

+ * + *

See ISO 18004:2006, 6.4.3 - 6.4.7

+ * + * @author Sean Owen + */ +final class DecodedBitStreamParser { + + /** + * See ISO 18004:2006, 6.4.4 Table 5 + */ + private static $ALPHANUMERIC_CHARS = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + ' ', '$', '%', '*', '+', '-', '.', '/', ':' + ); + private static $GB2312_SUBSET = 1; + + + private function DecodedBitStreamParser() { + + + } + + static function decode($bytes, + $version, + $ecLevel, + $hints) { + $bits = new BitSource($bytes); + $result = '';//new StringBuilder(50); + $byteSegments = array(); + $symbolSequence = -1; + $parityData = -1; + + try { + $currentCharacterSetECI = null; + $fc1InEffect = false; + $mode=''; + do { + // While still another segment to read... + if ($bits->available() < 4) { + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + $mode = Mode::$TERMINATOR; + } else { + $mode = Mode::forBits($bits->readBits(4)); // mode is encoded by 4 bits + } + if ($mode != Mode::$TERMINATOR) { + if ($mode == Mode::$FNC1_FIRST_POSITION || $mode == Mode::$FNC1_SECOND_POSITION) { + // We do little with FNC1 except alter the parsed result a bit according to the spec + $fc1InEffect = true; + } else if ($mode == Mode::$STRUCTURED_APPEND) { + if ($bits->available() < 16) { + throw FormatException::getFormatInstance(); + } + // sequence number and parity is added later to the result metadata + // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue + $symbolSequence = $bits->readBits(8); + $parityData = $bits->readBits(8); + } else if ($mode == Mode::$ECI) { + // Count doesn't apply to ECI + $value = self::parseECIValue($bits); + $currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue($value); + if ($currentCharacterSetECI == null) { + throw FormatException::getFormatInstance(); + } + } else { + // First handle Hanzi mode which does not start with character count + if ($mode == Mode::$HANZI) { + //chinese mode contains a sub set indicator right after mode indicator + $subset = $bits->readBits(4); + $countHanzi = $bits->readBits($mode->getCharacterCountBits($version)); + if ($subset == self::$GB2312_SUBSET) { + self::decodeHanziSegment($bits, $result, $countHanzi); + } + } else { + // "Normal" QR code modes: + // How many characters will follow, encoded in this mode? + $count = $bits->readBits($mode->getCharacterCountBits($version)); + if ($mode == Mode::$NUMERIC) { + self::decodeNumericSegment($bits, $result, $count); + } else if ($mode == Mode::$ALPHANUMERIC) { + self::decodeAlphanumericSegment($bits, $result, $count, $fc1InEffect); + } else if ($mode == Mode::$BYTE) { + self::decodeByteSegment($bits, $result, $count, $currentCharacterSetECI, $byteSegments, $hints); + } else if ($mode == Mode::$KANJI) { + self::decodeKanjiSegment($bits, $result, $count); + } else { + throw FormatException::getFormatInstance(); + } + } + } + } + } while ($mode != Mode::$TERMINATOR); + } catch (IllegalArgumentException $iae) { + // from readBits() calls + throw FormatException::getFormatInstance(); + } + + return new DecoderResult($bytes, + $result, + empty($byteSegments) ? null : $byteSegments, + $ecLevel == null ? null : 'L',//ErrorCorrectionLevel::toString($ecLevel), + $symbolSequence, + $parityData); + } + + /** + * See specification GBT 18284-2000 + */ + private static function decodeHanziSegment($bits, + &$result, + $count) { + // Don't crash trying to read more bits than we have available. + if ($count * 13 > $bits->available()) { + throw FormatException::getFormatInstance(); + } + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as GB2312 afterwards + $buffer = fill_array(0,2 * $count,0); + $offset = 0; + while ($count > 0) { + // Each 13 bits encodes a 2-byte character + $twoBytes = $bits->readBits(13); + $assembledTwoBytes = (($twoBytes / 0x060) << 8) | ($twoBytes % 0x060); + if ($assembledTwoBytes < 0x003BF) { + // In the 0xA1A1 to 0xAAFE range + $assembledTwoBytes += 0x0A1A1; + } else { + // In the 0xB0A1 to 0xFAFE range + $assembledTwoBytes += 0x0A6A1; + } + $buffer[$offset] = (($assembledTwoBytes >> 8) & 0xFF);//(byte) + $buffer[$offset + 1] = ($assembledTwoBytes & 0xFF);//(byte) + $offset += 2; + $count--; + } + + try { + $result .= iconv('GB2312', 'UTF-8', implode($buffer)); + } catch (UnsupportedEncodingException $ignored) { + throw FormatException::getFormatInstance(); + } + } + + private static function decodeKanjiSegment($bits, + &$result, + $count) { + // Don't crash trying to read more bits than we have available. + if ($count * 13 > $bits->available()) { + throw FormatException::getFormatInstance(); + } + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + $buffer = array(0,2 * $count,0); + $offset = 0; + while ($count > 0) { + // Each 13 bits encodes a 2-byte character + $twoBytes = $bits->readBits(13); + $assembledTwoBytes = (($twoBytes / 0x0C0) << 8) | ($twoBytes % 0x0C0); + if ($assembledTwoBytes < 0x01F00) { + // In the 0x8140 to 0x9FFC range + $assembledTwoBytes += 0x08140; + } else { + // In the 0xE040 to 0xEBBF range + $assembledTwoBytes += 0x0C140; + } + $buffer[$offset] = ($assembledTwoBytes >> 8);//(byte) + $buffer[$offset + 1] = $assembledTwoBytes; //(byte) + $offset += 2; + $count--; + } + // Shift_JIS may not be supported in some environments: + try { + $result .= iconv('shift-jis','utf-8',implode($buffer)); + + + } catch (UnsupportedEncodingException $ignored) { + throw FormatException::getFormatInstance(); + } + } + + private static function decodeByteSegment($bits, + &$result, + $count, + $currentCharacterSetECI, + &$byteSegments, + $hints) { + // Don't crash trying to read more bits than we have available. + if (8 * $count > $bits->available()) { + throw FormatException::getFormatInstance(); + } + + $readBytes = fill_array(0,$count,0); + for ($i = 0; $i < $count; $i++) { + $readBytes[$i] = $bits->readBits(8);//(byte) + } + $text = implode(array_map('chr',$readBytes)); + $encoding = ''; + if ($currentCharacterSetECI == null) { + // The spec isn't clear on this mode; see + // section 6.4.5: t does not say which encoding to assuming + // upon decoding. I have seen ISO-8859-1 used as well as + // Shift_JIS -- without anything like an ECI designator to + // give a hint. + + $encoding = mb_detect_encoding($text, $hints); + } else { + $encoding = $currentCharacterSetECI->name(); + } + try { + // $result.= mb_convert_encoding($text ,$encoding);//(new String(readBytes, encoding)); + $result.= $text;//(new String(readBytes, encoding)); + } catch (UnsupportedEncodingException $ignored) { + throw FormatException::getFormatInstance(); + } + $byteSegments = array_merge($byteSegments, $readBytes); + } + + private static function toAlphaNumericChar($value) { + if ($value >= count(self::$ALPHANUMERIC_CHARS)) { + throw FormatException::getFormatInstance(); + } + return self::$ALPHANUMERIC_CHARS[$value]; + } + + private static function decodeAlphanumericSegment($bits, + &$result, + $count, + $fc1InEffect) { + // Read two characters at a time + $start = strlen($result); + while ($count > 1) { + if ($bits->available() < 11) { + throw FormatException::getFormatInstance(); + } + $nextTwoCharsBits = $bits->readBits(11); + $result.=(self::toAlphaNumericChar($nextTwoCharsBits / 45)); + $result.=(self::toAlphaNumericChar($nextTwoCharsBits % 45)); + $count -= 2; + } + if ($count == 1) { + // special case: one character left + if ($bits->available() < 6) { + throw FormatException::getFormatInstance(); + } + $result.=self::toAlphaNumericChar($bits->readBits(6)); + } + // See section 6.4.8.1, 6.4.8.2 + if ($fc1InEffect) { + // We need to massage the result a bit if in an FNC1 mode: + for ($i = $start; $i < strlen($result); $i++) { + if ($result{$i} == '%') { + if ($i < strlen($result) - 1 && $result{$i + 1} == '%') { + // %% is rendered as % + $result = substr_replace($result,'',$i + 1,1);//deleteCharAt(i + 1); + } else { + // In alpha mode, % should be converted to FNC1 separator 0x1D + $result.setCharAt($i, chr(0x1D)); + } + } + } + } + } + + private static function decodeNumericSegment($bits, + &$result, + $count) { + // Read three digits at a time + while ($count >= 3) { + // Each 10 bits encodes three digits + if ($bits->available() < 10) { + throw FormatException::getFormatInstance(); + } + $threeDigitsBits = $bits->readBits(10); + if ($threeDigitsBits >= 1000) { + throw FormatException::getFormatInstance(); + } + $result.=(self::toAlphaNumericChar($threeDigitsBits / 100)); + $result.=(self::toAlphaNumericChar(($threeDigitsBits / 10) % 10)); + $result.=(self::toAlphaNumericChar($threeDigitsBits % 10)); + $count -= 3; + } + if ($count == 2) { + // Two digits left over to read, encoded in 7 bits + if ($bits->available() < 7) { + throw FormatException::getFormatInstance(); + } + $twoDigitsBits = $bits->readBits(7); + if ($twoDigitsBits >= 100) { + throw FormatException::getFormatInstance(); + } + $result.=(self::toAlphaNumericChar($twoDigitsBits / 10)); + $result.=(self::toAlphaNumericChar($twoDigitsBits % 10)); + } else if ($count == 1) { + // One digit left over to read + if ($bits->available() < 4) { + throw FormatException::getFormatInstance(); + } + $digitBits = $bits->readBits(4); + if ($digitBits >= 10) { + throw FormatException::getFormatInstance(); + } + $result.=(self::toAlphaNumericChar($digitBits)); + } + } + + private static function parseECIValue($bits) { + $firstByte = $bits->readBits(8); + if (($firstByte & 0x80) == 0) { + // just one byte + return $firstByte & 0x7F; + } + if (($firstByte & 0xC0) == 0x80) { + // two bytes + $secondByte = $bits->readBits(8); + return (($firstByte & 0x3F) << 8) | $secondByte; + } + if (($firstByte & 0xE0) == 0xC0) { + // three bytes + $secondThirdBytes = $bits->readBits(16); + return (($firstByte & 0x1F) << 16) | $secondThirdBytes; + } + throw FormatException::getFormatInstance(); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php new file mode 100755 index 00000000..1859fc7a --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php @@ -0,0 +1,214 @@ +The main class which implements QR Code decoding -- as opposed to locating and extracting + * the QR Code from an image.

+ * + * @author Sean Owen + */ +final class Decoder { + + private $rsDecoder; + + public function __construct() { + $this->rsDecoder = new ReedSolomonDecoder(GenericGF::$QR_CODE_FIELD_256); + } + + + function decode($variable, $hints=null){ + if(is_array($variable)){ + return $this->decodeImage($variable,$hints); + }elseif(is_object($variable)&&$variable instanceof BitMatrix){ + return $this->decodeBits($variable,$hints); + }elseif(is_object($variable)&&$variable instanceof BitMatrixParser){ + return $this->decodeParser($variable,$hints); + }else{ + die('decode error Decoder.php'); + } + + + } + + /** + *

Convenience method that can decode a QR Code represented as a 2D array of booleans. + * "true" is taken to mean a black module.

+ * + * @param image booleans representing white/black QR Code modules + * @param hints decoding hints that should be used to influence decoding + * @return text and bytes encoded within the QR Code + * @throws FormatException if the QR Code cannot be decoded + * @throws ChecksumException if error correction fails + */ + public function decodeImage($image, $hints=null) + { + $dimension = count($image); + $bits = new BitMatrix($dimension); + for ($i = 0; $i < $dimension; $i++) { + for ($j = 0; $j < $dimension; $j++) { + if ($image[$i][$j]) { + $bits->set($j, $i); + } + } + } + return $this->decode($bits, $hints); + } + + + + /** + *

Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.

+ * + * @param bits booleans representing white/black QR Code modules + * @param hints decoding hints that should be used to influence decoding + * @return text and bytes encoded within the QR Code + * @throws FormatException if the QR Code cannot be decoded + * @throws ChecksumException if error correction fails + */ + public function decodeBits($bits, $hints=null) + { + +// Construct a parser and read version, error-correction level + $parser = new BitMatrixParser($bits); + $fe = null; + $ce = null; + try { + return $this->decode($parser, $hints); + } catch (FormatException $e) { + $fe = $e; + } catch (ChecksumException $e) { + $ce = $e; + } + + try { + +// Revert the bit matrix + $parser->remask(); + +// Will be attempting a mirrored reading of the version and format info. + $parser->setMirror(true); + +// Preemptively read the version. + $parser->readVersion(); + +// Preemptively read the format information. + $parser->readFormatInformation(); + + /* + * Since we're here, this means we have successfully detected some kind + * of version and format information when mirrored. This is a good sign, + * that the QR code may be mirrored, and we should try once more with a + * mirrored content. + */ +// Prepare for a mirrored reading. + $parser->mirror(); + + $result = $this->decode($parser, $hints); + +// Success! Notify the caller that the code was mirrored. + $result->setOther(new QRCodeDecoderMetaData(true)); + + return $result; + + } catch (FormatException $e ) {// catch (FormatException | ChecksumException e) { +// Throw the exception from the original reading + if ($fe != null) { + throw $fe; + } + if ($ce != null) { + throw $ce; + } + throw $e; + + } + } + + private function decodeParser($parser,$hints=null) + { + $version = $parser->readVersion(); + $ecLevel = $parser->readFormatInformation()->getErrorCorrectionLevel(); + +// Read codewords + $codewords = $parser->readCodewords(); +// Separate into data blocks + $dataBlocks = DataBlock::getDataBlocks($codewords, $version, $ecLevel); + +// Count total number of data bytes + $totalBytes = 0; + foreach ($dataBlocks as $dataBlock) { + $totalBytes += $dataBlock->getNumDataCodewords(); + } + $resultBytes = fill_array(0,$totalBytes,0); + $resultOffset = 0; + +// Error-correct and copy data blocks together into a stream of bytes + foreach ($dataBlocks as $dataBlock) { + $codewordBytes = $dataBlock->getCodewords(); + $numDataCodewords = $dataBlock->getNumDataCodewords(); + $this->correctErrors($codewordBytes, $numDataCodewords); + for ($i = 0; $i < $numDataCodewords; $i++) { + $resultBytes[$resultOffset++] = $codewordBytes[$i]; + } + } + +// Decode the contents of that stream of bytes + return DecodedBitStreamParser::decode($resultBytes, $version, $ecLevel, $hints); + } + + /** + *

Given data and error-correction codewords received, possibly corrupted by errors, attempts to + * correct the errors in-place using Reed-Solomon error correction.

+ * + * @param codewordBytes data and error correction codewords + * @param numDataCodewords number of codewords that are data bytes + * @throws ChecksumException if error correction fails + */ + private function correctErrors(&$codewordBytes, $numDataCodewords){ + $numCodewords = count($codewordBytes); +// First read into an array of ints + $codewordsInts =fill_array(0,$numCodewords,0); + for ($i = 0; $i < $numCodewords; $i++) { + $codewordsInts[$i] = $codewordBytes[$i] & 0xFF; + } + $numECCodewords = count($codewordBytes)- $numDataCodewords; + try { + $this->rsDecoder->decode($codewordsInts, $numECCodewords); + } catch (ReedSolomonException $ignored) { + throw ChecksumException::getChecksumInstance(); + } +// Copy back into array of bytes -- only need to worry about the bytes that were data +// We don't care about errors in the error-correction codewords + for ($i = 0; $i < $numDataCodewords; $i++) { + $codewordBytes[$i] = $codewordsInts[$i]; + } + + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php new file mode 100755 index 00000000..5f61b5ce --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php @@ -0,0 +1,86 @@ +See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + * defined by the QR code standard.

+ * + * @author Sean Owen + */ +class ErrorCorrectionLevel { + + + private static $FOR_BITS; + + + private $bits; + private $ordinal; + + function __construct($bits,$ordinal=0) { + $this->bits = $bits; + $this->ordinal = $ordinal; + } + + public static function Init(){ + self::$FOR_BITS = array( + + + new ErrorCorrectionLevel(0x00,1), //M + new ErrorCorrectionLevel(0x01,0), //L + new ErrorCorrectionLevel(0x02,3), //H + new ErrorCorrectionLevel(0x03,2), //Q + + ); + } + /** L = ~7% correction */ + // self::$L = new ErrorCorrectionLevel(0x01); + /** M = ~15% correction */ + //self::$M = new ErrorCorrectionLevel(0x00); + /** Q = ~25% correction */ + //self::$Q = new ErrorCorrectionLevel(0x03); + /** H = ~30% correction */ + //self::$H = new ErrorCorrectionLevel(0x02); + + + public function getBits() { + return $this->bits; + } + public function toString() { + return $this->bits; + } + public function getOrdinal() { + return $this->ordinal; + } + + /** + * @param bits int containing the two bits encoding a QR Code's error correction level + * @return ErrorCorrectionLevel representing the encoded error correction level + */ + public static function forBits($bits) { + if ($bits < 0 || $bits >= count(self::$FOR_BITS)) { + throw new \InvalidArgumentException(); + } + $level = self::$FOR_BITS[$bits]; + // $lev = self::$$bit; + return $level; + } + + +} +ErrorCorrectionLevel::Init(); diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php new file mode 100755 index 00000000..ac802fd6 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php @@ -0,0 +1,179 @@ +Encapsulates a QR Code's format information, including the data mask used and + * error correction level.

+ * + * @author Sean Owen + * @see DataMask + * @see ErrorCorrectionLevel + */ +final class FormatInformation { + + public static $FORMAT_INFO_MASK_QR; + + /** + * See ISO 18004:2006, Annex C, Table C.1 + */ + public static $FORMAT_INFO_DECODE_LOOKUP; + /** + * Offset i holds the number of 1 bits in the binary representation of i + */ + private static $BITS_SET_IN_HALF_BYTE; + + private $errorCorrectionLevel; + private $dataMask; + + public static function Init(){ + + self::$FORMAT_INFO_MASK_QR= 0x5412; + self::$BITS_SET_IN_HALF_BYTE = array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); + self::$FORMAT_INFO_DECODE_LOOKUP = array( + array(0x5412, 0x00), + array (0x5125, 0x01), + array(0x5E7C, 0x02), + array(0x5B4B, 0x03), + array(0x45F9, 0x04), + array(0x40CE, 0x05), + array(0x4F97, 0x06), + array(0x4AA0, 0x07), + array(0x77C4, 0x08), + array(0x72F3, 0x09), + array(0x7DAA, 0x0A), + array(0x789D, 0x0B), + array(0x662F, 0x0C), + array(0x6318, 0x0D), + array(0x6C41, 0x0E), + array(0x6976, 0x0F), + array(0x1689, 0x10), + array(0x13BE, 0x11), + array(0x1CE7, 0x12), + array(0x19D0, 0x13), + array(0x0762, 0x14), + array(0x0255, 0x15), + array(0x0D0C, 0x16), + array(0x083B, 0x17), + array(0x355F, 0x18), + array(0x3068, 0x19), + array(0x3F31, 0x1A), + array(0x3A06, 0x1B), + array(0x24B4, 0x1C), + array(0x2183, 0x1D), + array(0x2EDA, 0x1E), + array(0x2BED, 0x1F), + ); + + } + private function __construct($formatInfo) { + // Bits 3,4 + $this->errorCorrectionLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x03); + // Bottom 3 bits + $this->dataMask = ($formatInfo & 0x07);//(byte) + } + + static function numBitsDiffering($a, $b) { + $a ^= $b; // a now has a 1 bit exactly where its bit differs with b's + // Count bits set quickly with a series of lookups: + return self::$BITS_SET_IN_HALF_BYTE[$a & 0x0F] + + self::$BITS_SET_IN_HALF_BYTE[intval(uRShift($a, 4) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a ,8) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a , 12) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 16) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a , 20) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 24) & 0x0F)] + + self::$BITS_SET_IN_HALF_BYTE[(uRShift($a ,28) & 0x0F)]; + } + + /** + * @param maskedFormatInfo1; format info indicator, with mask still applied + * @param maskedFormatInfo2; second copy of same info; both are checked at the same time + * to establish best match + * @return information about the format it specifies, or {@code null} + * if doesn't seem to match any known pattern + */ + static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + if ($formatInfo != null) { + return $formatInfo; + } + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + return self::doDecodeFormatInformation($maskedFormatInfo1 ^ self::$FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::$FORMAT_INFO_MASK_QR); + } + + private static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2) { + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + foreach (self::$FORMAT_INFO_DECODE_LOOKUP as $decodeInfo ) { + $targetInfo = $decodeInfo[0]; + if ($targetInfo == $maskedFormatInfo1 || $targetInfo == $maskedFormatInfo2) { + // Found an exact match + return new FormatInformation($decodeInfo[1]); + } + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + if ($maskedFormatInfo1 != $maskedFormatInfo2) { + // also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits + // differing means we found a match + if ($bestDifference <= 3) { + return new FormatInformation($bestFormatInfo); + } + return null; + } + + function getErrorCorrectionLevel() { + return $this->errorCorrectionLevel; + } + + function getDataMask() { + return $this->dataMask; + } + + //@Override + public function hashCode() { + return ($this->errorCorrectionLevel->ordinal() << 3) | intval($this->dataMask); + } + + //@Override + public function equals($o) { + if (!($o instanceof FormatInformation)) { + return false; + } + $other =$o; + return $this->errorCorrectionLevel == $other->errorCorrectionLevel && + $this->dataMask == $other->dataMask; + } + +} +FormatInformation::Init(); diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php new file mode 100755 index 00000000..30421ad9 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php @@ -0,0 +1,118 @@ +See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which + * data can be encoded to bits in the QR code standard.

+ * + * @author Sean Owen + */ +class Mode { + static $TERMINATOR; + static $NUMERIC; + static $ALPHANUMERIC; + static $STRUCTURED_APPEND; + static $BYTE; + static $ECI; + static $KANJI; + static $FNC1_FIRST_POSITION; + static $FNC1_SECOND_POSITION; + static $HANZI; + + + private $characterCountBitsForVersions; + private $bits; + + function __construct($characterCountBitsForVersions, $bits) { + $this->characterCountBitsForVersions = $characterCountBitsForVersions; + $this->bits = $bits; + } + static function Init() + { + + + self::$TERMINATOR = new Mode(array(0, 0, 0), 0x00); // Not really a mode... + self::$NUMERIC = new Mode(array(10, 12, 14), 0x01); + self::$ALPHANUMERIC = new Mode(array(9, 11, 13), 0x02); + self::$STRUCTURED_APPEND = new Mode(array(0, 0, 0), 0x03); // Not supported + self::$BYTE = new Mode(array(8, 16, 16), 0x04); + self::$ECI = new Mode(array(0, 0, 0), 0x07); // character counts don't apply + self::$KANJI = new Mode(array(8, 10, 12), 0x08); + self::$FNC1_FIRST_POSITION = new Mode(array(0, 0, 0), 0x05); + self::$FNC1_SECOND_POSITION =new Mode(array(0, 0, 0), 0x09); + /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ + self::$HANZI = new Mode(array(8, 10, 12), 0x0D); + } + /** + * @param bits four bits encoding a QR Code data mode + * @return Mode encoded by these bits + * @throws IllegalArgumentException if bits do not correspond to a known mode + */ + public static function forBits($bits) { + switch ($bits) { + case 0x0: + return self::$TERMINATOR; + case 0x1: + return self::$NUMERIC; + case 0x2: + return self::$ALPHANUMERIC; + case 0x3: + return self::$STRUCTURED_APPEND; + case 0x4: + return self::$BYTE; + case 0x5: + return self::$FNC1_FIRST_POSITION; + case 0x7: + return self::$ECI; + case 0x8: + return self::$KANJI; + case 0x9: + return self::$FNC1_SECOND_POSITION; + case 0xD: + // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + return self::$HANZI; + default: + throw new \InvalidArgumentException(); + } + } + + /** + * @param version version in question + * @return number of bits used, in this QR Code symbol {@link Version}, to encode the + * count of characters that will follow encoded in this Mode + */ + public function getCharacterCountBits($version) { + $number = $version->getVersionNumber(); + $offset = 0; + if ($number <= 9) { + $offset = 0; + } else if ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + return $this->characterCountBitsForVersions[$offset]; + } + + public function getBits() { + return $this->bits; + } + +} +Mode::Init(); \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php new file mode 100755 index 00000000..a3cc03f3 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php @@ -0,0 +1,619 @@ +versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->ecBlocks = $ecBlocks; + $total = 0; + if(is_array($ecBlocks)) { + $ecCodewords = $ecBlocks[0]->getECCodewordsPerBlock(); + $ecbArray = $ecBlocks[0]->getECBlocks(); + }else{ + $ecCodewords = $ecBlocks->getECCodewordsPerBlock(); + $ecbArray = $ecBlocks->getECBlocks(); + } + foreach ($ecbArray as $ecBlock) { + $total += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + $this->totalCodewords = $total; + } + public function getVersionNumber() + { + return $this->versionNumber; + } + + public function getAlignmentPatternCenters() + { + return $this->alignmentPatternCenters; + } + + public function getTotalCodewords() + { + return $this->totalCodewords; + } + + public function getDimensionForVersion() + { + return 17 + 4 * $this->versionNumber; + } + + public function getECBlocksForLevel($ecLevel) + { + return $this->ecBlocks[$ecLevel->getOrdinal()]; + } + + /** + *

Deduces version information purely from QR Code dimensions.

+ * + * @param dimension dimension in modules + * @return Version for a QR Code of that dimension + * @throws FormatException if dimension is not 1 mod 4 + */ + public static function getProvisionalVersionForDimension($dimension) + { + if ($dimension % 4 != 1) { + throw FormatException::getFormatInstance(); + } + try { + return self::getVersionForNumber(($dimension - 17) / 4); + } catch (InvalidArgumentException $ignored) { + throw FormatException::getFormatInstance(); + } + } + + public static function getVersionForNumber($versionNumber) + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new \InvalidArgumentException(); + } + if(!self::$VERSIONS){ + + self::$VERSIONS = self::buildVersions(); + + } + return self::$VERSIONS[$versionNumber - 1]; + } + + static function decodeVersionInformation($versionBits) + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + for ($i = 0; $i < count(self::$VERSION_DECODE_INFO); $i++) { + $targetVersion = self::$VERSION_DECODE_INFO[$i]; +// Do the version info bits match exactly? done. + if ($targetVersion == $versionBits) { + return self::getVersionForNumber($i + 7); + } +// Otherwise see if this is the closest to a real version info bit string +// we have seen so far + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } +// We can tolerate up to 3 bits of error since no two version info codewords will +// differ in less than 8 bits. + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } +// If we didn't find a close enough match, fail + return null; + } + + /** + * See ISO 18004:2006 Annex E + */ + function buildFunctionPattern() + { + $dimension = self::getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + +// Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); +// Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); +// Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + +// Alignment patterns + $max = count($this->alignmentPatternCenters); + for ($x = 0; $x < $max; $x++) { + $i = $this->alignmentPatternCenters[$x] - 2; + for ($y = 0; $y < $max; $y++) { + if (($x == 0 && ($y == 0 || $y == $max - 1)) || ($x == $max - 1 && $y == 0)) { +// No alignment patterns near the three finder paterns + continue; + } + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + +// Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); +// Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { +// Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); +// Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + /** + * See ISO 18004:2006 6.5.1 Table 9 + */ + private static function buildVersions() + { + + + return array( + new Version(1, array(), + array(new ECBlocks(7, array(new ECB(1, 19))), + new ECBlocks(10, array(new ECB(1, 16))), + new ECBlocks(13, array(new ECB(1, 13))), + new ECBlocks(17, array(new ECB(1, 9))))), + new Version(2, array(6, 18), + array(new ECBlocks(10, array(new ECB(1, 34))), + new ECBlocks(16, array(new ECB(1, 28))), + new ECBlocks(22, array(new ECB(1, 22))), + new ECBlocks(28, array(new ECB(1, 16))))), + new Version(3, array(6, 22), + array( new ECBlocks(15, array(new ECB(1, 55))), + new ECBlocks(26, array(new ECB(1, 44))), + new ECBlocks(18, array(new ECB(2, 17))), + new ECBlocks(22, array(new ECB(2, 13))))), + new Version(4, array(6, 26), + array(new ECBlocks(20, array(new ECB(1, 80))), + new ECBlocks(18, array(new ECB(2, 32))), + new ECBlocks(26, array(new ECB(2, 24))), + new ECBlocks(16, array(new ECB(4, 9))))), + new Version(5, array(6, 30), + array(new ECBlocks(26, array(new ECB(1, 108))), + new ECBlocks(24, array(new ECB(2, 43))), + new ECBlocks(18, array(new ECB(2, 15), + new ECB(2, 16))), + new ECBlocks(22, array(new ECB(2, 11), + new ECB(2, 12))))), + new Version(6, array(6, 34), + array(new ECBlocks(18, array(new ECB(2, 68))), + new ECBlocks(16, array(new ECB(4, 27))), + new ECBlocks(24, array(new ECB(4, 19))), + new ECBlocks(28, array(new ECB(4, 15))))), + new Version(7, array(6, 22, 38), + array(new ECBlocks(20, array(new ECB(2, 78))), + new ECBlocks(18, array(new ECB(4, 31))), + new ECBlocks(18, array(new ECB(2, 14), + new ECB(4, 15))), + new ECBlocks(26, array(new ECB(4, 13), + new ECB(1, 14))))), + new Version(8, array(6, 24, 42), + array(new ECBlocks(24, array(new ECB(2, 97))), + new ECBlocks(22, array(new ECB(2, 38), + new ECB(2, 39))), + new ECBlocks(22, array(new ECB(4, 18), + new ECB(2, 19))), + new ECBlocks(26, array(new ECB(4, 14), + new ECB(2, 15))))), + new Version(9, array(6, 26, 46), + array(new ECBlocks(30, array(new ECB(2, 116))), + new ECBlocks(22, array(new ECB(3, 36), + new ECB(2, 37))), + new ECBlocks(20, array(new ECB(4, 16), + new ECB(4, 17))), + new ECBlocks(24, array(new ECB(4, 12), + new ECB(4, 13))))), + new Version(10, array(6, 28, 50), + array(new ECBlocks(18, array(new ECB(2, 68), + new ECB(2, 69))), + new ECBlocks(26, array(new ECB(4, 43), + new ECB(1, 44))), + new ECBlocks(24, array(new ECB(6, 19), + new ECB(2, 20))), + new ECBlocks(28, array(new ECB(6, 15), + new ECB(2, 16))))), + new Version(11, array(6, 30, 54), + array(new ECBlocks(20, array(new ECB(4, 81))), + new ECBlocks(30, array(new ECB(1, 50), + new ECB(4, 51))), + new ECBlocks(28, array(new ECB(4, 22), + new ECB(4, 23))), + new ECBlocks(24, array(new ECB(3, 12), + new ECB(8, 13))))), + new Version(12, array(6, 32, 58), + array(new ECBlocks(24, array(new ECB(2, 92), + new ECB(2, 93))), + new ECBlocks(22, array(new ECB(6, 36), + new ECB(2, 37))), + new ECBlocks(26, array(new ECB(4, 20), + new ECB(6, 21))), + new ECBlocks(28, array(new ECB(7, 14), + new ECB(4, 15))))), + new Version(13, array(6, 34, 62), + array(new ECBlocks(26, array(new ECB(4, 107))), + new ECBlocks(22, array(new ECB(8, 37), + new ECB(1, 38))), + new ECBlocks(24, array(new ECB(8, 20), + new ECB(4, 21))), + new ECBlocks(22, array(new ECB(12, 11), + new ECB(4, 12))))), + new Version(14, array(6, 26, 46, 66), + array(new ECBlocks(30, array(new ECB(3, 115), + new ECB(1, 116))), + new ECBlocks(24, array(new ECB(4, 40), + new ECB(5, 41))), + new ECBlocks(20, array(new ECB(11, 16), + new ECB(5, 17))), + new ECBlocks(24, array(new ECB(11, 12), + new ECB(5, 13))))), + new Version(15, array(6, 26, 48, 70), + array(new ECBlocks(22, array(new ECB(5, 87), + new ECB(1, 88))), + new ECBlocks(24, array(new ECB(5, 41), + new ECB(5, 42))), + new ECBlocks(30, array(new ECB(5, 24), + new ECB(7, 25))), + new ECBlocks(24, array(new ECB(11, 12), + new ECB(7, 13))))), + new Version(16, array(6, 26, 50, 74), + array(new ECBlocks(24, array(new ECB(5, 98), + new ECB(1, 99))), + new ECBlocks(28, array(new ECB(7, 45), + new ECB(3, 46))), + new ECBlocks(24, array(new ECB(15, 19), + new ECB(2, 20))), + new ECBlocks(30, array(new ECB(3, 15), + new ECB(13, 16))))), + new Version(17, array(6, 30, 54, 78), + array(new ECBlocks(28, array(new ECB(1, 107), + new ECB(5, 108))), + new ECBlocks(28, array(new ECB(10, 46), + new ECB(1, 47))), + new ECBlocks(28, array(new ECB(1, 22), + new ECB(15, 23))), + new ECBlocks(28, array(new ECB(2, 14), + new ECB(17, 15))))), + new Version(18, array(6, 30, 56, 82), + array(new ECBlocks(30, array(new ECB(5, 120), + new ECB(1, 121))), + new ECBlocks(26, array(new ECB(9, 43), + new ECB(4, 44))), + new ECBlocks(28, array(new ECB(17, 22), + new ECB(1, 23))), + new ECBlocks(28, array(new ECB(2, 14), + new ECB(19, 15))))), + new Version(19, array(6, 30, 58, 86), + array(new ECBlocks(28, array(new ECB(3, 113), + new ECB(4, 114))), + new ECBlocks(26, array(new ECB(3, 44), + new ECB(11, 45))), + new ECBlocks(26, array(new ECB(17, 21), + new ECB(4, 22))), + new ECBlocks(26, array(new ECB(9, 13), + new ECB(16, 14))))), + new Version(20, array(6, 34, 62, 90), + array(new ECBlocks(28, array(new ECB(3, 107), + new ECB(5, 108))), + new ECBlocks(26, array(new ECB(3, 41), + new ECB(13, 42))), + new ECBlocks(30, array(new ECB(15, 24), + new ECB(5, 25))), + new ECBlocks(28, array(new ECB(15, 15), + new ECB(10, 16))))), + new Version(21, array(6, 28, 50, 72, 94), + array( new ECBlocks(28, array(new ECB(4, 116), + new ECB(4, 117))), + new ECBlocks(26, array(new ECB(17, 42))), + new ECBlocks(28, array(new ECB(17, 22), + new ECB(6, 23))), + new ECBlocks(30, array(new ECB(19, 16), + new ECB(6, 17))))), + new Version(22, array(6, 26, 50, 74, 98), + array(new ECBlocks(28, array(new ECB(2, 111), + new ECB(7, 112))), + new ECBlocks(28, array(new ECB(17, 46))), + new ECBlocks(30, array(new ECB(7, 24), + new ECB(16, 25))), + new ECBlocks(24, array(new ECB(34, 13))))), + new Version(23, array(6, 30, 54, 78, 102), + new ECBlocks(30, array(new ECB(4, 121), + new ECB(5, 122))), + new ECBlocks(28, array(new ECB(4, 47), + new ECB(14, 48))), + new ECBlocks(30, array(new ECB(11, 24), + new ECB(14, 25))), + new ECBlocks(30, array(new ECB(16, 15), + new ECB(14, 16)))), + new Version(24, array(6, 28, 54, 80, 106), + array(new ECBlocks(30, array(new ECB(6, 117), + new ECB(4, 118))), + new ECBlocks(28, array(new ECB(6, 45), + new ECB(14, 46))), + new ECBlocks(30, array(new ECB(11, 24), + new ECB(16, 25))), + new ECBlocks(30, array(new ECB(30, 16), + new ECB(2, 17))))), + new Version(25, array(6, 32, 58, 84, 110), + array(new ECBlocks(26, array(new ECB(8, 106), + new ECB(4, 107))), + new ECBlocks(28, array(new ECB(8, 47), + new ECB(13, 48))), + new ECBlocks(30, array(new ECB(7, 24), + new ECB(22, 25))), + new ECBlocks(30, array(new ECB(22, 15), + new ECB(13, 16))))), + new Version(26, array(6, 30, 58, 86, 114), + array(new ECBlocks(28, array(new ECB(10, 114), + new ECB(2, 115))), + new ECBlocks(28, array(new ECB(19, 46), + new ECB(4, 47))), + new ECBlocks(28, array(new ECB(28, 22), + new ECB(6, 23))), + new ECBlocks(30, array(new ECB(33, 16), + new ECB(4, 17))))), + new Version(27, array(6, 34, 62, 90, 118), + array(new ECBlocks(30, array(new ECB(8, 122), + new ECB(4, 123))), + new ECBlocks(28, array(new ECB(22, 45), + new ECB(3, 46))), + new ECBlocks(30, array(new ECB(8, 23), + new ECB(26, 24))), + new ECBlocks(30, array(new ECB(12, 15), + new ECB(28, 16))))), + new Version(28, array(6, 26, 50, 74, 98, 122), + array(new ECBlocks(30, array(new ECB(3, 117), + new ECB(10, 118))), + new ECBlocks(28, array(new ECB(3, 45), + new ECB(23, 46))), + new ECBlocks(30, array(new ECB(4, 24), + new ECB(31, 25))), + new ECBlocks(30, array(new ECB(11, 15), + new ECB(31, 16))))), + new Version(29, array(6, 30, 54, 78, 102, 126), + array(new ECBlocks(30, array(new ECB(7, 116), + new ECB(7, 117))), + new ECBlocks(28, array(new ECB(21, 45), + new ECB(7, 46))), + new ECBlocks(30, array(new ECB(1, 23), + new ECB(37, 24))), + new ECBlocks(30, array(new ECB(19, 15), + new ECB(26, 16))))), + new Version(30, array(6, 26, 52, 78, 104, 130), + array(new ECBlocks(30, array(new ECB(5, 115), + new ECB(10, 116))), + new ECBlocks(28, array(new ECB(19, 47), + new ECB(10, 48))), + new ECBlocks(30, array(new ECB(15, 24), + new ECB(25, 25))), + new ECBlocks(30, array(new ECB(23, 15), + new ECB(25, 16))))), + new Version(31, array(6, 30, 56, 82, 108, 134), + array(new ECBlocks(30, array(new ECB(13, 115), + new ECB(3, 116))), + new ECBlocks(28, array(new ECB(2, 46), + new ECB(29, 47))), + new ECBlocks(30, array(new ECB(42, 24), + new ECB(1, 25))), + new ECBlocks(30, array(new ECB(23, 15), + new ECB(28, 16))))), + new Version(32, array(6, 34, 60, 86, 112, 138), + array(new ECBlocks(30, array(new ECB(17, 115))), + new ECBlocks(28, array(new ECB(10, 46), + new ECB(23, 47))), + new ECBlocks(30, array(new ECB(10, 24), + new ECB(35, 25))), + new ECBlocks(30, array(new ECB(19, 15), + new ECB(35, 16))))), + new Version(33, array(6, 30, 58, 86, 114, 142), + array(new ECBlocks(30, array(new ECB(17, 115), + new ECB(1, 116))), + new ECBlocks(28, array(new ECB(14, 46), + new ECB(21, 47))), + new ECBlocks(30, array(new ECB(29, 24), + new ECB(19, 25))), + new ECBlocks(30, array(new ECB(11, 15), + new ECB(46, 16))))), + new Version(34, array(6, 34, 62, 90, 118, 146), + array(new ECBlocks(30, array(new ECB(13, 115), + new ECB(6, 116))), + new ECBlocks(28, array(new ECB(14, 46), + new ECB(23, 47))), + new ECBlocks(30, array(new ECB(44, 24), + new ECB(7, 25))), + new ECBlocks(30, array(new ECB(59, 16), + new ECB(1, 17))))), + new Version(35, array(6, 30, 54, 78, 102, 126, 150), + array(new ECBlocks(30, array(new ECB(12, 121), + new ECB(7, 122))), + new ECBlocks(28, array(new ECB(12, 47), + new ECB(26, 48))), + new ECBlocks(30, array(new ECB(39, 24), + new ECB(14, 25))), + new ECBlocks(30, array(new ECB(22, 15), + new ECB(41, 16))))), + new Version(36, array(6, 24, 50, 76, 102, 128, 154), + array(new ECBlocks(30, array(new ECB(6, 121), + new ECB(14, 122))), + new ECBlocks(28, array(new ECB(6, 47), + new ECB(34, 48))), + new ECBlocks(30, array(new ECB(46, 24), + new ECB(10, 25))), + new ECBlocks(30, array(new ECB(2, 15), + new ECB(64, 16))))), + new Version(37, array(6, 28, 54, 80, 106, 132, 158), + array(new ECBlocks(30, array(new ECB(17, 122), + new ECB(4, 123))), + new ECBlocks(28, array(new ECB(29, 46), + new ECB(14, 47))), + new ECBlocks(30, array(new ECB(49, 24), + new ECB(10, 25))), + new ECBlocks(30, array(new ECB(24, 15), + new ECB(46, 16))))), + new Version(38, array(6, 32, 58, 84, 110, 136, 162), + array(new ECBlocks(30, array(new ECB(4, 122), + new ECB(18, 123))), + new ECBlocks(28, array(new ECB(13, 46), + new ECB(32, 47))), + new ECBlocks(30, array(new ECB(48, 24), + new ECB(14, 25))), + new ECBlocks(30, array(new ECB(42, 15), + new ECB(32, 16))))), + new Version(39, array(6, 26, 54, 82, 110, 138, 166), + array(new ECBlocks(30, array(new ECB(20, 117), + new ECB(4, 118))), + new ECBlocks(28, array(new ECB(40, 47), + new ECB(7, 48))), + new ECBlocks(30, array(new ECB(43, 24), + new ECB(22, 25))), + new ECBlocks(30, array(new ECB(10, 15), + new ECB(67, 16))))), + new Version(40, array(6, 30, 58, 86, 114, 142, 170), + array(new ECBlocks(30, array(new ECB(19, 118), + new ECB(6, 119))), + new ECBlocks(28, array(new ECB(18, 47), + new ECB(31, 48))), + new ECBlocks(30, array(new ECB(34, 24), + new ECB(34, 25))), + new ECBlocks(30, array(new ECB(20, 15), + new ECB(61, 16))))) + ); + } +} + +/** + *

Encapsulates a set of error-correction blocks in one symbol version. Most versions will + * use blocks of differing sizes within one version, so, this encapsulates the parameters for + * each set of blocks. It also holds the number of error-correction codewords per block since it + * will be the same across all blocks within one version.

+ */ +final class ECBlocks +{ + private $ecCodewordsPerBlock; + private $ecBlocks; + + function __construct($ecCodewordsPerBlock, $ecBlocks) + { + $this->ecCodewordsPerBlock = $ecCodewordsPerBlock; + $this->ecBlocks = $ecBlocks; + } + + public function getECCodewordsPerBlock() + { + return $this->ecCodewordsPerBlock; + } + + public function getNumBlocks() + { + $total = 0; + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + return $total; + } + + public function getTotalECCodewords() + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + public function getECBlocks() + { + return $this->ecBlocks; + } +} + +/** + *

Encapsualtes the parameters for one error-correction block in one symbol version. + * This includes the number of data codewords, and the number of times a block with these + * parameters is used consecutively in the QR code version's format.

+ */ +final class ECB +{ + private $count; + private $dataCodewords; + + function __construct($count, $dataCodewords) + { + $this->count = $count; + $this->dataCodewords = $dataCodewords; + } + + public function getCount() + { + return $this->count; + } + + public function getDataCodewords() + { + return $this->dataCodewords; + } + + +//@Override + public function toString() + { + die('Version ECB toString()'); + // return parent::$versionNumber; + } + + +} + + diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php new file mode 100755 index 00000000..b6d41307 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php @@ -0,0 +1,60 @@ +Encapsulates an alignment pattern, which are the smaller square patterns found in + * all but the simplest QR Codes.

+ * + * @author Sean Owen + */ +final class AlignmentPattern extends ResultPoint { + +private $estimatedModuleSize; + +function __construct($posX, $posY, $estimatedModuleSize) { +parent::__construct($posX, $posY); +$this->estimatedModuleSize = $estimatedModuleSize; +} + + /** + *

Determines if this alignment pattern "about equals" an alignment pattern at the stated + * position and size -- meaning, it is at nearly the same center with nearly the same size.

+ */ + function aboutEquals($moduleSize, $i, $j) { + if (abs($i - $this->getY()) <= $moduleSize && abs($j - $this->getX()) <= $moduleSize) { + $moduleSizeDiff = abs($moduleSize - $this->estimatedModuleSize); + return $moduleSizeDiff <= 1.0 || $moduleSizeDiff <= $this->estimatedModuleSize; + } + return false; +} + + /** + * Combines this object's current estimate of a finder pattern position and module size + * with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. + */ + function combineEstimate($i, $j, $newModuleSize) { + $combinedX = ($this->getX() + $j) / 2.0; + $combinedY = ($this->getY() + $i) / 2.0; + $combinedModuleSize = ($this->estimatedModuleSize + $newModuleSize) / 2.0; + return new AlignmentPattern($combinedX, $combinedY, $combinedModuleSize); + } + +} \ No newline at end of file diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php new file mode 100755 index 00000000..0484ffa6 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php @@ -0,0 +1,277 @@ +This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder + * patterns but are smaller and appear at regular intervals throughout the image.

+ * + *

At the moment this only looks for the bottom-right alignment pattern.

+ * + *

This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, + * pasted and stripped down here for maximum performance but does unfortunately duplicate + * some code.

+ * + *

This class is thread-safe but not reentrant. Each thread must allocate its own object.

+ * + * @author Sean Owen + */ +final class AlignmentPatternFinder { + + private $image; + private $possibleCenters; + private $startX; + private $startY; + private $width; + private $height; + private $moduleSize; + private $crossCheckStateCount; + private $resultPointCallback; + + /** + *

Creates a finder that will look in a portion of the whole image.

+ * + * @param image image to search + * @param startX left column from which to start searching + * @param startY top row from which to start searching + * @param width width of region to search + * @param height height of region to search + * @param moduleSize estimated module size so far + */ + function __construct($image, + $startX, + $startY, + $width, + $height, + $moduleSize, + $resultPointCallback) { + $this->image = $image; + $this->possibleCenters = array(); + $this->startX = $startX; + $this->startY = $startY; + $this->width = $width; + $this->height = $height; + $this->moduleSize = $moduleSize; + $this->crossCheckStateCount = array(); + $this->resultPointCallback = $resultPointCallback; + } + + /** + *

This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since + * it's pretty performance-critical and so is written to be fast foremost.

+ * + * @return {@link AlignmentPattern} if found + * @throws NotFoundException if not found + */ + function find() { + $startX = $this->startX; + $height = $this->height; + $maxJ = $startX + $this->width; + $middleI = $this->startY + ($height / 2); + // We are looking for black/white/black modules in 1:1:1 ratio; + // this tracks the number of black/white/black modules seen so far + $stateCount = array(); + for ($iGen = 0; $iGen < $height; $iGen++) { + // Search from middle outwards + $i = $middleI + (($iGen & 0x01) == 0 ? ($iGen + 1) / 2 : -(($iGen + 1) / 2)); + $i = intval($i); + $stateCount[0] = 0; + $stateCount[1] = 0; + $stateCount[2] = 0; + $j = $startX; + // Burn off leading white pixels before anything else; if we start in the middle of + // a white run, it doesn't make sense to count its length, since we don't know if the + // white run continued to the left of the start point + while ($j < $maxJ && !$this->image->get($j, $i)) { + $j++; + } + $currentState = 0; + while ($j < $maxJ) { + if ($this->image->get($j, $i)) { + // Black pixel + if ($currentState == 1) { // Counting black pixels + $stateCount[$currentState]++; + } else { // Counting white pixels + if ($currentState == 2) { // A winner? + if ($this->foundPatternCross($stateCount)) { // Yes + $confirmed = $this->handlePossibleCenter($stateCount, $i, $j); + if ($confirmed != null) { + return $confirmed; + } + } + $stateCount[0] = $stateCount[2]; + $stateCount[1] = 1; + $stateCount[2] = 0; + $currentState = 1; + } else { + $stateCount[++$currentState]++; + } + } + } else { // White pixel + if ($currentState == 1) { // Counting black pixels + $currentState++; + } + $stateCount[$currentState]++; + } + $j++; + } + if ($this->foundPatternCross($stateCount)) { + $confirmed = $this->handlePossibleCenter($stateCount, $i, $maxJ); + if ($confirmed != null) { + return $confirmed; + } + } + + } + + // Hmm, nothing we saw was observed and confirmed twice. If we had + // any guess at all, return it. + if (count($this->possibleCenters)) { + return $this->possibleCenters[0]; + } + + throw NotFoundException::getNotFoundInstance(); + } + + /** + * Given a count of black/white/black pixels just seen and an end position, + * figures the location of the center of this black/white/black run. + */ + private static function centerFromEnd($stateCount, $end) { + return (float) ($end - $stateCount[2]) - $stateCount[1] / 2.0; + } + + /** + * @param stateCount count of black/white/black pixels just read + * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios + * used by alignment patterns to be considered a match + */ + private function foundPatternCross($stateCount) { + $moduleSize = $this->moduleSize; + $maxVariance = $moduleSize / 2.0; + for ($i = 0; $i < 3; $i++) { + if (abs($moduleSize - $stateCount[$i]) >= $maxVariance) { + return false; + } + } + return true; + } + + /** + *

After a horizontal scan finds a potential alignment pattern, this method + * "cross-checks" by scanning down vertically through the center of the possible + * alignment pattern to see if the same proportion is detected.

+ * + * @param startI row where an alignment pattern was detected + * @param centerJ center of the section that appears to cross an alignment pattern + * @param maxCount maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @return vertical center of alignment pattern, or {@link Float#NaN} if not found + */ + private function crossCheckVertical($startI, $centerJ, $maxCount, + $originalStateCountTotal) { + $image = $this->image; + + $maxI = $image->getHeight(); + $stateCount = $this->crossCheckStateCount; + $stateCount[0] = 0; + $stateCount[1] = 0; + $stateCount[2] = 0; + + // Start counting up from center + $i = $startI; + while ($i >= 0 && $image->get($centerJ, $i) && $stateCount[1] <= $maxCount) { + $stateCount[1]++; + $i--; + } + // If already too many modules in this state or ran off the edge: + if ($i < 0 || $stateCount[1] > $maxCount) { + return NAN; + } + while ($i >= 0 && !$image->get($centerJ, $i) && $stateCount[0] <= $maxCount) { + $stateCount[0]++; + $i--; + } + if ($stateCount[0] > $maxCount) { + return NAN; + } + + // Now also count down from center + $i = $startI + 1; + while ($i < $maxI && $image->get($centerJ, $i) && $stateCount[1] <= $maxCount) { + $stateCount[1]++; + $i++; + } + if ($i == $maxI || $stateCount[1] > $maxCount) { + return NAN; + } + while ($i < $maxI && !$image->get($centerJ, $i) && $stateCount[2] <= $maxCount) { + $stateCount[2]++; + $i++; + } + if ($stateCount[2] > $maxCount) { + return NAN; + } + + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2]; + if (5 * abs($stateCountTotal - $originalStateCountTotal) >= 2 * $originalStateCountTotal) { + return NAN; + } + + return $this->foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $i) : NAN; + } + + /** + *

This is called when a horizontal scan finds a possible alignment pattern. It will + * cross check with a vertical scan, and if successful, will see if this pattern had been + * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have + * found the alignment pattern.

+ * + * @param stateCount reading state module counts from horizontal scan + * @param i row where alignment pattern may be found + * @param j end of possible alignment pattern in row + * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not + */ + private function handlePossibleCenter($stateCount, $i, $j) { + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2]; + $centerJ = $this->centerFromEnd($stateCount, $j); + $centerI = $this->crossCheckVertical($i, (int) $centerJ, 2 * $stateCount[1], $stateCountTotal); + if (!is_nan($centerI)) { + $estimatedModuleSize = (float) ($stateCount[0] + $stateCount[1] + $stateCount[2]) / 3.0; + foreach ($this->possibleCenters as $center) { + // Look for about the same center and module size: + if ($center->aboutEquals($estimatedModuleSize, $centerI, $centerJ)) { + return $center->combineEstimate($centerI, $centerJ, $estimatedModuleSize); + } + } + // Hadn't found this before; save it + $point = new AlignmentPattern($centerJ, $centerI, $estimatedModuleSize); + $this->possibleCenters[] = $point; + if ($this->resultPointCallback != null) { + $this->resultPointCallback->foundPossibleResultPoint($point); + } + } + return null; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php new file mode 100755 index 00000000..2043a49a --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php @@ -0,0 +1,405 @@ +Encapsulates logic that can detect a QR Code in an image, even if the QR Code + * is rotated or skewed, or partially obscured.

+ * + * @author Sean Owen + */ +?> +image = $image; + } + + protected final function getImage() { + return $this->image; + } + + protected final function getResultPointCallback() { + return $this->resultPointCallback; + } + + /** + *

Detects a QR Code in an image.

+ * + * @return {@link DetectorResult} encapsulating results of detecting a QR Code + * @throws NotFoundException if QR Code cannot be found + * @throws FormatException if a QR Code cannot be decoded + */ + + + /** + *

Detects a QR Code in an image.

+ * + * @param hints optional hints to detector + * @return {@link DetectorResult} encapsulating results of detecting a QR Code + * @throws NotFoundException if QR Code cannot be found + * @throws FormatException if a QR Code cannot be decoded + */ + public final function detect($hints=null){/*Map*/ + + $resultPointCallback = $hints == null ? null : + $hints->get('NEED_RESULT_POINT_CALLBACK'); + /* resultPointCallback = hints == null ? null : + (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);*/ + $finder = new FinderPatternFinder($this->image, $resultPointCallback); + $info = $finder->find($hints); + + return $this->processFinderPatternInfo($info); + } + + protected final function processFinderPatternInfo($info){ + + $topLeft = $info->getTopLeft(); + $topRight = $info->getTopRight(); + $bottomLeft = $info->getBottomLeft(); + + $moduleSize = (float) $this->calculateModuleSize($topLeft, $topRight, $bottomLeft); + if ($moduleSize < 1.0) { + throw NotFoundException::getNotFoundInstance(); + } + $dimension =(int) $this->computeDimension($topLeft, $topRight, $bottomLeft, $moduleSize); + $provisionalVersion = Version::getProvisionalVersionForDimension($dimension); + $modulesBetweenFPCenters = $provisionalVersion->getDimensionForVersion() - 7; + + $alignmentPattern = null; +// Anything above version 1 has an alignment pattern + if (count($provisionalVersion->getAlignmentPatternCenters())> 0) { + +// Guess where a "bottom right" finder pattern would have been + $bottomRightX = $topRight->getX() - $topLeft->getX() + $bottomLeft->getX(); + $bottomRightY = $topRight->getY() - $topLeft->getY() + $bottomLeft->getY(); + +// Estimate that alignment pattern is closer by 3 modules +// from "bottom right" to known top left location + $correctionToTopLeft = 1.0 - 3.0 / (float) $modulesBetweenFPCenters; + $estAlignmentX = (int) ($topLeft->getX() + $correctionToTopLeft * ($bottomRightX - $topLeft->getX())); + $estAlignmentY = (int) ($topLeft->getY() + $correctionToTopLeft * ($bottomRightY - $topLeft->getY())); + +// Kind of arbitrary -- expand search radius before giving up + for ($i = 4; $i <= 16; $i <<= 1) {//?????????? + try { + $alignmentPattern = $this->findAlignmentInRegion($moduleSize, + $estAlignmentX, + $estAlignmentY, + (float) $i); + break; + } catch (NotFoundException $re) { +// try next round + } + } +// If we didn't find alignment pattern... well try anyway without it + } + + $transform = + $this->createTransform($topLeft, $topRight, $bottomLeft, $alignmentPattern, $dimension); + + $bits = $this->sampleGrid($this->image, $transform, $dimension); + + $points = array(); + if ($alignmentPattern == null) { + $points = array($bottomLeft, $topLeft, $topRight); + } else { + // die('$points = new ResultPoint[]{bottomLeft, topLeft, topRight, alignmentPattern};'); +$points = array($bottomLeft, $topLeft, $topRight, $alignmentPattern); + } + return new DetectorResult($bits, $points); + } + + private static function createTransform($topLeft, + $topRight, + $bottomLeft, + $alignmentPattern, + $dimension) { + $dimMinusThree = (float) $dimension - 3.5; + $bottomRightX = 0.0; + $bottomRightY = 0.0; + $sourceBottomRightX = 0.0; + $sourceBottomRightY = 0.0; + if ($alignmentPattern != null) { + $bottomRightX = $alignmentPattern->getX(); + $bottomRightY = $alignmentPattern->getY(); + $sourceBottomRightX = $dimMinusThree - 3.0; + $sourceBottomRightY = $sourceBottomRightX; + } else { +// Don't have an alignment pattern, just make up the bottom-right point + $bottomRightX = ($topRight->getX() - $topLeft->getX()) + $bottomLeft->getX(); + $bottomRightY = ($topRight->getY() - $topLeft->getY()) + $bottomLeft->getY(); + $sourceBottomRightX = $dimMinusThree; + $sourceBottomRightY = $dimMinusThree; + } + + return PerspectiveTransform::quadrilateralToQuadrilateral( + 3.5, + 3.5, + $dimMinusThree, + 3.5, + $sourceBottomRightX, + $sourceBottomRightY, + 3.5, + $dimMinusThree, + $topLeft->getX(), + $topLeft->getY(), + $topRight->getX(), + $topRight->getY(), + $bottomRightX, + $bottomRightY, + $bottomLeft->getX(), + $bottomLeft->getY()); + } + + private static function sampleGrid($image, $transform, + $dimension) { + + $sampler = GridSampler::getInstance(); + return $sampler->sampleGrid_($image, $dimension, $dimension, $transform); + } + + /** + *

Computes the dimension (number of modules on a size) of the QR Code based on the position + * of the finder patterns and estimated module size.

+ */ + private static function computeDimension($topLeft, + $topRight, + $bottomLeft, + $moduleSize) { + $tltrCentersDimension = MathUtils::round(ResultPoint::distance($topLeft, $topRight) / $moduleSize); + $tlblCentersDimension = MathUtils::round(ResultPoint::distance($topLeft, $bottomLeft) / $moduleSize); + $dimension = (($tltrCentersDimension + $tlblCentersDimension) / 2) + 7; + switch ($dimension & 0x03) { // mod 4 + case 0: + $dimension++; + break; +// 1? do nothing + case 2: + $dimension--; + break; + case 3: + throw NotFoundException::getNotFoundInstance(); + } + return $dimension; + } + + /** + *

Computes an average estimated module size based on estimated derived from the positions + * of the three finder patterns.

+ * + * @param topLeft detected top-left finder pattern center + * @param topRight detected top-right finder pattern center + * @param bottomLeft detected bottom-left finder pattern center + * @return estimated module size + */ + protected final function calculateModuleSize($topLeft, + $topRight, + $bottomLeft) { +// Take the average + return ($this->calculateModuleSizeOneWay($topLeft, $topRight) + + $this->calculateModuleSizeOneWay($topLeft, $bottomLeft)) / 2.0; + } + + /** + *

Estimates module size based on two finder patterns -- it uses + * {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the + * width of each, measuring along the axis between their centers.

+ */ + private function calculateModuleSizeOneWay($pattern, $otherPattern) { + $moduleSizeEst1 = $this->sizeOfBlackWhiteBlackRunBothWays($pattern->getX(), + (int) $pattern->getY(), + (int) $otherPattern->getX(), + (int) $otherPattern->getY()); + $moduleSizeEst2 = $this->sizeOfBlackWhiteBlackRunBothWays((int) $otherPattern->getX(), + (int) $otherPattern->getY(), + (int) $pattern->getX(), + (int) $pattern->getY()); + if (is_nan($moduleSizeEst1)) { + return $moduleSizeEst2 / 7.0; + } + if (is_nan($moduleSizeEst2)) { + return $moduleSizeEst1 / 7.0; + } +// Average them, and divide by 7 since we've counted the width of 3 black modules, +// and 1 white and 1 black module on either side. Ergo, divide sum by 14. + return ($moduleSizeEst1 + $moduleSizeEst2) / 14.0; + } + + /** + * See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of + * a finder pattern by looking for a black-white-black run from the center in the direction + * of another po$(another finder pattern center), and in the opposite direction too.

+ */ + private function sizeOfBlackWhiteBlackRunBothWays($fromX, $fromY, $toX, $toY) { + + $result = $this->sizeOfBlackWhiteBlackRun($fromX, $fromY, $toX, $toY); + +// Now count other way -- don't run off image though of course + $scale = 1.0; + $otherToX = $fromX - ($toX - $fromX); + if ($otherToX < 0) { + $scale = (float) $fromX / (float) ($fromX - $otherToX); + $otherToX = 0; + } else if ($otherToX >= $this->image->getWidth()) { + $scale = (float) ($this->image->getWidth() - 1 - $fromX) / (float) ($otherToX - $fromX); + $otherToX = $this->image->getWidth() - 1; + } + $otherToY = (int) ($fromY - ($toY - $fromY) * $scale); + + $scale = 1.0; + if ($otherToY < 0) { + $scale = (float) $fromY / (float) ($fromY - $otherToY); + $otherToY = 0; + } else if ($otherToY >= $this->image->getHeight()) { + $scale = (float) ($this->image->getHeight() - 1 - $fromY) / (float) ($otherToY - $fromY); + $otherToY = $this->image->getHeight() - 1; + } + $otherToX = (int) ($fromX + ($otherToX - $fromX) * $scale); + + $result += $this->sizeOfBlackWhiteBlackRun($fromX, $fromY, $otherToX, $otherToY); + +// Middle pixel is double-counted this way; subtract 1 + return $result - 1.0; + } + + /** + *

This method traces a line from a po$in the image, in the direction towards another point. + * It begins in a black region, and keeps going until it finds white, then black, then white again. + * It reports the distance from the start to this point.

+ * + *

This is used when figuring out how wide a finder pattern is, when the finder pattern + * may be skewed or rotated.

+ */ + private function sizeOfBlackWhiteBlackRun($fromX, $fromY, $toX, $toY) { +// Mild variant of Bresenham's algorithm; +// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + $steep = abs($toY - $fromY) > abs($toX - $fromX); + if ($steep) { + $temp = $fromX; + $fromX = $fromY; + $fromY = $temp; + $temp = $toX; + $toX = $toY; + $toY = $temp; + } + + $dx = abs($toX - $fromX); + $dy = abs($toY - $fromY); + $error = -$dx / 2; + $xstep = $fromX < $toX ? 1 : -1; + $ystep = $fromY < $toY ? 1 : -1; + +// In black pixels, looking for white, first or second time. + $state = 0; +// Loop up until x == toX, but not beyond + $xLimit = $toX + $xstep; + for ($x = $fromX, $y = $fromY; $x != $xLimit; $x += $xstep) { + $realX = $steep ? $y : $x; + $realY = $steep ? $x : $y; + +// Does current pixel mean we have moved white to black or vice versa? +// Scanning black in state 0,2 and white in state 1, so if we find the wrong +// color, advance to next state or end if we are in state 2 already + if (($state == 1) == $this->image->get($realX, $realY)) { + if ($state == 2) { + return MathUtils::distance($x, $y, $fromX, $fromY); + } + $state++; + } + + $error += $dy; + if ($error > 0) { + if ($y == $toY) { + break; + } + $y += $ystep; + $error -= $dx; + } + } +// Found black-white-black; give the benefit of the doubt that the next pixel outside the image +// is "white" so this last po$at (toX+xStep,toY) is the right ending. This is really a +// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. + if ($state == 2) { + return MathUtils::distance($toX + $xstep, $toY, $fromX, $fromY); + } +// else we didn't find even black-white-black; no estimate is really possible + return NAN; + } + + /** + *

Attempts to locate an alignment pattern in a limited region of the image, which is + * guessed to contain it. This method uses {@link AlignmentPattern}.

+ * + * @param overallEstModuleSize estimated module size so far + * @param estAlignmentX x coordinate of center of area probably containing alignment pattern + * @param estAlignmentY y coordinate of above + * @param allowanceFactor number of pixels in all directions to search from the center + * @return {@link AlignmentPattern} if found, or null otherwise + * @throws NotFoundException if an unexpected error occurs during detection + */ + protected final function findAlignmentInRegion($overallEstModuleSize, + $estAlignmentX, + $estAlignmentY, + $allowanceFactor) + { +// Look for an alignment pattern (3 modules in size) around where it +// should be + $allowance = (int) ($allowanceFactor * $overallEstModuleSize); + $alignmentAreaLeftX = max(0, $estAlignmentX - $allowance); + $alignmentAreaRightX = min($this->image->getWidth() - 1, $estAlignmentX + $allowance); + if ($alignmentAreaRightX - $alignmentAreaLeftX < $overallEstModuleSize * 3) { + throw NotFoundException::getNotFoundInstance(); + } + + $alignmentAreaTopY = max(0, $estAlignmentY - $allowance); + $alignmentAreaBottomY = min($this->image->getHeight() - 1, $estAlignmentY + $allowance); + if ($alignmentAreaBottomY - $alignmentAreaTopY < $overallEstModuleSize * 3) { + throw NotFoundException::getNotFoundInstance(); + } + + $alignmentFinder = + new AlignmentPatternFinder( + $this->image, + $alignmentAreaLeftX, + $alignmentAreaTopY, + $alignmentAreaRightX - $alignmentAreaLeftX, + $alignmentAreaBottomY - $alignmentAreaTopY, + $overallEstModuleSize, + $this->resultPointCallback); + return $alignmentFinder->find(); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php new file mode 100755 index 00000000..1900a78e --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php @@ -0,0 +1,81 @@ +Encapsulates a finder pattern, which are the three square patterns found in + * the corners of QR Codes. It also encapsulates a count of similar finder patterns, + * as a convenience to the finder's bookkeeping.

+ * + * @author Sean Owen + */ +final class FinderPattern extends ResultPoint { + +private $estimatedModuleSize; +private $count; + + + + function __construct($posX, $posY, $estimatedModuleSize, $count=1) { + parent::__construct($posX, $posY); + $this->estimatedModuleSize = $estimatedModuleSize; + $this->count = $count; +} + + public function getEstimatedModuleSize() { + return $this->estimatedModuleSize; + } + + function getCount() { + return $this->count; + } + + /* + void incrementCount() { + this.count++; + } + */ + + /** + *

Determines if this finder pattern "about equals" a finder pattern at the stated + * position and size -- meaning, it is at nearly the same center with nearly the same size.

+ */ + function aboutEquals($moduleSize, $i, $j) { + if (abs($i - $this->getY()) <= $moduleSize && abs($j - $this->getX()) <= $moduleSize) { + $moduleSizeDiff = abs($moduleSize - $this->estimatedModuleSize); + return $moduleSizeDiff <= 1.0 || $moduleSizeDiff <= $this->estimatedModuleSize; + } + return false; +} + + /** + * Combines this object's current estimate of a finder pattern position and module size + * with a new estimate. It returns a new {@code FinderPattern} containing a weighted average + * based on count. + */ + function combineEstimate($i, $j, $newModuleSize) { + $combinedCount = $this->count + 1; + $combinedX = ($this->count * $this->getX() + $j) / $combinedCount; + $combinedY = ($this->count * $this->getY() + $i) / $combinedCount; + $combinedModuleSize = ($this->count * $this->estimatedModuleSize + $newModuleSize) / $combinedCount; + return new FinderPattern($combinedX, $combinedY, $combinedModuleSize, $combinedCount); + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php new file mode 100755 index 00000000..d2fe473a --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php @@ -0,0 +1,705 @@ +This class attempts to find finder patterns in a QR Code. Finder patterns are the square + * markers at three corners of a QR Code.

+ * + *

This class is thread-safe but not reentrant. Each thread must allocate its own object. + * + * @author Sean Owen + */ +class FinderPatternFinder +{ + + private static $CENTER_QUORUM = 2; + protected static $MIN_SKIP = 3; // 1 pixel/module times 3 modules/center + protected static $MAX_MODULES = 57; // support up to version 10 for mobile clients + + private $image; + private $average; + private $possibleCenters; //private final List possibleCenters; + private $hasSkipped = false; + private $crossCheckStateCount; + private $resultPointCallback; + + /** + *

Creates a finder that will search the image for three finder patterns.

+ * + * @param image image to search + */ + public function __construct($image, $resultPointCallback = null) + { + $this->image = $image; + + + $this->possibleCenters = array();//new ArrayList<>(); + $this->crossCheckStateCount = fill_array(0,5,0); + $this->resultPointCallback = $resultPointCallback; + } + + protected final function getImage() + { + return $this->image; + } + + protected final function getPossibleCenters() + { //List getPossibleCenters() + return $this->possibleCenters; + } + + final function find($hints) + {/*final FinderPatternInfo find(Map hints) throws NotFoundException {*/ + $tryHarder = $hints != null && $hints['TRY_HARDER']; + $pureBarcode = $hints != null && $hints['PURE_BARCODE']; + $maxI = $this->image->getHeight(); + $maxJ = $this->image->getWidth(); + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + $iSkip = intval((3 * $maxI) / (4 * self::$MAX_MODULES)); + if ($iSkip < self::$MIN_SKIP || $tryHarder) { + $iSkip = self::$MIN_SKIP; + } + + $done = false; + $stateCount = array(); + for ($i = $iSkip - 1; $i < $maxI && !$done; $i += $iSkip) { + // Get a row of black/white values + $stateCount[0] = 0; + $stateCount[1] = 0; + $stateCount[2] = 0; + $stateCount[3] = 0; + $stateCount[4] = 0; + $currentState = 0; + for ($j = 0; $j < $maxJ; $j++) { + if ($this->image->get($j, $i)) { + // Black pixel + if (($currentState & 1) == 1) { // Counting white pixels + $currentState++; + } + $stateCount[$currentState]++; + } else { // White pixel + if (($currentState & 1) == 0) { // Counting black pixels + if ($currentState == 4) { // A winner? + if ($this->foundPatternCross($stateCount)) { // Yes + $confirmed = $this->handlePossibleCenter($stateCount, $i, $j, $pureBarcode); + if ($confirmed) { + // Start examining every other line. Checking each line turned out to be too + // expensive and didn't improve performance. + $iSkip = 2; + if ($this->hasSkipped) { + $done = $this->haveMultiplyConfirmedCenters(); + } else { + $rowSkip = $this->findRowSkip(); + if ($rowSkip > $stateCount[2]) { + // Skip rows between row of lower confirmed center + // and top of presumed third confirmed center + // but back up a bit to get a full chance of detecting + // it, entire width of center of finder pattern + + // Skip by rowSkip, but back off by $stateCount[2] (size of last center + // of pattern we saw) to be conservative, and also back off by iSkip which + // is about to be re-added + $i += $rowSkip - $stateCount[2] - $iSkip; + $j = $maxJ - 1; + } + } + } else { + + + + $stateCount[0] = $stateCount[2]; + $stateCount[1] = $stateCount[3]; + $stateCount[2] = $stateCount[4]; + $stateCount[3] = 1; + $stateCount[4] = 0; + $currentState = 3; + continue; + } + // Clear state to start looking again + $currentState = 0; + $stateCount[0] = 0; + $stateCount[1] = 0; + $stateCount[2] = 0; + $stateCount[3] = 0; + $stateCount[4] = 0; + } else { // No, shift counts back by two + $stateCount[0] = $stateCount[2]; + $stateCount[1] = $stateCount[3]; + $stateCount[2] = $stateCount[4]; + $stateCount[3] = 1; + $stateCount[4] = 0; + $currentState = 3; + } + } else { + $stateCount[++$currentState]++; + } + } else { // Counting white pixels + $stateCount[$currentState]++; + } + } + } + if ($this->foundPatternCross($stateCount)) { + $confirmed = $this->handlePossibleCenter($stateCount, $i, $maxJ, $pureBarcode); + if ($confirmed) { + $iSkip = $stateCount[0]; + if ($this->hasSkipped) { + // Found a third one + $done = $this->haveMultiplyConfirmedCenters(); + } + } + } + } + + $patternInfo = $this->selectBestPatterns(); + $patternInfo = ResultPoint::orderBestPatterns($patternInfo); + + return new FinderPatternInfo($patternInfo); + } + + /** + * Given a count of black/white/black/white/black pixels just seen and an end position, + * figures the location of the center of this run. + */ + private static function centerFromEnd($stateCount, $end) + { + return (float)($end - $stateCount[4] - $stateCount[3]) - $stateCount[2] / 2.0; + } + + /** + * @param $stateCount ; count of black/white/black/white/black pixels just read + * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios + * used by finder patterns to be considered a match + */ + protected static function foundPatternCross($stateCount) + { + $totalModuleSize = 0; + for ($i = 0; $i < 5; $i++) { + $count = $stateCount[$i]; + if ($count == 0) { + return false; + } + $totalModuleSize += $count; + } + if ($totalModuleSize < 7) { + return false; + } + $moduleSize = $totalModuleSize / 7.0; + $maxVariance = $moduleSize / 2.0; + // Allow less than 50% variance from 1-1-3-1-1 proportions + return + abs($moduleSize - $stateCount[0]) < $maxVariance && + abs($moduleSize - $stateCount[1]) < $maxVariance && + abs(3.0 * $moduleSize - $stateCount[2]) < 3 * $maxVariance && + abs($moduleSize - $stateCount[3]) < $maxVariance && + abs($moduleSize - $stateCount[4]) < $maxVariance; + } + + private function getCrossCheckStateCount() + { + $this->crossCheckStateCount[0] = 0; + $this->crossCheckStateCount[1] = 0; + $this->crossCheckStateCount[2] = 0; + $this->crossCheckStateCount[3] = 0; + $this->crossCheckStateCount[4] = 0; + return $this->crossCheckStateCount; + } + + /** + * After a vertical and horizontal scan finds a potential finder pattern, this method + * "cross-cross-cross-checks" by scanning down diagonally through the center of the possible + * finder pattern to see if the same proportion is detected. + * + * @param $startI ; row where a finder pattern was detected + * @param centerJ ; center of the section that appears to cross a finder pattern + * @param $maxCount ; maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @param originalStateCountTotal ; The original state count total. + * @return true if proportions are withing expected limits + */ + private function crossCheckDiagonal($startI, $centerJ, $maxCount, $originalStateCountTotal) + { + $stateCount = $this->getCrossCheckStateCount(); + + // Start counting up, left from center finding black center mass + $i = 0; + $startI = intval($startI); + $centerJ = intval($centerJ); + while ($startI >= $i && $centerJ >= $i && $this->image->get($centerJ - $i, $startI - $i)) { + $stateCount[2]++; + $i++; + } + + if ($startI < $i || $centerJ < $i) { + return false; + } + + // Continue up, left finding white space + while ($startI >= $i && $centerJ >= $i && !$this->image->get($centerJ - $i, $startI - $i) && + $stateCount[1] <= $maxCount) { + $stateCount[1]++; + $i++; + } + + // If already too many modules in this state or ran off the edge: + if ($startI < $i || $centerJ < $i || $stateCount[1] > $maxCount) { + return false; + } + + // Continue up, left finding black border + while ($startI >= $i && $centerJ >= $i && $this->image->get($centerJ - $i, $startI - $i) && + $stateCount[0] <= $maxCount) { + $stateCount[0]++; + $i++; + } + if ($stateCount[0] > $maxCount) { + return false; + } + + $maxI = $this->image->getHeight(); + $maxJ = $this->image->getWidth(); + + // Now also count down, right from center + $i = 1; + while ($startI + $i < $maxI && $centerJ + $i < $maxJ && $this->image->get($centerJ + $i, $startI + $i)) { + $stateCount[2]++; + $i++; + } + + // Ran off the edge? + if ($startI + $i >= $maxI || $centerJ + $i >= $maxJ) { + return false; + } + + while ($startI + $i < $maxI && $centerJ + $i < $maxJ && !$this->image->get($centerJ + $i, $startI + $i) && + $stateCount[3] < $maxCount) { + $stateCount[3]++; + $i++; + } + + if ($startI + $i >= $maxI || $centerJ + $i >= $maxJ || $stateCount[3] >= $maxCount) { + return false; + } + + while ($startI + $i < $maxI && $centerJ + $i < $maxJ && $this->image->get($centerJ + $i, $startI + $i) && + $stateCount[4] < $maxCount) { + $stateCount[4]++; + $i++; + } + + if ($stateCount[4] >= $maxCount) { + return false; + } + + // If we found a finder-pattern-like section, but its size is more than 100% different than + // the original, assume it's a false positive + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] + $stateCount[4]; + return + abs($stateCountTotal - $originalStateCountTotal) < 2 * $originalStateCountTotal && + $this->foundPatternCross($stateCount); + } + + /** + *

After a horizontal scan finds a potential finder pattern, this method + * "cross-checks" by scanning down vertically through the center of the possible + * finder pattern to see if the same proportion is detected.

+ * + * @param $startI ; row where a finder pattern was detected + * @param centerJ ; center of the section that appears to cross a finder pattern + * @param $maxCount ; maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @return vertical center of finder pattern, or {@link Float#NaN} if not found + */ + private function crossCheckVertical($startI, $centerJ, $maxCount, + $originalStateCountTotal) + { + $image = $this->image; + + $maxI = $image->getHeight(); + $stateCount = $this->getCrossCheckStateCount(); + + // Start counting up from center + $i = $startI; + while ($i >= 0 && $image->get($centerJ, $i)) { + $stateCount[2]++; + $i--; + } + if ($i < 0) { + return NAN; + } + while ($i >= 0 && !$image->get($centerJ, $i) && $stateCount[1] <= $maxCount) { + $stateCount[1]++; + $i--; + } + // If already too many modules in this state or ran off the edge: + if ($i < 0 || $stateCount[1] > $maxCount) { + return NAN; + } + while ($i >= 0 && $image->get($centerJ, $i) && $stateCount[0] <= $maxCount) { + $stateCount[0]++; + $i--; + } + if ($stateCount[0] > $maxCount) { + return NAN; + } + + // Now also count down from center + $i = $startI + 1; + while ($i < $maxI && $image->get($centerJ, $i)) { + $stateCount[2]++; + $i++; + } + if ($i == $maxI) { + return NAN; + } + while ($i < $maxI && !$image->get($centerJ, $i) && $stateCount[3] < $maxCount) { + $stateCount[3]++; + $i++; + } + if ($i == $maxI || $stateCount[3] >= $maxCount) { + return NAN; + } + while ($i < $maxI && $image->get($centerJ, $i) && $stateCount[4] < $maxCount) { + $stateCount[4]++; + $i++; + } + if ($stateCount[4] >= $maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is more than 40% different than + // the original, assume it's a false positive + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] + + $stateCount[4]; + if (5 * abs($stateCountTotal - $originalStateCountTotal) >= 2 * $originalStateCountTotal) { + return NAN; + } + + return $this->foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $i) : NAN; + } + + /** + *

Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, + * except it reads horizontally instead of vertically. This is used to cross-cross + * check a vertical cross check and locate the real center of the alignment pattern.

+ */ + private function crossCheckHorizontal($startJ, $centerI, $maxCount, + $originalStateCountTotal) + { + $image = $this->image; + + $maxJ = $this->image->getWidth(); + $stateCount = $this->getCrossCheckStateCount(); + + $j = $startJ; + while ($j >= 0 && $image->get($j, $centerI)) { + $stateCount[2]++; + $j--; + } + if ($j < 0) { + return NAN; + } + while ($j >= 0 && !$image->get($j, $centerI) && $stateCount[1] <= $maxCount) { + $stateCount[1]++; + $j--; + } + if ($j < 0 || $stateCount[1] > $maxCount) { + return NAN; + } + while ($j >= 0 && $image->get($j, $centerI) && $stateCount[0] <= $maxCount) { + $stateCount[0]++; + $j--; + } + if ($stateCount[0] > $maxCount) { + return NAN; + } + + $j = $startJ + 1; + while ($j < $maxJ && $image->get($j, $centerI)) { + $stateCount[2]++; + $j++; + } + if ($j == $maxJ) { + return NAN; + } + while ($j < $maxJ && !$image->get($j, $centerI) && $stateCount[3] < $maxCount) { + $stateCount[3]++; + $j++; + } + if ($j == $maxJ || $stateCount[3] >= $maxCount) { + return NAN; + } + while ($j < $maxJ && $this->image->get($j, $centerI) && $stateCount[4] < $maxCount) { + $stateCount[4]++; + $j++; + } + if ($stateCount[4] >= $maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is significantly different than + // the original, assume it's a false positive + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] + + $stateCount[4]; + if (5 * abs($stateCountTotal - $originalStateCountTotal) >= $originalStateCountTotal) { + return NAN; + } + + return $this->foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $j) : NAN; + } + + /** + *

This is called when a horizontal scan finds a possible alignment pattern. It will + * cross check with a vertical scan, and if successful, will, ah, cross-cross-check + * with another horizontal scan. This is needed primarily to locate the real horizontal + * center of the pattern in cases of extreme skew. + * And then we cross-cross-cross check with another diagonal scan.

+ * + *

If that succeeds the finder pattern location is added to a list that tracks + * the number of times each location has been nearly-matched as a finder pattern. + * Each additional find is more evidence that the location is in fact a finder + * pattern center + * + * @param $stateCount reading state module counts from horizontal scan + * @param i row where finder pattern may be found + * @param j end of possible finder pattern in row + * @param pureBarcode true if in "pure barcode" mode + * @return true if a finder pattern candidate was found this time + */ + protected final function handlePossibleCenter($stateCount, $i, $j, $pureBarcode) + { + $stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] + + $stateCount[4]; + $centerJ = $this->centerFromEnd($stateCount, $j); + $centerI = $this->crossCheckVertical($i, intval($centerJ), $stateCount[2], $stateCountTotal); + if (!is_nan($centerI)) { + // Re-cross check + $centerJ = $this->crossCheckHorizontal(intval($centerJ), intval($centerI), $stateCount[2], $stateCountTotal); + if (!is_nan($centerJ) && + (!$pureBarcode || $this->crossCheckDiagonal(intval($centerI), intval($centerJ), $stateCount[2], $stateCountTotal)) + ) { + $estimatedModuleSize = (float)$stateCountTotal / 7.0; + $found = false; + for ($index = 0; $index < count($this->possibleCenters); $index++) { + $center = $this->possibleCenters[$index]; + // Look for about the same center and module size: + if ($center->aboutEquals($estimatedModuleSize, $centerI, $centerJ)) { + $this->possibleCenters[$index] = $center->combineEstimate($centerI, $centerJ, $estimatedModuleSize); + $found = true; + break; + } + } + if (!$found) { + $point = new FinderPattern($centerJ, $centerI, $estimatedModuleSize); + $this->possibleCenters[] = $point; + if ($this->resultPointCallback != null) { + $this->resultPointCallback->foundPossibleResultPoint($point); + } + } + return true; + } + } + return false; + } + + /** + * @return number of rows we could safely skip during scanning, based on the first + * two finder patterns that have been located. In some cases their position will + * allow us to infer that the third pattern must lie below a certain point farther + * down in the image. + */ + private function findRowSkip() + { + $max = count($this->possibleCenters); + if ($max <= 1) { + return 0; + } + $firstConfirmedCenter = null; + foreach ($this->possibleCenters as $center) { + + + if ($center->getCount() >= self::$CENTER_QUORUM) { + if ($firstConfirmedCenter == null) { + $firstConfirmedCenter = $center; + } else { + // We have two confirmed centers + // How far down can we skip before resuming looking for the next + // pattern? In the worst case, only the difference between the + // difference in the x / y coordinates of the two centers. + // This is the case where you find top left last. + $this->hasSkipped = true; + return intval((abs($firstConfirmedCenter->getX() - $center->getX()) - + abs($firstConfirmedCenter->getY() - $center->getY())) / 2); + } + } + } + return 0; + } + + /** + * @return true iff we have found at least 3 finder patterns that have been detected + * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the + * candidates is "pretty similar" + */ + private function haveMultiplyConfirmedCenters() + { + $confirmedCount = 0; + $totalModuleSize = 0.0; + $max = count($this->possibleCenters); + foreach ($this->possibleCenters as $pattern) { + if ($pattern->getCount() >= self::$CENTER_QUORUM) { + $confirmedCount++; + $totalModuleSize += $pattern->getEstimatedModuleSize(); + } + } + if ($confirmedCount < 3) { + return false; + } + // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" + // and that we need to keep looking. We detect this by asking if the estimated module sizes + // vary too much. We arbitrarily say that when the total deviation from average exceeds + // 5% of the total module size estimates, it's too much. + $average = $totalModuleSize / (float)$max; + $totalDeviation = 0.0; + foreach ($this->possibleCenters as $pattern) { + $totalDeviation += abs($pattern->getEstimatedModuleSize() - $average); + } + return $totalDeviation <= 0.05 * $totalModuleSize; + } + + /** + * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are + * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module + * size differs from the average among those patterns the least + * @throws NotFoundException if 3 such finder patterns do not exist + */ + private function selectBestPatterns() + { + $startSize = count($this->possibleCenters); + if ($startSize < 3) { + // Couldn't find enough finder patterns + throw new NotFoundException; + } + + // Filter outlier possibilities whose module size is too different + if ($startSize > 3) { + // But we can only afford to do so if we have at least 4 possibilities to choose from + $totalModuleSize = 0.0; + $square = 0.0; + foreach ($this->possibleCenters as $center) { + $size = $center->getEstimatedModuleSize(); + $totalModuleSize += $size; + $square += $size * $size; + } + $this->average = $totalModuleSize / (float)$startSize; + $stdDev = (float)sqrt($square / $startSize - $this->average * $this->average); + + usort($this->possibleCenters, array($this,'FurthestFromAverageComparator')); + + $limit = max(0.2 * $this->average, $stdDev); + + for ($i = 0; $i < count($this->possibleCenters) && count($this->possibleCenters) > 3; $i++) { + $pattern = $this->possibleCenters[$i]; + if (abs($pattern->getEstimatedModuleSize() - $this->average) > $limit) { + unset($this->possibleCenters[$i]);//возможно что ключи меняются в java при вызове .remove(i) ??? + $this->possibleCenters = array_values($this->possibleCenters); + $i--; + } + } + } + + if (count($this->possibleCenters) > 3) { + // Throw away all but those first size candidate points we found. + + $totalModuleSize = 0.0; + foreach ($this->possibleCenters as $possibleCenter) { + $totalModuleSize += $possibleCenter->getEstimatedModuleSize(); + } + + $this->average = $totalModuleSize / (float)count($this->possibleCenters); + + usort($this->possibleCenters, array($this,'CenterComparator')); + + array_slice($this->possibleCenters, 3, count($this->possibleCenters) - 3); + + + } + + return array($this->possibleCenters[0], $this->possibleCenters[1], $this->possibleCenters[2]); + + + } + /** + *

Orders by furthest from average

+ */ +public function FurthestFromAverageComparator($center1, $center2) +{ + + $dA = abs($center2->getEstimatedModuleSize() - $this->average); + $dB = abs($center1->getEstimatedModuleSize() - $this->average); + if ($dA < $dB) { + return -1; + } elseif ($dA == $dB) { + return 0; + } else { + return 1; + } +} + /** + *

Orders by {@link FinderPattern#getCount()}, descending.

+ */ + + //@Override + public function CenterComparator($center1, $center2) { + if ($center2->getCount() == $center1->getCount()) { + $dA = abs($center2->getEstimatedModuleSize() - $this->average); + $dB = abs($center1->getEstimatedModuleSize() - $this->average); + if($dA < $dB){ + return 1; + }elseif( $dA == $dB){ + return 0; + }else{ + return -1; + } + + } else { + return $center2->getCount() - $center1->getCount(); + } + + } +} + + + + + + diff --git a/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php new file mode 100755 index 00000000..801b7df1 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php @@ -0,0 +1,50 @@ +Encapsulates information about finder patterns in an image, including the location of + * the three finder patterns, and their estimated module size.

+ * + * @author Sean Owen + */ + final class FinderPatternInfo { + +private $bottomLeft; +private $topLeft; +private $topRight; + +public function __construct($patternCenters) { +$this->bottomLeft = $patternCenters[0]; +$this->topLeft = $patternCenters[1]; +$this->topRight = $patternCenters[2]; +} + + public function getBottomLeft() { + return $this->bottomLeft; + } + + public function getTopLeft() { + return $this->topLeft; + } + + public function getTopRight() { + return $this->topRight; + } + +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/phpunit.xml.dist b/vendor/khanamiryan/qrcode-detector-decoder/phpunit.xml.dist new file mode 100755 index 00000000..7c557c8c --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/phpunit.xml.dist @@ -0,0 +1,10 @@ + + + tests + + + + src + + + diff --git a/vendor/khanamiryan/qrcode-detector-decoder/tests/QrReaderTest.php b/vendor/khanamiryan/qrcode-detector-decoder/tests/QrReaderTest.php new file mode 100755 index 00000000..0521ec33 --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/tests/QrReaderTest.php @@ -0,0 +1,15 @@ +assertSame("Hello world!", $qrcode->text()); + } +} diff --git a/vendor/khanamiryan/qrcode-detector-decoder/tests/bootstrap.php b/vendor/khanamiryan/qrcode-detector-decoder/tests/bootstrap.php new file mode 100755 index 00000000..a3f233fc --- /dev/null +++ b/vendor/khanamiryan/qrcode-detector-decoder/tests/bootstrap.php @@ -0,0 +1,3 @@ + + * @copyright 2023 KrmPesan + */ + +namespace KrmPesan; + +use DateTime; +use DateTimeZone; +use Exception; + +/** + * KrmPesan Client Class For Handle REST API Request. + * + * @see https://docs.krmpesan.com/ + */ +class ClientV3 +{ + /** + * Default Curl Timeout. + * + * @var int + * + * @see https://www.php.net/manual/en/function.curl-setopt + */ + protected $timeout; + + /** + * Default API Url. + * + * @var string + */ + protected $apiUrl = 'https://api.krmpesan.app'; + + /** + * Default TimeZone For DateTime + * Example: Asia/Jakarta. + * + * @var string + */ + protected $timezone; + + /** + * Store Token to File JSON Format. + */ + protected $tokenFile; + + /** + * API Token. + * + * @var string + */ + protected $token; + + /** + * Refresh Token. + * + * @var string + */ + protected $refreshToken; + + /** + * API Token. + * + * @var string + */ + protected $deviceId; + + /** + * Token Expired. + * + * @var string + */ + protected $expiredAt; + + /** + * Custom Request Header. + * + * @var array + */ + protected $customHeader; + + /** + * Construct Function. + * + * @param array $data + */ + public function __construct(array $data) + { + $this->timezone = isset($data['timezone']) ? $data['timezone'] : 'Asia/Jakarta'; + + // Set Token Path + if (isset($data['tokenFile']) and !empty($data['tokenFile'])) { + // check path directory is exist + if (!is_dir($data['tokenFile'])) { + throw new Exception('Directory not found.'); + } + + // save path + $this->tokenFile = $data['tokenFile'] . '/token.json'; + + // load token + $this->getToken(); + } else { + // Set Token (optional) + $this->token = $data['idToken']; + + // Set DeviceId + if (!isset($data['deviceId']) or empty($data['deviceId'])) { + throw new Exception('DeviceId is required.'); + } else { + $this->deviceId = $data['deviceId']; + } + + // Set Refresh Token + if (!isset($data['refreshToken']) or empty($data['refreshToken'])) { + throw new Exception('Token is required.'); + } else { + $this->refreshToken = $data['refreshToken']; + } + } + + // Set Custom Header + $this->customHeader = $data['headers'] ?? null; + + // validate token + $this->validateToken(); + } + + /** + * Curl Post or Get Function. + * + * @param string $type + * @param string $url + * @param array $form + */ + private function action($type, $url, $form = null, $file = null) + { + // setup url + $buildUrl = $this->apiUrl . '/' . $url; + + // set default header + $headers = []; + $headers[] = 'Content-Type: application/json'; + $headers[] = 'Authorization: Bearer ' . $this->token; + + // use custom header if not null + if ($this->customHeader) { + $headers = $this->customHeader; + } + + // build curl instance + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $buildUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, false); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + if (isset($file)) { + curl_setopt($ch, CURLOPT_INFILE, fopen($file, 'r')); + curl_setopt($ch, CURLOPT_INFILESIZE, filesize($file)); + } else { + $headers[] = 'Content-Type: application/json'; + } + + if (isset($form)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $form); + } + + // check action type + if ($type == 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + } elseif ($type == 'PUT') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); + } elseif ($type == 'DELETE') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + } else { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); + } + + // running curl + $result = curl_exec($ch); + + // throw error + if (curl_errno($ch)) { + throw new Exception(curl_error($ch)); + } + + // stop connection + curl_close($ch); + + // return result request + return $result; + } + + public function request($type, $url, $form = null) + { + try { + $this->validateToken(); + + return $this->action($type, $url, $form); + } catch (Exception $e) { + throw new Exception($e->getMessage()); + } + } + + /** + * Refresh Token. + * + * @return void + */ + public function refreshToken() + { + $url = 'tokens?refresh_token=' . $this->refreshToken . '&device_key=' . $this->deviceId; + $response = $this->action('GET', $url); + $data = json_decode($response, true); + $this->token = $data['IdToken']; + + // load token to internal function + $this->storeToken(); + + return $data; + } + + public function getToken() + { + if (isset($this->tokenFile) and !empty($this->tokenFile)) { + $getFile = file_get_contents($this->tokenFile); + $parseFile = json_decode($getFile, true); + + $refreshToken = isset($parseFile['refreshToken']) ? $parseFile['refreshToken'] : null; + $deviceId = isset($parseFile['deviceId']) ? $parseFile['deviceId'] : null; + $idToken = isset($parseFile['idToken']) ? $parseFile['idToken'] : null; + $expiredAt = isset($parseFile['expiredAt']) ? $parseFile['expiredAt'] : null; + + if (!$refreshToken) { + throw new Exception('refreshToken Not Found at ' . $this->tokenFile); + } + + // set refresh token + $this->refreshToken = $refreshToken; + + if (!$deviceId) { + throw new Exception('deviceId Not Found at ' . $this->tokenFile); + } + + // set refresh token + $this->deviceId = $deviceId; + + if (!$idToken xor !$expiredAt) { + $this->refreshToken(); + } else { + $this->token = $idToken; + $this->expiredAt = $expiredAt; + } + } + + $result = [ + 'idToken' => $this->token, + 'refreshToken' => $this->refreshToken, + 'expiredAt' => $this->expiredAt, + ]; + + return $result; + } + + public function storeToken() + { + if (isset($this->tokenFile) and !empty($this->tokenFile)) { + try { + $getFile = file_get_contents($this->tokenFile); + $parseFile = json_decode($getFile, true); + + $date = new DateTime('now', new DateTimeZone($this->timezone)); + $date->modify('+1 day'); + $parseFile['idToken'] = $this->token; + $parseFile['expiredAt'] = $date->format('Y-m-d H:i:s'); + + file_put_contents($this->tokenFile, json_encode($parseFile)); + } catch (Exception $e) { + throw new Exception('tokenFile Error.!'); + } + } + } + + public function validateToken() + { + try { + $date = new DateTime('now', new DateTimeZone($this->timezone)); + $now = $date->format('Y-m-d H:i:s'); + + if ($now > $this->expiredAt) { + $this->refreshToken(); + } + + // success + } catch (Exception $e) { + // error + print_r($e); + } + } + + /** + * Create Template Message. + * + * @param string $name + * @param string $category UTILLITY, AUTHENTICATION, MARKETING + * @param string $description + */ + public function createTemplate($name, $category, $description) + { + // build form + $form = json_encode([ + 'name' => $name, + 'category' => $category, + 'description' => $description, + ]); + + return $this->request('POST', 'messages/template', $form); + } + + /** + * Create Template Language. + * + * @param string $slug + * @param string $lang en, id + * @param string $message + * @param array $fields ["fields-1", "fields-2", "fields-3"] + * @param array $header [ + * "type" => "image|document", + * "url" => "https://example.com/image.png" + * ] + * @param string $footer + * @param array $button + */ + public function createTemplateLang($slug, $lang, $message, $fields, $header = null, $footer = null, $button = null) + { + // build form + $form = json_encode([ + 'slug' => $slug, + 'language' => $lang, + 'message' => $message, + 'fields' => $fields, + 'header' => isset($header) ? $header : null, + 'footer' => isset($footer) ? $footer : null, + 'button' => isset($button) ? $button : null, + ]); + + return $this->request('POST', 'messages/template/lang', $form); + } + + /** + * Send Message Text Template with Parameter or Without Parameter. + * + * @param string|int $to + * @param string $templateLanguage + * @param string $templateName + * @param array|null $body + */ + public function sendMessageTemplateText($to, $templateName, $templateLanguage, $body = null) + { + // build form + $form = [ + 'phone' => $to, + 'template_name' => $templateName, + 'template_language' => $templateLanguage, + ]; + + // use body if not null + if (isset($body) or !empty($body)) { + $form['template'] = (object) [ + 'body' => $body, + ]; + } + + return $this->request('POST', 'messages', json_encode($form)); + } + + /** + * Send Message Image. + * + * @param string|int $to + * @param string $templateLanguage + * @param string $templateName + * @param array $body + * @param string $image + * + * @return void + */ + public function sendMessageTemplateImage($to, $templateName, $templateLanguage, $body, $image) + { + // build form + $form = json_encode([ + 'phone' => $to, + 'template_name' => $templateName, + 'template_language' => $templateLanguage, + 'template' => (object) [ + 'body' => $body, + 'header' => [ + 'type' => 'image', + 'url' => $image, + ], + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Send Message Document. + * + * @param string|int $to + * @param string $templateLanguage + * @param string $templateName + * @param array $body + * @param string $document + * + * @return void + */ + public function sendMessageTemplateDocument($to, $templateName, $templateLanguage, $body, $document) + { + // build form + $form = json_encode([ + 'phone' => $to, + 'template_name' => $templateName, + 'template_language' => $templateLanguage, + 'template' => (object) [ + 'body' => $body, + 'header' => [ + 'type' => 'document', + 'url' => $document, + ], + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Send Message Button. + * + * @param string|int $to + * @param string $templateLanguage + * @param string $templateName + * @param array $body + * @param string $button + * + * @return void + */ + public function sendMessageTemplateButton($to, $templateName, $templateLanguage, $body, $button) + { + // build form + $form = json_encode([ + 'phone' => $to, + 'template_name' => $templateName, + 'template_language' => $templateLanguage, + 'template' => (object) [ + 'body' => $body, + 'buttons' => [ + 'url' => $button, + ], + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Send Reply Text. + * + * @param string|int $to + * @param string $text + * + * @return void + */ + public function sendReplyText($to, $text) + { + // build form + $form = json_encode([ + 'phone' => $to, + 'reply' => (object) [ + 'type' => 'text', + 'text' => $text, + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Send Reply Image. + * + * @param string|int $to + * @param string $image + * @param string $caption + * + * @return void + */ + public function sendReplyImage($to, $image, $caption = '') + { + // build form + $form = json_encode([ + 'phone' => $to, + 'reply' => (object) [ + 'type' => 'image', + 'image' => $image, + 'caption' => $caption, + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Send Reply document. + * + * @param string|int $to + * @param string $document + * + * @return void + */ + public function sendReplyDocument($to, $document) + { + // build form + $form = json_encode([ + 'phone' => $to, + 'reply' => (object) [ + 'type' => 'image', + 'document' => $document, + ], + ]); + + return $this->request('POST', 'messages', $form); + } + + /** + * Get Device Data. + */ + public function getDevice() + { + return $this->request('GET', 'devices'); + } + + /** + * Get All Messages. + */ + public function getMessages() + { + return $this->request('GET', 'messages'); + } + + public function upload($fileData) + { + // parse file and get file information + // https://www.php.net/manual/en/function.realpath + $file = realpath($fileData); + // https://www.php.net/manual/en/function.basename + $filename = basename($file); + // https://www.php.net/manual/en/function.mime-content-type + $filemime = mime_content_type($file); + + $presign = $this->request('POST', 'files/generate', json_encode([ + 'filename' => $filename, + 'mime' => $filemime, + 'expired' => 30, + ])); + + $resp = json_decode($presign, true); + + if (!isset($resp['data']) and !isset($resp['data']['url'])) { + throw new Exception('Failed to generate presign url'); + } + + $url = $resp['data']['url']; + $urlClean = explode('?', $url)[0]; + + // Create a cURL handle + $curl = curl_init(); + + // Set the cURL options + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_PUT, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYSTATUS, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_INFILE, fopen($fileData, 'r')); + curl_setopt($curl, CURLOPT_INFILESIZE, filesize($fileData)); + curl_setopt($curl, CURLOPT_HTTPHEADER, ["Content-Type: $filemime"]); + + // Execute the cURL request + $response = curl_exec($curl); + + // Check if the request was successful + if ($response === false) { + throw new Exception('Error uploading file: ' . curl_error($curl)); + } + + // Close the cURL handle + curl_close($curl); + + return $urlClean; + } + + /** + * Send Message Template Authentication. + * + * @param string|int $to + * @param string $templateName + * @param string $templateLanguage + * @param string $otp + */ + public function sendMessageTemplateAuthentication($to, $templateName, $templateLanguage, $otp) + { + // build form + $form = [ + 'phone' => $to, + 'template_name' => $templateName, + 'template_language' => $templateLanguage, + 'template' => (object) [ + 'body' => [$otp], + 'buttons' => [ + 'otp_copy_code' => $otp, + ], + ], + ]; + + return $this->request('POST', 'messages', json_encode($form)); + } +} + diff --git a/vendor/mikey179/vfsStream/.gitignore b/vendor/mikey179/vfsStream/.gitignore new file mode 100755 index 00000000..2258246f --- /dev/null +++ b/vendor/mikey179/vfsStream/.gitignore @@ -0,0 +1,2 @@ +/composer.lock +/nbproject diff --git a/vendor/mikey179/vfsStream/.travis.yml b/vendor/mikey179/vfsStream/.travis.yml new file mode 100755 index 00000000..8509d3f8 --- /dev/null +++ b/vendor/mikey179/vfsStream/.travis.yml @@ -0,0 +1,11 @@ +language: php + +php: + - 5.3 + - 5.4 + +before_script: + - wget -nc http://getcomposer.org/composer.phar + - php composer.phar install --dev + +script: phpunit --coverage-text \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/CHANGES b/vendor/mikey179/vfsStream/CHANGES new file mode 100755 index 00000000..3fb6b8ff --- /dev/null +++ b/vendor/mikey179/vfsStream/CHANGES @@ -0,0 +1,158 @@ +1.1.0, 2012-08-25 +================== +- implemented issue #11: add support for streamWrapper::stream_metadata() + vfsStream now supports touch(), chown(), chgrp() and chmod() +- implemented issue #33: add support for stream_truncate + (provided by https://github.com/nikcorg) +- implemented issue #35: size limit (quota) for VFS + + +1.0.0, 2012-05-15 +================== +- raised requirement for PHP version to 5.3.0 +- migrated codebase to use namespaces +- changed distribution from PEAR to Composer +- implemented issue #30: support "c" mode for fopen() +- fixed issue #31: prohibit aquiring locks when already locked / release lock on + fclose() +- fixed issue #32: problems when subfolder has same name as folder +- fixed issue #36: vfsStreamWrapper::stream_open should return false while + trying to open existing non-writable file, patch provided by Alexander Peresypkin + + +0.11.2, 2012-01-14 +================== +- fixed issue #29: set permissions properly when using + vfsStream::copyFromFileSystem(), patch provided by predakanga +- fixed failing tests under PHP > 5.3.2 + + +0.11.1, 2011-12-04 +================== +- fixed issue #28: mkdir overwrites existing directories/files + + +0.11.0, 2011-11-29 +================== +- implemented issue #20: vfsStream::create() removes old structure +- implemented issue #4: possibility to copy structure from existing file system +- fixed issue #23: unlink should not remove any directory +- fixed issue #25: vfsStreamDirectory::hasChild() gives false positives for + nested paths, patch provided by Andrew Coulton +- fixed issue #26: opening a file for reading only should not update its + modification time, reported and initial patch provided by Ludovic Chabant + + +0.10.1, 2011-08-22 +================== +- fixed issue #16: replace vfsStreamContent to vfsStreamContainer for + autocompletion +- fixed issue #17: vfsStream::create() has issues with numeric directories, + patch provided by mathieuk + + +0.10.0, 2011-07-22 +================== +- added new method vfsStreamContainer::hasChildren() and + vfsStreamDirectory::hasChildren() +- implemented issue #14: less verbose way to initialize vfsStream +- implemented issue #13: remove deprecated method vfsStreamContent::setFilemtime() +- implemented issue #6: locking meachanism for files +- ensured that stream_set_blocking(), stream_set_timeout() and + stream_set_write_buffer() on vfsStream urls have the same behaviour + with PHP 5.2 and 5.3 +- implemented issue #10: method to print directory structure + + +0.9.0, 2011-07-13 +================= +- implemented feature request issue #7: add support for fileatime() and filectime() +- fixed issue #3: add support for streamWrapper::stream_cast() +- fixed issue #9: resolve path not called everywhere its needed +- deprecated vfsStreamAbstractContent::setFilemtime(), use + vfsStreamAbstractContent::lastModified() instead, will be removed with 0.10.0 + + +0.8.0, 2010-10-08 +================= +- implemented enhancement #6: use vfsStream::umask() to influence initial file + mode for files and directories +- implemented enhancement #19: support of .. in the url, patch provided by + Guislain Duthieuw +- fixed issue #18: getChild() returns NULL when child's name contains parent name +- fixed bug with incomplete error message when accessing non-existing files on + root level + + +0.7.0, 2010-06-08 +================= +- added new vfsStream::setup() method to simplify vfsStream usage +- fixed issue #15: mkdir creates a subfolder in a folder without permissions + + +0.6.0, 2010-02-15 +================= +- added support for $mode param when opening files, implements enhancement #7 + and fixes issue #13 +- vfsStreamWrapper::stream_open() now evaluates $options for STREAM_REPORT_ERRORS + + +0.5.0, 2010-01-25 +================= +- added support for rename(), patch provided by Benoit Aubuchon +- added support for . as directory alias so that vfs://foo/. resolves to + vfs://foo, can be used as workaround for bug #8 + + +0.4.0, 2009-07-13 +================= +- added support for file modes, users and groups (with restrictions, see + http://code.google.com/p/bovigo/wiki/vfsStreamDocsKnownIssues) +- fixed bug #5: vfsStreamDirectory::addChild() does not replace child with same + name +- fixed bug with is_writable() because of missing stat() fields, patch provided + by Sergey Galkin + + +0.3.2, 2009-02-16 +================= +- support trailing slashes on directories in vfsStream urls, patch provided by + Gabriel Birke +- fixed bug #4: vfsstream can only be read once, reported by Christoph Bloemer +- enabled multiple iterations at the same time over the same directory + + +0.3.1, 2008-02-18 +================= +- fixed path/directory separator issues under linux systems +- fixed uid/gid issues under linux systems + + +0.3.0, 2008-01-02 +================= +- added support for rmdir() +- added vfsStream::newDirectory(), dropped vfsStreamDirectory::ceate() +- added new interface vfsStreamContainer +- added vfsStreamContent::at() which allows code like + $file = vfsStream::newFile('file.txt.')->withContent('foo')->at($otherDir); +- added vfsStreamContent::lastModified(), made vfsStreamContent::setFilemtime() + an alias for this +- moved from Stubbles development environment to bovigo +- refactorings to reduce crap index of various methods + + +0.2.0, 2007-12-29 +================= +- moved vfsStreamWrapper::PROTOCOL to vfsStream::SCHEME +- added new vfsStream::url() method to assist in creating correct vfsStream urls +- added vfsStream::path() method as opposite to vfsStream::url() +- a call to vfsStreamWrapper::register() will now reset the root to null, + implemented on request from David Zuelke +- added support for is_readable(), is_dir(), is_file() +- added vfsStream::newFile() to be able to do + $file = vfsStream::newFile("foo.txt")->withContent("bar"); + + +0.1.0, 2007-12-14 +================= +Initial release. diff --git a/vendor/mikey179/vfsStream/LICENSE b/vendor/mikey179/vfsStream/LICENSE new file mode 100755 index 00000000..7cca32a1 --- /dev/null +++ b/vendor/mikey179/vfsStream/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2007-2012, Frank Kleine +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 of Stubbles 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. \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/composer.json b/vendor/mikey179/vfsStream/composer.json new file mode 100755 index 00000000..f21f4521 --- /dev/null +++ b/vendor/mikey179/vfsStream/composer.json @@ -0,0 +1,12 @@ +{ + "name": "mikey179/vfsStream", + "type": "library", + "homepage": "http://vfs.bovigo.org/", + "license": "BSD", + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": { "org\\bovigo\\vfs": "src/main/php" } + } +} \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/Example.php b/vendor/mikey179/vfsStream/examples/Example.php new file mode 100755 index 00000000..a12caeec --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/Example.php @@ -0,0 +1,54 @@ +id = $id; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function setDirectory($directory) + { + $this->directory = $directory . DIRECTORY_SEPARATOR . $this->id; + if (file_exists($this->directory) === false) { + mkdir($this->directory, 0700, true); + } + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/ExampleTestCaseOldWay.php b/vendor/mikey179/vfsStream/examples/ExampleTestCaseOldWay.php new file mode 100755 index 00000000..4ecb9d8d --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/ExampleTestCaseOldWay.php @@ -0,0 +1,48 @@ +assertFalse(file_exists(__DIR__ . '/id')); + $example->setDirectory(__DIR__); + $this->assertTrue(file_exists(__DIR__ . '/id')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/ExampleTestCaseWithVfsStream.php b/vendor/mikey179/vfsStream/examples/ExampleTestCaseWithVfsStream.php new file mode 100755 index 00000000..97c8a374 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/ExampleTestCaseWithVfsStream.php @@ -0,0 +1,47 @@ +root = vfsStream::setup('exampleDir'); + } + + /** + * @test + */ + public function directoryIsCreated() + { + $example = new Example('id'); + $this->assertFalse($this->root->hasChild('id')); + $example->setDirectory(vfsStream::url('exampleDir')); + $this->assertTrue($this->root->hasChild('id')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FailureExample.php b/vendor/mikey179/vfsStream/examples/FailureExample.php new file mode 100755 index 00000000..472468b2 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FailureExample.php @@ -0,0 +1,50 @@ +filename = $filename; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function writeData($data) + { + $bytes = @file_put_contents($this->filename, $data); + if (false === $bytes) { + return 'could not write data'; + } + + return 'ok'; + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FailureExampleTestCase.php b/vendor/mikey179/vfsStream/examples/FailureExampleTestCase.php new file mode 100755 index 00000000..e2123055 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FailureExampleTestCase.php @@ -0,0 +1,58 @@ +root = vfsStream::setup('exampleDir'); + } + + /** + * @test + */ + public function returnsOkOnNoFailure() + { + $example = new FailureExample(vfsStream::url('exampleDir/test.txt')); + $this->assertSame('ok', $example->writeData('testdata')); + $this->assertTrue($this->root->hasChild('test.txt')); + $this->assertSame('testdata', $this->root->getChild('test.txt')->getContent()); + } + + /** + * @test + */ + public function returnsErrorMessageIfWritingToFileFails() + { + $file = vfsStream::newFile('test.txt', 0000) + ->withContent('notoverwritten') + ->at($this->root); + $example = new FailureExample(vfsStream::url('exampleDir/test.txt')); + $this->assertSame('could not write data', $example->writeData('testdata')); + $this->assertTrue($this->root->hasChild('test.txt')); + $this->assertSame('notoverwritten', $this->root->getChild('test.txt')->getContent()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FileModeExampleTestCaseOldWay.php b/vendor/mikey179/vfsStream/examples/FileModeExampleTestCaseOldWay.php new file mode 100755 index 00000000..9f996711 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FileModeExampleTestCaseOldWay.php @@ -0,0 +1,67 @@ +setDirectory(__DIR__); + if (DIRECTORY_SEPARATOR === '\\') { + // can not really test on windows, filemode from mkdir() is ignored + $this->assertEquals(40777, decoct(fileperms(__DIR__ . '/id'))); + } else { + $this->assertEquals(40700, decoct(fileperms(__DIR__ . '/id'))); + } + } + + /** + * test correct file mode for created directory + */ + public function testDirectoryHasCorrectDifferentFilePermissions() + { + $example = new FilemodeExample('id', 0755); + $example->setDirectory(__DIR__); + if (DIRECTORY_SEPARATOR === '\\') { + // can not really test on windows, filemode from mkdir() is ignored + $this->assertEquals(40777, decoct(fileperms(__DIR__ . '/id'))); + } else { + $this->assertEquals(40755, decoct(fileperms(__DIR__ . '/id'))); + } + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FilePermissionsExample.php b/vendor/mikey179/vfsStream/examples/FilePermissionsExample.php new file mode 100755 index 00000000..6258a5d7 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FilePermissionsExample.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FilePermissionsExampleTestCase.php b/vendor/mikey179/vfsStream/examples/FilePermissionsExampleTestCase.php new file mode 100755 index 00000000..66466362 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FilePermissionsExampleTestCase.php @@ -0,0 +1,44 @@ +writeConfig(array('foo' => 'bar'), + vfsStream::url('exampleDir/writable.ini') + ); + + // assertions here + } + + /** + * @test + */ + public function directoryNotWritable() + { + vfsStream::setup('exampleDir', 0444); + $example = new FilePermissionsExample(); + $example->writeConfig(array('foo' => 'bar'), + vfsStream::url('exampleDir/notWritable.ini') + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FilemodeExample.php b/vendor/mikey179/vfsStream/examples/FilemodeExample.php new file mode 100755 index 00000000..c2ac364c --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FilemodeExample.php @@ -0,0 +1,62 @@ +id = $id; + $this->fileMode = $fileMode; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function setDirectory($directory) + { + $this->directory = $directory . DIRECTORY_SEPARATOR . $this->id; + if (file_exists($this->directory) === false) { + mkdir($this->directory, $this->fileMode, true); + } + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php b/vendor/mikey179/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php new file mode 100755 index 00000000..675a2c72 --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php @@ -0,0 +1,53 @@ +root = vfsStream::setup('exampleDir'); + } + + /** + * test that the directory is created + */ + public function testDirectoryIsCreatedWithDefaultPermissions() + { + $example = new FilemodeExample('id'); + $example->setDirectory(vfsStream::url('exampleDir')); + $this->assertEquals(0700, $this->root->getChild('id')->getPermissions()); + } + + /** + * test that the directory is created + */ + public function testDirectoryIsCreatedWithGivenPermissions() + { + $example = new FilemodeExample('id', 0755); + $example->setDirectory(vfsStream::url('exampleDir')); + $this->assertEquals(0755, $this->root->getChild('id')->getPermissions()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/examples/bootstrap.php b/vendor/mikey179/vfsStream/examples/bootstrap.php new file mode 100755 index 00000000..998c43db --- /dev/null +++ b/vendor/mikey179/vfsStream/examples/bootstrap.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/phpdoc.dist.xml b/vendor/mikey179/vfsStream/phpdoc.dist.xml new file mode 100755 index 00000000..9cc27972 --- /dev/null +++ b/vendor/mikey179/vfsStream/phpdoc.dist.xml @@ -0,0 +1,14 @@ + + + vfsStream API Doc + + docs/api + org\bovigo\vfs + + + docs/api + + + src/main/php + + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/phpunit.xml.dist b/vendor/mikey179/vfsStream/phpunit.xml.dist new file mode 100755 index 00000000..8d2140ed --- /dev/null +++ b/vendor/mikey179/vfsStream/phpunit.xml.dist @@ -0,0 +1,42 @@ + + + + + ./src/test/php + + + + + + src/main/php + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/readme.md b/vendor/mikey179/vfsStream/readme.md new file mode 100755 index 00000000..1635eddd --- /dev/null +++ b/vendor/mikey179/vfsStream/readme.md @@ -0,0 +1,3 @@ +For more information have a look in the [wiki](https://github.com/mikey179/vfsStream/wiki). + +[![Build Status](https://secure.travis-ci.org/mikey179/vfsStream.png)](http://travis-ci.org/mikey179/vfsStream) \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/Quota.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/Quota.php new file mode 100755 index 00000000..b86ad8cd --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/Quota.php @@ -0,0 +1,87 @@ +amount = $amount; + } + + /** + * create with unlimited space + * + * @return Quota + */ + public static function unlimited() + { + return new self(self::UNLIMITED); + } + + /** + * checks if a quota is set + * + * @return bool + */ + public function isLimited() + { + return self::UNLIMITED < $this->amount; + } + + /** + * checks if given used space exceeda quota limit + * + * + * @param int $usedSpace + * @return int + */ + public function spaceLeft($usedSpace) + { + if (self::UNLIMITED === $this->amount) { + return $usedSpace; + } + + if ($usedSpace >= $this->amount) { + return 0; + } + + $spaceLeft = $this->amount - $usedSpace; + if (0 >= $spaceLeft) { + return 0; + } + + return $spaceLeft; + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStream.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStream.php new file mode 100755 index 00000000..f68fefd8 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStream.php @@ -0,0 +1,389 @@ + + * array('Core' = array('AbstractFactory' => array('test.php' => 'some text content', + * 'other.php' => 'Some more text content', + * 'Invalid.csv' => 'Something else', + * ), + * 'AnEmptyFolder' => array(), + * 'badlocation.php' => 'some bad content', + * ) + * ) + * + * the resulting directory tree will look like this: + *
+     * root
+     * \- Core
+     *  |- badlocation.php
+     *  |- AbstractFactory
+     *  | |- test.php
+     *  | |- other.php
+     *  | \- Invalid.csv
+     *  \- AnEmptyFolder
+     * 
+ * Arrays will become directories with their key as directory name, and + * strings becomes files with their key as file name and their value as file + * content. + * + * @param string $rootDirName name of root directory + * @param int $permissions file permissions of root directory + * @param array $structure directory structure to add under root directory + * @return \org\bovigo\vfs\vfsStreamDirectory + * @since 0.7.0 + * @see https://github.com/mikey179/vfsStream/issues/14 + * @see https://github.com/mikey179/vfsStream/issues/20 + */ + public static function setup($rootDirName = 'root', $permissions = null, array $structure = array()) + { + vfsStreamWrapper::register(); + return self::create($structure, vfsStreamWrapper::setRoot(self::newDirectory($rootDirName, $permissions))); + } + + /** + * creates vfsStream directory structure from an array and adds it to given base dir + * + * Assumed $structure contains an array like this: + * + * array('Core' = array('AbstractFactory' => array('test.php' => 'some text content', + * 'other.php' => 'Some more text content', + * 'Invalid.csv' => 'Something else', + * ), + * 'AnEmptyFolder' => array(), + * 'badlocation.php' => 'some bad content', + * ) + * ) + * + * the resulting directory tree will look like this: + *
+     * baseDir
+     * \- Core
+     *  |- badlocation.php
+     *  |- AbstractFactory
+     *  | |- test.php
+     *  | |- other.php
+     *  | \- Invalid.csv
+     *  \- AnEmptyFolder
+     * 
+ * Arrays will become directories with their key as directory name, and + * strings becomes files with their key as file name and their value as file + * content. + * + * If no baseDir is given it will try to add the structure to the existing + * root directory without replacing existing childs except those with equal + * names. + * + * @param array $structure directory structure to add under root directory + * @param vfsStreamDirectory $baseDir base directory to add structure to + * @return vfsStreamDirectory + * @throws \InvalidArgumentException + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/14 + * @see https://github.com/mikey179/vfsStream/issues/20 + */ + public static function create(array $structure, vfsStreamDirectory $baseDir = null) + { + if (null === $baseDir) { + $baseDir = vfsStreamWrapper::getRoot(); + } + + if (null === $baseDir) { + throw new \InvalidArgumentException('No baseDir given and no root directory set.'); + } + + return self::addStructure($structure, $baseDir); + } + + /** + * helper method to create subdirectories recursively + * + * @param array $structure subdirectory structure to add + * @param vfsStreamDirectory $baseDir directory to add the structure to + * @return vfsStreamDirectory + */ + protected static function addStructure(array $structure, vfsStreamDirectory $baseDir) + { + foreach ($structure as $name => $data) { + $name = (string) $name; + if (is_array($data) === true) { + self::addStructure($data, self::newDirectory($name)->at($baseDir)); + } elseif (is_string($data) === true) { + self::newFile($name)->withContent($data)->at($baseDir); + } + } + + return $baseDir; + } + + /** + * copies the file system structure from given path into the base dir + * + * If no baseDir is given it will try to add the structure to the existing + * root directory without replacing existing childs except those with equal + * names. + * File permissions are copied as well. + * Please note that file contents will only be copied if their file size + * does not exceed the given $maxFileSize which is 1024 KB. + * + * @param string $path path to copy the structure from + * @param vfsStreamDirectory $baseDir directory to add the structure to + * @param int $maxFileSize maximum file size of files to copy content from + * @return vfsStreamDirectory + * @throws \InvalidArgumentException + * @since 0.11.0 + * @see https://github.com/mikey179/vfsStream/issues/4 + */ + public static function copyFromFileSystem($path, vfsStreamDirectory $baseDir = null, $maxFileSize = 1048576) + { + if (null === $baseDir) { + $baseDir = vfsStreamWrapper::getRoot(); + } + + if (null === $baseDir) { + throw new \InvalidArgumentException('No baseDir given and no root directory set.'); + } + + $dir = new \DirectoryIterator($path); + foreach ($dir as $fileinfo) { + if ($fileinfo->isFile() === true) { + if ($fileinfo->getSize() <= $maxFileSize) { + $content = file_get_contents($fileinfo->getPathname()); + } else { + $content = ''; + } + + self::newFile($fileinfo->getFilename(), + octdec(substr(sprintf('%o', $fileinfo->getPerms()), -4)) + ) + ->withContent($content) + ->at($baseDir); + } elseif ($fileinfo->isDir() === true && $fileinfo->isDot() === false) { + self::copyFromFileSystem($fileinfo->getPathname(), + self::newDirectory($fileinfo->getFilename(), + octdec(substr(sprintf('%o', $fileinfo->getPerms()), -4)) + ) + ->at($baseDir), + $maxFileSize + ); + } + } + + return $baseDir; + } + + /** + * returns a new file with given name + * + * @param string $name name of file to create + * @param int $permissions permissions of file to create + * @return vfsStreamFile + */ + public static function newFile($name, $permissions = null) + { + return new vfsStreamFile($name, $permissions); + } + + /** + * returns a new directory with given name + * + * If the name contains slashes, a new directory structure will be created. + * The returned directory will always be the parent directory of this + * directory structure. + * + * @param string $name name of directory to create + * @param int $permissions permissions of directory to create + * @return vfsStreamDirectory + */ + public static function newDirectory($name, $permissions = null) + { + if ('/' === $name{0}) { + $name = substr($name, 1); + } + + $firstSlash = strpos($name, '/'); + if (false === $firstSlash) { + return new vfsStreamDirectory($name, $permissions); + } + + $ownName = substr($name, 0, $firstSlash); + $subDirs = substr($name, $firstSlash + 1); + $directory = new vfsStreamDirectory($ownName, $permissions); + self::newDirectory($subDirs, $permissions)->at($directory); + return $directory; + } + + /** + * returns current user + * + * If the system does not support posix_getuid() the current user will be root (0). + * + * @return int + */ + public static function getCurrentUser() + { + return function_exists('posix_getuid') ? posix_getuid() : self::OWNER_ROOT; + } + + /** + * returns current group + * + * If the system does not support posix_getgid() the current group will be root (0). + * + * @return int + */ + public static function getCurrentGroup() + { + return function_exists('posix_getgid') ? posix_getgid() : self::GROUP_ROOT; + } + + /** + * use visitor to inspect a content structure + * + * If the given content is null it will fall back to use the current root + * directory of the stream wrapper. + * + * Returns given visitor for method chaining comfort. + * + * @param vfsStreamVisitor $visitor the visitor who inspects + * @param vfsStreamContent $content directory structure to inspect + * @return vfsStreamVisitor + * @throws \InvalidArgumentException + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/10 + */ + public static function inspect(vfsStreamVisitor $visitor, vfsStreamContent $content = null) + { + if (null !== $content) { + return $visitor->visit($content); + } + + $root = vfsStreamWrapper::getRoot(); + if (null === $root) { + throw new \InvalidArgumentException('No content given and no root directory set.'); + } + + return $visitor->visitDirectory($root); + } + + /** + * sets quota to given amount of bytes + * + * @param int $bytes + * @since 1.1.0 + */ + public static function setQuota($bytes) + { + vfsStreamWrapper::setQuota(new Quota($bytes)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamAbstractContent.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamAbstractContent.php new file mode 100755 index 00000000..d3d2d614 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamAbstractContent.php @@ -0,0 +1,375 @@ +name = $name; + $time = time(); + if (null === $permissions) { + $permissions = $this->getDefaultPermissions() & ~vfsStream::umask(); + } + + $this->lastAccessed = $time; + $this->lastAttributeModified = $time; + $this->lastModified = $time; + $this->permissions = $permissions; + $this->user = vfsStream::getCurrentUser(); + $this->group = vfsStream::getCurrentGroup(); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected abstract function getDefaultPermissions(); + + /** + * returns the file name of the content + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * renames the content + * + * @param string $newName + */ + public function rename($newName) + { + $this->name = $newName; + } + + /** + * checks whether the container can be applied to given name + * + * @param string $name + * @return bool + */ + public function appliesTo($name) + { + if ($name === $this->name) { + return true; + } + + $segment_name = $this->name.'/'; + return (strncmp($segment_name, $name, strlen($segment_name)) == 0); + } + + /** + * returns the type of the container + * + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * sets the last modification time of the stream content + * + * @param int $filemtime + * @return vfsStreamContent + */ + public function lastModified($filemtime) + { + $this->lastModified = $filemtime; + return $this; + } + + /** + * returns the last modification time of the stream content + * + * @return int + */ + public function filemtime() + { + return $this->lastModified; + } + + /** + * sets last access time of the stream content + * + * @param int $fileatime + * @return vfsStreamContent + * @since 0.9 + */ + public function lastAccessed($fileatime) + { + $this->lastAccessed = $fileatime; + return $this; + } + + /** + * returns the last access time of the stream content + * + * @return int + * @since 0.9 + */ + public function fileatime() + { + return $this->lastAccessed; + } + + /** + * sets the last attribute modification time of the stream content + * + * @param int $filectime + * @return vfsStreamContent + * @since 0.9 + */ + public function lastAttributeModified($filectime) + { + $this->lastAttributeModified = $filectime; + return $this; + } + + /** + * returns the last attribute modification time of the stream content + * + * @return int + * @since 0.9 + */ + public function filectime() + { + return $this->lastAttributeModified; + } + + /** + * adds content to given container + * + * @param vfsStreamContainer $container + * @return vfsStreamContent + */ + public function at(vfsStreamContainer $container) + { + $container->addChild($this); + return $this; + } + + /** + * change file mode to given permissions + * + * @param int $permissions + * @return vfsStreamContent + */ + public function chmod($permissions) + { + $this->permissions = $permissions; + $this->lastAttributeModified = time(); + clearstatcache(); + return $this; + } + + /** + * returns permissions + * + * @return int + */ + public function getPermissions() + { + return $this->permissions; + } + + /** + * checks whether content is readable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isReadable($user, $group) + { + if ($this->user === $user) { + $check = 0400; + } elseif ($this->group === $group) { + $check = 0040; + } else { + $check = 0004; + } + + return (bool) ($this->permissions & $check); + } + + /** + * checks whether content is writable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isWritable($user, $group) + { + if ($this->user === $user) { + $check = 0200; + } elseif ($this->group === $group) { + $check = 0020; + } else { + $check = 0002; + } + + return (bool) ($this->permissions & $check); + } + + /** + * checks whether content is executable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isExecutable($user, $group) + { + if ($this->user === $user) { + $check = 0100; + } elseif ($this->group === $group) { + $check = 0010; + } else { + $check = 0001; + } + + return (bool) ($this->permissions & $check); + } + + /** + * change owner of file to given user + * + * @param int $user + * @return vfsStreamContent + */ + public function chown($user) + { + $this->user = $user; + $this->lastAttributeModified = time(); + return $this; + } + + /** + * checks whether file is owned by given user + * + * @param int $user + * @return bool + */ + public function isOwnedByUser($user) + { + return $this->user === $user; + } + + /** + * returns owner of file + * + * @return int + */ + public function getUser() + { + return $this->user; + } + + /** + * change owner group of file to given group + * + * @param int $group + * @return vfsStreamContent + */ + public function chgrp($group) + { + $this->group = $group; + $this->lastAttributeModified = time(); + return $this; + } + + /** + * checks whether file is owned by group + * + * @param int $group + * @return bool + */ + public function isOwnedByGroup($group) + { + return $this->group === $group; + } + + /** + * returns owner group of file + * + * @return int + */ + public function getGroup() + { + return $this->group; + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainer.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainer.php new file mode 100755 index 00000000..e27a5810 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainer.php @@ -0,0 +1,62 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainerIterator.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainerIterator.php new file mode 100755 index 00000000..0f3e3a79 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContainerIterator.php @@ -0,0 +1,90 @@ +children = $children; + reset($this->children); + } + + /** + * resets children pointer + */ + public function rewind() + { + reset($this->children); + } + + /** + * returns the current child + * + * @return vfsStreamContent + */ + public function current() + { + $child = current($this->children); + if (false === $child) { + return null; + } + + return $child; + } + + /** + * returns the name of the current child + * + * @return string + */ + public function key() + { + $child = current($this->children); + if (false === $child) { + return null; + } + + return $child->getName(); + } + + /** + * iterates to next child + */ + public function next() + { + next($this->children); + } + + /** + * checks if the current value is valid + * + * @return bool + */ + public function valid() + { + return (false !== current($this->children)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContent.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContent.php new file mode 100755 index 00000000..197c51ae --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamContent.php @@ -0,0 +1,182 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamDirectory.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamDirectory.php new file mode 100755 index 00000000..229dcd04 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamDirectory.php @@ -0,0 +1,235 @@ +type = vfsStreamContent::TYPE_DIR; + parent::__construct($name, $permissions); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected function getDefaultPermissions() + { + return 0777; + } + + /** + * returns size of directory + * + * The size of a directory is always 0 bytes. To calculate the summarized + * size of all children in the directory use sizeSummarized(). + * + * @return int + */ + public function size() + { + return 0; + } + + /** + * returns summarized size of directory and its children + * + * @return int + */ + public function sizeSummarized() + { + $size = 0; + foreach ($this->children as $child) { + if ($child->getType() === vfsStreamContent::TYPE_DIR) { + $size += $child->sizeSummarized(); + } else { + $size += $child->size(); + } + } + + return $size; + } + + /** + * renames the content + * + * @param string $newName + * @throws vfsStreamException + */ + public function rename($newName) + { + if (strstr($newName, '/') !== false) { + throw new vfsStreamException('Directory name can not contain /.'); + } + + parent::rename($newName); + } + + /** + * adds child to the directory + * + * @param vfsStreamContent $child + */ + public function addChild(vfsStreamContent $child) + { + $this->children[$child->getName()] = $child; + $this->updateModifications(); + } + + /** + * removes child from the directory + * + * @param string $name + * @return bool + */ + public function removeChild($name) + { + foreach ($this->children as $key => $child) { + if ($child->appliesTo($name) === true) { + unset($this->children[$key]); + $this->updateModifications(); + return true; + } + } + + return false; + } + + /** + * updates internal timestamps + */ + protected function updateModifications() + { + $time = time(); + $this->lastAttributeModified = $time; + $this->lastModified = $time; + } + + /** + * checks whether the container contains a child with the given name + * + * @param string $name + * @return bool + */ + public function hasChild($name) + { + return ($this->getChild($name) !== null); + } + + /** + * returns the child with the given name + * + * @param string $name + * @return vfsStreamContent + */ + public function getChild($name) + { + $childName = $this->getRealChildName($name); + foreach ($this->children as $child) { + if ($child->getName() === $childName) { + return $child; + } + + if ($child->appliesTo($childName) === true && $child->hasChild($childName) === true) { + return $child->getChild($childName); + } + } + + return null; + } + + /** + * helper method to detect the real child name + * + * @param string $name + * @return string + */ + protected function getRealChildName($name) + { + if ($this->appliesTo($name) === true) { + return self::getChildName($name, $this->name); + } + + return $name; + } + + /** + * helper method to calculate the child name + * + * @param string $name + * @param string $ownName + * @return string + */ + protected static function getChildName($name, $ownName) + { + if ($name === $ownName) { + return $name; + } + + return substr($name, strlen($ownName) + 1); + } + + /** + * checks whether directory contains any children + * + * @return bool + * @since 0.10.0 + */ + public function hasChildren() + { + return (count($this->children) > 0); + } + + /** + * returns a list of children for this directory + * + * @return vfsStreamContent[] + */ + public function getChildren() + { + return array_values($this->children); + } + + /** + * returns iterator for the children + * + * @return vfsStreamContainerIterator + */ + public function getIterator() + { + return new vfsStreamContainerIterator($this->children); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamException.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamException.php new file mode 100755 index 00000000..aa79d645 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamException.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamFile.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamFile.php new file mode 100755 index 00000000..2ab3fbe9 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamFile.php @@ -0,0 +1,327 @@ +type = vfsStreamContent::TYPE_FILE; + parent::__construct($name, $permissions); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected function getDefaultPermissions() + { + return 0666; + } + + /** + * checks whether the container can be applied to given name + * + * @param string $name + * @return bool + */ + public function appliesTo($name) + { + return ($name === $this->name); + } + + /** + * alias for withContent() + * + * @param string $content + * @return vfsStreamFile + * @see withContent() + */ + public function setContent($content) + { + return $this->withContent($content); + } + + /** + * sets the contents of the file + * + * Setting content with this method does not change the time when the file + * was last modified. + * + * @param string $content + * @return vfsStreamFile + */ + public function withContent($content) + { + $this->content = $content; + return $this; + } + + /** + * returns the contents of the file + * + * Getting content does not change the time when the file + * was last accessed. + * + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * simply open the file + * + * @since 0.9 + */ + public function open() + { + $this->seek(0, SEEK_SET); + $this->lastAccessed = time(); + } + + /** + * open file and set pointer to end of file + * + * @since 0.9 + */ + public function openForAppend() + { + $this->seek(0, SEEK_END); + $this->lastAccessed = time(); + } + + /** + * open file and truncate content + * + * @since 0.9 + */ + public function openWithTruncate() + { + $this->open(); + $this->content = ''; + $time = time(); + $this->lastAccessed = $time; + $this->lastModified = $time; + } + + /** + * reads the given amount of bytes from content + * + * Using this method changes the time when the file was last accessed. + * + * @param int $count + * @return string + */ + public function read($count) + { + $data = substr($this->content, $this->bytes_read, $count); + $this->bytes_read += $count; + $this->lastAccessed = time(); + return $data; + } + + /** + * returns the content until its end from current offset + * + * Using this method changes the time when the file was last accessed. + * + * @return string + */ + public function readUntilEnd() + { + $this->lastAccessed = time(); + return substr($this->content, $this->bytes_read); + } + + /** + * writes an amount of data + * + * Using this method changes the time when the file was last modified. + * + * @param string $data + * @return amount of written bytes + */ + public function write($data) + { + $dataLen = strlen($data); + $this->content = substr($this->content, 0, $this->bytes_read) . $data . substr($this->content, $this->bytes_read + $dataLen); + $this->bytes_read += $dataLen; + $this->lastModified = time(); + return $dataLen; + } + + /** + * Truncates a file to a given length + * + * @param int $size length to truncate file to + * @return bool + * @since 1.1.0 + */ + public function truncate($size) { + if ($size > $this->size()) { + // Pad with null-chars if we're "truncating up" + $this->setContent($this->getContent() . str_repeat("\0", $size - $this->size())); + } else { + $this->setContent(substr($this->getContent(), 0, $size)); + } + + $this->lastModified = time(); + return true; + } + + /** + * checks whether pointer is at end of file + * + * @return bool + */ + public function eof() + { + return $this->bytes_read >= strlen($this->content); + } + + /** + * returns the current position within the file + * + * @return int + */ + public function getBytesRead() + { + return $this->bytes_read; + } + + /** + * seeks to the given offset + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function seek($offset, $whence) + { + switch ($whence) { + case SEEK_CUR: + $this->bytes_read += $offset; + return true; + + case SEEK_END: + $this->bytes_read = strlen($this->content) + $offset; + return true; + + case SEEK_SET: + $this->bytes_read = $offset; + return true; + + default: + return false; + } + + return false; + } + + /** + * returns size of content + * + * @return int + */ + public function size() + { + return strlen($this->content); + } + + + /** + * locks file for + * + * @param int $operation + * @return vfsStreamFile + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/6 + */ + public function lock($operation) + { + if ((LOCK_NB & $operation) == LOCK_NB) { + $this->lock = $operation - LOCK_NB; + } else { + $this->lock = $operation; + } + + return $this; + } + + /** + * checks whether file is locked + * + * @return bool + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/6 + */ + public function isLocked() + { + return (LOCK_UN !== $this->lock); + } + + /** + * checks whether file is locked in shared mode + * + * @return bool + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/6 + */ + public function hasSharedLock() + { + return (LOCK_SH === $this->lock); + } + + /** + * checks whether file is locked in exclusive mode + * + * @return bool + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/6 + */ + public function hasExclusiveLock() + { + return (LOCK_EX === $this->lock); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamWrapper.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamWrapper.php new file mode 100755 index 00000000..72b76e76 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamWrapper.php @@ -0,0 +1,932 @@ +getName() === $path) { + return self::$root; + } + + if (self::$root->hasChild($path) === true) { + return self::$root->getChild($path); + } + + return null; + } + + /** + * returns content for given path but only when it is of given type + * + * @param string $path + * @param int $type + * @return vfsStreamContent + */ + protected function getContentOfType($path, $type) + { + $content = $this->getContent($path); + if (null !== $content && $content->getType() === $type) { + return $content; + } + + return null; + } + + /** + * splits path into its dirname and the basename + * + * @param string $path + * @return string[] + */ + protected function splitPath($path) + { + $lastSlashPos = strrpos($path, '/'); + if (false === $lastSlashPos) { + return array('dirname' => '', 'basename' => $path); + } + + return array('dirname' => substr($path, 0, $lastSlashPos), + 'basename' => substr($path, $lastSlashPos + 1) + ); + } + + /** + * helper method to resolve a path from /foo/bar/. to /foo/bar + * + * @param string $path + * @return string + */ + protected function resolvePath($path) + { + $newPath = array(); + foreach (explode('/', $path) as $pathPart) { + if ('.' !== $pathPart) { + if ('..' !== $pathPart) { + $newPath[] = $pathPart; + } else { + array_pop($newPath); + } + } + } + + return implode('/', $newPath); + } + + /** + * open the stream + * + * @param string $path the path to open + * @param string $mode mode for opening + * @param string $options options for opening + * @param string $opened_path full path that was actually opened + * @return bool + */ + public function stream_open($path, $mode, $options, $opened_path) + { + $extended = ((strstr($mode, '+') !== false) ? (true) : (false)); + $mode = str_replace(array('b', '+'), '', $mode); + if (in_array($mode, array('r', 'w', 'a', 'x', 'c')) === false) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Illegal mode ' . $mode . ', use r, w, a, x or c, flavoured with b and/or +', E_USER_WARNING); + } + + return false; + } + + $this->mode = $this->calculateMode($mode, $extended); + $path = $this->resolvePath(vfsStream::path($path)); + $this->content = $this->getContentOfType($path, vfsStreamContent::TYPE_FILE); + if (null !== $this->content) { + if (self::WRITE === $mode) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('File ' . $path . ' already exists, can not open with mode x', E_USER_WARNING); + } + + return false; + } + + if ( + (self::TRUNCATE === $mode || self::APPEND === $mode) && + $this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false + ) { + return false; + } + + if (self::TRUNCATE === $mode) { + $this->content->openWithTruncate(); + } elseif (self::APPEND === $mode) { + $this->content->openForAppend(); + } else { + if (!$this->content->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Permission denied', E_USER_WARNING); + } + return false; + } + $this->content->open(); + } + + return true; + } + + $content = $this->createFile($path, $mode, $options); + if (false === $content) { + return false; + } + + $this->content = $content; + return true; + } + + /** + * creates a file at given path + * + * @param string $path the path to open + * @param string $mode mode for opening + * @param string $options options for opening + * @return bool + */ + private function createFile($path, $mode = null, $options = null) + { + $names = $this->splitPath($path); + if (empty($names['dirname']) === true) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('File ' . $names['basename'] . ' does not exist', E_USER_WARNING); + } + + return false; + } + + $dir = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR); + if (null === $dir) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Directory ' . $names['dirname'] . ' does not exist', E_USER_WARNING); + } + + return false; + } elseif ($dir->hasChild($names['basename']) === true) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Directory ' . $names['dirname'] . ' already contains a director named ' . $names['basename'], E_USER_WARNING); + } + + return false; + } + + if (self::READ === $mode) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Can not open non-existing file ' . $path . ' for reading', E_USER_WARNING); + } + + return false; + } + + if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) { + trigger_error('Can not create new file in non-writable path ' . $names['dirname'], E_USER_WARNING); + } + + return false; + } + + return vfsStream::newFile($names['basename'])->at($dir); + } + + /** + * calculates the file mode + * + * @param string $mode opening mode: r, w, a or x + * @param bool $extended true if + was set with opening mode + * @return int + */ + protected function calculateMode($mode, $extended) + { + if (true === $extended) { + return self::ALL; + } + + if (self::READ === $mode) { + return self::READONLY; + } + + return self::WRITEONLY; + } + + /** + * closes the stream + */ + public function stream_close() + { + $this->content->lock(LOCK_UN); + } + + /** + * read the stream up to $count bytes + * + * @param int $count amount of bytes to read + * @return string + */ + public function stream_read($count) + { + if (self::WRITEONLY === $this->mode) { + return ''; + } + + if ($this->content->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return ''; + } + + return $this->content->read($count); + } + + /** + * writes data into the stream + * + * @param string $data + * @return int amount of bytes written + */ + public function stream_write($data) + { + if (self::READONLY === $this->mode) { + return 0; + } + + if ($this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return 0; + } + + if (self::$quota->isLimited()) { + $data = substr($data, 0, self::$quota->spaceLeft(self::$root->sizeSummarized())); + } + + return $this->content->write($data); + } + + /** + * truncates a file to a given length + * + * @param int $size length to truncate file to + * @return bool + * @since 1.1.0 + */ + public function stream_truncate($size) + { + if (self::READONLY === $this->mode) { + return false; + } + + if ($this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + if ($this->content->getType() !== vfsStreamContent::TYPE_FILE) { + return false; + } + + if (self::$quota->isLimited() && $this->content->size() < $size) { + $maxSize = self::$quota->spaceLeft(self::$root->sizeSummarized()); + if (0 === $maxSize) { + return false; + } + + if ($size > $maxSize) { + $size = $maxSize; + } + } + + return $this->content->truncate($size); + } + + /** + * sets metadata like owner, user or permissions + * + * @param string $path + * @param int $option + * @param mixed $var + * @return bool + * @since 1.1.0 + */ + public function stream_metadata($path, $option, $var) + { + $path = $this->resolvePath(vfsStream::path($path)); + $content = $this->getContent($path); + switch ($option) { + case STREAM_META_TOUCH: + if (null === $content) { + $content = $this->createFile($path); + } + + if (isset($var[0])) { + $content->lastModified($var[0]); + } + + if (isset($var[1])) { + $content->lastAccessed($var[1]); + } + + return true; + + case STREAM_META_OWNER_NAME: + return false; + + case STREAM_META_OWNER: + if (null === $content) { + return false; + } + + $content->chown($var); + return true; + + case STREAM_META_GROUP_NAME: + return false; + + case STREAM_META_GROUP: + if (null === $content) { + return false; + } + + $content->chgrp($var); + return true; + + case STREAM_META_ACCESS: + if (null === $content) { + return false; + } + + $content->chmod($var); + return true; + + default: + return false; + } + } + + /** + * checks whether stream is at end of file + * + * @return bool + */ + public function stream_eof() + { + return $this->content->eof(); + } + + /** + * returns the current position of the stream + * + * @return int + */ + public function stream_tell() + { + return $this->content->getBytesRead(); + } + + /** + * seeks to the given offset + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function stream_seek($offset, $whence) + { + return $this->content->seek($offset, $whence); + } + + /** + * flushes unstored data into storage + * + * @return bool + */ + public function stream_flush() + { + return true; + } + + /** + * returns status of stream + * + * @return array + */ + public function stream_stat() + { + $fileStat = array('dev' => 0, + 'ino' => 0, + 'mode' => $this->content->getType() | $this->content->getPermissions(), + 'nlink' => 0, + 'uid' => $this->content->getUser(), + 'gid' => $this->content->getGroup(), + 'rdev' => 0, + 'size' => $this->content->size(), + 'atime' => $this->content->fileatime(), + 'mtime' => $this->content->filemtime(), + 'ctime' => $this->content->filectime(), + 'blksize' => -1, + 'blocks' => -1 + ); + return array_merge(array_values($fileStat), $fileStat); + } + + /** + * retrieve the underlaying resource + * + * Please note that this method always returns false as there is no + * underlaying resource to return. + * + * @param int $cast_as + * @since 0.9.0 + * @see https://github.com/mikey179/vfsStream/issues/3 + * @return bool + */ + public function stream_cast($cast_as) + { + return false; + } + + /** + * set lock status for stream + * + * @param int $operation + * @return bool + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/6 + * @see https://github.com/mikey179/vfsStream/issues/31 + */ + public function stream_lock($operation) + { + if ((LOCK_NB & $operation) == LOCK_NB) { + $operation = $operation - LOCK_NB; + } + + if (LOCK_EX === $operation && $this->content->isLocked()) { + return false; + } elseif (LOCK_SH === $operation && $this->content->hasExclusiveLock()) { + return false; + } + + $this->content->lock($operation); + return true; + } + + /** + * sets options on the stream + * + * @param int $option key of option to set + * @param int $arg1 + * @param int $arg2 + * @return bool + * @since 0.10.0 + * @see https://github.com/mikey179/vfsStream/issues/15 + * @see http://www.php.net/manual/streamwrapper.stream-set-option.php + */ + public function stream_set_option($option, $arg1, $arg2) + { + switch ($option) { + case STREAM_OPTION_BLOCKING: + // break omitted + + case STREAM_OPTION_READ_TIMEOUT: + // break omitted + + case STREAM_OPTION_WRITE_BUFFER: + // break omitted + + default: + // nothing to do here + } + + return false; + } + + /** + * remove the data under the given path + * + * @param string $path + * @return bool + */ + public function unlink($path) + { + $realPath = $this->resolvePath(vfsStream::path($path)); + $content = $this->getContent($realPath); + if (null === $content || $content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + if ($content->getType() !== vfsStreamContent::TYPE_FILE) { + trigger_error('unlink(' . $path . '): Operation not permitted', E_USER_WARNING); + return false; + } + + return $this->doUnlink($realPath); + } + + /** + * removes a path + * + * @param string $path + * @return bool + */ + protected function doUnlink($path) + { + if (self::$root->getName() === $path) { + // delete root? very brave. :) + self::$root = null; + clearstatcache(); + return true; + } + + $names = $this->splitPath($path); + $content = $this->getContent($names['dirname']); + if ($content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + clearstatcache(); + return $content->removeChild($names['basename']); + } + + /** + * rename from one path to another + * + * @param string $path_from + * @param string $path_to + * @return bool + * @author Benoit Aubuchon + */ + public function rename($path_from, $path_to) + { + $srcRealPath = $this->resolvePath(vfsStream::path($path_from)); + $dstRealPath = $this->resolvePath(vfsStream::path($path_to)); + $srcContent = $this->getContent($srcRealPath); + if (null == $srcContent) { + trigger_error(' No such file or directory', E_USER_WARNING); + return false; + } + $dstNames = $this->splitPath($dstRealPath); + $dstParentContent = $this->getContent($dstNames['dirname']); + if (null == $dstParentContent) { + trigger_error('No such file or directory', E_USER_WARNING); + return false; + } + if (!$dstParentContent->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) { + trigger_error('Permission denied', E_USER_WARNING); + return false; + } + if ($dstParentContent->getType() !== vfsStreamContent::TYPE_DIR) { + trigger_error('Target is not a directory', E_USER_WARNING); + return false; + } + + $dstContent = clone $srcContent; + // Renaming the filename + $dstContent->rename($dstNames['basename']); + // Copying to the destination + $dstParentContent->addChild($dstContent); + // Removing the source + return $this->doUnlink($srcRealPath); + } + + /** + * creates a new directory + * + * @param string $path + * @param int $mode + * @param int $options + * @return bool + */ + public function mkdir($path, $mode, $options) + { + $umask = vfsStream::umask(); + if (0 < $umask) { + $permissions = $mode & ~$umask; + } else { + $permissions = $mode; + } + + $path = $this->resolvePath(vfsStream::path($path)); + if (null !== $this->getContent($path)) { + trigger_error('mkdir(): Path vfs://' . $path . ' exists', E_USER_WARNING); + return false; + } + + if (null === self::$root) { + self::$root = vfsStream::newDirectory($path, $permissions); + return true; + } + + $maxDepth = count(explode('/', $path)); + $names = $this->splitPath($path); + $newDirs = $names['basename']; + $dir = null; + $i = 0; + while ($dir === null && $i < $maxDepth) { + $dir = $this->getContent($names['dirname']); + $names = $this->splitPath($names['dirname']); + if (null == $dir) { + $newDirs = $names['basename'] . '/' . $newDirs; + } + + $i++; + } + + if (null === $dir + || $dir->getType() !== vfsStreamContent::TYPE_DIR + || $dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + $recursive = ((STREAM_MKDIR_RECURSIVE & $options) !== 0) ? (true) : (false); + if (strpos($newDirs, '/') !== false && false === $recursive) { + return false; + } + + vfsStream::newDirectory($newDirs, $permissions)->at($dir); + return true; + } + + /** + * removes a directory + * + * @param string $path + * @param int $options + * @return bool + * @todo consider $options with STREAM_MKDIR_RECURSIVE + */ + public function rmdir($path, $options) + { + $path = $this->resolvePath(vfsStream::path($path)); + $child = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR); + if (null === $child) { + return false; + } + + // can only remove empty directories + if (count($child->getChildren()) > 0) { + return false; + } + + if (self::$root->getName() === $path) { + // delete root? very brave. :) + self::$root = null; + clearstatcache(); + return true; + } + + $names = $this->splitPath($path); + $dir = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR); + if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + clearstatcache(); + return $dir->removeChild($child->getName()); + } + + /** + * opens a directory + * + * @param string $path + * @param int $options + * @return bool + */ + public function dir_opendir($path, $options) + { + $path = $this->resolvePath(vfsStream::path($path)); + $this->dir = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR); + if (null === $this->dir || $this->dir->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + $this->dirIterator = $this->dir->getIterator(); + return true; + } + + /** + * reads directory contents + * + * @return string + */ + public function dir_readdir() + { + $dir = $this->dirIterator->current(); + if (null === $dir) { + return false; + } + + $this->dirIterator->next(); + return $dir->getName(); + } + + /** + * reset directory iteration + * + * @return bool + */ + public function dir_rewinddir() + { + return $this->dirIterator->rewind(); + } + + /** + * closes directory + * + * @return bool + */ + public function dir_closedir() + { + $this->dirIterator = null; + return true; + } + + /** + * returns status of url + * + * @param string $path path of url to return status for + * @param int $flags flags set by the stream API + * @return array + */ + public function url_stat($path, $flags) + { + $content = $this->getContent($this->resolvePath(vfsStream::path($path))); + if (null === $content) { + if (($flags & STREAM_URL_STAT_QUIET) != STREAM_URL_STAT_QUIET) { + trigger_error(' No such file or directory: ' . $path, E_USER_WARNING); + } + + return false; + + } + + $fileStat = array('dev' => 0, + 'ino' => 0, + 'mode' => $content->getType() | $content->getPermissions(), + 'nlink' => 0, + 'uid' => $content->getUser(), + 'gid' => $content->getGroup(), + 'rdev' => 0, + 'size' => $content->size(), + 'atime' => $content->fileatime(), + 'mtime' => $content->filemtime(), + 'ctime' => $content->filectime(), + 'blksize' => -1, + 'blocks' => -1 + ); + return array_merge(array_values($fileStat), $fileStat); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitor.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitor.php new file mode 100755 index 00000000..6af70b6a --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitor.php @@ -0,0 +1,45 @@ +getType()) { + case vfsStreamContent::TYPE_FILE: + $this->visitFile($content); + break; + + case vfsStreamContent::TYPE_DIR: + $this->visitDirectory($content); + break; + + default: + throw new \InvalidArgumentException('Unknown content type ' . $content->getType() . ' for ' . $content->getName()); + } + + return $this; + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitor.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitor.php new file mode 100755 index 00000000..eb742d34 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitor.php @@ -0,0 +1,93 @@ +out = $out; + } + + /** + * visit a file and process it + * + * @param vfsStreamFile $file + * @return vfsStreamPrintVisitor + */ + public function visitFile(vfsStreamFile $file) + { + $this->printContent($file); + return $this; + } + + /** + * visit a directory and process it + * + * @param vfsStreamDirectory $dir + * @return vfsStreamPrintVisitor + */ + public function visitDirectory(vfsStreamDirectory $dir) + { + $this->printContent($dir); + $this->depth++; + foreach ($dir as $child) { + $this->visit($child); + } + + $this->depth--; + return $this; + } + + /** + * helper method to print the content + * + * @param vfsStreamContent $content + */ + protected function printContent(vfsStreamContent $content) + { + fwrite($this->out, str_repeat(' ', $this->depth) . '- ' . $content->getName() . "\n"); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitor.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitor.php new file mode 100755 index 00000000..bbf38a4f --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitor.php @@ -0,0 +1,98 @@ +reset(); + } + + /** + * visit a file and process it + * + * @param vfsStreamFile $file + * @return vfsStreamStructureVisitor + */ + public function visitFile(vfsStreamFile $file) + { + $this->current[$file->getName()] = $file->getContent(); + return $this; + } + + /** + * visit a directory and process it + * + * @param vfsStreamDirectory $dir + * @return vfsStreamStructureVisitor + */ + public function visitDirectory(vfsStreamDirectory $dir) + { + $this->current[$dir->getName()] = array(); + $tmp =& $this->current; + $this->current =& $tmp[$dir->getName()]; + foreach ($dir as $child) { + $this->visit($child); + } + + $this->current =& $tmp; + return $this; + } + + /** + * returns structure of visited contents + * + * @return array + * @api + */ + public function getStructure() + { + return $this->structure; + } + + /** + * resets structure so visitor could be reused + * + * @return vfsStreamStructureVisitor + */ + public function reset() + { + $this->structure = array(); + $this->current =& $this->structure; + return $this; + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamVisitor.php b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamVisitor.php new file mode 100755 index 00000000..eba73bad --- /dev/null +++ b/vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/visitor/vfsStreamVisitor.php @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/QuotaTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/QuotaTestCase.php new file mode 100755 index 00000000..7007183e --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/QuotaTestCase.php @@ -0,0 +1,81 @@ +quota = new Quota(10); + } + + /** + * @test + */ + public function unlimitedQuotaIsNotLimited() + { + $this->assertFalse(Quota::unlimited()->isLimited()); + } + + /** + * @test + */ + public function limitedQuotaIsLimited() + { + $this->assertTrue($this->quota->isLimited()); + } + + /** + * @test + */ + public function unlimitedQuotaHasAlwaysSpaceLeft() + { + $this->assertEquals(303, Quota::unlimited()->spaceLeft(303)); + } + + /** + * @test + */ + public function hasNoSpaceLeftWhenUsedSpaceIsLargerThanQuota() + { + $this->assertEquals(0, $this->quota->spaceLeft(11)); + } + + /** + * @test + */ + public function hasNoSpaceLeftWhenUsedSpaceIsEqualToQuota() + { + $this->assertEquals(0, $this->quota->spaceLeft(10)); + } + + /** + * @test + */ + public function hasSpaceLeftWhenUsedSpaceIsLowerThanQuota() + { + $this->assertEquals(1, $this->quota->spaceLeft(9)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/proxy/vfsStreamWrapperRecordingProxy.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/proxy/vfsStreamWrapperRecordingProxy.php new file mode 100755 index 00000000..899931d6 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/proxy/vfsStreamWrapperRecordingProxy.php @@ -0,0 +1,326 @@ + + */ + public static function getMethodCalls($path) + { + if (isset(self::$calledMethods[$path]) === true) { + return self::$calledMethods[$path]; + } + + return array(); + } + + /** + * helper method for setting up vfsStream with the proxy + * + * @param string $rootDirName optional name of root directory + * @param int $permissions optional file permissions of root directory + * @return vfsStreamDirectory + * @throws vfsStreamException + */ + public static function setup($rootDirName = 'root', $permissions = null) + { + self::$root = vfsStream::newDirectory($rootDirName, $permissions); + if (true === self::$registered) { + return self::$root; + } + + if (@stream_wrapper_register(vfsStream::SCHEME, __CLASS__) === false) { + throw new vfsStreamException('A handler has already been registered for the ' . vfsStream::SCHEME . ' protocol.'); + } + + self::$registered = true; + return self::$root; + } + + /** + * open the stream + * + * @param string $path the path to open + * @param string $mode mode for opening + * @param string $options options for opening + * @param string $opened_path full path that was actually opened + * @return bool + */ + public function stream_open($path, $mode, $options, $opened_path) + { + $this->path = $path; + self::recordMethodCall('stream_open', $this->path); + return parent::stream_open($path, $mode, $options, $opened_path); + } + + /** + * closes the stream + */ + public function stream_close() + { + self::recordMethodCall('stream_close', $this->path); + return parent::stream_close(); + } + + /** + * read the stream up to $count bytes + * + * @param int $count amount of bytes to read + * @return string + */ + public function stream_read($count) + { + self::recordMethodCall('stream_read', $this->path); + return parent::stream_read($count); + } + + /** + * writes data into the stream + * + * @param string $data + * @return int amount of bytes written + */ + public function stream_write($data) + { + self::recordMethodCall('stream_write', $this->path); + return parent::stream_write($data); + } + + /** + * checks whether stream is at end of file + * + * @return bool + */ + public function stream_eof() + { + self::recordMethodCall('stream_eof', $this->path); + return parent::stream_eof(); + } + + /** + * returns the current position of the stream + * + * @return int + */ + public function stream_tell() + { + self::recordMethodCall('stream_tell', $this->path); + return parent::stream_tell(); + } + + /** + * seeks to the given offset + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function stream_seek($offset, $whence) + { + self::recordMethodCall('stream_seek', $this->path); + return parent::stream_seek($offset, $whence); + } + + /** + * flushes unstored data into storage + * + * @return bool + */ + public function stream_flush() + { + self::recordMethodCall('stream_flush', $this->path); + return parent::stream_flush(); + } + + /** + * returns status of stream + * + * @return array + */ + public function stream_stat() + { + self::recordMethodCall('stream_stat', $this->path); + return parent::stream_stat(); + } + + /** + * retrieve the underlaying resource + * + * @param int $cast_as + * @return bool + */ + public function stream_cast($cast_as) + { + self::recordMethodCall('stream_cast', $this->path); + return parent::stream_cast($cast_as); + } + + /** + * set lock status for stream + * + * @param int $operation + * @return bool + */ + public function stream_lock($operation) + { + self::recordMethodCall('stream_link', $this->path); + return parent::stream_lock($operation); + } + + /** + * remove the data under the given path + * + * @param string $path + * @return bool + */ + public function unlink($path) + { + self::recordMethodCall('unlink', $path); + return parent::unlink($path); + } + + /** + * rename from one path to another + * + * @param string $path_from + * @param string $path_to + * @return bool + */ + public function rename($path_from, $path_to) + { + self::recordMethodCall('rename', $path_from); + return parent::rename($path_from, $path_to); + } + + /** + * creates a new directory + * + * @param string $path + * @param int $mode + * @param int $options + * @return bool + */ + public function mkdir($path, $mode, $options) + { + self::recordMethodCall('mkdir', $path); + return parent::mkdir($path, $mode, $options); + } + + /** + * removes a directory + * + * @param string $path + * @param int $options + * @return bool + */ + public function rmdir($path, $options) + { + self::recordMethodCall('rmdir', $path); + return parent::rmdir($path, $options); + } + + /** + * opens a directory + * + * @param string $path + * @param int $options + * @return bool + */ + public function dir_opendir($path, $options) + { + $this->path = $path; + self::recordMethodCall('dir_opendir', $this->path); + return parent::dir_opendir($path, $options); + } + + /** + * reads directory contents + * + * @return string + */ + public function dir_readdir() + { + self::recordMethodCall('dir_readdir', $this->path); + return parent::dir_readdir(); + } + + /** + * reset directory iteration + * + * @return bool + */ + public function dir_rewinddir() + { + self::recordMethodCall('dir_rewinddir', $this->path); + return parent::dir_rewinddir(); + } + + /** + * closes directory + * + * @return bool + */ + public function dir_closedir() + { + self::recordMethodCall('dir_closedir', $this->path); + return parent::dir_closedir(); + } + + /** + * returns status of url + * + * @param string $path path of url to return status for + * @param int $flags flags set by the stream API + * @return array + */ + public function url_stat($path, $flags) + { + self::recordMethodCall('url_stat', $path); + return parent::url_stat($path, $flags); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamAbstractContentTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamAbstractContentTestCase.php new file mode 100755 index 00000000..9bb60795 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamAbstractContentTestCase.php @@ -0,0 +1,1054 @@ +assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executePermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0100); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executePermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0010); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executePermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0001); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function writePermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0200); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function writePermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0020); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function writePermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0002); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executeAndWritePermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0300); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executeAndWritePermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0030); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function executeAndWritePermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0003); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readPermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0400); + $this->assertTrue($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readPermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0040); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readPermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0004); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndExecutePermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0500); + $this->assertTrue($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndExecutePermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0050); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndExecutePermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0005); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndWritePermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0600); + $this->assertTrue($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndWritePermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0060); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function readAndWritePermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0006); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function allPermissionsForUser() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0700); + $this->assertTrue($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertTrue($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function allPermissionsForGroup() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0070); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + -1 + ) + ); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function allPermissionsForOther() + { + $abstractContent = new TestvfsStreamAbstractContent('foo', 0007); + $this->assertFalse($abstractContent->isReadable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isReadable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isReadable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isWritable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isWritable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isWritable(-1, + -1 + ) + ); + $this->assertFalse($abstractContent->isExecutable(vfsStream::getCurrentUser(), + vfsStream::getCurrentGroup() + ) + ); + $this->assertFalse($abstractContent->isExecutable(-1, + vfsStream::getCurrentGroup() + ) + ); + $this->assertTrue($abstractContent->isExecutable(-1, + -1 + ) + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamContainerIteratorTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamContainerIteratorTestCase.php new file mode 100755 index 00000000..9aa6960d --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamContainerIteratorTestCase.php @@ -0,0 +1,55 @@ +getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild1->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + $dir->addChild($mockChild1); + $mockChild2 = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild2->expects($this->any()) + ->method('getName') + ->will($this->returnValue('baz')); + $dir->addChild($mockChild2); + $dirIterator = $dir->getIterator(); + $this->assertEquals('bar', $dirIterator->key()); + $this->assertTrue($dirIterator->valid()); + $bar = $dirIterator->current(); + $this->assertSame($mockChild1, $bar); + $dirIterator->next(); + $this->assertEquals('baz', $dirIterator->key()); + $this->assertTrue($dirIterator->valid()); + $baz = $dirIterator->current(); + $this->assertSame($mockChild2, $baz); + $dirIterator->next(); + $this->assertFalse($dirIterator->valid()); + $this->assertNull($dirIterator->key()); + $this->assertNull($dirIterator->current()); + $dirIterator->rewind(); + $this->assertTrue($dirIterator->valid()); + $this->assertEquals('bar', $dirIterator->key()); + $bar2 = $dirIterator->current(); + $this->assertSame($mockChild1, $bar2); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryIssue18TestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryIssue18TestCase.php new file mode 100755 index 00000000..89cde1ce --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryIssue18TestCase.php @@ -0,0 +1,81 @@ +rootDirectory = vfsStream::newDirectory('/'); + $this->rootDirectory->addChild(vfsStream::newDirectory('var/log/app')); + $dir = $this->rootDirectory->getChild('var/log/app'); + $dir->addChild(vfsStream::newDirectory('app1')); + $dir->addChild(vfsStream::newDirectory('app2')); + $dir->addChild(vfsStream::newDirectory('foo')); + } + + /** + * @test + */ + public function shouldContainThreeSubdirectories() + { + $this->assertEquals(3, + count($this->rootDirectory->getChild('var/log/app')->getChildren()) + ); + } + + /** + * @test + */ + public function shouldContainSubdirectoryFoo() + { + $this->assertTrue($this->rootDirectory->getChild('var/log/app')->hasChild('foo')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $this->rootDirectory->getChild('var/log/app')->getChild('foo') + ); + } + + /** + * @test + */ + public function shouldContainSubdirectoryApp1() + { + $this->assertTrue($this->rootDirectory->getChild('var/log/app')->hasChild('app1')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $this->rootDirectory->getChild('var/log/app')->getChild('app1') + ); + } + + /** + * @test + */ + public function shouldContainSubdirectoryApp2() + { + $this->assertTrue($this->rootDirectory->getChild('var/log/app')->hasChild('app2')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $this->rootDirectory->getChild('var/log/app')->getChild('app2') + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryTestCase.php new file mode 100755 index 00000000..f8b93842 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamDirectoryTestCase.php @@ -0,0 +1,335 @@ +dir = new vfsStreamDirectory('foo'); + } + + /** + * assure that a directory seperator inside the name throws an exception + * + * @test + * @expectedException org\bovigo\vfs\vfsStreamException + */ + public function invalidCharacterInName() + { + $dir = new vfsStreamDirectory('foo/bar'); + } + + /** + * test default values and methods + * + * @test + */ + public function defaultValues() + { + $this->assertEquals(vfsStreamContent::TYPE_DIR, $this->dir->getType()); + $this->assertEquals('foo', $this->dir->getName()); + $this->assertTrue($this->dir->appliesTo('foo')); + $this->assertTrue($this->dir->appliesTo('foo/bar')); + $this->assertFalse($this->dir->appliesTo('bar')); + $this->assertEquals(array(), $this->dir->getChildren()); + } + + /** + * test renaming the directory + * + * @test + */ + public function rename() + { + $this->dir->rename('bar'); + $this->assertEquals('bar', $this->dir->getName()); + $this->assertFalse($this->dir->appliesTo('foo')); + $this->assertFalse($this->dir->appliesTo('foo/bar')); + $this->assertTrue($this->dir->appliesTo('bar')); + } + + /** + * renaming the directory to an invalid name throws a vfsStreamException + * + * @test + * @expectedException org\bovigo\vfs\vfsStreamException + */ + public function renameToInvalidNameThrowsvfsStreamException() + { + $this->dir->rename('foo/baz'); + } + + /** + * @test + * @since 0.10.0 + */ + public function hasNoChildrenByDefault() + { + $this->assertFalse($this->dir->hasChildren()); + } + + /** + * @test + * @since 0.10.0 + */ + public function hasChildrenReturnsTrueIfAtLeastOneChildPresent() + { + $mockChild = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild->expects($this->any()) + ->method('appliesTo') + ->will($this->returnValue(false)); + $mockChild->expects($this->any()) + ->method('getName') + ->will($this->returnValue('baz')); + $this->dir->addChild($mockChild); + $this->assertTrue($this->dir->hasChildren()); + } + + /** + * @test + */ + public function hasChildReturnsFalseForNonExistingChild() + { + $this->assertFalse($this->dir->hasChild('bar')); + } + + /** + * @test + */ + public function getChildReturnsNullForNonExistingChild() + { + $this->assertNull($this->dir->getChild('bar')); + } + + /** + * @test + */ + public function removeChildReturnsFalseForNonExistingChild() + { + $this->assertFalse($this->dir->removeChild('bar')); + } + + /** + * @test + */ + public function nonExistingChild() + { + $mockChild = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild->expects($this->any()) + ->method('appliesTo') + ->will($this->returnValue(false)); + $mockChild->expects($this->any()) + ->method('getName') + ->will($this->returnValue('baz')); + $this->dir->addChild($mockChild); + $this->assertFalse($this->dir->removeChild('bar')); + } + + /** + * test that adding, handling and removing of a child works as expected + * + * @test + */ + public function childHandling() + { + $mockChild = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild->expects($this->any()) + ->method('getType') + ->will($this->returnValue(vfsStreamContent::TYPE_FILE)); + $mockChild->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + $mockChild->expects($this->any()) + ->method('appliesTo') + ->with($this->equalTo('bar')) + ->will($this->returnValue(true)); + $mockChild->expects($this->once()) + ->method('size') + ->will($this->returnValue(5)); + $this->dir->addChild($mockChild); + $this->assertTrue($this->dir->hasChild('bar')); + $bar = $this->dir->getChild('bar'); + $this->assertSame($mockChild, $bar); + $this->assertEquals(array($mockChild), $this->dir->getChildren()); + $this->assertEquals(0, $this->dir->size()); + $this->assertEquals(5, $this->dir->sizeSummarized()); + $this->assertTrue($this->dir->removeChild('bar')); + $this->assertEquals(array(), $this->dir->getChildren()); + $this->assertEquals(0, $this->dir->size()); + $this->assertEquals(0, $this->dir->sizeSummarized()); + } + + /** + * test that adding, handling and removing of a child works as expected + * + * @test + */ + public function childHandlingWithSubdirectory() + { + $mockChild = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild->expects($this->any()) + ->method('getType') + ->will($this->returnValue(vfsStreamContent::TYPE_FILE)); + $mockChild->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + $mockChild->expects($this->once()) + ->method('size') + ->will($this->returnValue(5)); + $subdir = new vfsStreamDirectory('subdir'); + $subdir->addChild($mockChild); + $this->dir->addChild($subdir); + $this->assertTrue($this->dir->hasChild('subdir')); + $this->assertSame($subdir, $this->dir->getChild('subdir')); + $this->assertEquals(array($subdir), $this->dir->getChildren()); + $this->assertEquals(0, $this->dir->size()); + $this->assertEquals(5, $this->dir->sizeSummarized()); + $this->assertTrue($this->dir->removeChild('subdir')); + $this->assertEquals(array(), $this->dir->getChildren()); + $this->assertEquals(0, $this->dir->size()); + $this->assertEquals(0, $this->dir->sizeSummarized()); + } + + /** + * dd + * + * @test + * @group regression + * @group bug_5 + */ + public function addChildReplacesChildWithSameName_Bug_5() + { + $mockChild1 = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild1->expects($this->any()) + ->method('getType') + ->will($this->returnValue(vfsStreamContent::TYPE_FILE)); + $mockChild1->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + $mockChild2 = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild2->expects($this->any()) + ->method('getType') + ->will($this->returnValue(vfsStreamContent::TYPE_FILE)); + $mockChild2->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + $this->dir->addChild($mockChild1); + $this->assertTrue($this->dir->hasChild('bar')); + $this->assertSame($mockChild1, $this->dir->getChild('bar')); + $this->dir->addChild($mockChild2); + $this->assertTrue($this->dir->hasChild('bar')); + $this->assertSame($mockChild2, $this->dir->getChild('bar')); + } + + /** + * When testing for a nested path, verify that directory separators are respected properly + * so that subdir1/subdir2 is not considered equal to subdir1Xsubdir2. + * + * @test + * @group bug_24 + * @group regression + */ + public function explicitTestForSeparatorWithNestedPaths_Bug_24() + { + $mockChild = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockChild->expects($this->any()) + ->method('getType') + ->will($this->returnValue(vfsStreamContent::TYPE_FILE)); + $mockChild->expects($this->any()) + ->method('getName') + ->will($this->returnValue('bar')); + + $subdir1 = new vfsStreamDirectory('subdir1'); + $this->dir->addChild($subdir1); + + $subdir2 = new vfsStreamDirectory('subdir2'); + $subdir1->addChild($subdir2); + + $subdir2->addChild($mockChild); + + $this->assertTrue($this->dir->hasChild('subdir1'), "Level 1 path with separator exists"); + $this->assertTrue($this->dir->hasChild('subdir1/subdir2'), "Level 2 path with separator exists"); + $this->assertTrue($this->dir->hasChild('subdir1/subdir2/bar'), "Level 3 path with separator exists"); + $this->assertFalse($this->dir->hasChild('subdir1.subdir2'), "Path with period does not exist"); + $this->assertFalse($this->dir->hasChild('subdir1.subdir2/bar'), "Nested path with period does not exist"); + } + + + /** + * setting and retrieving permissions for a directory + * + * @test + * @group permissions + */ + public function permissions() + { + $this->assertEquals(0777, $this->dir->getPermissions()); + $this->assertSame($this->dir, $this->dir->chmod(0755)); + $this->assertEquals(0755, $this->dir->getPermissions()); + } + + /** + * setting and retrieving permissions for a directory + * + * @test + * @group permissions + */ + public function permissionsSet() + { + $this->dir = new vfsStreamDirectory('foo', 0755); + $this->assertEquals(0755, $this->dir->getPermissions()); + $this->assertSame($this->dir, $this->dir->chmod(0700)); + $this->assertEquals(0700, $this->dir->getPermissions()); + } + + /** + * setting and retrieving owner of a file + * + * @test + * @group permissions + */ + public function owner() + { + $this->assertEquals(vfsStream::getCurrentUser(), $this->dir->getUser()); + $this->assertTrue($this->dir->isOwnedByUser(vfsStream::getCurrentUser())); + $this->assertSame($this->dir, $this->dir->chown(vfsStream::OWNER_USER_1)); + $this->assertEquals(vfsStream::OWNER_USER_1, $this->dir->getUser()); + $this->assertTrue($this->dir->isOwnedByUser(vfsStream::OWNER_USER_1)); + } + + /** + * setting and retrieving owner group of a file + * + * @test + * @group permissions + */ + public function group() + { + $this->assertEquals(vfsStream::getCurrentGroup(), $this->dir->getGroup()); + $this->assertTrue($this->dir->isOwnedByGroup(vfsStream::getCurrentGroup())); + $this->assertSame($this->dir, $this->dir->chgrp(vfsStream::GROUP_USER_1)); + $this->assertEquals(vfsStream::GROUP_USER_1, $this->dir->getGroup()); + $this->assertTrue($this->dir->isOwnedByGroup(vfsStream::GROUP_USER_1)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamFileTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamFileTestCase.php new file mode 100755 index 00000000..d93e9942 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamFileTestCase.php @@ -0,0 +1,278 @@ +file = new vfsStreamFile('foo'); + } + + /** + * test default values and methods + * + * @test + */ + public function defaultValues() + { + $this->assertEquals(vfsStreamContent::TYPE_FILE, $this->file->getType()); + $this->assertEquals('foo', $this->file->getName()); + $this->assertTrue($this->file->appliesTo('foo')); + $this->assertFalse($this->file->appliesTo('foo/bar')); + $this->assertFalse($this->file->appliesTo('bar')); + } + + /** + * test setting and getting the content of a file + * + * @test + */ + public function content() + { + $this->assertNull($this->file->getContent()); + $this->assertSame($this->file, $this->file->setContent('bar')); + $this->assertEquals('bar', $this->file->getContent()); + $this->assertSame($this->file, $this->file->withContent('baz')); + $this->assertEquals('baz', $this->file->getContent()); + } + + /** + * test renaming the directory + * + * @test + */ + public function rename() + { + $this->file->rename('bar'); + $this->assertEquals('bar', $this->file->getName()); + $this->assertFalse($this->file->appliesTo('foo')); + $this->assertFalse($this->file->appliesTo('foo/bar')); + $this->assertTrue($this->file->appliesTo('bar')); + } + + /** + * test reading contents from the file + * + * @test + */ + public function readEmptyFile() + { + $this->assertTrue($this->file->eof()); + $this->assertEquals(0, $this->file->size()); + $this->assertEquals('', $this->file->read(5)); + $this->assertEquals(5, $this->file->getBytesRead()); + $this->assertTrue($this->file->eof()); + } + + /** + * test reading contents from the file + * + * @test + */ + public function read() + { + $this->file->setContent('foobarbaz'); + $this->assertFalse($this->file->eof()); + $this->assertEquals(9, $this->file->size()); + $this->assertEquals('foo', $this->file->read(3)); + $this->assertEquals(3, $this->file->getBytesRead()); + $this->assertFalse($this->file->eof()); + $this->assertEquals(9, $this->file->size()); + $this->assertEquals('bar', $this->file->read(3)); + $this->assertEquals(6, $this->file->getBytesRead()); + $this->assertFalse($this->file->eof()); + $this->assertEquals(9, $this->file->size()); + $this->assertEquals('baz', $this->file->read(3)); + $this->assertEquals(9, $this->file->getBytesRead()); + $this->assertEquals(9, $this->file->size()); + $this->assertTrue($this->file->eof()); + $this->assertEquals('', $this->file->read(3)); + } + + /** + * test seeking to offset + * + * @test + */ + public function seekEmptyFile() + { + $this->assertFalse($this->file->seek(0, 55)); + $this->assertTrue($this->file->seek(0, SEEK_SET)); + $this->assertEquals(0, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(5, SEEK_SET)); + $this->assertEquals(5, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(0, SEEK_CUR)); + $this->assertEquals(5, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(2, SEEK_CUR)); + $this->assertEquals(7, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(0, SEEK_END)); + $this->assertEquals(0, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(2, SEEK_END)); + $this->assertEquals(2, $this->file->getBytesRead()); + } + + /** + * test seeking to offset + * + * @test + */ + public function seekRead() + { + $this->file->setContent('foobarbaz'); + $this->assertFalse($this->file->seek(0, 55)); + $this->assertTrue($this->file->seek(0, SEEK_SET)); + $this->assertEquals('foobarbaz', $this->file->readUntilEnd()); + $this->assertEquals(0, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(5, SEEK_SET)); + $this->assertEquals('rbaz', $this->file->readUntilEnd()); + $this->assertEquals(5, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(0, SEEK_CUR)); + $this->assertEquals('rbaz', $this->file->readUntilEnd()); + $this->assertEquals(5, $this->file->getBytesRead(), 5); + $this->assertTrue($this->file->seek(2, SEEK_CUR)); + $this->assertEquals('az', $this->file->readUntilEnd()); + $this->assertEquals(7, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(0, SEEK_END)); + $this->assertEquals('', $this->file->readUntilEnd()); + $this->assertEquals(9, $this->file->getBytesRead()); + $this->assertTrue($this->file->seek(2, SEEK_END)); + $this->assertEquals('', $this->file->readUntilEnd()); + $this->assertEquals(11, $this->file->getBytesRead()); + } + + /** + * test writing data into the file + * + * @test + */ + public function writeEmptyFile() + { + $this->assertEquals(3, $this->file->write('foo')); + $this->assertEquals('foo', $this->file->getContent()); + $this->assertEquals(3, $this->file->size()); + $this->assertEquals(3, $this->file->write('bar')); + $this->assertEquals('foobar', $this->file->getContent()); + $this->assertEquals(6, $this->file->size()); + } + + /** + * test writing data into the file + * + * @test + */ + public function write() + { + $this->file->setContent('foobarbaz'); + $this->assertTrue($this->file->seek(3, SEEK_SET)); + $this->assertEquals(3, $this->file->write('foo')); + $this->assertEquals('foofoobaz', $this->file->getContent()); + $this->assertEquals(9, $this->file->size()); + $this->assertEquals(3, $this->file->write('bar')); + $this->assertEquals('foofoobar', $this->file->getContent()); + $this->assertEquals(9, $this->file->size()); + } + + /** + * setting and retrieving permissions for a file + * + * @test + * @group permissions + */ + public function permissions() + { + $this->assertEquals(0666, $this->file->getPermissions()); + $this->assertSame($this->file, $this->file->chmod(0644)); + $this->assertEquals(0644, $this->file->getPermissions()); + } + + /** + * setting and retrieving permissions for a file + * + * @test + * @group permissions + */ + public function permissionsSet() + { + $this->file = new vfsStreamFile('foo', 0644); + $this->assertEquals(0644, $this->file->getPermissions()); + $this->assertSame($this->file, $this->file->chmod(0600)); + $this->assertEquals(0600, $this->file->getPermissions()); + } + + /** + * setting and retrieving owner of a file + * + * @test + * @group permissions + */ + public function owner() + { + $this->assertEquals(vfsStream::getCurrentUser(), $this->file->getUser()); + $this->assertTrue($this->file->isOwnedByUser(vfsStream::getCurrentUser())); + $this->assertSame($this->file, $this->file->chown(vfsStream::OWNER_USER_1)); + $this->assertEquals(vfsStream::OWNER_USER_1, $this->file->getUser()); + $this->assertTrue($this->file->isOwnedByUser(vfsStream::OWNER_USER_1)); + } + + /** + * setting and retrieving owner group of a file + * + * @test + * @group permissions + */ + public function group() + { + $this->assertEquals(vfsStream::getCurrentGroup(), $this->file->getGroup()); + $this->assertTrue($this->file->isOwnedByGroup(vfsStream::getCurrentGroup())); + $this->assertSame($this->file, $this->file->chgrp(vfsStream::GROUP_USER_1)); + $this->assertEquals(vfsStream::GROUP_USER_1, $this->file->getGroup()); + $this->assertTrue($this->file->isOwnedByGroup(vfsStream::GROUP_USER_1)); + } + + /** + * @test + * @group issue_33 + * @since 1.1.0 + */ + public function truncateRemovesSuperflouosContent() + { + $this->assertEquals(11, $this->file->write("lorem ipsum")); + $this->assertTrue($this->file->truncate(5)); + $this->assertEquals(5, $this->file->size()); + $this->assertEquals('lorem', $this->file->getContent()); + } + + /** + * @test + * @group issue_33 + * @since 1.1.0 + */ + public function truncateToGreaterSizeAddsZeroBytes() + { + $this->assertEquals(11, $this->file->write("lorem ipsum")); + $this->assertTrue($this->file->truncate(25)); + $this->assertEquals(25, $this->file->size()); + $this->assertEquals("lorem ipsum\0\0\0\0\0\0\0\0\0\0\0\0\0\0", $this->file->getContent()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamGlobTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamGlobTestCase.php new file mode 100755 index 00000000..24884edf --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamGlobTestCase.php @@ -0,0 +1,29 @@ +assertEmpty(glob(vfsStream::url('example'), GLOB_MARK)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamResolveIncludePathTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamResolveIncludePathTestCase.php new file mode 100755 index 00000000..a4d70b54 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamResolveIncludePathTestCase.php @@ -0,0 +1,62 @@ +backupIncludePath = get_include_path(); + vfsStream::setup(); + mkdir('vfs://root/a/path', 0777, true); + set_include_path('vfs://root/a' . PATH_SEPARATOR . $this->backupIncludePath); + } + + /** + * clean up test environment + */ + public function tearDown() + { + set_include_path($this->backupIncludePath); + } + + /** + * @test + */ + public function knownFileCanBeResolved() + { + file_put_contents('vfs://root/a/path/knownFile.php', ''); + $this->assertEquals('vfs://root/a/path/knownFile.php', stream_resolve_include_path('path/knownFile.php')); + } + + /** + * @test + */ + public function unknownFileCanNotBeResolvedYieldsFalse() + { + $this->assertFalse(@stream_resolve_include_path('path/unknownFile.php')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamTestCase.php new file mode 100755 index 00000000..32101160 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamTestCase.php @@ -0,0 +1,707 @@ +assertEquals('vfs://foo', vfsStream::url('foo')); + $this->assertEquals('vfs://foo/bar.baz', vfsStream::url('foo/bar.baz')); + $this->assertEquals('vfs://foo/bar.baz', vfsStream::url('foo\bar.baz')); + } + + /** + * assure that url2path conversion works correct + * + * @test + */ + public function path() + { + $this->assertEquals('foo', vfsStream::path('vfs://foo')); + $this->assertEquals('foo/bar.baz', vfsStream::path('vfs://foo/bar.baz')); + $this->assertEquals('foo/bar.baz', vfsStream::path('vfs://foo\bar.baz')); + } + + /** + * windows directory separators are converted into default separator + * + * @author Gabriel Birke + * @test + */ + public function pathConvertsWindowsDirectorySeparators() + { + $this->assertEquals('foo/bar', vfsStream::path('vfs://foo\\bar')); + } + + /** + * trailing whitespace should be removed + * + * @author Gabriel Birke + * @test + */ + public function pathRemovesTrailingWhitespace() + { + $this->assertEquals('foo/bar', vfsStream::path('vfs://foo/bar ')); + } + + /** + * trailing slashes are removed + * + * @author Gabriel Birke + * @test + */ + public function pathRemovesTrailingSlash() + { + $this->assertEquals('foo/bar', vfsStream::path('vfs://foo/bar/')); + } + + /** + * trailing slash and whitespace should be removed + * + * @author Gabriel Birke + * @test + */ + public function pathRemovesTrailingSlashAndWhitespace() + { + $this->assertEquals('foo/bar', vfsStream::path('vfs://foo/bar/ ')); + } + + /** + * double slashes should be replaced by single slash + * + * @author Gabriel Birke + * @test + */ + public function pathRemovesDoubleSlashes() + { + // Regular path + $this->assertEquals('my/path', vfsStream::path('vfs://my/path')); + // Path with double slashes + $this->assertEquals('my/path', vfsStream::path('vfs://my//path')); + } + + /** + * test to create a new file + * + * @test + */ + public function newFile() + { + $file = vfsStream::newFile('filename.txt'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamFile', $file); + $this->assertEquals('filename.txt', $file->getName()); + $this->assertEquals(0666, $file->getPermissions()); + } + + /** + * test to create a new file with non-default permissions + * + * @test + * @group permissions + */ + public function newFileWithDifferentPermissions() + { + $file = vfsStream::newFile('filename.txt', 0644); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamFile', $file); + $this->assertEquals('filename.txt', $file->getName()); + $this->assertEquals(0644, $file->getPermissions()); + } + + /** + * test to create a new directory structure + * + * @test + */ + public function newSingleDirectory() + { + $foo = vfsStream::newDirectory('foo'); + $this->assertEquals('foo', $foo->getName()); + $this->assertEquals(0, count($foo->getChildren())); + $this->assertEquals(0777, $foo->getPermissions()); + } + + /** + * test to create a new directory structure with non-default permissions + * + * @test + * @group permissions + */ + public function newSingleDirectoryWithDifferentPermissions() + { + $foo = vfsStream::newDirectory('foo', 0755); + $this->assertEquals('foo', $foo->getName()); + $this->assertEquals(0, count($foo->getChildren())); + $this->assertEquals(0755, $foo->getPermissions()); + } + + /** + * test to create a new directory structure + * + * @test + */ + public function newDirectoryStructure() + { + $foo = vfsStream::newDirectory('foo/bar/baz'); + $this->assertEquals('foo', $foo->getName()); + $this->assertEquals(0777, $foo->getPermissions()); + $this->assertTrue($foo->hasChild('bar')); + $this->assertTrue($foo->hasChild('bar/baz')); + $this->assertFalse($foo->hasChild('baz')); + $bar = $foo->getChild('bar'); + $this->assertEquals('bar', $bar->getName()); + $this->assertEquals(0777, $bar->getPermissions()); + $this->assertTrue($bar->hasChild('baz')); + $baz1 = $bar->getChild('baz'); + $this->assertEquals('baz', $baz1->getName()); + $this->assertEquals(0777, $baz1->getPermissions()); + $baz2 = $foo->getChild('bar/baz'); + $this->assertSame($baz1, $baz2); + } + + /** + * test that correct directory structure is created + * + * @test + */ + public function newDirectoryWithSlashAtStart() + { + $foo = vfsStream::newDirectory('/foo/bar/baz', 0755); + $this->assertEquals('foo', $foo->getName()); + $this->assertEquals(0755, $foo->getPermissions()); + $this->assertTrue($foo->hasChild('bar')); + $this->assertTrue($foo->hasChild('bar/baz')); + $this->assertFalse($foo->hasChild('baz')); + $bar = $foo->getChild('bar'); + $this->assertEquals('bar', $bar->getName()); + $this->assertEquals(0755, $bar->getPermissions()); + $this->assertTrue($bar->hasChild('baz')); + $baz1 = $bar->getChild('baz'); + $this->assertEquals('baz', $baz1->getName()); + $this->assertEquals(0755, $baz1->getPermissions()); + $baz2 = $foo->getChild('bar/baz'); + $this->assertSame($baz1, $baz2); + } + + /** + * @test + * @group setup + * @since 0.7.0 + */ + public function setupRegistersStreamWrapperAndCreatesRootDirectoryWithDefaultNameAndPermissions() + { + $root = vfsStream::setup(); + $this->assertSame($root, vfsStreamWrapper::getRoot()); + $this->assertEquals('root', $root->getName()); + $this->assertEquals(0777, $root->getPermissions()); + } + + /** + * @test + * @group setup + * @since 0.7.0 + */ + public function setupRegistersStreamWrapperAndCreatesRootDirectoryWithGivenNameAndDefaultPermissions() + { + $root = vfsStream::setup('foo'); + $this->assertSame($root, vfsStreamWrapper::getRoot()); + $this->assertEquals('foo', $root->getName()); + $this->assertEquals(0777, $root->getPermissions()); + } + + /** + * @test + * @group setup + * @since 0.7.0 + */ + public function setupRegistersStreamWrapperAndCreatesRootDirectoryWithGivenNameAndPermissions() + { + $root = vfsStream::setup('foo', 0444); + $this->assertSame($root, vfsStreamWrapper::getRoot()); + $this->assertEquals('foo', $root->getName()); + $this->assertEquals(0444, $root->getPermissions()); + } + + /** + * @test + * @group issue_14 + * @group issue_20 + * @since 0.10.0 + */ + public function setupWithEmptyArrayIsEqualToSetup() + { + $root = vfsStream::setup('example', + 0755, + array() + ); + $this->assertEquals('example', $root->getName()); + $this->assertEquals(0755, $root->getPermissions()); + $this->assertFalse($root->hasChildren()); + } + + /** + * @test + * @group issue_14 + * @group issue_20 + * @since 0.10.0 + */ + public function setupArraysAreTurnedIntoSubdirectories() + { + $root = vfsStream::setup('root', + null, + array('test' => array()) + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $root->getChild('test') + ); + $this->assertFalse($root->getChild('test')->hasChildren()); + } + + /** + * @test + * @group issue_14 + * @group issue_20 + * @since 0.10.0 + */ + public function setupStringsAreTurnedIntoFilesWithContent() + { + $root = vfsStream::setup('root', + null, + array('test.txt' => 'some content') + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test.txt')); + $this->assertVfsFile($root->getChild('test.txt'), 'some content'); + } + + /** + * @test + * @group issue_14 + * @group issue_20 + * @since 0.10.0 + */ + public function setupWorksRecursively() + { + $root = vfsStream::setup('root', + null, + array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ) + ) + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test')); + $test = $root->getChild('test'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $test); + $this->assertTrue($test->hasChildren()); + $this->assertTrue($test->hasChild('baz.txt')); + $this->assertVfsFile($test->getChild('baz.txt'), 'world'); + + $this->assertTrue($test->hasChild('foo')); + $foo = $test->getChild('foo'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $foo); + $this->assertTrue($foo->hasChildren()); + $this->assertTrue($foo->hasChild('test.txt')); + $this->assertVfsFile($foo->getChild('test.txt'), 'hello'); + } + + /** + * @test + * @group issue_17 + * @group issue_20 + */ + public function setupCastsNumericDirectoriesToStrings() + { + $root = vfsStream::setup('root', + null, + array(2011 => array ('test.txt' => 'some content')) + ); + $this->assertTrue($root->hasChild('2011')); + + $directory = $root->getChild('2011'); + $this->assertVfsFile($directory->getChild('test.txt'), 'some content'); + + $this->assertTrue(file_exists('vfs://2011/test.txt')); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createArraysAreTurnedIntoSubdirectories() + { + $baseDir = vfsStream::create(array('test' => array()), new vfsStreamDirectory('baseDir')); + $this->assertTrue($baseDir->hasChildren()); + $this->assertTrue($baseDir->hasChild('test')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $baseDir->getChild('test') + ); + $this->assertFalse($baseDir->getChild('test')->hasChildren()); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createArraysAreTurnedIntoSubdirectoriesOfRoot() + { + $root = vfsStream::setup(); + $this->assertSame($root, vfsStream::create(array('test' => array()))); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test')); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', + $root->getChild('test') + ); + $this->assertFalse($root->getChild('test')->hasChildren()); + } + + /** + * @test + * @group issue_20 + * @expectedException \InvalidArgumentException + * @since 0.11.0 + */ + public function createThrowsExceptionIfNoBaseDirGivenAndNoRootSet() + { + vfsStream::create(array('test' => array())); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createWorksRecursively() + { + $baseDir = vfsStream::create(array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ) + ), + new vfsStreamDirectory('baseDir') + ); + $this->assertTrue($baseDir->hasChildren()); + $this->assertTrue($baseDir->hasChild('test')); + $test = $baseDir->getChild('test'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $test); + $this->assertTrue($test->hasChildren()); + $this->assertTrue($test->hasChild('baz.txt')); + $this->assertVfsFile($test->getChild('baz.txt'), 'world'); + + $this->assertTrue($test->hasChild('foo')); + $foo = $test->getChild('foo'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $foo); + $this->assertTrue($foo->hasChildren()); + $this->assertTrue($foo->hasChild('test.txt')); + $this->assertVfsFile($foo->getChild('test.txt'), 'hello'); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createWorksRecursivelyWithRoot() + { + $root = vfsStream::setup(); + $this->assertSame($root, + vfsStream::create(array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ) + ) + ) + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test')); + $test = $root->getChild('test'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $test); + $this->assertTrue($test->hasChildren()); + $this->assertTrue($test->hasChild('baz.txt')); + $this->assertVfsFile($test->getChild('baz.txt'), 'world'); + + $this->assertTrue($test->hasChild('foo')); + $foo = $test->getChild('foo'); + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamDirectory', $foo); + $this->assertTrue($foo->hasChildren()); + $this->assertTrue($foo->hasChild('test.txt')); + $this->assertVfsFile($foo->getChild('test.txt'), 'hello'); + } + + /** + * @test + * @group issue_20 + * @since 0.10.0 + */ + public function createStringsAreTurnedIntoFilesWithContent() + { + $baseDir = vfsStream::create(array('test.txt' => 'some content'), new vfsStreamDirectory('baseDir')); + $this->assertTrue($baseDir->hasChildren()); + $this->assertTrue($baseDir->hasChild('test.txt')); + $this->assertVfsFile($baseDir->getChild('test.txt'), 'some content'); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createStringsAreTurnedIntoFilesWithContentWithRoot() + { + $root = vfsStream::setup(); + $this->assertSame($root, + vfsStream::create(array('test.txt' => 'some content')) + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('test.txt')); + $this->assertVfsFile($root->getChild('test.txt'), 'some content'); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createCastsNumericDirectoriesToStrings() + { + $baseDir = vfsStream::create(array(2011 => array ('test.txt' => 'some content')), new vfsStreamDirectory('baseDir')); + $this->assertTrue($baseDir->hasChild('2011')); + + $directory = $baseDir->getChild('2011'); + $this->assertVfsFile($directory->getChild('test.txt'), 'some content'); + } + + /** + * @test + * @group issue_20 + * @since 0.11.0 + */ + public function createCastsNumericDirectoriesToStringsWithRoot() + { + $root = vfsStream::setup(); + $this->assertSame($root, + vfsStream::create(array(2011 => array ('test.txt' => 'some content'))) + ); + $this->assertTrue($root->hasChild('2011')); + + $directory = $root->getChild('2011'); + $this->assertVfsFile($directory->getChild('test.txt'), 'some content'); + } + + /** + * helper function for assertions on vfsStreamFile + * + * @param vfsStreamFile $file + * @param string $content + */ + protected function assertVfsFile(vfsStreamFile $file, $content) + { + $this->assertInstanceOf('org\\bovigo\\vfs\\vfsStreamFile', + $file + ); + $this->assertEquals($content, + $file->getContent() + ); + } + + /** + * @test + * @group issue_10 + * @since 0.10.0 + */ + public function inspectWithContentGivesContentToVisitor() + { + $mockContent = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockVisitor = $this->getMock('org\\bovigo\\vfs\\visitor\\vfsStreamVisitor'); + $mockVisitor->expects($this->once()) + ->method('visit') + ->with($this->equalTo($mockContent)) + ->will($this->returnValue($mockVisitor)); + $this->assertSame($mockVisitor, vfsStream::inspect($mockVisitor, $mockContent)); + } + + /** + * @test + * @group issue_10 + * @since 0.10.0 + */ + public function inspectWithoutContentGivesRootToVisitor() + { + $root = vfsStream::setup(); + $mockVisitor = $this->getMock('org\\bovigo\\vfs\\visitor\\vfsStreamVisitor'); + $mockVisitor->expects($this->once()) + ->method('visitDirectory') + ->with($this->equalTo($root)) + ->will($this->returnValue($mockVisitor)); + $this->assertSame($mockVisitor, vfsStream::inspect($mockVisitor)); + } + + /** + * @test + * @group issue_10 + * @expectedException \InvalidArgumentException + * @since 0.10.0 + */ + public function inspectWithoutContentAndWithoutRootThrowsInvalidArgumentException() + { + $mockVisitor = $this->getMock('org\\bovigo\\vfs\\visitor\\vfsStreamVisitor'); + $mockVisitor->expects($this->never()) + ->method('visit'); + $mockVisitor->expects($this->never()) + ->method('visitDirectory'); + vfsStream::inspect($mockVisitor); + } + + /** + * returns path to file system copy resource directory + * + * @return string + */ + protected function getFileSystemCopyDir() + { + return realpath(dirname(__FILE__) . '/../../../../resources/filesystemcopy'); + } + + /** + * @test + * @group issue_4 + * @expectedException \InvalidArgumentException + * @since 0.11.0 + */ + public function copyFromFileSystemThrowsExceptionIfNoBaseDirGivenAndNoRootSet() + { + vfsStream::copyFromFileSystem($this->getFileSystemCopyDir()); + } + + /** + * @test + * @group issue_4 + * @since 0.11.0 + */ + public function copyFromEmptyFolder() + { + $baseDir = vfsStream::copyFromFileSystem($this->getFileSystemCopyDir() . '/emptyFolder', + vfsStream::newDirectory('test') + ); + $baseDir->removeChild('.gitignore'); + $this->assertFalse($baseDir->hasChildren()); + } + + /** + * @test + * @group issue_4 + * @since 0.11.0 + */ + public function copyFromEmptyFolderWithRoot() + { + $root = vfsStream::setup(); + $this->assertEquals($root, + vfsStream::copyFromFileSystem($this->getFileSystemCopyDir() . '/emptyFolder') + ); + $root->removeChild('.gitignore'); + $this->assertFalse($root->hasChildren()); + } + + /** + * @test + * @group issue_4 + * @since 0.11.0 + */ + public function copyFromWithSubFolders() + { + $baseDir = vfsStream::copyFromFileSystem($this->getFileSystemCopyDir(), + vfsStream::newDirectory('test'), + 3 + ); + $this->assertTrue($baseDir->hasChildren()); + $this->assertTrue($baseDir->hasChild('emptyFolder')); + $this->assertTrue($baseDir->hasChild('withSubfolders')); + $subfolderDir = $baseDir->getChild('withSubfolders'); + $this->assertTrue($subfolderDir->hasChild('subfolder1')); + $this->assertTrue($subfolderDir->getChild('subfolder1')->hasChild('file1.txt')); + $this->assertVfsFile($subfolderDir->getChild('subfolder1/file1.txt'), ''); + $this->assertTrue($subfolderDir->hasChild('subfolder2')); + $this->assertTrue($subfolderDir->hasChild('aFile.txt')); + $this->assertVfsFile($subfolderDir->getChild('aFile.txt'), 'foo'); + } + + /** + * @test + * @group issue_4 + * @since 0.11.0 + */ + public function copyFromWithSubFoldersWithRoot() + { + $root = vfsStream::setup(); + $this->assertEquals($root, + vfsStream::copyFromFileSystem($this->getFileSystemCopyDir(), + null, + 3 + ) + ); + $this->assertTrue($root->hasChildren()); + $this->assertTrue($root->hasChild('emptyFolder')); + $this->assertTrue($root->hasChild('withSubfolders')); + $subfolderDir = $root->getChild('withSubfolders'); + $this->assertTrue($subfolderDir->hasChild('subfolder1')); + $this->assertTrue($subfolderDir->getChild('subfolder1')->hasChild('file1.txt')); + $this->assertVfsFile($subfolderDir->getChild('subfolder1/file1.txt'), ''); + $this->assertTrue($subfolderDir->hasChild('subfolder2')); + $this->assertTrue($subfolderDir->hasChild('aFile.txt')); + $this->assertVfsFile($subfolderDir->getChild('aFile.txt'), 'foo'); + } + + /** + * @test + * @group issue_4 + * @group issue_29 + * @since 0.11.2 + */ + public function copyFromPreservesFilePermissions() + { + if (DIRECTORY_SEPARATOR !== '/') { + $this->markTestSkipped('Only applicable on Linux style systems.'); + } + + $copyDir = $this->getFileSystemCopyDir(); + $root = vfsStream::setup(); + $this->assertEquals($root, + vfsStream::copyFromFileSystem($copyDir, + null + ) + ); + $this->assertEquals(fileperms($copyDir . '/withSubfolders') - vfsStreamContent::TYPE_DIR, + $root->getChild('withSubfolders') + ->getPermissions() + ); + $this->assertEquals(fileperms($copyDir . '/withSubfolders/aFile.txt') - vfsStreamContent::TYPE_FILE, + $root->getChild('withSubfolders/aFile.txt') + ->getPermissions() + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamUmaskTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamUmaskTestCase.php new file mode 100755 index 00000000..342af310 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamUmaskTestCase.php @@ -0,0 +1,195 @@ +assertEquals(vfsStream::umask(), + vfsStream::umask() + ); + $this->assertEquals(0000, + vfsStream::umask() + ); + } + + /** + * @test + */ + public function changingUmaskSettingReturnsOldUmaskSetting() + { + $this->assertEquals(0000, + vfsStream::umask(0022) + ); + $this->assertEquals(0022, + vfsStream::umask() + ); + } + + /** + * @test + */ + public function createFileWithDefaultUmaskSetting() + { + $file = new vfsStreamFile('foo'); + $this->assertEquals(0666, $file->getPermissions()); + } + + /** + * @test + */ + public function createFileWithDifferentUmaskSetting() + { + vfsStream::umask(0022); + $file = new vfsStreamFile('foo'); + $this->assertEquals(0644, $file->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryWithDefaultUmaskSetting() + { + $directory = new vfsStreamDirectory('foo'); + $this->assertEquals(0777, $directory->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryWithDifferentUmaskSetting() + { + vfsStream::umask(0022); + $directory = new vfsStreamDirectory('foo'); + $this->assertEquals(0755, $directory->getPermissions()); + } + + /** + * @test + */ + public function createFileUsingStreamWithDefaultUmaskSetting() + { + $root = vfsStream::setup(); + file_put_contents(vfsStream::url('root/newfile.txt'), 'file content'); + $this->assertEquals(0666, $root->getChild('newfile.txt')->getPermissions()); + } + + /** + * @test + */ + public function createFileUsingStreamWithDifferentUmaskSetting() + { + $root = vfsStream::setup(); + vfsStream::umask(0022); + file_put_contents(vfsStream::url('root/newfile.txt'), 'file content'); + $this->assertEquals(0644, $root->getChild('newfile.txt')->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryUsingStreamWithDefaultUmaskSetting() + { + $root = vfsStream::setup(); + mkdir(vfsStream::url('root/newdir')); + $this->assertEquals(0777, $root->getChild('newdir')->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryUsingStreamWithDifferentUmaskSetting() + { + $root = vfsStream::setup(); + vfsStream::umask(0022); + mkdir(vfsStream::url('root/newdir')); + $this->assertEquals(0755, $root->getChild('newdir')->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryUsingStreamWithExplicit0() + { + $root = vfsStream::setup(); + vfsStream::umask(0022); + mkdir(vfsStream::url('root/newdir'), null); + $this->assertEquals(0000, $root->getChild('newdir')->getPermissions()); + } + + /** + * @test + * + */ + public function createDirectoryUsingStreamWithDifferentUmaskSettingButExplicit0777() + { + $root = vfsStream::setup(); + vfsStream::umask(0022); + mkdir(vfsStream::url('root/newdir'), 0777); + $this->assertEquals(0755, $root->getChild('newdir')->getPermissions()); + } + + /** + * @test + */ + public function createDirectoryUsingStreamWithDifferentUmaskSettingButExplicitModeRequestedByCall() + { + $root = vfsStream::setup(); + vfsStream::umask(0022); + mkdir(vfsStream::url('root/newdir'), 0700); + $this->assertEquals(0700, $root->getChild('newdir')->getPermissions()); + } + + /** + * @test + */ + public function defaultUmaskSettingDoesNotInfluenceSetup() + { + $root = vfsStream::setup(); + $this->assertEquals(0777, $root->getPermissions()); + } + + /** + * @test + */ + public function umaskSettingShouldBeRespectedBySetup() + { + vfsStream::umask(0022); + $root = vfsStream::setup(); + $this->assertEquals(0755, $root->getPermissions()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperAlreadyRegisteredTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperAlreadyRegisteredTestCase.php new file mode 100755 index 00000000..c7f78dcc --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperAlreadyRegisteredTestCase.php @@ -0,0 +1,63 @@ +getMock('org\\bovigo\\vfs\\vfsStreamWrapper'); + stream_wrapper_register(vfsStream::SCHEME, get_class($mock)); + } + + /** + * clean up test environment + */ + public function tearDown() + { + TestvfsStreamWrapper::unregister(); + } + + /** + * registering the stream wrapper when another stream wrapper is already + * registered for the vfs scheme should throw an exception + * + * @test + * @expectedException org\bovigo\vfs\vfsStreamException + */ + public function registerOverAnotherStreamWrapper() + { + vfsStreamWrapper::register(); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperBaseTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperBaseTestCase.php new file mode 100755 index 00000000..52ec40cf --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperBaseTestCase.php @@ -0,0 +1,99 @@ +fooURL = vfsStream::url('foo'); + $this->barURL = vfsStream::url('foo/bar'); + $this->baz1URL = vfsStream::url('foo/bar/baz1'); + $this->baz2URL = vfsStream::url('foo/baz2'); + $this->foo = new vfsStreamDirectory('foo'); + $this->bar = new vfsStreamDirectory('bar'); + $this->baz1 = vfsStream::newFile('baz1') + ->lastModified(300) + ->lastAccessed(300) + ->lastAttributeModified(300) + ->withContent('baz 1'); + $this->baz2 = vfsStream::newFile('baz2') + ->withContent('baz2') + ->lastModified(400) + ->lastAccessed(400) + ->lastAttributeModified(400); + $this->bar->addChild($this->baz1); + $this->foo->addChild($this->bar); + $this->foo->addChild($this->baz2); + $this->foo->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + $this->bar->lastModified(200) + ->lastAccessed(100) + ->lastAttributeModified(100); + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot($this->foo); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirSeparatorTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirSeparatorTestCase.php new file mode 100755 index 00000000..f08f0a7f --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirSeparatorTestCase.php @@ -0,0 +1,57 @@ +root = vfsStream::setup(); + } + + /** + * @test + */ + public function fileCanBeAccessedUsingWinDirSeparator() + { + vfsStream::newFile('foo/bar/baz.txt') + ->at($this->root) + ->withContent('test'); + $this->assertEquals('test', file_get_contents('vfs://root/foo\bar\baz.txt')); + } + + + /** + * @test + */ + public function directoryCanBeCreatedUsingWinDirSeparator() + { + mkdir('vfs://root/dir\bar\foo', true, 0777); + $this->assertTrue($this->root->hasChild('dir')); + $this->assertTrue($this->root->getChild('dir')->hasChild('bar')); + $this->assertTrue($this->root->getChild('dir/bar')->hasChild('foo')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirTestCase.php new file mode 100755 index 00000000..cf4efdd4 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperDirTestCase.php @@ -0,0 +1,617 @@ +assertFalse(mkdir(vfsStream::url('another'))); + $this->assertEquals(2, count($this->foo->getChildren())); + $this->assertSame($this->foo, vfsStreamWrapper::getRoot()); + } + + /** + * mkdir() should not overwrite existing root + * + * @test + */ + public function mkdirNoNewRootRecursively() + { + $this->assertFalse(mkdir(vfsStream::url('another/more'), 0777, true)); + $this->assertEquals(2, count($this->foo->getChildren())); + $this->assertSame($this->foo, vfsStreamWrapper::getRoot()); + } + + /** + * assert that mkdir() creates the correct directory structure + * + * @test + * @group permissions + */ + public function mkdirNonRecursively() + { + $this->assertFalse(mkdir($this->barURL . '/another/more')); + $this->assertEquals(2, count($this->foo->getChildren())); + $this->assertTrue(mkdir($this->fooURL . '/another')); + $this->assertEquals(3, count($this->foo->getChildren())); + $this->assertEquals(0777, $this->foo->getChild('another')->getPermissions()); + } + + /** + * assert that mkdir() creates the correct directory structure + * + * @test + * @group permissions + */ + public function mkdirRecursively() + { + $this->assertTrue(mkdir($this->fooURL . '/another/more', 0777, true)); + $this->assertEquals(3, count($this->foo->getChildren())); + $another = $this->foo->getChild('another'); + $this->assertTrue($another->hasChild('more')); + $this->assertEquals(0777, $this->foo->getChild('another')->getPermissions()); + $this->assertEquals(0777, $this->foo->getChild('another')->getChild('more')->getPermissions()); + } + + /** + * @test + * @group issue_9 + * @since 0.9.0 + */ + public function mkdirWithDots() + { + $this->assertTrue(mkdir($this->fooURL . '/another/../more/.', 0777, true)); + $this->assertEquals(3, count($this->foo->getChildren())); + $this->assertTrue($this->foo->hasChild('more')); + } + + /** + * no root > new directory becomes root + * + * @test + * @group permissions + */ + public function mkdirWithoutRootCreatesNewRoot() + { + vfsStreamWrapper::register(); + $this->assertTrue(@mkdir(vfsStream::url('foo'))); + $this->assertEquals(vfsStreamContent::TYPE_DIR, vfsStreamWrapper::getRoot()->getType()); + $this->assertEquals('foo', vfsStreamWrapper::getRoot()->getName()); + $this->assertEquals(0777, vfsStreamWrapper::getRoot()->getPermissions()); + } + + /** + * trying to create a subdirectory of a file should not work + * + * @test + */ + public function mkdirOnFileReturnsFalse() + { + $this->assertFalse(mkdir($this->baz1URL . '/another/more', 0777, true)); + } + + /** + * assert that mkdir() creates the correct directory structure + * + * @test + * @group permissions + */ + public function mkdirNonRecursivelyDifferentPermissions() + { + $this->assertTrue(mkdir($this->fooURL . '/another', 0755)); + $this->assertEquals(0755, $this->foo->getChild('another')->getPermissions()); + } + + /** + * assert that mkdir() creates the correct directory structure + * + * @test + * @group permissions + */ + public function mkdirRecursivelyDifferentPermissions() + { + $this->assertTrue(mkdir($this->fooURL . '/another/more', 0755, true)); + $this->assertEquals(3, count($this->foo->getChildren())); + $another = $this->foo->getChild('another'); + $this->assertTrue($another->hasChild('more')); + $this->assertEquals(0755, $this->foo->getChild('another')->getPermissions()); + $this->assertEquals(0755, $this->foo->getChild('another')->getChild('more')->getPermissions()); + } + + /** + * assert that mkdir() creates the correct directory structure + * + * @test + * @group permissions + */ + public function mkdirRecursivelyUsesDefaultPermissions() + { + $this->foo->chmod(0700); + $this->assertTrue(mkdir($this->fooURL . '/another/more', 0777, true)); + $this->assertEquals(3, count($this->foo->getChildren())); + $another = $this->foo->getChild('another'); + $this->assertTrue($another->hasChild('more')); + $this->assertEquals(0777, $this->foo->getChild('another')->getPermissions()); + $this->assertEquals(0777, $this->foo->getChild('another')->getChild('more')->getPermissions()); + } + + /** + * no root > new directory becomes root + * + * @test + * @group permissions + */ + public function mkdirWithoutRootCreatesNewRootDifferentPermissions() + { + vfsStreamWrapper::register(); + $this->assertTrue(@mkdir(vfsStream::url('foo'), 0755)); + $this->assertEquals(vfsStreamContent::TYPE_DIR, vfsStreamWrapper::getRoot()->getType()); + $this->assertEquals('foo', vfsStreamWrapper::getRoot()->getName()); + $this->assertEquals(0755, vfsStreamWrapper::getRoot()->getPermissions()); + } + + /** + * no root > new directory becomes root + * + * @test + * @group permissions + */ + public function mkdirWithoutRootCreatesNewRootWithDefaultPermissions() + { + vfsStreamWrapper::register(); + $this->assertTrue(@mkdir(vfsStream::url('foo'))); + $this->assertEquals(vfsStreamContent::TYPE_DIR, vfsStreamWrapper::getRoot()->getType()); + $this->assertEquals('foo', vfsStreamWrapper::getRoot()->getName()); + $this->assertEquals(0777, vfsStreamWrapper::getRoot()->getPermissions()); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function mkdirDirCanNotCreateNewDirInNonWritingDirectory() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root')); + vfsStreamWrapper::getRoot()->addChild(new vfsStreamDirectory('restrictedFolder', 0000)); + $this->assertFalse(is_writable(vfsStream::url('root/restrictedFolder/'))); + $this->assertFalse(mkdir(vfsStream::url('root/restrictedFolder/newFolder'))); + $this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('restrictedFolder/newFolder')); + } + + /** + * @test + * @group issue_28 + */ + public function mkDirShouldNotOverwriteExistingDirectories() + { + vfsStream::setup('root'); + $dir = vfsStream::url('root/dir'); + $this->assertTrue(mkdir($dir)); + $this->assertFalse(@mkdir($dir)); + } + + /** + * @test + * @group issue_28 + * @expectedException PHPUnit_Framework_Error + * @expectedExceptionMessage mkdir(): Path vfs://root/dir exists + */ + public function mkDirShouldNotOverwriteExistingDirectoriesAndTriggerE_USER_WARNING() + { + vfsStream::setup('root'); + $dir = vfsStream::url('root/dir'); + $this->assertTrue(mkdir($dir)); + $this->assertFalse(mkdir($dir)); + } + + /** + * @test + * @group issue_28 + */ + public function mkDirShouldNotOverwriteExistingFiles() + { + $root = vfsStream::setup('root'); + vfsStream::newFile('test.txt')->at($root); + $this->assertFalse(@mkdir(vfsStream::url('root/test.txt'))); + } + + /** + * @test + * @group issue_28 + * @expectedException PHPUnit_Framework_Error + * @expectedExceptionMessage mkdir(): Path vfs://root/test.txt exists + */ + public function mkDirShouldNotOverwriteExistingFilesAndTriggerE_USER_WARNING() + { + $root = vfsStream::setup('root'); + vfsStream::newFile('test.txt')->at($root); + $this->assertFalse(mkdir(vfsStream::url('root/test.txt'))); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function canNotIterateOverNonReadableDirectory() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0000)); + $this->assertFalse(@opendir(vfsStream::url('root'))); + $this->assertFalse(@dir(vfsStream::url('root'))); + } + + /** + * @test + */ + public function directoryIteration() + { + $dir = dir($this->fooURL); + $i = 0; + while (false !== ($entry = $dir->read())) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + $dir->rewind(); + $i = 0; + while (false !== ($entry = $dir->read())) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + $dir->close(); + } + + /** + * @test + */ + public function directoryIterationWithDot() + { + $dir = dir($this->fooURL . '/.'); + $i = 0; + while (false !== ($entry = $dir->read())) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + $dir->rewind(); + $i = 0; + while (false !== ($entry = $dir->read())) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + $dir->close(); + } + + /** + * assure that a directory iteration works as expected + * + * @test + * @group regression + * @group bug_2 + */ + public function directoryIterationWithOpenDir_Bug_2() + { + $handle = opendir($this->fooURL); + $i = 0; + while (false !== ($entry = readdir($handle))) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + + rewind($handle); + $i = 0; + while (false !== ($entry = readdir($handle))) { + $i++; + $this->assertTrue('bar' === $entry || 'baz2' === $entry); + } + + $this->assertEquals(2, $i, 'Directory foo contains two children, but got ' . $i . ' children while iterating over directory contents'); + closedir($handle); + } + + /** + * assure that a directory iteration works as expected + * + * @author Christoph Bloemer + * @test + * @group regression + * @group bug_4 + */ + public function directoryIteration_Bug_4() + { + $dir = $this->fooURL; + $list1 = array(); + if ($handle = opendir($dir)) { + while (false !== ($listItem = readdir($handle))) { + if ('.' != $listItem && '..' != $listItem) { + if (is_file($dir . '/' . $listItem) === true) { + $list1[] = 'File:[' . $listItem . ']'; + } elseif (is_dir($dir . '/' . $listItem) === true) { + $list1[] = 'Folder:[' . $listItem . ']'; + } + } + } + + closedir($handle); + } + + $list2 = array(); + if ($handle = opendir($dir)) { + while (false !== ($listItem = readdir($handle))) { + if ('.' != $listItem && '..' != $listItem) { + if (is_file($dir . '/' . $listItem) === true) { + $list2[] = 'File:[' . $listItem . ']'; + } elseif (is_dir($dir . '/' . $listItem) === true) { + $list2[] = 'Folder:[' . $listItem . ']'; + } + } + } + + closedir($handle); + } + + $this->assertEquals($list1, $list2); + $this->assertEquals(2, count($list1)); + $this->assertEquals(2, count($list2)); + } + + /** + * assure that a directory iteration works as expected + * + * @test + */ + public function directoryIterationShouldBeIndependent() + { + $list1 = array(); + $list2 = array(); + $handle1 = opendir($this->fooURL); + if (false !== ($listItem = readdir($handle1))) { + $list1[] = $listItem; + } + + $handle2 = opendir($this->fooURL); + if (false !== ($listItem = readdir($handle2))) { + $list2[] = $listItem; + } + + if (false !== ($listItem = readdir($handle1))) { + $list1[] = $listItem; + } + + if (false !== ($listItem = readdir($handle2))) { + $list2[] = $listItem; + } + + closedir($handle1); + closedir($handle2); + $this->assertEquals($list1, $list2); + $this->assertEquals(2, count($list1)); + $this->assertEquals(2, count($list2)); + } + + /** + * assert is_dir() returns correct result + * + * @test + */ + public function is_dir() + { + $this->assertTrue(is_dir($this->fooURL)); + $this->assertTrue(is_dir($this->fooURL . '/.')); + $this->assertTrue(is_dir($this->barURL)); + $this->assertTrue(is_dir($this->barURL . '/.')); + $this->assertFalse(is_dir($this->baz1URL)); + $this->assertFalse(is_dir($this->baz2URL)); + $this->assertFalse(is_dir($this->fooURL . '/another')); + $this->assertFalse(is_dir(vfsStream::url('another'))); + } + + /** + * can not unlink without root + * + * @test + */ + public function canNotUnlinkDirectoryWithoutRoot() + { + vfsStreamWrapper::register(); + $this->assertFalse(@rmdir(vfsStream::url('foo'))); + } + + /** + * rmdir() can not remove files + * + * @test + */ + public function rmdirCanNotRemoveFiles() + { + $this->assertFalse(rmdir($this->baz1URL)); + $this->assertFalse(rmdir($this->baz2URL)); + } + + /** + * rmdir() can not remove a non-existing directory + * + * @test + */ + public function rmdirCanNotRemoveNonExistingDirectory() + { + $this->assertFalse(rmdir($this->fooURL . '/another')); + } + + /** + * rmdir() can not remove non-empty directories + * + * @test + */ + public function rmdirCanNotRemoveNonEmptyDirectory() + { + $this->assertFalse(rmdir($this->fooURL)); + $this->assertFalse(rmdir($this->barURL)); + } + + /** + * @test + */ + public function rmdirCanRemoveEmptyDirectory() + { + vfsStream::newDirectory('empty')->at($this->foo); + $this->assertTrue($this->foo->hasChild('empty')); + $this->assertTrue(rmdir($this->fooURL . '/empty')); + $this->assertFalse($this->foo->hasChild('empty')); + } + + /** + * @test + */ + public function rmdirCanRemoveEmptyDirectoryWithDot() + { + vfsStream::newDirectory('empty')->at($this->foo); + $this->assertTrue($this->foo->hasChild('empty')); + $this->assertTrue(rmdir($this->fooURL . '/empty/.')); + $this->assertFalse($this->foo->hasChild('empty')); + } + + /** + * rmdir() can remove empty directories + * + * @test + */ + public function rmdirCanRemoveEmptyRoot() + { + $this->foo->removeChild('bar'); + $this->foo->removeChild('baz2'); + $this->assertTrue(rmdir($this->fooURL)); + $this->assertFalse(file_exists($this->fooURL)); // make sure statcache was cleared + $this->assertNull(vfsStreamWrapper::getRoot()); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function rmdirDirCanNotRemoveDirFromNonWritingDirectory() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0000)); + vfsStreamWrapper::getRoot()->addChild(new vfsStreamDirectory('nonRemovableFolder')); + $this->assertFalse(is_writable(vfsStream::url('root'))); + $this->assertFalse(rmdir(vfsStream::url('root/nonRemovableFolder'))); + $this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('nonRemovableFolder')); + } + + /** + * @test + * @group permissions + * @group bug_17 + */ + public function issue17() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0770)); + vfsStreamWrapper::getRoot()->chgrp(vfsStream::GROUP_USER_1) + ->chown(vfsStream::OWNER_USER_1); + $this->assertFalse(mkdir(vfsStream::url('root/doesNotWork'))); + $this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('doesNotWork')); + } + + /** + * @test + * @group bug_19 + */ + public function accessWithDoubleDotReturnsCorrectContent() + { + $this->assertEquals('baz2', + file_get_contents(vfsStream::url('foo/bar/../baz2')) + ); + } + + /** + * @test + * @since 0.11.0 + * @group issue_23 + */ + public function unlinkCanNotRemoveNonEmptyDirectory() + { + try { + $this->assertFalse(unlink($this->barURL)); + } catch (\PHPUnit_Framework_Error $fe) { + $this->assertEquals('unlink(vfs://foo/bar): Operation not permitted', $fe->getMessage()); + } + + $this->assertTrue($this->foo->hasChild('bar')); + $this->assertFileExists($this->barURL); + } + + /** + * @test + * @since 0.11.0 + * @group issue_23 + */ + public function unlinkCanNotRemoveEmptyDirectory() + { + vfsStream::newDirectory('empty')->at($this->foo); + try { + $this->assertTrue(unlink($this->fooURL . '/empty')); + } catch (\PHPUnit_Framework_Error $fe) { + $this->assertEquals('unlink(vfs://foo/empty): Operation not permitted', $fe->getMessage()); + } + + $this->assertTrue($this->foo->hasChild('empty')); + $this->assertFileExists($this->fooURL . '/empty'); + } + + /** + * @test + * @group issue_32 + */ + public function canCreateFolderOfSameNameAsParentFolder() + { + $root = vfsStream::setup('testFolder'); + mkdir(vfsStream::url('testFolder') . '/testFolder/subTestFolder', 0777, true); + $this->assertTrue(file_exists(vfsStream::url('testFolder/testFolder/subTestFolder/.'))); + } + + /** + * @test + * @group issue_32 + */ + public function canRetrieveFolderOfSameNameAsParentFolder() + { + $root = vfsStream::setup('testFolder'); + mkdir(vfsStream::url('testFolder') . '/testFolder/subTestFolder', 0777, true); + $this->assertTrue($root->hasChild('testFolder')); + $this->assertNotNull($root->getChild('testFolder')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTestCase.php new file mode 100755 index 00000000..4ca9a61a --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTestCase.php @@ -0,0 +1,472 @@ +assertEquals('baz2', file_get_contents($this->baz2URL)); + $this->assertEquals('baz 1', file_get_contents($this->baz1URL)); + $this->assertFalse(@file_get_contents($this->barURL)); + $this->assertFalse(@file_get_contents($this->fooURL)); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function file_get_contentsNonReadableFile() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root')); + vfsStream::newFile('new.txt', 0000)->at(vfsStreamWrapper::getRoot())->withContent('content'); + $this->assertEquals('', @file_get_contents(vfsStream::url('root/new.txt'))); + } + + /** + * assert that file_put_contents() delivers correct file contents + * + * @test + */ + public function file_put_contentsExistingFile() + { + $this->assertEquals(14, file_put_contents($this->baz2URL, 'baz is not bar')); + $this->assertEquals('baz is not bar', $this->baz2->getContent()); + $this->assertEquals(6, file_put_contents($this->baz1URL, 'foobar')); + $this->assertEquals('foobar', $this->baz1->getContent()); + $this->assertFalse(@file_put_contents($this->barURL, 'This does not work.')); + $this->assertFalse(@file_put_contents($this->fooURL, 'This does not work, too.')); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function file_put_contentsExistingFileNonWritableDirectory() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0000)); + vfsStream::newFile('new.txt')->at(vfsStreamWrapper::getRoot())->withContent('content'); + $this->assertEquals(15, @file_put_contents(vfsStream::url('root/new.txt'), 'This does work.')); + $this->assertEquals('This does work.', file_get_contents(vfsStream::url('root/new.txt'))); + + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function file_put_contentsExistingNonWritableFile() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root')); + vfsStream::newFile('new.txt', 0400)->at(vfsStreamWrapper::getRoot())->withContent('content'); + $this->assertFalse(@file_put_contents(vfsStream::url('root/new.txt'), 'This does not work.')); + $this->assertEquals('content', file_get_contents(vfsStream::url('root/new.txt'))); + } + + /** + * assert that file_put_contents() delivers correct file contents + * + * @test + */ + public function file_put_contentsNonExistingFile() + { + $this->assertEquals(14, file_put_contents($this->fooURL . '/baznot.bar', 'baz is not bar')); + $this->assertEquals(3, count($this->foo->getChildren())); + $this->assertEquals(14, file_put_contents($this->barURL . '/baznot.bar', 'baz is not bar')); + $this->assertEquals(2, count($this->bar->getChildren())); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function file_put_contentsNonExistingFileNonWritableDirectory() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0000)); + $this->assertFalse(@file_put_contents(vfsStream::url('root/new.txt'), 'This does not work.')); + $this->assertFalse(file_exists(vfsStream::url('root/new.txt'))); + + } + + /** + * using a file pointer should work without any problems + * + * @test + */ + public function usingFilePointer() + { + $fp = fopen($this->baz1URL, 'r'); + $this->assertEquals(0, ftell($fp)); + $this->assertFalse(feof($fp)); + $this->assertEquals(0, fseek($fp, 2)); + $this->assertEquals(2, ftell($fp)); + $this->assertEquals(0, fseek($fp, 1, SEEK_CUR)); + $this->assertEquals(3, ftell($fp)); + $this->assertEquals(0, fseek($fp, 1, SEEK_END)); + $this->assertEquals(6, ftell($fp)); + $this->assertTrue(feof($fp)); + $this->assertEquals(0, fseek($fp, 2)); + $this->assertFalse(feof($fp)); + $this->assertEquals(2, ftell($fp)); + $this->assertEquals('z', fread($fp, 1)); + $this->assertEquals(3, ftell($fp)); + $this->assertEquals(' 1', fread($fp, 8092)); + $this->assertEquals(5, ftell($fp)); + $this->assertTrue(fclose($fp)); + } + + /** + * assert is_file() returns correct result + * + * @test + */ + public function is_file() + { + $this->assertFalse(is_file($this->fooURL)); + $this->assertFalse(is_file($this->barURL)); + $this->assertTrue(is_file($this->baz1URL)); + $this->assertTrue(is_file($this->baz2URL)); + $this->assertFalse(is_file($this->fooURL . '/another')); + $this->assertFalse(is_file(vfsStream::url('another'))); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function issue13CanNotOverwriteFiles() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + file_put_contents($vfsFile, 'd'); + $this->assertEquals('d', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function appendContentIfOpenedWithModeA() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'ab'); + fwrite($fp, 'd'); + fclose($fp); + $this->assertEquals('testd', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canOverwriteNonExistingFileWithModeX() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + $fp = fopen($vfsFile, 'xb'); + fwrite($fp, 'test'); + fclose($fp); + $this->assertEquals('test', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotOverwriteExistingFileWithModeX() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $this->assertFalse(@fopen($vfsFile, 'xb')); + $this->assertEquals('test', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotOpenNonExistingFileReadonly() + { + $this->assertFalse(@fopen(vfsStream::url('foo/doesNotExist.txt'), 'rb')); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotOpenNonExistingFileReadAndWrite() + { + $this->assertFalse(@fopen(vfsStream::url('foo/doesNotExist.txt'), 'rb+')); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotOpenWithIllegalMode() + { + $this->assertFalse(@fopen($this->baz2URL, 'invalid')); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotWriteToReadOnlyFile() + { + $fp = fopen($this->baz2URL, 'rb'); + $this->assertEquals('baz2', fread($fp, 4096)); + $this->assertEquals(0, fwrite($fp, 'foo')); + fclose($fp); + $this->assertEquals('baz2', file_get_contents($this->baz2URL)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotReadFromWriteOnlyFileWithModeW() + { + $fp = fopen($this->baz2URL, 'wb'); + $this->assertEquals('', fread($fp, 4096)); + $this->assertEquals(3, fwrite($fp, 'foo')); + fseek($fp, 0); + $this->assertEquals('', fread($fp, 4096)); + fclose($fp); + $this->assertEquals('foo', file_get_contents($this->baz2URL)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotReadFromWriteOnlyFileWithModeA() + { + $fp = fopen($this->baz2URL, 'ab'); + $this->assertEquals('', fread($fp, 4096)); + $this->assertEquals(3, fwrite($fp, 'foo')); + fseek($fp, 0); + $this->assertEquals('', fread($fp, 4096)); + fclose($fp); + $this->assertEquals('baz2foo', file_get_contents($this->baz2URL)); + } + + /** + * @test + * @group issue7 + * @group issue13 + */ + public function canNotReadFromWriteOnlyFileWithModeX() + { + $vfsFile = vfsStream::url('foo/modeXtest.txt'); + $fp = fopen($vfsFile, 'xb'); + $this->assertEquals('', fread($fp, 4096)); + $this->assertEquals(3, fwrite($fp, 'foo')); + fseek($fp, 0); + $this->assertEquals('', fread($fp, 4096)); + fclose($fp); + $this->assertEquals('foo', file_get_contents($vfsFile)); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function canNotRemoveFileWithoutWritePermissions() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root')); + vfsStream::newFile('new.txt', 0000)->at(vfsStreamWrapper::getRoot()); + $this->assertFalse(unlink(vfsStream::url('root/new.txt'))); + $this->assertTrue(file_exists(vfsStream::url('root/new.txt'))); + } + + /** + * @test + * @group permissions + * @group bug_15 + */ + public function canNotRemoveFileFromDirectoryWithoutWritePermissions() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('root', 0000)); + vfsStream::newFile('new.txt')->at(vfsStreamWrapper::getRoot()); + $this->assertFalse(unlink(vfsStream::url('root/new.txt'))); + $this->assertTrue(file_exists(vfsStream::url('root/new.txt'))); + } + + /** + * @test + * @group issue_30 + */ + public function truncatesFileWhenOpenedWithModeW() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'wb'); + $this->assertEquals('', file_get_contents($vfsFile)); + fclose($fp); + } + + /** + * @test + * @group issue_30 + */ + public function createsNonExistingFileWhenOpenedWithModeC() + { + $vfsFile = vfsStream::url('foo/tobecreated.txt'); + $fp = fopen($vfsFile, 'cb'); + fwrite($fp, 'some content'); + $this->assertTrue($this->foo->hasChild('tobecreated.txt')); + fclose($fp); + $this->assertEquals('some content', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue_30 + */ + public function createsNonExistingFileWhenOpenedWithModeCplus() + { + $vfsFile = vfsStream::url('foo/tobecreated.txt'); + $fp = fopen($vfsFile, 'cb+'); + fwrite($fp, 'some content'); + $this->assertTrue($this->foo->hasChild('tobecreated.txt')); + fclose($fp); + $this->assertEquals('some content', file_get_contents($vfsFile)); + } + + /** + * @test + * @group issue_30 + */ + public function doesNotTruncateFileWhenOpenedWithModeC() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'cb'); + $this->assertEquals('test', file_get_contents($vfsFile)); + fclose($fp); + } + + /** + * @test + * @group issue_30 + */ + public function setsPointerToStartWhenOpenedWithModeC() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'cb'); + $this->assertEquals(0, ftell($fp)); + fclose($fp); + } + + /** + * @test + * @group issue_30 + */ + public function doesNotTruncateFileWhenOpenedWithModeCplus() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'cb+'); + $this->assertEquals('test', file_get_contents($vfsFile)); + fclose($fp); + } + + /** + * @test + * @group issue_30 + */ + public function setsPointerToStartWhenOpenedWithModeCplus() + { + $vfsFile = vfsStream::url('foo/overwrite.txt'); + file_put_contents($vfsFile, 'test'); + $fp = fopen($vfsFile, 'cb+'); + $this->assertEquals(0, ftell($fp)); + fclose($fp); + } + + /** + * @test + */ + public function cannotOpenExistingNonwritableFileWithModeA() + { + $this->baz1->chmod(0400); + $this->assertFalse(@fopen($this->baz1URL, 'a')); + } + + /** + * @test + */ + public function cannotOpenExistingNonwritableFileWithModeW() + { + $this->baz1->chmod(0400); + $this->assertFalse(@fopen($this->baz1URL, 'w')); + } + + /** + * @test + */ + public function cannotOpenNonReadableFileWithModeR() + { + $this->baz1->chmod(0); + $this->assertFalse(@fopen($this->baz1URL, 'r')); + } + + /** + * @test + */ + public function cannotRenameToNonWritableDir() + { + $this->bar->chmod(0); + $this->assertFalse(@rename($this->baz2URL, vfsStream::url('foo/bar/baz3'))); + } + + /** + * @test + * @group issue_38 + */ + public function cannotReadFileFromNonReadableDir() + { + $this->markTestSkipped("Issue #38."); + $this->bar->chmod(0); + $this->assertFalse(@file_get_contents($this->baz1URL)); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTimesTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTimesTestCase.php new file mode 100755 index 00000000..2d036c0a --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFileTimesTestCase.php @@ -0,0 +1,315 @@ +lastModified(50) + ->lastAccessed(50) + ->lastAttributeModified(50); + $this->fooUrl = vfsStream::url('root/foo.txt'); + $this->barUrl = vfsStream::url('root/bar'); + $this->bazUrl = vfsStream::url('root/bar/baz.txt'); + } + + /** + * helper assertion for the tests + * + * @param string $url url to check + * @param vfsStreamContent $content content to compare + */ + protected function assertFileTimesEqualStreamTimes($url, vfsStreamContent $content) + { + $this->assertEquals(filemtime($url), $content->filemtime()); + $this->assertEquals(fileatime($url), $content->fileatime()); + $this->assertEquals(filectime($url), $content->filectime()); + } + + /** + * @test + * @group issue_7 + * @group issue_26 + */ + public function openFileChangesAttributeTimeOnly() + { + $file = vfsStream::newFile('foo.txt') + ->withContent('test') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + fclose(fopen($this->fooUrl, 'rb')); + $this->assertGreaterThan(time() - 2, fileatime($this->fooUrl)); + $this->assertLessThanOrEqual(time(), fileatime($this->fooUrl)); + $this->assertLessThanOrEqual(100, filemtime($this->fooUrl)); + $this->assertEquals(100, filectime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, $file); + } + + /** + * @test + * @group issue_7 + * @group issue_26 + */ + public function fileGetContentsChangesAttributeTimeOnly() + { + $file = vfsStream::newFile('foo.txt') + ->withContent('test') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + file_get_contents($this->fooUrl); + $this->assertGreaterThan(time() - 2, fileatime($this->fooUrl)); + $this->assertLessThanOrEqual(time(), fileatime($this->fooUrl)); + $this->assertLessThanOrEqual(100, filemtime($this->fooUrl)); + $this->assertEquals(100, filectime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, $file); + } + + /** + * @test + * @group issue_7 + * @group issue_26 + */ + public function openFileWithTruncateChangesAttributeAndModificationTime() + { + $file = vfsStream::newFile('foo.txt') + ->withContent('test') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + fclose(fopen($this->fooUrl, 'wb')); + $this->assertGreaterThan(time() - 2, filemtime($this->fooUrl)); + $this->assertGreaterThan(time() - 2, fileatime($this->fooUrl)); + $this->assertLessThanOrEqual(time(), filemtime($this->fooUrl)); + $this->assertLessThanOrEqual(time(), fileatime($this->fooUrl)); + $this->assertEquals(100, filectime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, $file); + } + + /** + * @test + * @group issue_7 + */ + public function readFileChangesAccessTime() + { + $file = vfsStream::newFile('foo.txt') + ->withContent('test') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + $fp = fopen($this->fooUrl, 'rb'); + $openTime = time(); + sleep(3); + fread($fp, 1024); + fclose($fp); + $this->assertLessThanOrEqual($openTime, filemtime($this->fooUrl)); + $this->assertLessThanOrEqual($openTime + 3, fileatime($this->fooUrl)); + $this->assertEquals(100, filectime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, $file); + } + + /** + * @test + * @group issue_7 + */ + public function writeFileChangesModificationTime() + { + $file = vfsStream::newFile('foo.txt') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + $fp = fopen($this->fooUrl, 'wb'); + $openTime = time(); + sleep(3); + fwrite($fp, 'test'); + fclose($fp); + $this->assertLessThanOrEqual($openTime + 3, filemtime($this->fooUrl)); + $this->assertLessThanOrEqual($openTime, fileatime($this->fooUrl)); + $this->assertEquals(100, filectime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, $file); + + } + + /** + * @test + * @group issue_7 + */ + public function createNewFileSetsAllTimesToCurrentTime() + { + file_put_contents($this->fooUrl, 'test'); + $this->assertLessThanOrEqual(time(), filemtime($this->fooUrl)); + $this->assertEquals(fileatime($this->fooUrl), filectime($this->fooUrl)); + $this->assertEquals(fileatime($this->fooUrl), filemtime($this->fooUrl)); + $this->assertFileTimesEqualStreamTimes($this->fooUrl, vfsStreamWrapper::getRoot()->getChild('foo.txt')); + } + + /** + * @test + * @group issue_7 + */ + public function createNewFileChangesAttributeAndModificationTimeOfContainingDirectory() + { + $dir = vfsStream::newDirectory('bar') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + file_put_contents($this->bazUrl, 'test'); + $this->assertLessThanOrEqual(time(), filemtime($this->barUrl)); + $this->assertLessThanOrEqual(time(), filectime($this->barUrl)); + $this->assertEquals(100, fileatime($this->barUrl)); + $this->assertFileTimesEqualStreamTimes($this->barUrl, $dir); + } + + /** + * @test + * @group issue_7 + */ + public function addNewFileNameWithLinkFunctionChangesAttributeTimeOfOriginalFile() + { + $this->markTestSkipped('Links are currently not supported by vfsStream.'); + } + + /** + * @test + * @group issue_7 + */ + public function addNewFileNameWithLinkFunctionChangesAttributeAndModificationTimeOfDirectoryContainingLink() + { + $this->markTestSkipped('Links are currently not supported by vfsStream.'); + } + + /** + * @test + * @group issue_7 + */ + public function removeFileChangesAttributeAndModificationTimeOfContainingDirectory() + { + $dir = vfsStream::newDirectory('bar') + ->at(vfsStreamWrapper::getRoot()); + $file = vfsStream::newFile('baz.txt') + ->at($dir) + ->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + $dir->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + unlink($this->bazUrl); + $this->assertLessThanOrEqual(time(), filemtime($this->barUrl)); + $this->assertLessThanOrEqual(time(), filectime($this->barUrl)); + $this->assertEquals(100, fileatime($this->barUrl)); + $this->assertFileTimesEqualStreamTimes($this->barUrl, $dir); + } + + /** + * @test + * @group issue_7 + */ + public function renameFileChangesAttributeAndModificationTimeOfAffectedDirectories() + { + $target = vfsStream::newDirectory('target') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(200) + ->lastAccessed(200) + ->lastAttributeModified(200); + $source = vfsStream::newDirectory('bar') + ->at(vfsStreamWrapper::getRoot()); + $file = vfsStream::newFile('baz.txt') + ->at($source) + ->lastModified(300) + ->lastAccessed(300) + ->lastAttributeModified(300); + $source->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + rename($this->bazUrl, vfsStream::url('root/target/baz.txt')); + $this->assertLessThanOrEqual(time(), filemtime($this->barUrl)); + $this->assertLessThanOrEqual(time(), filectime($this->barUrl)); + $this->assertEquals(100, fileatime($this->barUrl)); + $this->assertFileTimesEqualStreamTimes($this->barUrl, $source); + $this->assertLessThanOrEqual(time(), filemtime(vfsStream::url('root/target'))); + $this->assertLessThanOrEqual(time(), filectime(vfsStream::url('root/target'))); + $this->assertEquals(200, fileatime(vfsStream::url('root/target'))); + $this->assertFileTimesEqualStreamTimes(vfsStream::url('root/target'), $target); + } + + /** + * @test + * @group issue_7 + */ + public function renameFileDoesNotChangeFileTimesOfFileItself() + { + $target = vfsStream::newDirectory('target') + ->at(vfsStreamWrapper::getRoot()) + ->lastModified(200) + ->lastAccessed(200) + ->lastAttributeModified(200); + $source = vfsStream::newDirectory('bar') + ->at(vfsStreamWrapper::getRoot()); + $file = vfsStream::newFile('baz.txt') + ->at($source) + ->lastModified(300) + ->lastAccessed(300) + ->lastAttributeModified(300); + $source->lastModified(100) + ->lastAccessed(100) + ->lastAttributeModified(100); + rename($this->bazUrl, vfsStream::url('root/target/baz.txt')); + $this->assertEquals(300, filemtime(vfsStream::url('root/target/baz.txt'))); + $this->assertEquals(300, filectime(vfsStream::url('root/target/baz.txt'))); + $this->assertEquals(300, fileatime(vfsStream::url('root/target/baz.txt'))); + $this->assertFileTimesEqualStreamTimes(vfsStream::url('root/target/baz.txt'), $file); + } + + /** + * @test + * @group issue_7 + */ + public function changeFileAttributesChangesAttributeTimeOfFileItself() + { + $this->markTestSkipped('Changing file attributes via stream wrapper for self-defined streams is not supported by PHP.'); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFlockTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFlockTestCase.php new file mode 100755 index 00000000..8c07308d --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperFlockTestCase.php @@ -0,0 +1,240 @@ +root = vfsStream::setup(); + } + + /** + * @test + */ + public function fileIsNotLockedByDefault() + { + $this->assertFalse(vfsStream::newFile('foo.txt')->isLocked()); + } + + /** + * @test + */ + public function streamIsNotLockedByDefault() + { + file_put_contents(vfsStream::url('root/foo.txt'), 'content'); + $this->assertFalse($this->root->getChild('foo.txt')->isLocked()); + } + + /** + * @test + */ + public function canAquireSharedLock() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertTrue(flock($fp, LOCK_SH)); + $this->assertTrue($file->isLocked()); + $this->assertTrue($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + + } + + /** + * @test + */ + public function canAquireSharedLockWithNonBlockingFlockCall() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertTrue(flock($fp, LOCK_SH | LOCK_NB)); + $this->assertTrue($file->isLocked()); + $this->assertTrue($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + + } + + /** + * @test + */ + public function canAquireEclusiveLock() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertTrue(flock($fp, LOCK_EX)); + $this->assertTrue($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertTrue($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @test + */ + public function canAquireEclusiveLockWithNonBlockingFlockCall() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertTrue(flock($fp, LOCK_EX | LOCK_NB)); + $this->assertTrue($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertTrue($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @test + */ + public function canRemoveLock() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_EX); + $this->assertTrue(flock($fp, LOCK_UN)); + $this->assertFalse($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @test + */ + public function canRemoveLockWithNonBlockingFlockCall() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_EX); + $this->assertTrue(flock($fp, LOCK_UN | LOCK_NB)); + $this->assertFalse($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function canNotAquireExclusiveLockIfAlreadyExclusivelyLocked() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_EX); + $this->assertFalse(flock($fp, LOCK_EX + LOCK_NB)); + $this->assertTrue($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertTrue($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function canNotAquireExclusiveLockIfAlreadySharedLocked() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_SH); + $this->assertFalse(flock($fp, LOCK_EX)); + $this->assertTrue($file->isLocked()); + $this->assertTrue($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function canNotAquireSharedLockIfAlreadyExclusivelyLocked() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_EX); + $this->assertFalse(flock($fp, LOCK_SH + LOCK_NB)); + $this->assertTrue($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertTrue($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function canAquireSharedLockIfAlreadySharedLocked() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $file->lock(LOCK_SH); + $this->assertTrue(flock($fp, LOCK_SH)); + $this->assertTrue($file->isLocked()); + $this->assertTrue($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + fclose($fp); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function removesExclusiveLockOnStreamClose() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $file->lock(LOCK_EX); + fclose(fopen(vfsStream::url('root/foo.txt'), 'rb')); + $this->assertFalse($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + } + + /** + * @see https://github.com/mikey179/vfsStream/issues/31 + * @test + * @group issue_31 + */ + public function removesSharedLockOnStreamClose() + { + $file = vfsStream::newFile('foo.txt')->at($this->root); + $file->lock(LOCK_SH); + fclose(fopen(vfsStream::url('root/foo.txt'), 'rb')); + $this->assertFalse($file->isLocked()); + $this->assertFalse($file->hasSharedLock()); + $this->assertFalse($file->hasExclusiveLock()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperQuotaTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperQuotaTestCase.php new file mode 100755 index 00000000..84c45461 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperQuotaTestCase.php @@ -0,0 +1,204 @@ +root = vfsStream::setup(); + vfsStream::setQuota(10); + } + + /** + * @test + */ + public function writeLessThanQuotaWritesEverything() + { + $this->assertEquals(9, file_put_contents(vfsStream::url('root/file.txt'), '123456789')); + $this->assertEquals('123456789', $this->root->getChild('file.txt')->getContent()); + } + + /** + * @test + */ + public function writeUpToQotaWritesEverything() + { + $this->assertEquals(10, file_put_contents(vfsStream::url('root/file.txt'), '1234567890')); + $this->assertEquals('1234567890', $this->root->getChild('file.txt')->getContent()); + } + + /** + * @test + */ + public function writeMoreThanQotaWritesOnlyUpToQuota() + { + try { + file_put_contents(vfsStream::url('root/file.txt'), '12345678901'); + } catch (\PHPUnit_Framework_Error $e) { + $this->assertEquals('file_put_contents(): Only 10 of 11 bytes written, possibly out of free disk space', + $e->getMessage() + ); + } + + $this->assertEquals('1234567890', $this->root->getChild('file.txt')->getContent()); + } + + /** + * @test + */ + public function considersAllFilesForQuota() + { + vfsStream::newFile('foo.txt') + ->withContent('foo') + ->at(vfsStream::newDirectory('bar') + ->at($this->root) + ); + try { + file_put_contents(vfsStream::url('root/file.txt'), '12345678901'); + } catch (\PHPUnit_Framework_Error $e) { + $this->assertEquals('file_put_contents(): Only 7 of 11 bytes written, possibly out of free disk space', + $e->getMessage() + ); + } + + $this->assertEquals('1234567', $this->root->getChild('file.txt')->getContent()); + } + + /** + * @test + * @group issue_33 + */ + public function truncateToLessThanQuotaWritesEverything() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $fp = fopen(vfsStream::url('root/file.txt'), 'w+'); + $this->assertTrue(ftruncate($fp, 9)); + fclose($fp); + $this->assertEquals(9, + $this->root->getChild('file.txt')->size() + ); + $this->assertEquals("\0\0\0\0\0\0\0\0\0", + $this->root->getChild('file.txt')->getContent() + ); + } + + /** + * @test + * @group issue_33 + */ + public function truncateUpToQotaWritesEverything() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $fp = fopen(vfsStream::url('root/file.txt'), 'w+'); + $this->assertTrue(ftruncate($fp, 10)); + fclose($fp); + $this->assertEquals(10, + $this->root->getChild('file.txt')->size() + ); + $this->assertEquals("\0\0\0\0\0\0\0\0\0\0", + $this->root->getChild('file.txt')->getContent() + ); + } + + /** + * @test + * @group issue_33 + */ + public function truncateToMoreThanQotaWritesOnlyUpToQuota() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $fp = fopen(vfsStream::url('root/file.txt'), 'w+'); + $this->assertTrue(ftruncate($fp, 11)); + fclose($fp); + $this->assertEquals(10, + $this->root->getChild('file.txt')->size() + ); + $this->assertEquals("\0\0\0\0\0\0\0\0\0\0", + $this->root->getChild('file.txt')->getContent() + ); + } + + /** + * @test + * @group issue_33 + */ + public function truncateConsidersAllFilesForQuota() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + vfsStream::newFile('bar.txt') + ->withContent('bar') + ->at(vfsStream::newDirectory('bar') + ->at($this->root) + ); + $fp = fopen(vfsStream::url('root/file.txt'), 'w+'); + $this->assertTrue(ftruncate($fp, 11)); + fclose($fp); + $this->assertEquals(7, + $this->root->getChild('file.txt')->size() + ); + $this->assertEquals("\0\0\0\0\0\0\0", + $this->root->getChild('file.txt')->getContent() + ); + } + + /** + * @test + * @group issue_33 + */ + public function canNotTruncateToGreaterLengthWhenDiscQuotaReached() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + vfsStream::newFile('bar.txt') + ->withContent('1234567890') + ->at(vfsStream::newDirectory('bar') + ->at($this->root) + ); + $fp = fopen(vfsStream::url('root/file.txt'), 'w+'); + $this->assertFalse(ftruncate($fp, 11)); + fclose($fp); + $this->assertEquals(0, + $this->root->getChild('file.txt')->size() + ); + $this->assertEquals('', + $this->root->getChild('file.txt')->getContent() + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperSetOptionTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperSetOptionTestCase.php new file mode 100755 index 00000000..aa86bd34 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperSetOptionTestCase.php @@ -0,0 +1,76 @@ +root = vfsStream::setup(); + vfsStream::newFile('foo.txt')->at($this->root); + } + + /** + * @test + */ + public function setBlockingDoesNotWork() + { + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertFalse(stream_set_blocking($fp, 1)); + fclose($fp); + } + + /** + * @test + */ + public function removeBlockingDoesNotWork() + { + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertFalse(stream_set_blocking($fp, 0)); + fclose($fp); + } + + /** + * @test + */ + public function setTimeoutDoesNotWork() + { + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertFalse(stream_set_timeout($fp, 1)); + fclose($fp); + } + + /** + * @test + */ + public function setWriteBufferDoesNotWork() + { + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $this->assertEquals(-1, stream_set_write_buffer($fp, 512)); + fclose($fp); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperStreamSelectTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperStreamSelectTestCase.php new file mode 100755 index 00000000..c2aec997 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperStreamSelectTestCase.php @@ -0,0 +1,35 @@ +at($root)->withContent('testContent'); + + $fp = fopen(vfsStream::url('root/foo.txt'), 'rb'); + $readarray = array($fp); + $writearray = array(); + $exceptarray = array(); + stream_select($readarray, $writearray, $exceptarray, 1); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperTestCase.php new file mode 100755 index 00000000..2f5bb436 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperTestCase.php @@ -0,0 +1,711 @@ +assertSame($this->foo, vfsStreamWrapper::getRoot()); + vfsStreamWrapper::register(); + $this->assertNull(vfsStreamWrapper::getRoot()); + } + + /** + * @test + * @since 0.11.0 + */ + public function setRootReturnsRoot() + { + vfsStreamWrapper::register(); + $root = vfsStream::newDirectory('root'); + $this->assertSame($root, vfsStreamWrapper::setRoot($root)); + } + + /** + * assure that filesize is returned correct + * + * @test + */ + public function filesize() + { + $this->assertEquals(0, filesize($this->fooURL)); + $this->assertEquals(0, filesize($this->fooURL . '/.')); + $this->assertEquals(0, filesize($this->barURL)); + $this->assertEquals(0, filesize($this->barURL . '/.')); + $this->assertEquals(4, filesize($this->baz2URL)); + $this->assertEquals(5, filesize($this->baz1URL)); + } + + /** + * assert that file_exists() delivers correct result + * + * @test + */ + public function file_exists() + { + $this->assertTrue(file_exists($this->fooURL)); + $this->assertTrue(file_exists($this->fooURL . '/.')); + $this->assertTrue(file_exists($this->barURL)); + $this->assertTrue(file_exists($this->barURL . '/.')); + $this->assertTrue(file_exists($this->baz1URL)); + $this->assertTrue(file_exists($this->baz2URL)); + $this->assertFalse(file_exists($this->fooURL . '/another')); + $this->assertFalse(file_exists(vfsStream::url('another'))); + } + + /** + * assert that filemtime() delivers correct result + * + * @test + */ + public function filemtime() + { + $this->assertEquals(100, filemtime($this->fooURL)); + $this->assertEquals(100, filemtime($this->fooURL . '/.')); + $this->assertEquals(200, filemtime($this->barURL)); + $this->assertEquals(200, filemtime($this->barURL . '/.')); + $this->assertEquals(300, filemtime($this->baz1URL)); + $this->assertEquals(400, filemtime($this->baz2URL)); + } + + /** + * @test + * @group issue_23 + */ + public function unlinkRemovesFilesOnly() + { + $this->assertTrue(unlink($this->baz2URL)); + $this->assertFalse(file_exists($this->baz2URL)); // make sure statcache was cleared + $this->assertEquals(array($this->bar), $this->foo->getChildren()); + $this->assertFalse(unlink($this->fooURL . '/another')); + $this->assertFalse(unlink(vfsStream::url('another'))); + $this->assertEquals(array($this->bar), $this->foo->getChildren()); + } + + /** + * assert dirname() returns correct directory name + * + * @test + */ + public function dirname() + { + $this->assertEquals($this->fooURL, dirname($this->barURL)); + $this->assertEquals($this->barURL, dirname($this->baz1URL)); + # returns "vfs:" instead of "." + # however this seems not to be fixable because dirname() does not + # call the stream wrapper + #$this->assertEquals(dirname(vfsStream::url('doesNotExist')), '.'); + } + + /** + * assert basename() returns correct file name + * + * @test + */ + public function basename() + { + $this->assertEquals('bar', basename($this->barURL)); + $this->assertEquals('baz1', basename($this->baz1URL)); + $this->assertEquals('doesNotExist', basename(vfsStream::url('doesNotExist'))); + } + + /** + * assert is_readable() works correct + * + * @test + */ + public function is_readable() + { + $this->assertTrue(is_readable($this->fooURL)); + $this->assertTrue(is_readable($this->fooURL . '/.')); + $this->assertTrue(is_readable($this->barURL)); + $this->assertTrue(is_readable($this->barURL . '/.')); + $this->assertTrue(is_readable($this->baz1URL)); + $this->assertTrue(is_readable($this->baz2URL)); + $this->assertFalse(is_readable($this->fooURL . '/another')); + $this->assertFalse(is_readable(vfsStream::url('another'))); + + $this->foo->chmod(0222); + $this->assertFalse(is_readable($this->fooURL)); + + $this->baz1->chmod(0222); + $this->assertFalse(is_readable($this->baz1URL)); + } + + /** + * assert is_writable() works correct + * + * @test + */ + public function is_writable() + { + $this->assertTrue(is_writable($this->fooURL)); + $this->assertTrue(is_writable($this->fooURL . '/.')); + $this->assertTrue(is_writable($this->barURL)); + $this->assertTrue(is_writable($this->barURL . '/.')); + $this->assertTrue(is_writable($this->baz1URL)); + $this->assertTrue(is_writable($this->baz2URL)); + $this->assertFalse(is_writable($this->fooURL . '/another')); + $this->assertFalse(is_writable(vfsStream::url('another'))); + + $this->foo->chmod(0444); + $this->assertFalse(is_writable($this->fooURL)); + + $this->baz1->chmod(0444); + $this->assertFalse(is_writable($this->baz1URL)); + } + + /** + * assert is_executable() works correct + * + * @test + */ + public function is_executable() + { + $this->assertFalse(is_executable($this->baz1URL)); + $this->baz1->chmod(0766); + $this->assertTrue(is_executable($this->baz1URL)); + $this->assertFalse(is_executable($this->baz2URL)); + } + + /** + * assert is_executable() works correct + * + * @test + */ + public function directoriesAndNonExistingFilesAreNeverExecutable() + { + $this->assertFalse(is_executable($this->fooURL)); + $this->assertFalse(is_executable($this->fooURL . '/.')); + $this->assertFalse(is_executable($this->barURL)); + $this->assertFalse(is_executable($this->barURL . '/.')); + $this->assertFalse(is_executable($this->fooURL . '/another')); + $this->assertFalse(is_executable(vfsStream::url('another'))); + } + + /** + * file permissions + * + * @test + * @group permissions + */ + public function chmod() + { + $this->assertEquals(40777, decoct(fileperms($this->fooURL))); + $this->assertEquals(40777, decoct(fileperms($this->fooURL . '/.'))); + $this->assertEquals(40777, decoct(fileperms($this->barURL))); + $this->assertEquals(40777, decoct(fileperms($this->barURL . '/.'))); + $this->assertEquals(100666, decoct(fileperms($this->baz1URL))); + $this->assertEquals(100666, decoct(fileperms($this->baz2URL))); + + $this->foo->chmod(0755); + $this->bar->chmod(0700); + $this->baz1->chmod(0644); + $this->baz2->chmod(0600); + $this->assertEquals(40755, decoct(fileperms($this->fooURL))); + $this->assertEquals(40755, decoct(fileperms($this->fooURL . '/.'))); + $this->assertEquals(40700, decoct(fileperms($this->barURL))); + $this->assertEquals(40700, decoct(fileperms($this->barURL . '/.'))); + $this->assertEquals(100644, decoct(fileperms($this->baz1URL))); + $this->assertEquals(100600, decoct(fileperms($this->baz2URL))); + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function chmodModifiesPermissions() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertFalse(@chmod($this->fooURL, 0755)); + $this->assertFalse(@chmod($this->barURL, 0711)); + $this->assertFalse(@chmod($this->baz1URL, 0644)); + $this->assertFalse(@chmod($this->baz2URL, 0664)); + $this->assertEquals(40777, decoct(fileperms($this->fooURL))); + $this->assertEquals(40777, decoct(fileperms($this->barURL))); + $this->assertEquals(100666, decoct(fileperms($this->baz1URL))); + $this->assertEquals(100666, decoct(fileperms($this->baz2URL))); + } else { + $this->assertTrue(chmod($this->fooURL, 0755)); + $this->assertTrue(chmod($this->barURL, 0711)); + $this->assertTrue(chmod($this->baz1URL, 0644)); + $this->assertTrue(chmod($this->baz2URL, 0664)); + $this->assertEquals(40755, decoct(fileperms($this->fooURL))); + $this->assertEquals(40711, decoct(fileperms($this->barURL))); + $this->assertEquals(100644, decoct(fileperms($this->baz1URL))); + $this->assertEquals(100664, decoct(fileperms($this->baz2URL))); + } + } + + /** + * @test + * @group permissions + */ + public function fileownerIsCurrentUserByDefault() + { + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->fooURL)); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->fooURL . '/.')); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->barURL)); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->barURL . '/.')); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->baz1URL)); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->baz2URL)); + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function chownChangesUser() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->foo->chown(vfsStream::OWNER_USER_1); + $this->bar->chown(vfsStream::OWNER_USER_1); + $this->baz1->chown(vfsStream::OWNER_USER_2); + $this->baz2->chown(vfsStream::OWNER_USER_2); + } else { + chown($this->fooURL, vfsStream::OWNER_USER_1); + chown($this->barURL, vfsStream::OWNER_USER_1); + chown($this->baz1URL, vfsStream::OWNER_USER_2); + chown($this->baz2URL, vfsStream::OWNER_USER_2); + } + + $this->assertEquals(vfsStream::OWNER_USER_1, fileowner($this->fooURL)); + $this->assertEquals(vfsStream::OWNER_USER_1, fileowner($this->fooURL . '/.')); + $this->assertEquals(vfsStream::OWNER_USER_1, fileowner($this->barURL)); + $this->assertEquals(vfsStream::OWNER_USER_1, fileowner($this->barURL . '/.')); + $this->assertEquals(vfsStream::OWNER_USER_2, fileowner($this->baz1URL)); + $this->assertEquals(vfsStream::OWNER_USER_2, fileowner($this->baz2URL)); + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function chownDoesNotWorkOnVfsStreamUrls() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertFalse(@chown($this->fooURL, vfsStream::OWNER_USER_2)); + $this->assertEquals(vfsStream::getCurrentUser(), fileowner($this->fooURL)); + } + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function groupIsCurrentGroupByDefault() + { + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->fooURL)); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->fooURL . '/.')); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->barURL)); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->barURL . '/.')); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->baz1URL)); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->baz2URL)); + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function chgrp() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->foo->chgrp(vfsStream::GROUP_USER_1); + $this->bar->chgrp(vfsStream::GROUP_USER_1); + $this->baz1->chgrp(vfsStream::GROUP_USER_2); + $this->baz2->chgrp(vfsStream::GROUP_USER_2); + } else { + chgrp($this->fooURL, vfsStream::GROUP_USER_1); + chgrp($this->barURL, vfsStream::GROUP_USER_1); + chgrp($this->baz1URL, vfsStream::GROUP_USER_2); + chgrp($this->baz2URL, vfsStream::GROUP_USER_2); + } + + $this->assertEquals(vfsStream::GROUP_USER_1, filegroup($this->fooURL)); + $this->assertEquals(vfsStream::GROUP_USER_1, filegroup($this->fooURL . '/.')); + $this->assertEquals(vfsStream::GROUP_USER_1, filegroup($this->barURL)); + $this->assertEquals(vfsStream::GROUP_USER_1, filegroup($this->barURL . '/.')); + $this->assertEquals(vfsStream::GROUP_USER_2, filegroup($this->baz1URL)); + $this->assertEquals(vfsStream::GROUP_USER_2, filegroup($this->baz2URL)); + } + + /** + * @test + * @group issue_11 + * @group permissions + */ + public function chgrpDoesNotWorkOnVfsStreamUrls() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertFalse(@chgrp($this->fooURL, vfsStream::GROUP_USER_2)); + $this->assertEquals(vfsStream::getCurrentGroup(), filegroup($this->fooURL)); + } + } + + /** + * @test + * @author Benoit Aubuchon + */ + public function renameDirectory() + { + // move foo/bar to foo/baz3 + $baz3URL = vfsStream::url('foo/baz3'); + $this->assertTrue(rename($this->barURL, $baz3URL)); + $this->assertFileExists($baz3URL); + $this->assertFileNotExists($this->barURL); + } + + /** + * @test + */ + public function renameDirectoryWithDots() + { + // move foo/bar to foo/baz3 + $baz3URL = vfsStream::url('foo/baz3'); + $this->assertTrue(rename($this->barURL . '/.', $baz3URL)); + $this->assertFileExists($baz3URL); + $this->assertFileNotExists($this->barURL); + } + + /** + * @test + * @group issue_9 + * @since 0.9.0 + */ + public function renameDirectoryWithDotsInTarget() + { + // move foo/bar to foo/baz3 + $baz3URL = vfsStream::url('foo/../foo/baz3/.'); + $this->assertTrue(rename($this->barURL . '/.', $baz3URL)); + $this->assertFileExists($baz3URL); + $this->assertFileNotExists($this->barURL); + } + + /** + * @test + * @author Benoit Aubuchon + */ + public function renameDirectoryOverwritingExistingFile() + { + // move foo/bar to foo/baz2 + $this->assertTrue(rename($this->barURL, $this->baz2URL)); + $this->assertFileExists(vfsStream::url('foo/baz2/baz1')); + $this->assertFileNotExists($this->barURL); + } + + /** + * @test + * @expectedException PHPUnit_Framework_Error + */ + public function renameFileIntoFile() + { + // foo/baz2 is a file, so it can not be turned into a directory + $baz3URL = vfsStream::url('foo/baz2/baz3'); + $this->assertTrue(rename($this->baz1URL, $baz3URL)); + $this->assertFileExists($baz3URL); + $this->assertFileNotExists($this->baz1URL); + } + + /** + * @test + * @author Benoit Aubuchon + */ + public function renameFileToDirectory() + { + // move foo/bar/baz1 to foo/baz3 + $baz3URL = vfsStream::url('foo/baz3'); + $this->assertTrue(rename($this->baz1URL, $baz3URL)); + $this->assertFileExists($this->barURL); + $this->assertFileExists($baz3URL); + $this->assertFileNotExists($this->baz1URL); + } + + /** + * assert that trying to rename from a non existing file trigger a warning + * + * @expectedException PHPUnit_Framework_Error + * @test + */ + public function renameOnSourceFileNotFound() + { + rename(vfsStream::url('notfound'), $this->baz1URL); + } + /** + * assert that trying to rename to a directory that is not found trigger a warning + + * @expectedException PHPUnit_Framework_Error + * @test + */ + public function renameOnDestinationDirectoryFileNotFound() + { + rename($this->baz1URL, vfsStream::url('foo/notfound/file2')); + } + /** + * stat() and fstat() should return the same result + * + * @test + */ + public function statAndFstatReturnSameResult() + { + $fp = fopen($this->baz2URL, 'r'); + $this->assertEquals(stat($this->baz2URL), + fstat($fp) + ); + fclose($fp); + } + + /** + * stat() returns full data + * + * @test + */ + public function statReturnsFullDataForFiles() + { + $this->assertEquals(array(0 => 0, + 1 => 0, + 2 => 0100666, + 3 => 0, + 4 => vfsStream::getCurrentUser(), + 5 => vfsStream::getCurrentGroup(), + 6 => 0, + 7 => 4, + 8 => 400, + 9 => 400, + 10 => 400, + 11 => -1, + 12 => -1, + 'dev' => 0, + 'ino' => 0, + 'mode' => 0100666, + 'nlink' => 0, + 'uid' => vfsStream::getCurrentUser(), + 'gid' => vfsStream::getCurrentGroup(), + 'rdev' => 0, + 'size' => 4, + 'atime' => 400, + 'mtime' => 400, + 'ctime' => 400, + 'blksize' => -1, + 'blocks' => -1 + ), + stat($this->baz2URL) + ); + } + + /** + * @test + */ + public function statReturnsFullDataForDirectories() + { + $this->assertEquals(array(0 => 0, + 1 => 0, + 2 => 0040777, + 3 => 0, + 4 => vfsStream::getCurrentUser(), + 5 => vfsStream::getCurrentGroup(), + 6 => 0, + 7 => 0, + 8 => 100, + 9 => 100, + 10 => 100, + 11 => -1, + 12 => -1, + 'dev' => 0, + 'ino' => 0, + 'mode' => 0040777, + 'nlink' => 0, + 'uid' => vfsStream::getCurrentUser(), + 'gid' => vfsStream::getCurrentGroup(), + 'rdev' => 0, + 'size' => 0, + 'atime' => 100, + 'mtime' => 100, + 'ctime' => 100, + 'blksize' => -1, + 'blocks' => -1 + ), + stat($this->fooURL) + ); + } + + /** + * @test + */ + public function statReturnsFullDataForDirectoriesWithDot() + { + $this->assertEquals(array(0 => 0, + 1 => 0, + 2 => 0040777, + 3 => 0, + 4 => vfsStream::getCurrentUser(), + 5 => vfsStream::getCurrentGroup(), + 6 => 0, + 7 => 0, + 8 => 100, + 9 => 100, + 10 => 100, + 11 => -1, + 12 => -1, + 'dev' => 0, + 'ino' => 0, + 'mode' => 0040777, + 'nlink' => 0, + 'uid' => vfsStream::getCurrentUser(), + 'gid' => vfsStream::getCurrentGroup(), + 'rdev' => 0, + 'size' => 0, + 'atime' => 100, + 'mtime' => 100, + 'ctime' => 100, + 'blksize' => -1, + 'blocks' => -1 + ), + stat($this->fooURL . '/.') + ); + } + + /** + * @test + * @expectedException PHPUnit_Framework_Error + */ + public function openFileWithoutDirectory() + { + vfsStreamWrapper::register(); + $this->assertFalse(file_get_contents(vfsStream::url('file.txt'))); + } + + /** + * @test + * @group issue_33 + * @since 1.1.0 + */ + public function truncateRemovesSuperflouosContent() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $handle = fopen($this->baz1URL, "r+"); + $this->assertTrue(ftruncate($handle, 0)); + $this->assertEquals(0, filesize($this->baz1URL)); + $this->assertEquals('', file_get_contents($this->baz1URL)); + fclose($handle); + } + + /** + * @test + * @group issue_33 + * @since 1.1.0 + */ + public function truncateToGreaterSizeAddsZeroBytes() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $handle = fopen($this->baz1URL, "r+"); + $this->assertTrue(ftruncate($handle, 25)); + $this->assertEquals(25, filesize($this->baz1URL)); + $this->assertEquals("baz 1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", + file_get_contents($this->baz1URL)); + fclose($handle); + } + + /** + * @test + * @group issue_11 + */ + public function touchCreatesNonExistingFile() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $this->assertTrue(touch($this->fooURL . '/new.txt')); + $this->assertTrue($this->foo->hasChild('new.txt')); + } + + /** + * @test + * @group issue_11 + */ + public function touchChangesAccessAndModificationTimeForFile() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $this->assertTrue(touch($this->baz1URL, 303, 313)); + $this->assertEquals(303, $this->baz1->filemtime()); + $this->assertEquals(313, $this->baz1->fileatime()); + } + + /** + * @test + * @group issue_11 + */ + public function touchDoesNotChangeTimesWhenNoTimesGiven() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $this->assertTrue(touch($this->baz1URL)); + $this->assertEquals(300, $this->baz1->filemtime()); + $this->assertEquals(300, $this->baz1->fileatime()); + } + + /** + * @test + * @group issue_11 + */ + public function touchWithModifiedTimeChangesAccessAndModifiedTime() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $this->assertTrue(touch($this->baz1URL, 303)); + $this->assertEquals(303, $this->baz1->filemtime()); + $this->assertEquals(303, $this->baz1->fileatime()); + } + + /** + * @test + * @group issue_11 + */ + public function touchChangesAccessAndModificationTimeForDirectory() + { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('Requires PHP 5.4'); + } + + $this->assertTrue(touch($this->fooURL, 303, 313)); + $this->assertEquals(303, $this->foo->filemtime()); + $this->assertEquals(313, $this->foo->fileatime()); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperWithoutRootTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperWithoutRootTestCase.php new file mode 100755 index 00000000..6b030664 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamWrapperWithoutRootTestCase.php @@ -0,0 +1,64 @@ + no directory to open + * + * @test + */ + public function canNotOpenDirectory() + { + $this->assertFalse(@dir(vfsStream::url('foo'))); + } + + /** + * can not unlink without root + * + * @test + */ + public function canNotUnlink() + { + $this->assertFalse(@unlink(vfsStream::url('foo'))); + } + + /** + * can not open a file without root + * + * @test + */ + public function canNotOpen() + { + $this->assertFalse(@fopen(vfsStream::url('foo'))); + } + + /** + * can not rename a file without root + * + * @test + */ + public function canNotRename() + { + $this->assertFalse(@rename(vfsStream::url('foo'), vfsStream::url('bar'))); + } +} +?> diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamZipTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamZipTestCase.php new file mode 100755 index 00000000..45114c23 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/vfsStreamZipTestCase.php @@ -0,0 +1,53 @@ +markTestSkipped('No ext/zip installed, skipping test.'); + } + + $this->markTestSkipped('Zip extension can not work with vfsStream urls.'); + + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(vfsStream::newDirectory('root')); + + } + + /** + * @test + */ + public function createZipArchive() + { + $zip = new ZipArchive(); + $this->assertTrue($zip->open(vfsStream::url('root/test.zip'), ZIPARCHIVE::CREATE)); + $this->assertTrue($zip->addFromString("testfile1.txt", "#1 This is a test string added as testfile1.txt.\n")); + $this->assertTrue($zip->addFromString("testfile2.txt", "#2 This is a test string added as testfile2.txt.\n")); + $zip->setArchiveComment('a test'); + var_dump($zip); + $this->assertTrue($zip->close()); + var_dump($zip->getStatusString()); + var_dump($zip->close()); + var_dump($zip->getStatusString()); + var_dump($zip); + var_dump(file_exists(vfsStream::url('root/test.zip'))); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitorTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitorTestCase.php new file mode 100755 index 00000000..bc8eb7d5 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamAbstractVisitorTestCase.php @@ -0,0 +1,82 @@ +abstractVisitor = $this->getMock('org\\bovigo\\vfs\\visitor\\vfsStreamAbstractVisitor', + array('visitFile', 'visitDirectory') + ); + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function visitThrowsInvalidArgumentExceptionOnUnknownContentType() + { + $mockContent = $this->getMock('org\\bovigo\\vfs\\vfsStreamContent'); + $mockContent->expects($this->any()) + ->method('getType') + ->will($this->returnValue('invalid')); + $this->assertSame($this->abstractVisitor, + $this->abstractVisitor->visit($mockContent) + ); + } + + /** + * @test + */ + public function visitWithFileCallsVisitFile() + { + $file = new vfsStreamFile('foo.txt'); + $this->abstractVisitor->expects($this->once()) + ->method('visitFile') + ->with($this->equalTo($file)); + $this->assertSame($this->abstractVisitor, + $this->abstractVisitor->visit($file) + ); + } + + /** + * @test + */ + public function visitWithDirectoryCallsVisitDirectory() + { + $dir = new vfsStreamDirectory('bar'); + $this->abstractVisitor->expects($this->once()) + ->method('visitDirectory') + ->with($this->equalTo($dir)); + $this->assertSame($this->abstractVisitor, + $this->abstractVisitor->visit($dir) + ); + } +} +?> diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitorTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitorTestCase.php new file mode 100755 index 00000000..f0a5fe85 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamPrintVisitorTestCase.php @@ -0,0 +1,89 @@ +at(vfsStream::setup()); + $printVisitor = new vfsStreamPrintVisitor(fopen('vfs://root/foo.txt', 'wb')); + $this->assertSame($printVisitor, + $printVisitor->visitFile(vfsStream::newFile('bar.txt')) + ); + $this->assertEquals("- bar.txt\n", $output->getContent()); + } + + /** + * @test + */ + public function visitDirectoryWritesDirectoryNameToStream() + { + $output = vfsStream::newFile('foo.txt') + ->at(vfsStream::setup()); + $printVisitor = new vfsStreamPrintVisitor(fopen('vfs://root/foo.txt', 'wb')); + $this->assertSame($printVisitor, + $printVisitor->visitDirectory(vfsStream::newDirectory('baz')) + ); + $this->assertEquals("- baz\n", $output->getContent()); + } + + /** + * @test + */ + public function visitRecursiveDirectoryStructure() + { + $root = vfsStream::setup('root', + null, + array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ), + 'foo.txt' => '' + ) + ); + $printVisitor = new vfsStreamPrintVisitor(fopen('vfs://root/foo.txt', 'wb')); + $this->assertSame($printVisitor, + $printVisitor->visitDirectory($root) + ); + $this->assertEquals("- root\n - test\n - foo\n - test.txt\n - baz.txt\n - foo.txt\n", file_get_contents('vfs://root/foo.txt')); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitorTestCase.php b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitorTestCase.php new file mode 100755 index 00000000..633b1a9e --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/php/org/bovigo/vfs/visitor/vfsStreamStructureVisitorTestCase.php @@ -0,0 +1,72 @@ +assertEquals(array('foo.txt' => 'test'), + $structureVisitor->visitFile(vfsStream::newFile('foo.txt') + ->withContent('test') + ) + ->getStructure() + ); + } + + /** + * @test + */ + public function visitDirectoryCreatesStructureForDirectory() + { + $structureVisitor = new vfsStreamStructureVisitor(); + $this->assertEquals(array('baz' => array()), + $structureVisitor->visitDirectory(vfsStream::newDirectory('baz')) + ->getStructure() + ); + } + + /** + * @test + */ + public function visitRecursiveDirectoryStructure() + { + $root = vfsStream::setup('root', + null, + array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ), + 'foo.txt' => '' + ) + ); + $structureVisitor = new vfsStreamStructureVisitor(); + $this->assertEquals(array('root' => array('test' => array('foo' => array('test.txt' => 'hello'), + 'baz.txt' => 'world' + ), + 'foo.txt' => '' + ), + ), + $structureVisitor->visitDirectory($root) + ->getStructure() + ); + } +} +?> \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/emptyFolder/.gitignore b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/emptyFolder/.gitignore new file mode 100755 index 00000000..e69de29b diff --git a/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/aFile.txt b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/aFile.txt new file mode 100755 index 00000000..19102815 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/aFile.txt @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/subfolder1/file1.txt b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/subfolder1/file1.txt new file mode 100755 index 00000000..f6ea0495 --- /dev/null +++ b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/subfolder1/file1.txt @@ -0,0 +1 @@ +foobar \ No newline at end of file diff --git a/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/subfolder2/.gitignore b/vendor/mikey179/vfsStream/src/test/resources/filesystemcopy/withSubfolders/subfolder2/.gitignore new file mode 100755 index 00000000..e69de29b diff --git a/vendor/mongodb/mongodb/.gitignore b/vendor/mongodb/mongodb/.gitignore new file mode 100644 index 00000000..ef23673a --- /dev/null +++ b/vendor/mongodb/mongodb/.gitignore @@ -0,0 +1,8 @@ +# Composer +composer.phar +composer.lock +vendor/ + +# PHPUnit +phpunit.phar +phpunit.xml diff --git a/vendor/mongodb/mongodb/.travis.yml b/vendor/mongodb/mongodb/.travis.yml new file mode 100644 index 00000000..b3f961ae --- /dev/null +++ b/vendor/mongodb/mongodb/.travis.yml @@ -0,0 +1,74 @@ +language: php +dist: trusty +sudo: false + +services: + - mongodb + +addons: + apt: + packages: &common_packages + - gdb + +matrix: + fast_finish: true + include: + - php: 5.5 + env: &common_env DRIVER_VERSION=1.3.0RC1 SERVER_VERSION=3.4 + addons: &common_addons + apt: + sources: [ mongodb-3.4-precise ] + packages: [ mongodb-org, *common_packages ] + - php: 5.6 + env: *common_env + addons: *common_addons + - php: 7.0 + env: *common_env + addons: *common_addons + - php: 7.1 + env: *common_env + addons: *common_addons + - php: 7.2 + env: *common_env + addons: *common_addons + - php: 7.0 + env: DRIVER_VERSION=1.3.0RC1 SERVER_VERSION=2.4 + addons: + apt: + sources: [ mongodb-upstart ] + packages: [ mongodb-10gen, *common_packages ] + - php: 7.0 + env: DRIVER_VERSION=1.3.0RC1 SERVER_VERSION=2.6 + addons: + apt: + sources: [ mongodb-upstart ] + packages: [ mongodb-org, *common_packages ] + - php: 7.0 + env: DRIVER_VERSION=1.3.0RC1 SERVER_VERSION=3.0 + addons: + apt: + sources: [ mongodb-3.0-precise ] + packages: [ mongodb-org, *common_packages ] + - php: 7.0 + env: DRIVER_VERSION=1.3.0RC1 SERVER_VERSION=3.2 + addons: + apt: + sources: [ mongodb-3.2-precise ] + packages: [ mongodb-org, *common_packages ] + - php: 7.0 + env: DRIVER_VERSION=devel SERVER_VERSION=3.4 + addons: *common_addons + +before_script: + - mongod --version + - mongo --eval 'var v = db.runCommand({buildInfo:1}).versionArray; if ((v[0] == 3 && v[1] >= 4) || v[0] >= 4) db.adminCommand({setFeatureCompatibilityVersion:"3.4"});' + - pecl install -f mongodb-${DRIVER_VERSION} + - php --ri mongodb + - composer install --dev --no-interaction --prefer-source + - ulimit -c + - ulimit -c unlimited -S + +script: + - ./vendor/bin/phpunit --debug || RESULT=$? + - for i in $(find ./ -maxdepth 1 -name 'core*' -print); do gdb `php -r 'echo PHP_BINARY;'` core* -ex "thread apply all bt" -ex "set pagination 0" -batch; done; + - if [[ ${RESULT} != 0 ]]; then exit $RESULT ; fi; diff --git a/vendor/mongodb/mongodb/CONTRIBUTING.md b/vendor/mongodb/mongodb/CONTRIBUTING.md new file mode 100644 index 00000000..d833208b --- /dev/null +++ b/vendor/mongodb/mongodb/CONTRIBUTING.md @@ -0,0 +1,185 @@ +# Contributing to the PHP Library for MongoDB + +## Initializing the Repository + +Developers who would like to contribute to the library will need to clone it and +initialize the project dependencies with [Composer](https://getcomposer.org/): + +``` +$ git clone https://github.com/mongodb/mongo-php-library.git +$ cd mongo-php-library +$ composer update +``` + +In addition to installing project dependencies, Composer will check that the +required extension version is installed. Directions for installing the extension +may be found [here](http://php.net/manual/en/mongodb.installation.php). + +Installation directions for Composer may be found in its +[Getting Started](https://getcomposer.org/doc/00-intro.md) guide. + +## Testing + +The library's test suite uses [PHPUnit](https://phpunit.de/), which should be +installed as a development dependency by Composer. + +The test suite may be executed with: + +``` +$ vendor/bin/phpunit +``` + +The `phpunit.xml.dist` file is used as the default configuration file for the +test suite. In addition to various PHPUnit options, it defines required +`MONGODB_URI` and `MONGODB_DATABASE` environment variables. You may customize +this configuration by creating your own `phpunit.xml` file based on the +`phpunit.xml.dist` file we provide. + +### Testing on HHVM + +By default, the PHPUnit script relies on the `php` interpreter for your shell +(i.e. `#!/usr/bin/env php`). You can run the test suite with HHVM like so: + +``` +$ hhvm vendor/bin/phpunit +``` + +## Documentation + +Documentation for the library lives in the `docs/` directory and is built with +tools in the related +[mongodb/docs-php-library](https://github.com/mongodb/docs-php-library) +repository. The tools repository is already configured to reference our sources. + +That said, any changes to the documentation should be tested locally before +committing. Follow the following steps to build the docs locally with the tools +repository: + + * Clone the + [mongodb/docs-php-library](https://github.com/mongodb/docs-php-library) tools + repository. + * Install [giza](https://pypi.python.org/pypi/giza/), as noted in the tools + README. + * Sync your working copy of the documentation to the `source/` directory with + `rsync -a --delete /path/to/mongo-php-library/docs/ source/`. + * Build the documentation with `giza make publish`. You can suppress + informational log messages with the `--level warning` option. + * Generated documentation may be found in the `build/master/html` directory. + +## Releasing + +The follow steps outline the release process for a maintenance branch (e.g. +releasing the `vX.Y` branch as X.Y.Z). + +### Ensure PHP version compatibility + +Ensure that the library test suite completes on supported versions of PHP and +HHVM. + +### Transition JIRA issues and version + +All issues associated with the release version should be in the "Closed" state +and have a resolution of "Fixed". Issues with other resolutions (e.g. +"Duplicate", "Works as Designed") should be removed from the release version so +that they do not appear in the release notes. + +Check the corresponding ".x" fix version to see if it contains any issues that +are resolved as "Fixed" and should be included in this release version. + +Update the version's release date and status from the +[Manage Versions](https://jira.mongodb.org/plugins/servlet/project-config/PHPLIB/versions) +page. + +### Update version info + +The PHP library uses [semantic versioning](http://semver.org/). Do not break +backwards compatibility in a non-major release or your users will kill you. + +Before proceeding, ensure that the `master` branch is up-to-date with all code +changes in this maintenance branch. This is important because we will later +merge the ensuing release commits up to master with `--strategy=ours`, which +will ignore changes from the merged commits. + +A version constant may be added at a later date (see: +[PHPLIB-131](https://jira.mongodb.org/browse/PHPLIB-131)). For now, there is +nothing to update. + +### Tag release + +The maintenance branch's HEAD will be the target for our release tag: + +``` +$ git tag -a -m "Release X.Y.Z" X.Y.Z +``` + +### Push tags + +``` +$ git push --tags +``` + +### Merge the maintenance branch up to master + +``` +$ git checkout master +$ git merge vX.Y --strategy=ours +$ git push +``` + +The `--strategy=ours` option ensures that all changes from the merged commits +will be ignored. + +### Publish release notes + +The following template should be used for creating GitHub release notes via +[this form](https://github.com/mongodb/mongo-php-library/releases/new). + +``` +The PHP team is happy to announce that version X.Y.Z of our MongoDB PHP library is now available. This library is a high-level abstraction for the PHP 5, PHP 7, and HHVM drivers (i.e. [`mongodb`](http://php.net/mongodb) extension). + +**Release Highlights** + + + +A complete list of resolved issues in this release may be found at: +$JIRA_URL + +**Documentation** + +Documentation for this library may be found at: +https://docs.mongodb.com/php-library/ + +**Feedback** + +If you encounter any bugs or issues with this library, please report them via this form: +https://jira.mongodb.org/secure/CreateIssue.jspa?pid=12483&issuetype=1 + +**Installation** + +This library may be installed or upgraded with: + + composer require mongodb/mongodb + +Installation instructions for the PHP and HHVM driver may be found in the [PHP.net documentation](http://php.net/manual/en/mongodb.installation.php). +``` + +The URL for the list of resolved JIRA issues will need to be updated with each +release. You may obtain the list from +[this form](https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=12483). + +If commits from community contributors were included in this release, append the +following section: + +``` +**Thanks** + +Thanks for our community contributors for this release: + + * [$CONTRIBUTOR_NAME](https://github.com/$GITHUB_USERNAME) +``` + +Release announcements should also be sent to the `mongodb-user@googlegroups.com` +and `mongodb-announce@googlegroups.com` mailing lists. + +Consider announcing each release on Twitter. Significant releases should also be +announced via [@MongoDB](http://twitter.com/mongodb) as well. diff --git a/vendor/mongodb/mongodb/LICENSE b/vendor/mongodb/mongodb/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/mongodb/mongodb/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/mongodb/mongodb/Makefile b/vendor/mongodb/mongodb/Makefile new file mode 100644 index 00000000..a1d31b68 --- /dev/null +++ b/vendor/mongodb/mongodb/Makefile @@ -0,0 +1,17 @@ +.PHONY: composer test + +COMPOSER_ARGS=update --no-interaction --prefer-source + +composer: + @command -v composer >/dev/null 2>&1; \ + if test $$? -eq 0; then \ + composer $(COMPOSER_ARGS); \ + elif test -r composer.phar; then \ + php composer.phar $(COMPOSER_ARGS); \ + else \ + echo >&2 "Cannot find composer; aborting."; \ + false; \ + fi + +test: composer + vendor/bin/phpunit diff --git a/vendor/mongodb/mongodb/README.md b/vendor/mongodb/mongodb/README.md new file mode 100644 index 00000000..90bd8d8f --- /dev/null +++ b/vendor/mongodb/mongodb/README.md @@ -0,0 +1,45 @@ +MongoDB library for PHP +======================= + +This library provides a high-level abstraction around the lower-level drivers for +[PHP](https://github.com/mongodb/mongo-php-driver) and +[HHVM](https://github.com/mongodb/mongo-hhvm-driver) (i.e. the `mongodb` +extension). + +While the extension provides a limited API for executing commands, queries, and +write operations, this library implements an API similar to that of the +[legacy PHP driver](http://php.net/manual/en/book.mongo.php). It contains +abstractions for client, database, and collection objects, and provides methods +for CRUD operations and common commands (e.g. index and collection management). + +If you are developing an application with MongoDB, you should consider using +this library, or another high-level abstraction, instead of the extension alone. + +For further information about the architecture of this library and the `mongodb` +extension, see: + + - http://www.mongodb.com/blog/post/call-feedback-new-php-and-hhvm-drivers + +## Documentation + + - https://docs.mongodb.com/php-library/ + +# Installation + +As a high-level abstraction for the driver, this library naturally requires that +the [`mongodb` extension be installed](http://php.net/manual/en/mongodb.installation.php): + + $ pecl install mongodb + $ echo "extension=mongodb.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` + +The preferred method of installing this library is with +[Composer](https://getcomposer.org/) by running the following from your project +root: + + $ composer require mongodb/mongodb + +## Reporting Issues + +Please use the following form to report any issues: + + - https://jira.mongodb.org/secure/CreateIssue.jspa?pid=12483&issuetype=1 diff --git a/vendor/mongodb/mongodb/composer.json b/vendor/mongodb/mongodb/composer.json new file mode 100644 index 00000000..7c772ca0 --- /dev/null +++ b/vendor/mongodb/mongodb/composer.json @@ -0,0 +1,28 @@ +{ + "name": "mongodb/mongodb", + "description": "MongoDB driver library", + "keywords": ["database", "driver", "mongodb", "persistence"], + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "license": "Apache-2.0", + "authors": [ + { "name": "Hannes Magnusson", "email": "bjori@mongodb.com" }, + { "name": "Jeremy Mikola", "email": "jmikola@gmail.com" }, + { "name": "Derick Rethans", "email": "github@derickrethans.nl" } + ], + "require": { + "php": ">=5.5", + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "autoload": { + "psr-4": { "MongoDB\\": "src/" }, + "files": [ "src/functions.php" ] + }, + "autoload-dev": { + "psr-4": { "MongoDB\\Tests\\": "tests/" } + } +} diff --git a/vendor/mongodb/mongodb/docs/.static/.mongodb b/vendor/mongodb/mongodb/docs/.static/.mongodb new file mode 100644 index 00000000..e69de29b diff --git a/vendor/mongodb/mongodb/docs/images/save-flowchart.png b/vendor/mongodb/mongodb/docs/images/save-flowchart.png new file mode 100644 index 00000000..45e7b764 Binary files /dev/null and b/vendor/mongodb/mongodb/docs/images/save-flowchart.png differ diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml new file mode 100644 index 00000000..318d9d50 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml @@ -0,0 +1,115 @@ +arg_name: option +name: typeMap +type: array +description: | + Default :php:`type map + ` + to apply to cursors, which determines how BSON documents are converted to PHP + values. The |php-library| uses the following type map by default: + + .. code-block:: php + + [ + 'array' => 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ] +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: allow_invalid_hostname +type: boolean +description: | + Disables hostname validation if ``true``. Defaults to ``false``. + + Allowing invalid hostnames may expose the driver to a `man-in-the-middle + attack `_. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: ca_dir +type: string +description: | + Path to a correctly hashed certificate directory. The system certificate store + will be used by default. + + Falls back to the deprecated ``capath`` SSL context option if not specified. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: ca_file +type: string +description: | + Path to a certificate authority file. The system certificate store will be + used by default. + + Falls back to the deprecated ``cafile`` SSL context option if not specified. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: crl_file +type: string +description: | + Path to a certificate revocation list file. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: pem_file +type: string +description: | + Path to a PEM encoded certificate to use for client authentication. + + Falls back to the deprecated ``local_cert`` SSL context option if not + specified. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: pem_pwd +type: string +description: | + Passphrase for the PEM encoded certificate (if applicable). + + Falls back to the deprecated ``passphrase`` SSL context option if not + specified. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: weak_cert_validation +type: boolean +description: | + Disables certificate validation ``true``. Defaults to ``false``. + + Falls back to the deprecated ``allow_self_signed`` SSL context option if not + specified. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: context +type: resource +description: | + :php:`SSL context options ` to be used as fallbacks + for other driver options (as specified). Note that the driver does not consult + the default stream context. + + This option is supported for backwards compatibility, but should be considered + deprecated. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml new file mode 100644 index 00000000..4b6ff420 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml @@ -0,0 +1,51 @@ +arg_name: param +name: $uri +type: string +description: | + The URI of the standalone, replica set, or sharded cluster to which to + connect. Refer to :manual:`Connection String URI Format + ` in the MongoDB manual for more information. + + Defaults to ``"mongodb://127.0.0.1:27017"`` if unspecified. + + Any special characters in the URI components need to be encoded according to + `RFC 3986 `_. This is particularly + relevant to the username and password, which can often include special + characters such as ``@``, ``:``, or ``%``. When connecting via a Unix domain + socket, the socket path may contain special characters such as slashes and + must be encoded. The :php:`rawurlencode() ` function may be used + to encode constituent parts of the URI. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: param +name: $uriOptions +type: array +description: | + Specifies additional URI options, such as authentication credentials or query + string parameters. The options specified in ``$uriOptions`` take precedence + over any analogous options present in the ``$uri`` string and do not need to + be encoded according to `RFC 3986 `_. + + Refer to the :php:`MongoDB\\Driver\\Manager::__construct() + ` extension reference and :manual:`MongoDB + connection string ` documentation for accepted + options. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: param +name: $driverOptions +type: array +description: | + Specify driver-specific options, such as SSL options. In addition to any + options supported by the :php:`extension `, the + |php-library| allows you to specify a default :php:`type map + ` + to apply to the cursors it creates. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml new file mode 100644 index 00000000..22141f1a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml @@ -0,0 +1,19 @@ +source: + file: apiargs-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +arg_name: option +name: writeConcern +type: :php:`MongoDB\\Driver\\WriteConcern ` +description: | + :manual:`Write concern ` to use for the operation. + Defaults to the client's write concern. + + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-param.yaml new file mode 100644 index 00000000..07b76834 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-dropDatabase-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-common-param.yaml + ref: $databaseName +replacement: + action: " to drop" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-get-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-get-param.yaml new file mode 100644 index 00000000..e9d3ccc6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-get-param.yaml @@ -0,0 +1,6 @@ +source: + file: apiargs-common-param.yaml + ref: $databaseName +replacement: + action: " to select" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml new file mode 100644 index 00000000..4eb407fe --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-listDatabases-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-option.yaml new file mode 100644 index 00000000..d81d3181 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "collection" + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "collection" + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "collection" + parent: "client" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-param.yaml new file mode 100644 index 00000000..99c76446 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectCollection-param.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-common-param.yaml + ref: $databaseName +replacement: + action: " containing the collection to select" +--- +source: + file: apiargs-common-param.yaml + ref: $collectionName +replacement: + action: " to select" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-option.yaml new file mode 100644 index 00000000..e4ffd3c6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "database" + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "database" + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "client" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "database" + parent: "client" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-param.yaml new file mode 100644 index 00000000..8e5f9d45 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBClient-method-selectDatabase-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-common-param.yaml + ref: $databaseName +replacement: + action: " to select" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-option.yaml new file mode 100644 index 00000000..eaf8e421 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-option.yaml @@ -0,0 +1,85 @@ +arg_name: option +name: bypassDocumentValidation +type: boolean +description: | + If ``true``, allows the write operation to circumvent document level + validation. Defaults to ``false``. + + This option is available in MongoDB 3.2+ and is ignored for older server + versions, which do not support document level validation. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: collation +type: array|object +description: | + :manual:`Collation ` allows users to specify + language-specific rules for string comparison, such as rules for lettercase + and accent marks. When specifying collation, the ``locale`` field is + mandatory; all other collation fields are optional. For descriptions of the + fields, see :manual:`Collation Document + `. + + If the collation is unspecified but the collection has a default collation, + the operation uses the collation specified for the collection. If no + collation is specified for the collection or for the operation, MongoDB uses + the simple binary comparison used in prior versions for string comparisons. + + This option is available in MongoDB 3.4+ and will result in an exception at + execution time if specified for an older server version. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: readConcern +type: :php:`MongoDB\\Driver\\ReadConcern ` +description: | + :manual:`Read concern ` to use for the operation. + Defaults to the collection's read concern. + + This is not supported for server versions prior to 3.2 and will result in an + exception at execution time if used. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: readPreference +type: :php:`MongoDB\\Driver\\ReadPreference ` +description: | + :manual:`Read preference ` to use for the + operation. Defaults to the collection's read preference. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "collection" +--- +arg_name: option +name: writeConcern +type: :php:`MongoDB\\Driver\\WriteConcern ` +description: | + :manual:`Write concern ` to use for the operation. + Defaults to the collection's write concern. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: upsert +type: boolean +description: | + If set to ``true``, creates a new document when no document matches the query + criteria. The default value is ``false``, which does not insert a new + document when no match is found. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-param.yaml new file mode 100644 index 00000000..73c18fa4 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-common-param.yaml @@ -0,0 +1,31 @@ +arg_name: param +name: $filter +type: array|object +description: | + The filter criteria that specifies the documents{{action}}. +interface: phpmethod +operation: ~ +optional: false +replacement: + action: "" +--- +arg_name: param +name: $replacement +type: array|object +description: | + The replacement document. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $update +type: array|object +description: | + Specifies the field and value combinations to update and any relevant update + operators. ``$update`` uses MongoDB's :method:`update operators + `. +interface: phpmethod +operation: ~ +optional: false +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml new file mode 100644 index 00000000..4d353bfd --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml @@ -0,0 +1,77 @@ +arg_name: option +name: allowDiskUse +type: boolean +description: | + Enables writing to temporary files. When set to ``true``, aggregation stages + can write data to the ``_tmp`` sub-directory in the ``dbPath`` directory. The + default is ``false``. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: batchSize +type: integer +description: | + Specifies the initial batch size for the cursor. A batchSize of ``0`` means an + empty first batch and is useful for quickly returning a cursor or failure + message without doing significant server-side work. + + .. note:: + + This is not supported for inline aggregation results (i.e. ``useCursor`` + option is ``false`` or the server version is < 2.6). +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +post: | + This only applies when using the :ref:`$out ` stage. + + Document validation requires MongoDB 3.2 or later: if you are using an earlier + version of MongoDB, this option will be ignored. +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +--- +arg_name: option +name: useCursor +type: boolean +description: | + Indicates whether the command will request that the server provide results + using a cursor. The default is ``true``. + + For MongoDB version 2.6 or later, ``useCursor`` allows users to turn off + cursors if necessary to aid in replica set or shard cluster upgrades. + + ``useCursor`` is ignored for MongoDB versions prior to 2.6 as aggregation + cursors are not available. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This only applies when the :ref:`$out ` stage is specified. + + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-param.yaml new file mode 100644 index 00000000..cbad3b49 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-aggregate-param.yaml @@ -0,0 +1,14 @@ +arg_name: param +name: $pipeline +type: array +description: | + Specifies an :manual:`aggregation pipeline ` + operation. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml new file mode 100644 index 00000000..bb663bf3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml @@ -0,0 +1,23 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +arg_name: option +name: ordered +type: boolean +description: | + If ``true``: when a single write fails, the operation will stop without + performing the remaining writes and throw an exception. + + If ``false``: when a single write fails, the operation will continue with the + remaining writes, if any, and throw an exception. + + The default is ``true``. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-param.yaml new file mode 100644 index 00000000..79423a63 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-param.yaml @@ -0,0 +1,37 @@ +arg_name: param +name: $operations +type: array +description: | + An array containing the write operations to perform. + :phpmethod:`MongoDB\\Collection::bulkWrite()` supports + :phpmethod:`deleteMany() `, + :phpmethod:`deleteOne() `, + :phpmethod:`insertOne() `, + :phpmethod:`replaceOne() `, + :phpmethod:`updateMany() `, and + :phpmethod:`updateOne() ` operations in the + following array structure: + + .. code-block:: php + + [ + [ 'deleteMany' => [ $filter ] ], + [ 'deleteOne' => [ $filter ] ], + [ 'insertOne' => [ $document ] ], + [ 'replaceOne' => [ $filter, $replacement, $options ] ], + [ 'updateMany' => [ $filter, $update, $options ] ], + [ 'updateOne' => [ $filter, $update, $options ] ], + ] + + Arguments correspond to the respective operation methods. However, the + ``writeConcern`` option is specified as a top-level option to + :phpmethod:`MongoDB\\Collection::bulkWrite()` instead of each individual + operation. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-option.yaml new file mode 100644 index 00000000..7d422ca0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-option.yaml @@ -0,0 +1,25 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "collection" + parent: "manager" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "collection" + parent: "manager" +--- +source: + file: apiargs-MongoDBClient-method-construct-driverOptions.yaml + ref: typeMap +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "collection" + parent: "manager" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-param.yaml new file mode 100644 index 00000000..0827800b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-construct-param.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-common-param.yaml + ref: $manager +--- +source: + file: apiargs-common-param.yaml + ref: $databaseName +--- +source: + file: apiargs-common-param.yaml + ref: $collectionName +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml new file mode 100644 index 00000000..4999b78a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml @@ -0,0 +1,49 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +arg_name: option +name: hint +type: string|array|object +description: | + The index to use. Specify either the index name as a string or the index key + pattern as a document. If specified, then the query system will only consider + plans using the hinted index. + + .. versionchanged:: 1.2 + If a document is provided, it is passed to the command as-is. Previously, + the library would convert the key pattern to an index name. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: limit +type: integer +description: | + The maximum number of matching documents to return. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +--- +arg_name: option +name: skip +type: integer +description: | + The number of matching documents to skip before returning results. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-param.yaml new file mode 100644 index 00000000..e18c616b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-count-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: true +replacement: + action: " to count" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml new file mode 100644 index 00000000..a7364a66 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml @@ -0,0 +1,84 @@ +arg_name: option +name: unique +type: boolean +description: | + Creates a :manual:`unique ` index. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +pre: | + Specifies the :manual:`collation + ` for the index. +--- +arg_name: option +name: partialFilterExpression +type: array|object +description: | + Creates a :manual:`partial ` index. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: sparse +type: boolean +description: | + Creates a :manual:`sparse ` index. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: expireAfterSeconds +type: integer +description: | + Creates a :manual:`TTL ` index. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: name +type: string +description: | + A name that uniquely identifies the index. By default, MongoDB creates index + names based on the key. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: background +type: string +description: | + Instructs MongoDB to build the index :manual:`as a background + ` process. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: 2dsphereIndexVersion +type: integer +description: | + Specifies the :manual:`version of a 2dsphere ` index to + create. + + MongoDB 2.6 introduced version 2 of 2dsphere indexes. Version 2 is the default + version of 2dsphere indexes created in MongoDB 2.6 and later versions. + ``2dsphereIndexVersion`` enables you to override the default version 2. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-param.yaml new file mode 100644 index 00000000..c2979d91 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndex-param.yaml @@ -0,0 +1,20 @@ +arg_name: param +name: $key +type: array|object +description: | + Specifies the field or fields to index and the index order. + + For example, the following specifies a descending index on the ``username`` + field: + + .. code-block:: php + + [ 'username' => -1 ] +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml new file mode 100644 index 00000000..2be24cba --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml @@ -0,0 +1,7 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-param.yaml new file mode 100644 index 00000000..e98d9aad --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-createIndexes-param.yaml @@ -0,0 +1,23 @@ +arg_name: param +name: $indexes +type: array +description: | + The indexes to create on the collection. + + For example, the following specifies a unique index on the ``username`` field + and a compound index on the ``email`` and ``createdAt`` fields: + + .. code-block:: php + + [ + [ 'key' => [ 'username' => -1 ], 'unique' => true ], + [ 'key' => [ 'email' => 1, 'createdAt' => 1 ] ], + ] +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml new file mode 100644 index 00000000..8c775dde --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml @@ -0,0 +1,8 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-param.yaml new file mode 100644 index 00000000..92797eb5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteMany-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to delete" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml new file mode 100644 index 00000000..8c775dde --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml @@ -0,0 +1,8 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-param.yaml new file mode 100644 index 00000000..92797eb5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-deleteOne-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to delete" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml new file mode 100644 index 00000000..e8608b38 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-param.yaml new file mode 100644 index 00000000..37cd9b50 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-distinct-param.yaml @@ -0,0 +1,20 @@ +arg_name: param +name: $fieldName +type: string +description: | + The field for which to return distinct values. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: true +replacement: + action: " from which to retrieve the distinct values" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml new file mode 100644 index 00000000..6460329f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml @@ -0,0 +1,13 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-drop-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml new file mode 100644 index 00000000..6460329f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml @@ -0,0 +1,13 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-param.yaml new file mode 100644 index 00000000..53061d16 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndex-param.yaml @@ -0,0 +1,15 @@ +arg_name: param +name: $indexName +type: string +description: | + The name of the index to drop. View the existing indexes on the collection + using the :phpmethod:`listIndexes() ` + method. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml new file mode 100644 index 00000000..6460329f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml @@ -0,0 +1,13 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml new file mode 100644 index 00000000..1827b896 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml @@ -0,0 +1,247 @@ +arg_name: option +name: projection +type: array|object +description: | + The :ref:`projection specification ` to determine which fields to + include in the returned documents. See :manual:`Project Fields to Return from + Query ` and + :manual:`Projection Operators ` in the MongoDB + manual. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: sort +type: array|object +description: | + The sort specification for the ordering of the results. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: skip +type: integer +description: | + Number of documents to skip. Defaults to ``0``. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: limit +type: integer +description: | + The maximum number of documents to return. If unspecified, then defaults to no + limit. A limit of ``0`` is equivalent to setting no limit. + + A negative limit is similar to a positive limit but closes the cursor after + returning a single batch of results. As such, with a negative limit, if the + limited result set does not fit into a single batch, the number of documents + received will be less than the specified limit. By passing a negative limit, the + client indicates to the server that it will not ask for a subsequent batch via + getMore. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: batchSize +type: integer +description: | + The number of documents to return in the first batch. Defaults to ``101``. A + batchSize of ``0`` means that the cursor will be established, but no documents + will be returned in the first batch. + + Unlike the previous wire protocol version, a batchSize of ``1`` for the + :dbcommand:`find` command does not close the cursor. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +arg_name: option +name: comment +type: string +description: | + A comment to attach to the query to help interpret and trace query + :dbcommand:`profile` data. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: cursorType +type: integer +description: | + Indicates the type of cursor to use. ``cursorType`` supports the following + values: + + - ``MongoDB\Operation\Find::NON_TAILABLE`` (*default*) + - ``MongoDB\Operation\Find::TAILABLE`` +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: hint +type: string|array|object +description: | + The index to use. Specify either the index name as a string or the index key + pattern as a document. If specified, then the query system will only consider + plans using the hinted index. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: maxAwaitTimeMS +type: integer +description: | + Positive integer denoting the time limit in milliseconds for the server to + block a getMore operation if no data is available. This option should only be + used if cursorType is TAILABLE_AWAIT. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +--- +arg_name: option +name: max +type: array|object +description: | + The exclusive upper bound for a specific index. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: maxScan +type: integer +description: | + Maximum number of documents or index keys to scan when executing the query. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: min +type: array|object +description: | + The inclusive lower bound for a specific index. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: oplogReplay +type: boolean +description: | + Internal use for replica sets. To use ``oplogReplay``, you must include the + following condition in the filter: + + .. code-block:: javascript + + { ts: { $gte: } } + + The :php:`MongoDB\\BSON\\Timestamp ` class + reference describes how to represent MongoDB's BSON timestamp type with PHP. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: noCursorTimeout +type: boolean +description: | + Prevents the server from timing out idle cursors after an inactivity period + (10 minutes). +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: returnKey +type: boolean +description: | + If true, returns only the index keys in the resulting documents. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: showRecordId +type: boolean +description: | + Determines whether to return the record identifier for each document. If true, + adds a field $recordId to the returned documents. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: snapshot +type: boolean +description: | + Prevents the cursor from returning a document more than once because of an + intervening write operation. + + .. versionadded:: 1.2 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: allowPartialResults +type: boolean +description: | + For queries against a sharded collection, returns partial results from the + :program:`mongos` if some shards are unavailable instead of throwing an error. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +--- +arg_name: option +name: modifiers +type: array|object +description: | + :manual:`Meta operators ` that modify the + output or behavior of a query. Use of these operators is deprecated in favor + of named options. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-param.yaml new file mode 100644 index 00000000..5683a7bb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-find-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: true +replacement: + action: " to query" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml new file mode 100644 index 00000000..a4e20e57 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml @@ -0,0 +1,66 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: skip +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: comment +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: hint +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned result document. +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: max +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: maxScan +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: min +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: returnKey +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: showRecordId +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: modifiers +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-param.yaml new file mode 100644 index 00000000..5683a7bb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOne-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: true +replacement: + action: " to query" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml new file mode 100644 index 00000000..b7d4deaf --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml @@ -0,0 +1,29 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.2 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-param.yaml new file mode 100644 index 00000000..92797eb5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-param.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to delete" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml new file mode 100644 index 00000000..24743d29 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml @@ -0,0 +1,50 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +arg_name: option +name: returnDocument +type: integer +description: | + Specifies whether to return the document before the replacement is applied, or + after. ``returnDocument`` supports the following values: + + - ``MongoDB\Operation\FindOneAndReplace::RETURN_DOCUMENT_BEFORE`` (*default*) + - ``MongoDB\Operation\FindOneAndReplace::RETURN_DOCUMENT_AFTER`` +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: upsert +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.2 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-param.yaml new file mode 100644 index 00000000..32ed6b35 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to replace" +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $replacement +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml new file mode 100644 index 00000000..dcec8aa9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml @@ -0,0 +1,50 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +arg_name: option +name: returnDocument +type: integer +description: | + Specifies whether to return the document before the update is applied, or + after. ``returnDocument`` supports the following values: + + - ``MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_BEFORE`` (*default*) + - ``MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER`` +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned result document. +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: upsert +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.2 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-param.yaml new file mode 100644 index 00000000..a335678a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to update" +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $update +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml new file mode 100644 index 00000000..1b32b97a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml @@ -0,0 +1,12 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-method-bulkWrite-option.yaml + ref: ordered +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-param.yaml new file mode 100644 index 00000000..78246d30 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertMany-param.yaml @@ -0,0 +1,13 @@ +arg_name: param +name: $documents +type: array +description: | + The documents to insert into the collection. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml new file mode 100644 index 00000000..ee47d575 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml @@ -0,0 +1,8 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-param.yaml new file mode 100644 index 00000000..5dc231d3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-insertOne-param.yaml @@ -0,0 +1,13 @@ +arg_name: param +name: $document +type: array|object +description: | + The document to insert into the collection. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml new file mode 100644 index 00000000..4eb407fe --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-listIndexes-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml new file mode 100644 index 00000000..a2e97d11 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml @@ -0,0 +1,90 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +arg_name: option +name: finalize +type: :php:`MongoDB\\BSON\\Javascript ` +description: | + Follows the reduce method and modifies the output. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: jsMode +type: boolean +description: | + Specifies whether to convert intermediate data into BSON format between the + execution of the map and reduce functions. The default is ``false``. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: limit +type: integer +description: | + Specifies a maximum number of documents for the input into the map function. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +arg_name: option +name: query +type: document +description: | + Specifies the selection criteria using query operators for determining the + documents input to the map function. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: readPreference +--- +arg_name: option +name: scope +type: document +description: | + Specifies global variables that are accessible in the map, reduce, and finalize + functions. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +--- +arg_name: option +name: verbose +type: boolean +description: | + Specifies whether to include the timing information in the result information. + The default is ``true``. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml new file mode 100644 index 00000000..401d49ed --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml @@ -0,0 +1,36 @@ +arg_name: param +name: $map +type: :php:`MongoDB\\BSON\\Javascript ` +description: | + A JavaScript function that associates or "maps" a value with a key and emits + the key and value pair. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $reduce +type: :php:`MongoDB\\BSON\\Javascript ` +description: | + A JavaScript function that "reduces" to a single object all the values + associated with a particular key. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $out +type: string|document +description: | + Specifies where to output the result of the map-reduce operation. You can + either output to a collection or return the result inline. On a primary member + of a replica set you can output either to a collection or inline, but on a + secondary, only inline output is possible. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml new file mode 100644 index 00000000..4fec2f05 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: upsert +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-param.yaml new file mode 100644 index 00000000..32ed6b35 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-replaceOne-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to replace" +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $replacement +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml new file mode 100644 index 00000000..4fec2f05 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: upsert +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-param.yaml new file mode 100644 index 00000000..a335678a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateMany-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to update" +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $update +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml new file mode 100644 index 00000000..4fec2f05 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: upsert +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: bypassDocumentValidation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-param.yaml new file mode 100644 index 00000000..a335678a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-updateOne-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $filter +optional: false +replacement: + action: " to update" +--- +source: + file: apiargs-MongoDBCollection-common-param.yaml + ref: $update +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-option.yaml new file mode 100644 index 00000000..681144f3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "collection" + parent: "original collection" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "collection" + parent: "original collection" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "original collection" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "collection" + parent: "original collection" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBCollection-method-withOptions-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-common-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-common-option.yaml new file mode 100644 index 00000000..c18bd678 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-common-option.yaml @@ -0,0 +1,16 @@ +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "database" +--- +arg_name: option +name: writeConcern +type: :php:`MongoDB\\Driver\\WriteConcern ` +description: | + :manual:`Write concern ` to use for the operation. + Defaults to the database's write concern. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-option.yaml new file mode 100644 index 00000000..7dc5b5a0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-option.yaml @@ -0,0 +1,11 @@ +source: + file: apiargs-common-option.yaml + ref: readPreference +description: | + :manual:`Read preference ` to use for the + operation. Defaults to the database's read preference. +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: typeMap +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-param.yaml new file mode 100644 index 00000000..5a4b03d7 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-command-param.yaml @@ -0,0 +1,13 @@ +arg_name: param +name: $command +type: array|object +description: | + The :manual:`database command ` document. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-option.yaml new file mode 100644 index 00000000..d398069a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-option.yaml @@ -0,0 +1,25 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "database" + parent: "manager" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "database" + parent: "manager" +--- +source: + file: apiargs-MongoDBClient-method-construct-driverOptions.yaml + ref: typeMap +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "database" + parent: "manager" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-param.yaml new file mode 100644 index 00000000..5ef826c1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-construct-param.yaml @@ -0,0 +1,12 @@ +source: + file: apiargs-common-param.yaml + ref: $manager +--- +source: + file: apiargs-common-param.yaml + ref: $databaseName +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml new file mode 100644 index 00000000..d70a905f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -0,0 +1,230 @@ +arg_name: option +name: autoIndexId +type: boolean +description: | + Specify ``false`` to disable the automatic creation of an index on the ``_id`` + field. + + .. important:: + + For replica sets, do not set ``autoIndexId`` to ``false``. + + .. deprecated:: 3.2. The ``autoIndexId`` option will be removed in MongoDB 3.4. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: capped +type: boolean +description: | + To create a capped collection, specify ``true``. If you specify ``true``, you + must also set a maximum size in the ``size`` option. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +pre: | + Specifies the :manual:`collation + ` for the collection. +--- +arg_name: option +name: flags +type: integer +description: | + Available for the MMAPv1 storage engine only to set the ``usePowerOf2Sizes`` + and ``noPadding`` flags. + + The |php-library| provides constants that you can combine with a :php:`bitwise + OR operator ` to set the flag values: + + - ``MongoDB\Operation\CreateCollection::USE_POWER_OF_2_SIZES``: ``1`` + - ``MongoDB\Operation\CreateCollection::NO_PADDING``: ``2`` + + Defaults to ``1``. + + .. note:: + + MongoDB 3.0 and later ignores the ``usePowerOf2Sizes`` flag. See + :manual:`collMod ` and + :manual:`db.createCollection() + ` for more information. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: indexOptionDefaults +type: array|object +description: | + Allows users to specify a default configuration for indexes when creating a + collection. + + The ``indexOptionDefaults`` option accepts a ``storageEngine`` document, + which should take the following form:: + + { : } + + Storage engine configurations specified when creating indexes are validated + and logged to the :term:`oplog` during replication to support replica sets + with members that use different storage engines. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: max +type: integer +description: | + The maximum number of documents allowed in the capped collection. The ``size`` + option takes precedence over this limit. If a capped collection reaches the + ``size`` limit before it reaches the maximum number of documents, MongoDB + removes old documents. If you prefer to use the ``max`` limit, ensure that the + ``size`` limit, which is required for a capped collection, is sufficient to + contain the maximum number of documents. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +arg_name: option +name: size +type: integer +description: | + Specify a maximum size in bytes for a capped collection. Once a capped + collection reaches its maximum size, MongoDB removes the older documents to + make space for the new documents. The ``size`` option is required for capped + collections and ignored for other collections. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: storageEngine +type: array|object +description: | + Available for the WiredTiger storage engine only. + + Allows users to specify configuration to the storage engine on a + per-collection basis when creating a collection. The value of the + ``storageEngine`` option should take the following form:: + + { : } + + Storage engine configurations specified when creating collections are + validated and logged to the :term:`oplog` during replication to support + replica sets with members that use different storage engines. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +arg_name: option +name: validator +type: array +description: | + Allows users to specify :manual:`validation rules or expressions + ` for the collection. For more information, see + :manual:`Document Validation ` in the MongoDB + manual. + + The ``validator`` option takes an array that specifies the validation rules or + expressions. You can specify the expressions using the same operators as + MongoDB's :manual:`query operators ` with the + exception of :query:`$geoNear`, :query:`$near`, :query:`$nearSphere`, + :query:`$text`, and :query:`$where`. + + .. note:: + + - Validation occurs during updates and inserts. Existing documents do not + undergo validation checks until modification. + + - You cannot specify a validator for collections in the ``admin``, + ``local``, and ``config`` databases. + + - You cannot specify a validator for ``system.*`` collections. +operation: ~ +interface: phpmethod +optional: true +--- +arg_name: option +name: validationAction +type: string +description: | + Determines whether to ``error`` on invalid documents or just ``warn`` about + the violations but allow invalid documents to be inserted. + + .. important:: + + Validation of documents only applies to those documents as determined by + the ``validationLevel``. + + .. list-table:: + :header-rows: 1 + + * - ``validationAction`` + + - Description + + * - ``"error"`` + + - **Default**. Documents must pass validation before the write occurs. + Otherwise, the write operation fails. + + * - ``"warn"`` + + - Documents do not have to pass validation. If the document fails + validation, the write operation logs the validation failure. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: validationLevel +type: string +description: | + Determines how strictly MongoDB applies the validation rules to existing + documents during an update. + + .. list-table:: + :header-rows: 1 + + * - ``validationLevel`` + + - Description + + * - ``"off"`` + + - No validation for inserts or updates. + + * - ``"strict"`` + + - **Default**. Apply validation rules to all inserts and all updates. + + * - ``"moderate"`` + + - Apply validation rules to inserts and to updates on existing *valid* + documents. Do not apply rules to updates on existing *invalid* + documents. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-param.yaml new file mode 100644 index 00000000..b6bb2dcc --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-createCollection-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-common-param.yaml + ref: $collectionName +replacement: + action: " to create" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml new file mode 100644 index 00000000..630c1bd1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml @@ -0,0 +1,13 @@ +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-drop-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml new file mode 100644 index 00000000..630c1bd1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml @@ -0,0 +1,13 @@ +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-param.yaml new file mode 100644 index 00000000..c8e0a614 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-common-param.yaml + ref: $collectionName +replacement: + action: " to drop" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-get-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-get-param.yaml new file mode 100644 index 00000000..651c85f9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-get-param.yaml @@ -0,0 +1,6 @@ +source: + file: apiargs-common-param.yaml + ref: $collectionName +replacement: + action: " to select" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml new file mode 100644 index 00000000..c8bcc2c5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml @@ -0,0 +1,15 @@ +arg_name: option +name: filter +type: array|object +description: | + A query expression to filter the list of collections. + + You can specify a query expression on the collection ``name`` and ``options``. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-listCollections-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-option.yaml new file mode 100644 index 00000000..932c1b16 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "collection" + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "collection" + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "collection" + parent: "database" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-param.yaml new file mode 100644 index 00000000..46d4e72a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectCollection-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-common-param.yaml + ref: $collectionName +replacement: + action: " to select" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-option.yaml new file mode 100644 index 00000000..294bf6b6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-option.yaml @@ -0,0 +1,46 @@ +arg_name: option +name: bucketName +type: string +description: | + The bucket name, which will be used as a prefix for the files and chunks + collections. Defaults to ``"fs"``. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: chunkSizeBytes +type: integer +description: | + The chunk size in bytes. Defaults to ``261120`` (i.e. 255 KiB). +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "bucket" + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "bucket" + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "bucket" + parent: "database" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-option.yaml new file mode 100644 index 00000000..c048182c --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "database" + parent: "original database" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "database" + parent: "original database" +--- +source: + file: apiargs-common-option.yaml + ref: typeMap +replacement: + parent: "original database" +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "database" + parent: "original database" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-param.yaml new file mode 100644 index 00000000..73ad04d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBDatabase-method-withOptions-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-option.yaml new file mode 100644 index 00000000..fbfa0dcf --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-option.yaml @@ -0,0 +1,50 @@ +arg_name: option +name: _id +type: mixed +description: | + Value to use as the file document identifier. Defaults to a new + :php:`MongoDB\\BSON\\ObjectId ` object. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: chunkSizeBytes +type: integer +description: | + The chunk size in bytes. Defaults to the bucket's ``chunkSizeBytes`` option. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: metadata +type: array|object +description: | + User data for the ``metadata`` field of the file document. If not specified, + the ``metadata`` field will not be set on the file document. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: revision +type: integer +description: | + The revision of the file to retrieve. Files with the name ``filename`` will be + differentiated by their ``uploadDate`` field. + + Revision numbers are defined as follows: + + - 0 = the original stored file + - 1 = the first revision + - 2 = the second revision + - etc... + - -2 = the second most recent revision + - -1 = the most recent revision + + Defaults to -1 (i.e. the most recent revision). +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-param.yaml new file mode 100644 index 00000000..f1d6b136 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-common-param.yaml @@ -0,0 +1,39 @@ +arg_name: param +name: $filename +type: string +description: | + The ``filename`` of the file{{action}}. +interface: phpmethod +operation: ~ +optional: false +replacement: + action: "" +--- +arg_name: param +name: $id +type: mixed +description: | + The ``_id`` of the file{{action}}. +interface: phpmethod +operation: ~ +optional: false +replacement: + action: "" +--- +arg_name: param +name: $stream +type: resource +description: | + The GridFS stream resource. +interface: phpmethod +operation: ~ +--- +arg_name: param +name: $destination +type: resource +description: | + Writable stream, to which the GridFS file's contents will be written. +interface: phpmethod +operation: ~ +optional: false +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-option.yaml new file mode 100644 index 00000000..30be1b5d --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-option.yaml @@ -0,0 +1,44 @@ +arg_name: option +name: bucketName +type: string +description: | + The bucket name, which will be used as a prefix for the files and chunks + collections. Defaults to ``"fs"``. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: chunkSizeBytes +type: integer +description: | + The chunk size in bytes. Defaults to ``261120`` (i.e. 255 KiB). +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-option.yaml + ref: readConcern +replacement: + resource: "bucket" + parent: "database" +--- +source: + file: apiargs-common-option.yaml + ref: readPreference +replacement: + resource: "bucket" + parent: "database" +--- +source: + file: apiargs-MongoDBClient-method-construct-driverOptions.yaml + ref: typeMap +--- +source: + file: apiargs-common-option.yaml + ref: writeConcern +replacement: + resource: "bucket" + parent: "database" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-param.yaml new file mode 100644 index 00000000..5ef826c1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-construct-param.yaml @@ -0,0 +1,12 @@ +source: + file: apiargs-common-param.yaml + ref: $manager +--- +source: + file: apiargs-common-param.yaml + ref: $databaseName +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-delete-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-delete-param.yaml new file mode 100644 index 00000000..7e8baa21 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-delete-param.yaml @@ -0,0 +1,6 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $id +replacement: + resource: " to delete" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStream-param.yaml new file mode 100644 index 00000000..39d48dc5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStream-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $id +replacement: + resource: " to download" +--- +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $destination +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-option.yaml new file mode 100644 index 00000000..9dc941d9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-option.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: revision +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-param.yaml new file mode 100644 index 00000000..2704877b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-downloadToStreamByName-param.yaml @@ -0,0 +1,14 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $filename +replacement: + resource: " to download" +--- +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $destination +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-find-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-find-option.yaml new file mode 100644 index 00000000..84bab2c3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-find-option.yaml @@ -0,0 +1,72 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: skip +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: limit +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: batchSize +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: comment +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: cursorType +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: readConcern +description: | + :manual:`Read concern ` to use for the operation. + Defaults to the bucket's read concern. +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: readPreference +description: | + :manual:`Read preference ` to use for the + operation. Defaults to the bucket's read preference. +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: oplogReplay +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: noCursorTimeout +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: allowPartialResults +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: typeMap +replacement: + parent: "bucket" +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: modifiers +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-findOne-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-findOne-option.yaml new file mode 100644 index 00000000..25a9dc1d --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-findOne-option.yaml @@ -0,0 +1,42 @@ +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: projection +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: sort +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: skip +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: collation +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: comment +--- +source: + file: apiargs-common-option.yaml + ref: maxTimeMS +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: readConcern +--- +source: + file: apiargs-MongoDBGridFSBucket-method-find-option.yaml + ref: readPreference +--- +source: + file: apiargs-MongoDBGridFSBucket-method-find-option.yaml + ref: typeMap +post: | + This will be used for the returned result document. +--- +source: + file: apiargs-MongoDBCollection-method-find-option.yaml + ref: modifiers +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileDocumentForStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileDocumentForStream-param.yaml new file mode 100644 index 00000000..0801cb21 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileDocumentForStream-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $stream +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileIdForStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileIdForStream-param.yaml new file mode 100644 index 00000000..0801cb21 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-getFileIdForStream-param.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $stream +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStream-param.yaml new file mode 100644 index 00000000..54e7c8c2 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStream-param.yaml @@ -0,0 +1,6 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $id +replacement: + resource: " to download" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-option.yaml new file mode 100644 index 00000000..9dc941d9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-option.yaml @@ -0,0 +1,4 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: revision +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-param.yaml new file mode 100644 index 00000000..eb8ec932 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openDownloadStreamByName-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $filename +replacement: + resource: " to download" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-option.yaml new file mode 100644 index 00000000..6c4d2ff6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-option.yaml @@ -0,0 +1,12 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: _id +--- +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: chunkSizeBytes +--- +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: metadata +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-param.yaml new file mode 100644 index 00000000..6b8efb34 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-openUploadStream-param.yaml @@ -0,0 +1,10 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $filename +replacement: + resource: " to create" +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-rename-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-rename-param.yaml new file mode 100644 index 00000000..e1b140ae --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-rename-param.yaml @@ -0,0 +1,15 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $id +replacement: + resource: " to rename" +--- +arg_name: param +name: $newFilename +type: string +description: | + The new ``filename`` value. +interface: phpmethod +operation: ~ +optional: false +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-option.yaml new file mode 100644 index 00000000..6c4d2ff6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-option.yaml @@ -0,0 +1,12 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: _id +--- +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: chunkSizeBytes +--- +source: + file: apiargs-MongoDBGridFSBucket-common-option.yaml + ref: metadata +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-param.yaml new file mode 100644 index 00000000..48fa2db4 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-MongoDBGridFSBucket-method-uploadFromStream-param.yaml @@ -0,0 +1,19 @@ +source: + file: apiargs-MongoDBGridFSBucket-common-param.yaml + ref: $filename +replacement: + resource: " to create" +--- +arg_name: param +name: $source +type: resource +description: | + Readable stream, from which the new GridFS file's contents will be read. +interface: phpmethod +operation: ~ +optional: false +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-common-option.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-common-option.yaml new file mode 100644 index 00000000..54d6bd89 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-common-option.yaml @@ -0,0 +1,64 @@ +arg_name: option +name: maxTimeMS +type: integer +description: | + The cumulative time limit in milliseconds for processing operations on the + cursor. MongoDB aborts the operation at the earliest following + :term:`interrupt point`. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: readConcern +type: :php:`MongoDB\\Driver\\ReadConcern ` +description: | + The default read concern to use for {{resource}} operations. Defaults to the + {{parent}}'s read concern. +interface: phpmethod +operation: selectCollection +optional: true +replacement: + resource: "collection" + parent: "client" +--- +arg_name: option +name: readPreference +type: :php:`MongoDB\\Driver\\ReadPreference ` +description: | + The default read preference to use for {{resource}} operations. Defaults to + the {{parent}}'s read preference. +interface: phpmethod +operation: ~ +optional: true +replacement: + resource: "collection" + parent: "client" +--- +arg_name: option +name: typeMap +type: array +description: | + The :php:`type map + ` + to apply to cursors, which determines how BSON documents are converted to PHP + values. Defaults to the {{parent}}'s type map. +interface: phpmethod +operation: ~ +optional: true +replacement: + parent: "client" +--- +arg_name: option +name: writeConcern +type: :php:`MongoDB\\Driver\\WriteConcern ` +description: | + The default write concern to use for {{resource}} operations. Defaults + to the {{parent}}'s write concern. +interface: phpmethod +operation: ~ +optional: true +replacement: + resource: "collection" + parent: "client" +... diff --git a/vendor/mongodb/mongodb/docs/includes/apiargs-common-param.yaml b/vendor/mongodb/mongodb/docs/includes/apiargs-common-param.yaml new file mode 100644 index 00000000..0f152c82 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/apiargs-common-param.yaml @@ -0,0 +1,41 @@ +arg_name: param +name: $manager +type: :php:`MongoDB\\Driver\\Manager ` +description: | + The :php:`Manager ` instance from the driver. The + manager maintains connections between the driver and your MongoDB instances. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $databaseName +type: string +description: | + The name of the database{{action}}. +interface: phpmethod +operation: ~ +optional: false +replacement: + action: "" +--- +arg_name: param +name: $collectionName +type: string +description: | + The name of the collection{{action}}. +interface: phpmethod +operation: ~ +optional: false +replacement: + action: "" +--- +arg_name: param +name: $options +type: array +description: | + An array specifying the desired options. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/vendor/mongodb/mongodb/docs/includes/extracts-bulkwriteexception.yaml b/vendor/mongodb/mongodb/docs/includes/extracts-bulkwriteexception.yaml new file mode 100644 index 00000000..f002063f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/extracts-bulkwriteexception.yaml @@ -0,0 +1,21 @@ +ref: bulkwriteexception-result +content: | + If a :php:`MongoDB\\Driver\\Exception\\BulkWriteException + ` is thrown, users should call + :php:`getWriteResult() ` and + inspect the returned :php:`MongoDB\\Driver\\WriteResult + ` object to determine the nature of the error. + + For example, a write operation may have been successfully applied to the + primary server but failed to satisfy the write concern (e.g. replication took + too long). Alternatively, a write operation may have failed outright (e.g. + unique key violation). +--- +ref: bulkwriteexception-ordered +content: | + In the case of a bulk write, the result may indicate multiple successful write + operations and/or errors. If the ``ordered`` option is ``true``, some + operations may have succeeded before the first error was encountered and the + exception thrown. If the ``ordered`` option is ``false``, multiple errors may + have been encountered. +... diff --git a/vendor/mongodb/mongodb/docs/includes/extracts-error.yaml b/vendor/mongodb/mongodb/docs/includes/extracts-error.yaml new file mode 100644 index 00000000..cfada049 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/extracts-error.yaml @@ -0,0 +1,52 @@ +ref: error-driver-bulkwriteexception +content: | + :php:`MongoDB\\Driver\\Exception\\BulkWriteException + ` for errors related to the write + operation. Users should inspect the value returned by :php:`getWriteResult() + ` to determine the nature of the + error. +--- +ref: error-driver-invalidargumentexception +content: | + :php:`MongoDB\\Driver\\Exception\\InvalidArgumentException + ` for errors related to the + parsing of parameters or options at the driver level. +--- +ref: error-driver-runtimeexception +content: | + :php:`MongoDB\\Driver\\Exception\\RuntimeException + ` for other errors at the driver + level (e.g. connection errors). +--- +ref: error-badmethodcallexception-write-result +content: | + :phpclass:`MongoDB\\Exception\\BadMethodCallException` if this method is + called and the write operation used an unacknowledged :manual:`write concern + `. +--- +ref: error-invalidargumentexception +content: | + :phpclass:`MongoDB\\Exception\\InvalidArgumentException` for errors related to + the parsing of parameters or options. +--- +ref: error-unexpectedvalueexception +content: | + :phpclass:`MongoDB\\Exception\\UnexpectedValueException` if the command + response from the server was malformed. +--- +ref: error-unsupportedexception +content: | + :phpclass:`MongoDB\\Exception\\UnsupportedException` if options are used and + not supported by the selected server (e.g. ``collation``, ``readConcern``, + ``writeConcern``). +--- +ref: error-gridfs-filenotfoundexception +content: | + :phpclass:`MongoDB\\GridFS\\Exception\\FileNotFoundException` if no file was + found for the selection criteria. +--- +ref: error-gridfs-corruptfileexception +content: | + :phpclass:`MongoDB\\GridFS\\Exception\\CorruptFileException` if the file's + metadata or chunk documents contain unexpected or invalid data. +... diff --git a/vendor/mongodb/mongodb/docs/includes/extracts-note.yaml b/vendor/mongodb/mongodb/docs/includes/extracts-note.yaml new file mode 100644 index 00000000..7790f0c3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/includes/extracts-note.yaml @@ -0,0 +1,12 @@ +ref: note-bson-comparison +content: | + When evaluating query criteria, MongoDB compares types and values according to + its own :manual:`comparison rules for BSON types + `, which differs from PHP's + :php:`comparison ` and :php:`type juggling + ` rules. When matching a special + BSON type the query criteria should use the respective :php:`BSON class + ` in the driver (e.g. use + :php:`MongoDB\\BSON\\ObjectId ` to match an + :manual:`ObjectId `). +... diff --git a/vendor/mongodb/mongodb/docs/index.txt b/vendor/mongodb/mongodb/docs/index.txt new file mode 100644 index 00000000..6c3a9740 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/index.txt @@ -0,0 +1,61 @@ +=================== +MongoDB PHP Library +=================== + +.. default-domain:: mongodb + +The |php-library| provides a high-level abstraction around the lower-level +`PHP driver `_, also known as the ``mongodb`` +extension. + +While the ``mongodb`` extension provides a limited API for executing commands, +queries, and write operations, the |php-library| implements an API similar to +that of the `legacy PHP driver `_. The +library contains abstractions for client, database, and collection objects, and +provides methods for CRUD operations and common commands such as index and +collection management. + +If you are developing a PHP application with MongoDB, you should consider using +this library, or another high-level abstraction, instead of the extension alone. + +For additional information about this library and the ``mongodb`` extension, see +the `Architecture Overview `_ +article in the extension documentation. `Derick Rethans +`_ has also written a series of blog posts entitled +*New MongoDB Drivers for PHP and HHVM*: + +- `Part One: History `_ + +- `Part Two: Architecture + `_ + +- `Part Three: Cursor Behaviour + `_ + +New to MongoDB? +--------------- + +If you are a new MongoDB user, these links should help you become more familiar +with MongoDB and introduce some of the concepts and terms you will encounter in +this documentation: + +- :manual:`Introduction to CRUD operations in MongoDB ` + +- :manual:`What is a MongoDB document? ` + +- :manual:`Dot notation for accessing document properties + ` + +- :manual:`ObjectId: MongoDB's document identifier ` + +.. class:: hidden + + .. toctree:: + :titlesonly: + + Installation + /tutorial + /upgrade + /reference + +.. /getting-started diff --git a/vendor/mongodb/mongodb/docs/pretty.js b/vendor/mongodb/mongodb/docs/pretty.js new file mode 100644 index 00000000..cd0aa1e1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/pretty.js @@ -0,0 +1,4 @@ +$(document).ready(function() { + $('pre code').parent().addClass('prettyprint well'); + prettyPrint(); +}); diff --git a/vendor/mongodb/mongodb/docs/reference.txt b/vendor/mongodb/mongodb/docs/reference.txt new file mode 100644 index 00000000..b0606bd8 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference.txt @@ -0,0 +1,17 @@ +========= +Reference +========= + +.. default-domain:: mongodb + +.. toctree:: + :titlesonly: + + /reference/bson + /reference/class/MongoDBClient + /reference/class/MongoDBDatabase + /reference/class/MongoDBCollection + /reference/class/MongoDBGridFSBucket + /reference/write-result-classes + /reference/enumeration-classes + /reference/exception-classes diff --git a/vendor/mongodb/mongodb/docs/reference/bson.txt b/vendor/mongodb/mongodb/docs/reference/bson.txt new file mode 100644 index 00000000..c366ea8a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/bson.txt @@ -0,0 +1,261 @@ +==== +BSON +==== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Overview +-------- + +MongoDB stores data records as BSON documents. BSON is a binary representation +of :term:`JSON` documents, though it contains more data types than JSON. For the +BSON spec, see `bsonspec.org `_. + +By default, the |php-library| returns BSON documents as +:phpclass:`MongoDB\\Model\\BSONDocument` objects and BSON arrays as +:phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. + +BSON Classes +------------ + +.. phpclass:: MongoDB\\Model\\BSONArray + + This class extends PHP's :php:`ArrayObject ` class. It also + implements PHP's :php:`JsonSerializable ` interface and the + driver's :php:`MongoDB\\BSON\\Serializable ` and + :php:`MongoDB\\BSON\\Unserializable ` + interfaces. + + By default, the library will deserialize BSON arrays as instances of this + class. During BSON and JSON serialization, instances of this class will + serialize as an array type (:php:`array_values() ` is used + internally to numerically reindex the array). + +.. phpclass:: MongoDB\\Model\\BSONDocument + + This class extends PHP's :php:`ArrayObject ` class. It also + implements PHP's :php:`JsonSerializable ` interface and the + driver's :php:`MongoDB\\BSON\\Serializable ` and + :php:`MongoDB\\BSON\\Unserializable ` + interfaces. + + By default, the library will deserialize BSON documents as instances of this + class. During BSON and JSON serialization, instances of this class will + serialize as a document type (:php:`object casting + ` is used internally). + +.. _php-type-map: + +Type Maps +--------- + +Most methods that read data from MongoDB support a ``typeMap`` option, which +allows control over how BSON is converted to PHP. Additionally, +the :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`MongoDB\\Collection` classes accept a ``typeMap`` option, which can +be used to specify a default type map to apply to any supporting methods and +selected classes (e.g. :phpmethod:`MongoDB\\Client::selectDatabase()`). + +The :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`MongoDB\\Collection` classes use the following type map by +default: + +.. code-block:: php + + [ + 'array' => 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ] + +The type map above will convert BSON documents and arrays to +:phpclass:`MongoDB\\Model\\BSONDocument` and +:phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. The ``root`` and +``document`` keys are used to distinguish the top-level BSON document from +embedded documents, respectively. + +A type map may specify any class that implements +:php:`MongoDB\\BSON\\Unserializable ` as well as +``"array"``, ``"stdClass``", and ``"object"`` (``"stdClass``" and ``"object"`` +are aliases of one another). + +.. seealso:: :php:`Deserialization from BSON ` in the PHP manual + +``Persistable`` Classes +----------------------- + +The driver's :php:`persistence specification ` outlines how +classes implementing its :php:`MongoDB\\BSON\\Persistable +` interface are serialized to and deserialized from +BSON. The :php:`Persistable ` interface is analogous +to PHP's :php:`Serializable interface `. + +The driver automatically handles serialization and deserialization for classes +implementing the :php:`Persistable ` interface without +requiring the use of the ``typeMap`` option. This is done by encoding the name +of the PHP class in a special property within the BSON document. + +.. note:: + + When deserializing a PHP variable from BSON, the encoded class name of a + :php:`Persistable ` object will override any class + specified in the type map, but it will not override ``"array"`` and + ``"stdClass"`` or ``"object"``. This is discussed in the + :php:`persistence specification ` but it bears + repeating. + +Consider the following class definition: + +.. code-block:: php + + id = new MongoDB\BSON\ObjectId; + $this->name = (string) $name; + $this->createdAt = new MongoDB\BSON\UTCDateTime; + } + + function bsonSerialize() + { + return [ + '_id' => $this->id, + 'name' => $this->name, + 'createdAt' => $this->createdAt, + ]; + } + + function bsonUnserialize(array $data) + { + $this->id = $data['_id']; + $this->name = $data['name']; + $this->createdAt = $data['createdAt']; + } + } + +The following example constructs a ``Person`` object, inserts it into the +database, and reads it back as an object of the same type: + +.. code-block:: php + + test->persons; + + $result = $collection->insertOne(new Person('Bob')); + + $person = $collection->findOne(['_id' => $result->getInsertedId()]); + + var_dump($person); + +The output would then resemble: + +.. code-block:: none + + object(Person)#18 (3) { + ["id":"Person":private]=> + object(MongoDB\BSON\ObjectId)#15 (1) { + ["oid"]=> + string(24) "56fad2c36118fd2e9820cfc1" + } + ["name":"Person":private]=> + string(3) "Bob" + ["createdAt":"Person":private]=> + object(MongoDB\BSON\UTCDateTime)#17 (1) { + ["milliseconds"]=> + int(1459278531218) + } + } + +The same document in the MongoDB shell might display as: + +.. code-block:: js + + { + "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), + "__pclass" : BinData(128,"UGVyc29u"), + "name" : "Bob", + "createdAt" : ISODate("2016-03-29T19:08:51.218Z") + } + +.. note:: + + :php:`MongoDB\\BSON\\Persistable ` may only be used + for root and embedded BSON documents. It may not be used for BSON arrays. + +Emulating the Legacy Driver +--------------------------- + +The legacy :php:`mongo extension ` returned both BSON documents and +arrays as PHP arrays. While PHP arrays are convenient to work with, this +behavior was problematic: + +- Different BSON types could deserialize to the same PHP value (e.g. + ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the + original BSON type. + +- Numerically-indexed PHP arrays would be serialized as BSON documents if there + was a gap in their key sequence. Such gaps were easily caused by unsetting a + key to remove an element and forgetting to numerically reindex the array. + +The |php-library|'s :phpclass:`BSONDocument ` and +:phpclass:`BSONArray ` classes address these concerns +by preserving the BSON type information during serialization and +deserialization; however, some users may still prefer the legacy behavior. If +desired, you can use the ``typeMap`` option to have the library return +everything as a PHP array: + +.. code-block:: php + + [ + 'array' => 'array', + 'document' => 'array', + 'root' => 'array', + ], + ] + ); + + $document = $client->test->zips->findOne(['_id' => '94301']); + + var_dump($document); + +The above example would output something similar to: + +.. code-block:: php + + array(5) { + ["_id"]=> + string(5) "94301" + ["city"]=> + string(9) "PALO ALTO" + ["loc"]=> + array(2) { + [0]=> + float(-122.149685) + [1]=> + float(37.444324) + } + ["pop"]=> + int(15965) + ["state"]=> + string(2) "CA" + } diff --git a/vendor/mongodb/mongodb/docs/reference/class/MongoDBClient.txt b/vendor/mongodb/mongodb/docs/reference/class/MongoDBClient.txt new file mode 100644 index 00000000..2bf05682 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/class/MongoDBClient.txt @@ -0,0 +1,41 @@ +===================== +MongoDB\\Client Class +===================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpclass:: MongoDB\\Client + + This class serves as an entry point for the |php-library|. It is the + preferred class for connecting to a MongoDB server or cluster of servers and + acts as a gateway for accessing individual databases and collections. + :phpclass:`MongoDB\\Client` is analogous to the driver's + :php:`MongoDB\\Driver\\Manager ` class, which it + `composes `_. + +Methods +------- + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBClient__construct + /reference/method/MongoDBClient__get + /reference/method/MongoDBClient-dropDatabase + /reference/method/MongoDBClient-getManager + /reference/method/MongoDBClient-getReadConcern + /reference/method/MongoDBClient-getReadPreference + /reference/method/MongoDBClient-getTypeMap + /reference/method/MongoDBClient-getWriteConcern + /reference/method/MongoDBClient-listDatabases + /reference/method/MongoDBClient-selectCollection + /reference/method/MongoDBClient-selectDatabase diff --git a/vendor/mongodb/mongodb/docs/reference/class/MongoDBCollection.txt b/vendor/mongodb/mongodb/docs/reference/class/MongoDBCollection.txt new file mode 100644 index 00000000..2fe978cd --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/class/MongoDBCollection.txt @@ -0,0 +1,94 @@ +========================= +MongoDB\\Collection Class +========================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpclass:: MongoDB\\Collection + + Provides methods for common operations on collections and documents, + including CRUD operations and index management. + + You can construct collections directly using the driver's + :php:`MongoDB\\Driver\\Manager ` class or + select a collection from the library's :phpclass:`MongoDB\\Client` or + :phpclass:`MongoDB\\Database` classes. A collection may also be cloned from + an existing :phpclass:`MongoDB\\Collection` object via the + :phpmethod:`withOptions() ` method. + + :phpclass:`MongoDB\\Collection` supports the :php:`readConcern + `, :php:`readPreference + `, :php:`typeMap + `, + and :php:`writeConcern ` options. If you omit an + option, the collection inherits the value from the :php:`Manager + ` constructor argument or the :phpclass:`Client + ` or :phpclass:`Database ` object used to + select the collection. + + Operations within the :phpclass:`MongoDB\\Collection` class inherit the + collection's options. + +Type Map Limitations +-------------------- + + The :manual:`aggregate ` (when not using a + cursor), :manual:`distinct `, and + :manual:`findAndModify ` helpers do not + support a ``typeMap`` option due to a driver limitation. The + :phpmethod:`aggregate() `, + :phpmethod:`distinct() `, + :phpmethod:`findOneAndReplace() `, + :phpmethod:`findOneAndUpdate() `, and + :phpmethod:`findOneAndDelete() ` + methods return BSON documents as `stdClass` objects and BSON arrays as + arrays. + +Methods +------- + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBCollection__construct + /reference/method/MongoDBCollection-aggregate + /reference/method/MongoDBCollection-bulkWrite + /reference/method/MongoDBCollection-count + /reference/method/MongoDBCollection-createIndex + /reference/method/MongoDBCollection-createIndexes + /reference/method/MongoDBCollection-deleteMany + /reference/method/MongoDBCollection-deleteOne + /reference/method/MongoDBCollection-distinct + /reference/method/MongoDBCollection-drop + /reference/method/MongoDBCollection-dropIndex + /reference/method/MongoDBCollection-dropIndexes + /reference/method/MongoDBCollection-find + /reference/method/MongoDBCollection-findOne + /reference/method/MongoDBCollection-findOneAndDelete + /reference/method/MongoDBCollection-findOneAndReplace + /reference/method/MongoDBCollection-findOneAndUpdate + /reference/method/MongoDBCollection-getCollectionName + /reference/method/MongoDBCollection-getDatabaseName + /reference/method/MongoDBCollection-getManager + /reference/method/MongoDBCollection-getNamespace + /reference/method/MongoDBCollection-getReadConcern + /reference/method/MongoDBCollection-getReadPreference + /reference/method/MongoDBCollection-getTypeMap + /reference/method/MongoDBCollection-getWriteConcern + /reference/method/MongoDBCollection-insertMany + /reference/method/MongoDBCollection-insertOne + /reference/method/MongoDBCollection-listIndexes + /reference/method/MongoDBCollection-mapReduce + /reference/method/MongoDBCollection-replaceOne + /reference/method/MongoDBCollection-updateMany + /reference/method/MongoDBCollection-updateOne + /reference/method/MongoDBCollection-withOptions diff --git a/vendor/mongodb/mongodb/docs/reference/class/MongoDBDatabase.txt b/vendor/mongodb/mongodb/docs/reference/class/MongoDBDatabase.txt new file mode 100644 index 00000000..1cc6f858 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/class/MongoDBDatabase.txt @@ -0,0 +1,62 @@ +======================= +MongoDB\\Database Class +======================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpclass:: MongoDB\\Database + + Provides methods for common operations on a database, such as executing + database commands and managing collections. + + You can construct a database directly using the driver's + :php:`MongoDB\\Driver\\Manager ` class or + select a database from the library's :phpclass:`MongoDB\\Client` class. A + database may also be cloned from an existing :phpclass:`MongoDB\\Database` + object via the :phpmethod:`withOptions() ` + method. + + :phpclass:`MongoDB\\Database` supports the :php:`readConcern + `, :php:`readPreference + `, :php:`typeMap + `, + and :php:`writeConcern ` options. If you omit an + option, the database inherits the value from the :php:`Manager + ` constructor argument or the :phpclass:`Client + ` object used to select the database. + + Operations within the :phpclass:`MongoDB\\Database` class inherit the + Database's options. + +Methods +------- + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBDatabase__construct + /reference/method/MongoDBDatabase__get + /reference/method/MongoDBDatabase-command + /reference/method/MongoDBDatabase-createCollection + /reference/method/MongoDBDatabase-drop + /reference/method/MongoDBDatabase-dropCollection + /reference/method/MongoDBDatabase-getDatabaseName + /reference/method/MongoDBDatabase-getManager + /reference/method/MongoDBDatabase-getReadConcern + /reference/method/MongoDBDatabase-getReadPreference + /reference/method/MongoDBDatabase-getTypeMap + /reference/method/MongoDBDatabase-getWriteConcern + /reference/method/MongoDBDatabase-listCollections + /reference/method/MongoDBDatabase-selectCollection + /reference/method/MongoDBDatabase-selectGridFSBucket + /reference/method/MongoDBDatabase-withOptions + diff --git a/vendor/mongodb/mongodb/docs/reference/class/MongoDBGridFSBucket.txt b/vendor/mongodb/mongodb/docs/reference/class/MongoDBGridFSBucket.txt new file mode 100644 index 00000000..cea877f4 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/class/MongoDBGridFSBucket.txt @@ -0,0 +1,59 @@ +============================= +MongoDB\\GridFS\\Bucket Class +============================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpclass:: MongoDB\\GridFS\\Bucket + + :manual:`GridFS ` is a specification for storing and retrieving + files in MongoDB. GridFS uses two collections to store files. One collection + stores the file chunks (e.g. ``fs.chunks``), and the other stores file + metadata (e.g. ``fs.files``). The :phpclass:`MongoDB\\GridFS\\Bucket` class + provides an interface around these collections for working with the files as + PHP :php:`Streams `. + + You can construct a GridFS bucket using the driver's + :php:`Manager ` class, or select a bucket from + the library's :phpclass:`MongoDB\\Database` class via the + :phpmethod:`selectGridFSBucket() ` + method. + +Methods +------- + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBGridFSBucket__construct + /reference/method/MongoDBGridFSBucket-delete + /reference/method/MongoDBGridFSBucket-downloadToStream + /reference/method/MongoDBGridFSBucket-downloadToStreamByName + /reference/method/MongoDBGridFSBucket-drop + /reference/method/MongoDBGridFSBucket-find + /reference/method/MongoDBGridFSBucket-findOne + /reference/method/MongoDBGridFSBucket-getBucketName + /reference/method/MongoDBGridFSBucket-getChunksCollection + /reference/method/MongoDBGridFSBucket-getChunkSizeBytes + /reference/method/MongoDBGridFSBucket-getDatabaseName + /reference/method/MongoDBGridFSBucket-getFileDocumentForStream + /reference/method/MongoDBGridFSBucket-getFileIdForStream + /reference/method/MongoDBGridFSBucket-getFilesCollection + /reference/method/MongoDBGridFSBucket-getReadConcern + /reference/method/MongoDBGridFSBucket-getReadPreference + /reference/method/MongoDBGridFSBucket-getTypeMap + /reference/method/MongoDBGridFSBucket-getWriteConcern + /reference/method/MongoDBGridFSBucket-openDownloadStream + /reference/method/MongoDBGridFSBucket-openDownloadStreamByName + /reference/method/MongoDBGridFSBucket-openUploadStream + /reference/method/MongoDBGridFSBucket-rename + /reference/method/MongoDBGridFSBucket-uploadFromStream diff --git a/vendor/mongodb/mongodb/docs/reference/enumeration-classes.txt b/vendor/mongodb/mongodb/docs/reference/enumeration-classes.txt new file mode 100644 index 00000000..045091ac --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/enumeration-classes.txt @@ -0,0 +1,161 @@ +=================== +Enumeration Classes +=================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +MongoDB\\Model\\CollectionInfo +------------------------------ + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\Model\\CollectionInfo + + This class models information about a collection. Instances of this class are + returned by traversing a :phpclass:`MongoDB\\Model\\CollectionInfoIterator`, + which is returned by :phpmethod:`MongoDB\\Database::listCollections()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBModelCollectionInfo-getCappedMax + /reference/method/MongoDBModelCollectionInfo-getCappedSize + /reference/method/MongoDBModelCollectionInfo-getName + /reference/method/MongoDBModelCollectionInfo-getOptions + /reference/method/MongoDBModelCollectionInfo-isCapped + +---- + +MongoDB\\Model\\CollectionInfoIterator +-------------------------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\Model\\CollectionInfoIterator + + This interface extends PHP's :php:`Iterator ` + interface. An instance of this interface is returned by + :phpmethod:`MongoDB\\Database::listCollections()`. + +Methods +~~~~~~~ + +This interface adds no new methods to :php:`Iterator +`, but specifies that :php:`current() +` will return an instance of +:phpclass:`MongoDB\\Model\\CollectionInfo`. + +---- + +MongoDB\\Model\\DatabaseInfo +---------------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\Model\\DatabaseInfo + + This class models information about a database. Instances of this class are + returned by traversing a :phpclass:`MongoDB\\Model\\DatabaseInfoIterator`, + which is returned by :phpmethod:`MongoDB\\Client::listDatabases()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBModelDatabaseInfo-getName + /reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk + /reference/method/MongoDBModelDatabaseInfo-isEmpty + +---- + +MongoDB\\Model\\DatabaseInfoIterator +------------------------------------ + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\Model\\DatabaseInfoIterator + + This interface extends PHP's :php:`Iterator ` + interface. An instance of this interface is returned by + :phpmethod:`MongoDB\\Client::listDatabases()`. + +Methods +~~~~~~~ + +This interface adds no new methods to :php:`Iterator +`, but specifies that :php:`current() +` will return an instance of +:phpclass:`MongoDB\\Model\\DatabaseInfo`. + +---- + +MongoDB\\Model\\IndexInfo +------------------------- + +.. phpclass:: MongoDB\\Model\\IndexInfo + + This class models information about an index. Instances of this class are + returned by traversing a :phpclass:`MongoDB\\Model\\IndexInfoIterator`, + which is returned by :phpmethod:`MongoDB\\Collection::listIndexes()`. + + This class implements PHP's :php:`ArrayAccess ` interface. This + provides a mechanism for accessing index fields for which there exists no + helper method. :php`isset() ` may be used to check for the existence + of a field before accessing it with ``[]``. + + .. note:: + + The :phpclass:`MongoDB\\Model\\IndexInfo` class is immutable. Attempting + to modify it via the :php:`ArrayAccess ` interface will + result in a :phpclass:`MongoDB\\Exception\\BadMethodCallException`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBModelIndexInfo-getKey + /reference/method/MongoDBModelIndexInfo-getName + /reference/method/MongoDBModelIndexInfo-getNamespace + /reference/method/MongoDBModelIndexInfo-getVersion + /reference/method/MongoDBModelIndexInfo-isSparse + /reference/method/MongoDBModelIndexInfo-isTtl + /reference/method/MongoDBModelIndexInfo-isUnique + +---- + +MongoDB\\Model\\IndexInfoIterator +--------------------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\Model\\IndexInfoIterator + + This interface extends PHP's :php:`Iterator ` + interface. An instance of this interface is returned by + :phpmethod:`MongoDB\\Collection::listIndexes()`. + +Methods +~~~~~~~ + +This interface adds no new methods to :php:`Iterator +`, but specifies that :php:`current() +` will return an instance of +:phpclass:`MongoDB\\Model\\IndexInfo`. diff --git a/vendor/mongodb/mongodb/docs/reference/exception-classes.txt b/vendor/mongodb/mongodb/docs/reference/exception-classes.txt new file mode 100644 index 00000000..289e4ffa --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/exception-classes.txt @@ -0,0 +1,140 @@ +================= +Exception Classes +================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +MongoDB\\Exception\\BadMethodCallException +------------------------------------------ + +.. phpclass:: MongoDB\\Exception\\BadMethodCallException + + This exception is thrown when an unsupported method is invoked on an object. + + For example, using an unacknowledged write concern with + :phpmethod:`MongoDB\\Collection::insertMany()` will return a + :phpclass:`MongoDB\\InsertManyResult` object. It is a logical error to call + :phpmethod:`MongoDB\\InsertManyResult::getInsertedCount()`, since the number + of inserted documents can only be determined from the response of an + acknowledged write operation. + + This class extends PHP's :php:`BadMethodCallException + ` class and implements the library's + :phpclass:`Exception ` interface. + +---- + +MongoDB\\Exception\\InvalidArgumentException +-------------------------------------------- + +.. phpclass:: MongoDB\\Exception\\InvalidArgumentException + + Thrown for errors related to the parsing of parameters or options within the + library. + + This class extends the driver's :php:`InvalidArgumentException + ` class and implements the + library's :phpclass:`Exception ` interface. + +---- + +MongoDB\\Exception\\UnexpectedValueException +-------------------------------------------- + +.. phpclass:: MongoDB\\Exception\\UnexpectedValueException + + This exception is thrown when a command response from the server is + malformed or not what the library expected. This exception means that an + assertion in some operation, which abstracts a database command, has failed. + It may indicate a corrupted BSON response or bug in the server, driver, or + library. + + This class extends the driver's :php:`UnexpectedValueException + ` class and implements the + library's :phpclass:`Exception ` interface. + +---- + +MongoDB\\Exception\\UnsupportedException +---------------------------------------- + +.. phpclass:: MongoDB\\Exception\\UnsupportedException + + This exception is thrown if an option is used and not supported by the + selected server. It is used sparingly in cases where silently ignoring the + unsupported option might otherwise lead to unexpected behavior. + + For example, the ``collation`` option for + :phpmethod:`MongoDB\\Collection::deleteOne()` is only supported by + MongoDB 3.4+. Since collation determines how a document is matched, silently + ignoring the option for an older server version could result in an + unintended document being deleted. + + This class extends the library's :phpclass:`RuntimeException + ` class. + + .. note:: + + Unlike :phpclass:`InvalidArgumentException + `, which may be thrown when + an operation's parameters and options are parsed during construction, the + selected server is not known until an operation is executed. + +---- + +MongoDB\\GridFS\\Exception\\CorruptFileException +------------------------------------------------ + +.. phpclass:: MongoDB\\GridFS\\Exception\\CorruptFileException + + This exception is thrown if a GridFS file's metadata or chunk documents + contain unexpected or invalid data. + + When selecting a GridFS file, this may be thrown if a metadata field has an + incorrect type or its value is out of range (e.g. negative ``length``). When + reading a GridFS file, this may be thrown if a chunk's index is out of + sequence or its binary data's length out of range. + + This class extends the library's :phpclass:`RuntimeException + ` class. + +---- + +MongoDB\\GridFS\\Exception\\FileNotFoundException +------------------------------------------------- + +.. phpclass:: MongoDB\\GridFS\\Exception\\FileNotFoundException + + This exception is thrown if no GridFS file was found for the selection + criteria (e.g. ``id``, ``filename``). + + This class extends the library's :phpclass:`RuntimeException + ` class. + +---- + +MongoDB\\Exception\\Exception +----------------------------- + +.. phpclass:: MongoDB\\Exception\\Exception + + This interface extends the driver's :php:`Exception + ` interface and is implemented by all + exception classes within the library. + +---- + +MongoDB\\Exception\\RuntimeException +------------------------------------ + +.. phpclass:: MongoDB\\Exception\\RuntimeException + + This class extends the driver's :php:`RuntimeException + ` class, which in turn extends + PHP's :php:`RuntimeException ` class. diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getDeletedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getDeletedCount.txt new file mode 100644 index 00000000..d0501d3f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getDeletedCount.txt @@ -0,0 +1,42 @@ +=========================================== +MongoDB\\BulkWriteResult::getDeletedCount() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getDeletedCount() + + Return the total number of documents that were deleted by all delete + operations in the bulk write. + + .. code-block:: php + + function getDeletedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The total number of documents that were deleted by all delete operations in the +bulk write. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getDeletedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedCount.txt new file mode 100644 index 00000000..6eb1b5de --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedCount.txt @@ -0,0 +1,42 @@ +============================================ +MongoDB\\BulkWriteResult::getInsertedCount() +============================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getInsertedCount() + + Return the total number of documents that were inserted by all insert + operations in the bulk write. + + .. code-block:: php + + function getInsertedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The total number of documents that were inserted by all insert operations in the +bulk write. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getInsertedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedIds.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedIds.txt new file mode 100644 index 00000000..bcbcd536 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getInsertedIds.txt @@ -0,0 +1,38 @@ +========================================== +MongoDB\\BulkWriteResult::getInsertedIds() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getInsertedIds() + + Return a map of IDs (i.e. ``_id`` field values) for documents that were + inserted by all insert operations in the bulk write. + + .. code-block:: php + + function getInsertedIds(): array + + Since IDs are created by the driver, this method may be called irrespective + of whether the write was acknowledged. + +Return Values +------------- + +A map of IDs (i.e. ``_id`` field values) for documents that were inserted by all +insert operations in the bulk write. + +The index of each ID in the map corresponds to each document's position in the +bulk operation. If a document had an ID prior to inserting (i.e. the driver did +not generate an ID), the index will contain its ``_id`` field value. Any +driver-generated ID will be a :php:`MongoDB\\BSON\\ObjectId +` instance. diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getMatchedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getMatchedCount.txt new file mode 100644 index 00000000..af1ad98f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getMatchedCount.txt @@ -0,0 +1,51 @@ +=========================================== +MongoDB\\BulkWriteResult::getMatchedCount() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getMatchedCount() + + Return the total number of documents that were matched by all update and + replace operations in the bulk write. + + .. code-block:: php + + function getMatchedCount(): integer + + This method should only be called if the write was acknowledged. + + .. note:: + + If an update/replace operation results in no change to the document + (e.g. setting the value of a field to its current value), the matched + count may be greater than the value returned by + :phpmethod:`getModifiedCount() + `. + +Return Values +------------- + +The total number of documents that were matched by all update and replace +operations in the bulk write. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\BulkWriteResult::getModifiedCount()` +- :php:`MongoDB\\Driver\\WriteResult::getMatchedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getModifiedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getModifiedCount.txt new file mode 100644 index 00000000..674a03cf --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getModifiedCount.txt @@ -0,0 +1,54 @@ +============================================ +MongoDB\\BulkWriteResult::getModifiedCount() +============================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getModifiedCount() + + Return the total number of documents that were modified by all update and + replace operations in the bulk write. + + .. code-block:: php + + function getModifiedCount(): integer|null + + This method should only be called if the write was acknowledged. + + .. note:: + + If an update/replace operation results in no change to the document + (e.g. setting the value of a field to its current value), the modified + count may be less than the value returned by :phpmethod:`getMatchedCount() + `. + +Return Values +------------- + +The total number of documents that were modified by all update and replace +operations in the bulk write. + +The modified count is not available on versions of MongoDB before 2.6, which +used the legacy wire protocol version (i.e. ``OP_UPDATE``). If this is the case, +the modified count will be ``null``. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\BulkWriteResult::getMatchedCount()` +- :php:`MongoDB\\Driver\\WriteResult::getModifiedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedCount.txt new file mode 100644 index 00000000..1f0dff2b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedCount.txt @@ -0,0 +1,42 @@ +============================================ +MongoDB\\BulkWriteResult::getUpsertedCount() +============================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getUpsertedCount() + + Return the total number of documents that were upserted by all update and + replace operations in the bulk write. + + .. code-block:: php + + function getUpsertedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The total number of documents that were upserted by all update and replace +operations in the bulk write. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getUpsertedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedIds.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedIds.txt new file mode 100644 index 00000000..6abad98f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-getUpsertedIds.txt @@ -0,0 +1,46 @@ +========================================== +MongoDB\\BulkWriteResult::getUpsertedIds() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::getUpsertedIds() + + Return a map of IDs (i.e. ``_id`` field values) for documents that were + upserted by all update and replace operations in the bulk write. + + .. code-block:: php + + function getUpsertedIds(): array + +Return Values +------------- + +A map of IDs (i.e. ``_id`` field values) for documents that were upserted by all +update and replace operations in the bulk write. + +The index of each ID in the map corresponds to each document's position in the +bulk operation. If a document had an ID prior to upserting (i.e. the server did +not generate an ID), the index will contain its ``_id`` field value. Any +server-generated ID will be a :php:`MongoDB\\BSON\\ObjectId +` instance. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getUpsertedIds() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-isAcknowledged.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-isAcknowledged.txt new file mode 100644 index 00000000..1a857caa --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBBulkWriteResult-isAcknowledged.txt @@ -0,0 +1,34 @@ +========================================== +MongoDB\\BulkWriteResult::isAcknowledged() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\BulkWriteResult::isAcknowledged() + + Return whether the write was acknowledged. + + .. code-block:: php + + function isAcknowledged(): boolean + +Return Values +------------- + +A boolean indicating whether the write was acknowledged. + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::isAcknowledged() + ` +- :manual:`Write Concern ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-dropDatabase.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-dropDatabase.txt new file mode 100644 index 00000000..ccb303ff --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-dropDatabase.txt @@ -0,0 +1,78 @@ +=============================== +MongoDB\\Client::dropDatabase() +=============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::dropDatabase() + + Drop a database on the server. + + .. code-block:: php + + function dropDatabase($databaseName, array $options []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-dropDatabase-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBClient-method-dropDatabase-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`dropDatabase +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example drops the ``test`` database: + +.. code-block:: php + + dropDatabase('test'); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["dropped"]=> + string(4) "test" + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::drop()` +- :manual:`dropDatabase ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getManager.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getManager.txt new file mode 100644 index 00000000..c320595d --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getManager.txt @@ -0,0 +1,35 @@ +============================= +MongoDB\\Client::getManager() +============================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::getManager() + + Accessor for the + :php:`MongoDB\\Driver\\Manager ` used by this + :phpclass:`Client `. + + .. code-block:: php + + function getManager(): MongoDB\Manager + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Manager ` object. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::getManager()` +- :phpmethod:`MongoDB\\Database::getManager()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadConcern.txt new file mode 100644 index 00000000..b7c4c60b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadConcern.txt @@ -0,0 +1,58 @@ +================================= +MongoDB\\Client::getReadConcern() +================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::getReadConcern() + + Returns the read concern for this client. + + .. code-block:: php + + function getReadConcern(): MongoDB\Driver\ReadConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadConcern ` object. + +Example +------- + +.. code-block:: php + + 'majority', + ]); + + var_dump($client->getReadConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadConcern)#5 (1) { + ["level"]=> + string(8) "majority" + } + +See Also +-------- + +- :manual:`Read Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\ReadConcern::isDefault() ` +- :phpmethod:`MongoDB\\Collection::getReadConcern()` +- :phpmethod:`MongoDB\\Database::getReadConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadPreference.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadPreference.txt new file mode 100644 index 00000000..96d8eec5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getReadPreference.txt @@ -0,0 +1,58 @@ +==================================== +MongoDB\\Client::getReadPreference() +==================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::getReadPreference() + + Returns the read preference for this client. + + .. code-block:: php + + function getReadPreference(): MongoDB\Driver\ReadPreference + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadPreference ` +object. + +Example +------- + +.. code-block:: php + + 'primaryPreferred', + ]); + + var_dump($client->getReadPreference()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadPreference)#5 (1) { + ["mode"]=> + string(16) "primaryPreferred" + } + +See Also +-------- + +- :manual:`Read Preference ` in the MongoDB manual +- :phpmethod:`MongoDB\\Collection::getReadPreference()` +- :phpmethod:`MongoDB\\Database::getReadPreference()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadPreference()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getTypeMap.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getTypeMap.txt new file mode 100644 index 00000000..04697f33 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getTypeMap.txt @@ -0,0 +1,65 @@ +============================= +MongoDB\\Client::getTypeMap() +============================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::getTypeMap() + + Returns the type map for this client. + + .. code-block:: php + + function getTypeMap(): array + +Return Values +------------- + +A :ref:`type map ` array. + +Example +------- + +.. code-block:: php + + [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ]); + + var_dump($client->getTypeMap()); + +The output would then resemble:: + + array(3) { + ["root"]=> + string(5) "array" + ["document"]=> + string(5) "array" + ["array"]=> + string(5) "array" + } + +See Also +-------- + +- :doc:`/reference/bson` +- :phpmethod:`MongoDB\\Collection::getTypeMap()` +- :phpmethod:`MongoDB\\Database::getTypeMap()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getTypeMap()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getWriteConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getWriteConcern.txt new file mode 100644 index 00000000..b779aae9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-getWriteConcern.txt @@ -0,0 +1,59 @@ +================================== +MongoDB\\Client::getWriteConcern() +================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::getWriteConcern() + + Returns the write concern for this client. + + .. code-block:: php + + function getWriteConcern(): MongoDB\Driver\WriteConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\WriteConcern ` +object. + +Example +------- + +.. code-block:: php + + true, + ]); + + var_dump($client->getWriteConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\WriteConcern)#4 (1) { + ["j"]=> + bool(true) + } + +See Also +-------- + +- :manual:`Write Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\WriteConcern::isDefault() ` +- :phpmethod:`MongoDB\\Collection::getWriteConcern()` +- :phpmethod:`MongoDB\\Database::getWriteConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getWriteConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-listDatabases.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-listDatabases.txt new file mode 100644 index 00000000..876a3f0e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-listDatabases.txt @@ -0,0 +1,84 @@ +================================ +MongoDB\\Client::listDatabases() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::listDatabases() + + Returns information for all databases on the server. + + .. code-block:: php + + function listDatabases(array $options = []): MongoDB\Model\DatabaseInfoIterator + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-listDatabases-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBClient-method-listDatabases-option.rst + +Return Values +------------- + +A traversable :phpclass:`MongoDB\\Model\\DatabaseInfoIterator`, which contains +a :phpclass:`MongoDB\\Model\\DatabaseInfo` object for each database on the +server. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example lists all databases on the server: + +.. code-block:: php + + listDatabases() as $databaseInfo) { + var_dump($databaseInfo); + } + +The output would then resemble:: + + object(MongoDB\Model\DatabaseInfo)#4 (3) { + ["name"]=> + string(5) "local" + ["sizeOnDisk"]=> + float(65536) + ["empty"]=> + bool(false) + } + object(MongoDB\Model\DatabaseInfo)#7 (3) { + ["name"]=> + string(4) "test" + ["sizeOnDisk"]=> + float(32768) + ["empty"]=> + bool(false) + } + +See Also +-------- + +- :manual:`listDatabases ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectCollection.txt new file mode 100644 index 00000000..6ce12df7 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectCollection.txt @@ -0,0 +1,83 @@ +=================================== +MongoDB\\Client::selectCollection() +=================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::selectCollection() + + Selects a collection on the server. + + .. code-block:: php + + function selectCollection($databaseName, $collectionName, array $options = []): MongoDB\Collection + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-selectCollection-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBClient-method-selectCollection-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +The selected collection inherits options such as read preference and type +mapping from the :phpclass:`Client ` object. Options may be +overridden via the ``$options`` parameter. + +Example +------- + +The following example selects the ``users`` collection in the ``test`` database: + +.. code-block:: php + + selectCollection('test', 'users'); + +The following example selects the ``users`` collection in the ``test`` database +with a custom read preference: + +.. code-block:: php + + selectCollection( + 'test', + 'users', + [ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ] + ); + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::__construct()` +- :phpmethod:`MongoDB\\Database::selectCollection()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectDatabase.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectDatabase.txt new file mode 100644 index 00000000..10dc4d8a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient-selectDatabase.txt @@ -0,0 +1,82 @@ +================================= +MongoDB\\Client::selectDatabase() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::selectDatabase() + + Selects a database on the server. + + .. code-block:: php + + function selectDatabase($databaseName, array $options = []): MongoDB\Database + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-selectDatabase-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBClient-method-selectDatabase-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Database` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +The selected database inherits options such as read preference and type mapping +from the :phpclass:`Client ` object. Options may be overridden +via the ``$options`` parameter. + +Example +------- + +The following example selects the ``test`` database: + +.. code-block:: php + + selectDatabase('test'); + +The following examples selects the ``test`` database with a custom read +preference: + +.. code-block:: php + + selectDatabase( + 'test', + [ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ] + ); + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::__get()` +- :phpmethod:`MongoDB\\Database::__construct()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__construct.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__construct.txt new file mode 100644 index 00000000..ad864d18 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__construct.txt @@ -0,0 +1,143 @@ +============================== +MongoDB\\Client::__construct() +============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::__construct() + + Constructs a new :phpclass:`Client ` instance. + + .. code-block:: php + + function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) + + This constructor has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-construct-param.rst + + The ``$driverOptions`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBClient-method-construct-driverOptions.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +A :php:`MongoDB\\Driver\\Manager ` is constructed +internally. Per the `Server Discovery and Monitoring +`_ +specification, :php:`MongoDB\\Driver\\Manager::__construct() +` performs no I/O. Connections will be +initialized on demand, when the first operation is executed. + +Examples +-------- + +Connecting to a Replica Set +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you do not specify a ``$uri`` value, the driver connects to a standalone +:program:`mongod` on ``127.0.0.1`` via port ``27017``. The following example +demonstrates how to connect to a replica set with a custom read preference: + +.. code-block:: php + + 'secondaryPreferred', + ] + ); + +Connecting with SSL and Authentication +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example demonstrates how to connect to a MongoDB replica set with +SSL and authentication, as is used for `MongoDB Atlas +`_: + +.. code-block:: php + + 'myUsername', + 'password' => 'myPassword', + 'ssl' => true, + 'replicaSet' => 'myReplicaSet', + 'authSource' => 'admin', + ], + ); + +The driver supports additional :php:`SSL options +`, +which may be specified in the constructor's ``$driverOptions`` parameter. Those +options are covered in the :php:`MongoDB\\Driver\\Manager::__construct() +` documentation. + +Specifying a Custom Type Map +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, the |php-library| deserializes BSON documents and arrays +as :phpclass:`MongoDB\\Model\\BSONDocument` and +:phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. The following +example demonstrates how to have the library unserialize everything as a PHP +array, as was done in the legacy :php:`mongo extension `. + +.. code-block:: php + + [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ] + ); + +See Also +-------- + +- :php:`MongoDB\\Driver\\Manager::__construct() + ` +- :manual:`Connection String URI Format ` in the + MongoDB manual +- `Server Discovery and Monitoring + `_ + specification diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__get.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__get.txt new file mode 100644 index 00000000..c0824578 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBClient__get.txt @@ -0,0 +1,69 @@ +======================== +MongoDB\\Client::__get() +======================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::__get() + + Selects a database on the server. This :php:`magic method ` is + an alias for the :phpmethod:`selectDatabase() + ` method. + + .. code-block:: php + + function __get($databaseName): MongoDB\Database + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-get-param.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Database` object. + +Behavior +-------- + +The selected database inherits options such as read preference and type mapping +from the :phpclass:`Client ` object. If you wish to override +any options, use the :phpmethod:`MongoDB\\Client::selectDatabase` method. + +.. note:: + + To select databases whose names contain special characters, such as + ``-``, use complex syntax, as in ``$client->{'that-database'}``. + + Alternatively, :phpmethod:`MongoDB\\Client::selectDatabase()` supports + selecting databases whose names contain special characters. + +Examples +-------- + +The following example selects the ``test`` and ``another-app`` databases: + +.. code-block:: php + + test; + $anotherApp = $client->{'another-app'}; + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::selectDatabase()` +- :phpmethod:`MongoDB\\Database::__construct()` +- :php:`Property Overloading ` in the PHP Manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-aggregate.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-aggregate.txt new file mode 100644 index 00000000..6d092181 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-aggregate.txt @@ -0,0 +1,69 @@ +================================ +MongoDB\\Collection::aggregate() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::aggregate() + + Executes an :manual:`aggregation framework pipeline + ` operation on the collection. + + .. code-block:: php + + function aggregate(array $pipeline, array $options = []): Traversable + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-aggregate-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-aggregate-option.rst + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Cursor ` or +:php:`ArrayIterator ` object. In both cases, the return value +will be :php:`Traversable `. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. _php-agg-method-behavior: + +Behavior +-------- + +:phpmethod:`MongoDB\\Collection::aggregate()`'s return value depends on the +MongoDB server version and whether the ``useCursor`` option is specified. If +``useCursor`` is ``true``, a :php:`MongoDB\\Driver\\Cursor +` object is returned. If ``useCursor`` is +``false``, an :php:`ArrayIterator ` is returned that wraps the +``result`` array from the command response document. In both cases, the return +value will be :php:`Traversable `. + +.. todo: add examples + +See Also +-------- + +- :manual:`aggregate ` command reference in the + MongoDB manual +- :manual:`Aggregation Pipeline ` documentation in + the MongoDB Manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-bulkWrite.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-bulkWrite.txt new file mode 100644 index 00000000..e58688cb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-bulkWrite.txt @@ -0,0 +1,64 @@ +================================ +MongoDB\\Collection::bulkWrite() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::bulkWrite() + + Executes multiple write operations. + + .. code-block:: php + + function bulkWrite(array $operations, array $options = []): MongoDB\BulkWriteResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-bulkWrite-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-bulkWrite-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\BulkWriteResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/bulkwriteexception-result.rst +.. include:: /includes/extracts/bulkwriteexception-ordered.rst + +.. todo: add output and examples + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::deleteMany()` +- :phpmethod:`MongoDB\\Collection::deleteOne()` +- :phpmethod:`MongoDB\\Collection::insertMany()` +- :phpmethod:`MongoDB\\Collection::insertOne()` +- :phpmethod:`MongoDB\\Collection::replaceOne()` +- :phpmethod:`MongoDB\\Collection::updateMany()` +- :phpmethod:`MongoDB\\Collection::updateOne()` +- :doc:`/tutorial/crud` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-count.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-count.txt new file mode 100644 index 00000000..396ba25f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-count.txt @@ -0,0 +1,56 @@ +============================ +MongoDB\\Collection::count() +============================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::count() + + Count the number of documents that match the filter criteria. + + .. code-block:: php + + function count($filter = [], array $options = []): integer + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-count-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-count-option.rst + +Return Values +------------- + +The number of documents matching the filter criteria. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +.. todo: add output and examples + +See Also +-------- + +- :manual:`count ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndex.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndex.txt new file mode 100644 index 00000000..da7629da --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndex.txt @@ -0,0 +1,109 @@ +================================ +MongoDBCollection::createIndex() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::createIndex() + + Create an index for the collection. + + .. code-block:: php + + function createIndex($key, array $options = []): string + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-createIndex-param.rst + + The ``$options`` parameter accepts all index options that your MongoDB + version supports. MongoDB includes the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-createIndex-option.rst + + For a full list of the supported index creation options, refer to the + :manual:`createIndexes ` command reference + in the MongoDB manual. + +Return Values +------------- + +The name of the created index as a string. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Examples +-------- + +Create a Compound Index +~~~~~~~~~~~~~~~~~~~~~~~ + +The following example creates a :manual:`compound index ` +on the ``borough`` and ``cuisine`` fields in the ``restaurants`` collection in +the ``test`` database. + +.. code-block:: php + + selectCollection('test', 'restaurants'); + + $indexName = $collection->createIndex(['borough' => 1, 'cuisine' => 1]); + + var_dump($indexName); + +The output would then resemble:: + + string(19) "borough_1_cuisine_1" + +Create a Partial Index +~~~~~~~~~~~~~~~~~~~~~~ + +The following example adds a :manual:`partial index ` on +the ``borough`` field in the ``restaurants`` collection in the ``test`` +database. The partial index indexes only documents where the ``borough`` field +exists. + +.. code-block:: php + + selectCollection('test, 'restaurants'); + + $indexName = $collection->createIndex( + ['borough' => 1], + [ + 'partialFilterExpression' => [ + 'borough' => ['$exists' => true], + ], + ] + ); + + var_dump($indexName); + +The output would then resemble:: + + string(9) "borough_1" + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndexes()` +- :doc:`/tutorial/indexes` +- :manual:`createIndexes ` command reference + in the MongoDB manual +- :manual:`Index ` documentation in the MongoDB Manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndexes.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndexes.txt new file mode 100644 index 00000000..b2fc994b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-createIndexes.txt @@ -0,0 +1,100 @@ +================================== +MongoDBCollection::createIndexes() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::createIndexes($indexes) + + Create one or more indexes for the collection. + + .. code-block:: php + + function createIndexes(array $indexes, array $options = []): string[] + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-createIndexes-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-createIndexes-option.rst + +Return Values +------------- + +The names of the created indexes as an array of strings. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +``$indexes`` parameter +---------------------- + +The ``$indexes`` parameter is an array of index specification documents. Each +element in ``$indexes`` must itself be an array or object with a ``key`` field, +which corresponds to the ``$key`` parameter of :phpmethod:`createIndex() +`. The array or object may include other +fields that correspond to index options accepted by :phpmethod:`createIndex() +` (excluding ``writeConcern``). + +For example, the following ``$indexes`` parameter creates two indexes. The first +is an ascending unique index on the ``username`` field and the second is a +2dsphere index on the ``loc`` field with a custom name:: + + [ + [ 'key' => [ 'username' => 1 ], 'unique' => true ], + [ 'key' => [ 'loc' => '2dsphere' ], 'name' => 'geo_index' ], + ] + +Example +------- + +The following example creates two indexes on the ``restaurants`` collection in +the ``test`` database. One index is a compound index on the ``borough`` and +``cuisine`` fields and the other is 2dsphere index on the ``loc`` field with a +custom name. + +.. code-block:: php + + selectCollection('test', 'restaurants'); + + $indexNames = $collection->createIndexes([ + [ 'key' => [ 'borough' => 1, 'cuisine' => 1] ], + [ 'key' => [ 'loc' => '2dsphere'], 'name' => 'geo_index' ], + ]); + + var_dump($indexNames); + +The output would then resemble:: + + array(2) { + [0]=> + string(19) "borough_1_cuisine_1" + [1]=> + string(9) "geo_index" + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :doc:`/tutorial/indexes` +- :manual:`createIndexes ` command reference + in the MongoDB manual +- :manual:`Index ` documentation in the MongoDB Manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-deleteMany.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-deleteMany.txt new file mode 100644 index 00000000..fb84bd99 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-deleteMany.txt @@ -0,0 +1,82 @@ +================================= +MongoDB\\Collection::deleteMany() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::deleteMany() + + Deletes all documents that match the filter criteria. + + .. code-block:: php + + function deleteMany($filter, array $options = []): MongoDB\DeleteResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-deleteMany-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-deleteMany-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\DeleteResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Example +------- + +The following example deletes all of the documents in the ``users`` collection +that have ``"ny"`` as the value for the ``state`` field: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $deleteResult = $collection->deleteMany(['state' => 'ny']); + + printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); + +The output would then resemble:: + + Deleted 2 document(s) + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::deleteOne()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`delete ` + matching document will be deleted. + + .. code-block:: php + + function deleteOne($filter, array $options = []): MongoDB\DeleteResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-deleteOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-deleteOne-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\DeleteResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Example +------- + +The following example deletes one document in the ``users`` collection that has +has ``"ny"`` as the value for the ``state`` field: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $deleteResult = $collection->deleteOne(['state' => 'ny']); + + printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); + +The output would then resemble:: + + Deleted 1 document(s) + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::deleteMany()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`delete test->restaurants; + + $distinct = $collection->distinct('borough'); + + var_dump($distinct); + +The output would then resemble:: + + array(6) { + [0]=> + string(5) "Bronx" + [1]=> + string(8) "Brooklyn" + [2]=> + string(9) "Manhattan" + [3]=> + string(7) "Missing" + [4]=> + string(6) "Queens" + [5]=> + string(13) "Staten Island" + } + +Return Distinct Values Using a Filter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example identifies the distinct values for the ``cuisine`` field +in the ``restaurants`` collection in the ``test`` database for documents where +the ``borough`` is ``Queens``: + +.. code-block:: php + + test->restaurants; + + $distinct = $collection->distinct('cuisine', ['borough' => 'Queens']); + + var_dump($distinct); + +The output would then resemble:: + + array(75) { + [0]=> + string(6) "Afghan" + [1]=> + string(7) "African" + [2]=> + string(9) "American " + [3]=> + string(8) "Armenian" + [4]=> + string(5) "Asian" + [5]=> + string(10) "Australian" + [6]=> + string(15) "Bagels/Pretzels" + [7]=> + string(6) "Bakery" + [8]=> + string(11) "Bangladeshi" + [9]=> + string(8) "Barbecue" + [10]=> + string(55) "Bottled beverages, including water, sodas, juices, etc." + [11]=> + string(9) "Brazilian" + [12]=> + string(4) "Cafe" + [13]=> + string(16) "Café/Coffee/Tea" + [14]=> + string(5) "Cajun" + [15]=> + string(9) "Caribbean" + [16]=> + string(7) "Chicken" + [17]=> + string(7) "Chinese" + [18]=> + string(13) "Chinese/Cuban" + [19]=> + string(16) "Chinese/Japanese" + [20]=> + string(11) "Continental" + [21]=> + string(6) "Creole" + [22]=> + string(5) "Czech" + [23]=> + string(12) "Delicatessen" + [24]=> + string(6) "Donuts" + [25]=> + string(16) "Eastern European" + [26]=> + string(8) "Egyptian" + [27]=> + string(7) "English" + [28]=> + string(8) "Filipino" + [29]=> + string(6) "French" + [30]=> + string(17) "Fruits/Vegetables" + [31]=> + string(6) "German" + [32]=> + string(5) "Greek" + [33]=> + string(10) "Hamburgers" + [34]=> + string(16) "Hotdogs/Pretzels" + [35]=> + string(31) "Ice Cream, Gelato, Yogurt, Ices" + [36]=> + string(6) "Indian" + [37]=> + string(10) "Indonesian" + [38]=> + string(5) "Irish" + [39]=> + string(7) "Italian" + [40]=> + string(8) "Japanese" + [41]=> + string(13) "Jewish/Kosher" + [42]=> + string(30) "Juice, Smoothies, Fruit Salads" + [43]=> + string(6) "Korean" + [44]=> + string(64) "Latin (Cuban, Dominican, Puerto Rican, South & Central American)" + [45]=> + string(13) "Mediterranean" + [46]=> + string(7) "Mexican" + [47]=> + string(14) "Middle Eastern" + [48]=> + string(8) "Moroccan" + [49]=> + string(25) "Not Listed/Not Applicable" + [50]=> + string(18) "Nuts/Confectionary" + [51]=> + string(5) "Other" + [52]=> + string(9) "Pakistani" + [53]=> + string(16) "Pancakes/Waffles" + [54]=> + string(8) "Peruvian" + [55]=> + string(5) "Pizza" + [56]=> + string(13) "Pizza/Italian" + [57]=> + string(6) "Polish" + [58]=> + string(10) "Portuguese" + [59]=> + string(7) "Russian" + [60]=> + string(6) "Salads" + [61]=> + string(10) "Sandwiches" + [62]=> + string(30) "Sandwiches/Salads/Mixed Buffet" + [63]=> + string(7) "Seafood" + [64]=> + string(9) "Soul Food" + [65]=> + string(18) "Soups & Sandwiches" + [66]=> + string(12) "Southwestern" + [67]=> + string(7) "Spanish" + [68]=> + string(5) "Steak" + [69]=> + string(5) "Tapas" + [70]=> + string(7) "Tex-Mex" + [71]=> + string(4) "Thai" + [72]=> + string(7) "Turkish" + [73]=> + string(10) "Vegetarian" + [74]=> + string(29) "Vietnamese/Cambodian/Malaysia" + } + +See Also +-------- + +- :manual:`distinct ` command reference in the + MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-drop.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-drop.txt new file mode 100644 index 00000000..c1762871 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-drop.txt @@ -0,0 +1,81 @@ +=========================== +MongoDB\\Collection::drop() +=========================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::drop() + + Drop the collection. + + .. code-block:: php + + function drop(array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-drop-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-drop-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`drop +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following operation drops the ``restaurants`` collection in the ``test`` +database: + +.. code-block:: php + + test->restaurants; + + $result = $collection->drop(); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#9 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["ns"]=> + string(16) "test.restaurants" + ["nIndexesWas"]=> + int(3) + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::dropCollection()` +- :manual:`drop ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndex.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndex.txt new file mode 100644 index 00000000..880349bd --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndex.txt @@ -0,0 +1,81 @@ +================================ +MongoDB\\Collection::dropIndex() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::dropIndex() + + Drop an index from the collection. + + .. code-block:: php + + function dropIndex($indexName, array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-dropIndex-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-dropIndex-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`dropIndexes +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following drops an indexes with name ``borough_1`` from the ``restaurants`` +collection in the ``test`` database: + +.. code-block:: php + + test->restaurants; + + $result = $collection->dropIndex('borough_1'); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#9 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["nIndexesWas"]=> + int(2) + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::dropIndexes()` +- :doc:`/tutorial/indexes` +- :manual:`dropIndexes ` command reference in + the MongoDB manual +- :manual:`Index documentation ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndexes.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndexes.txt new file mode 100644 index 00000000..8cdf9e43 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-dropIndexes.txt @@ -0,0 +1,84 @@ +================================== +MongoDB\\Collection::dropIndexes() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::dropIndexes() + + Drop all indexes in the collection, except for the required index on the + ``_id`` field. + + .. code-block:: php + + function dropIndexes(array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-dropIndex-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-dropIndex-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`dropIndexes +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following drops all indexes from the ``restaurants`` collection in the +``test`` database: + +.. code-block:: php + + test->restaurants; + + $result = $collection->dropIndexes(); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#9 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["nIndexesWas"]=> + int(3) + ["msg"]=> + string(38) "non-_id indexes dropped for collection" + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::dropIndex()` +- :doc:`/tutorial/indexes` +- :manual:`dropIndexes ` command reference in + the MongoDB manual +- :manual:`Index documentation ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-find.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-find.txt new file mode 100644 index 00000000..34eed99a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-find.txt @@ -0,0 +1,168 @@ +=========================== +MongoDB\\Collection::find() +=========================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::find() + + Finds documents matching the query. + + .. code-block:: php + + function find($filter = [], array $options = []): MongoDB\Driver\Cursor + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-find-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-find-option.rst + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Cursor ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +Examples +-------- + +The following example finds restaurants based on the ``cuisine`` and ``borough`` +fields and uses a :manual:`projection +` to limit the fields that are +returned. It also limits the results to 5 documents. + +.. code-block:: php + + $collection = (new MongoDB\Client)->test->restaurants; + + $cursor = $collection->find( + [ + 'cuisine' => 'Italian', + 'borough' => 'Manhattan', + ], + [ + 'limit' => 5, + 'projection' => [ + 'name' => 1, + 'borough' => 1, + 'cuisine' => 1, + ], + ] + ); + + foreach ($cursor as $restaurant) { + var_dump($restaurant); + }; + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#10 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#8 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f983" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(23) "Isle Of Capri Resturant" + } + } + object(MongoDB\Model\BSONDocument)#13 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#12 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f98d" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(18) "Marchis Restaurant" + } + } + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#10 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f99b" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(19) "Forlinis Restaurant" + } + } + object(MongoDB\Model\BSONDocument)#12 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#13 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f9a8" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(22) "Angelo Of Mulberry St." + } + } + object(MongoDB\Model\BSONDocument)#10 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#8 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f9b4" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(16) "V & T Restaurant" + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::findOne()` +- :manual:`find ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOne.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOne.txt new file mode 100644 index 00000000..0bf95f64 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOne.txt @@ -0,0 +1,125 @@ +============================== +MongoDB\\Collection::findOne() +============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::findOne() + + Finds a single document matching the query. + + .. code-block:: php + + function findOne($filter = [], array $options = []): array|object|null + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOne-option.rst + +Return Values +------------- + +An array or object for the :term:`first document ` that matched +the query, or ``null`` if no document matched the query. The return type will +depend on the ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +Examples +-------- + +Matching BSON Types in Query Criteria +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the following example, documents in the ``restaurants`` collection use an +:manual:`ObjectId ` for their identifier (the default) +and documents in the ``zips`` collection use a string. Since ObjectId is a +special BSON type, the query criteria for selecting a restaurant must use the +:php:`MongoDB\\BSON\\ObjectId ` class. + +.. code-block:: php + + $database = (new MongoDB\Client)->test; + + $zip = $database->zips->findOne(['_id' => '10036']); + + $restaurant = $database->restaurants->findOne([ + '_id' => new MongoDB\BSON\ObjectId('594d5ef280a846852a4b3f70'), + ]); + +Projecting Fields +~~~~~~~~~~~~~~~~~ + +The following example finds a restaurant based on the ``cuisine`` and +``borough`` fields and uses a :manual:`projection +` to limit the fields that are +returned. + +.. code-block:: php + + $collection = (new MongoDB\Client)->test->restaurants; + + $restaurant = $collection->findOne( + [ + 'cuisine' => 'Italian', + 'borough' => 'Manhattan', + ], + [ + 'projection' => [ + 'name' => 1, + 'borough' => 1, + 'cuisine' => 1, + ], + ] + ); + + var_dump($restaurant); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#10 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#8 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f983" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(23) "Isle Of Capri Resturant" + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::find()` +- :manual:`find ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndDelete.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndDelete.txt new file mode 100644 index 00000000..1253bad4 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndDelete.txt @@ -0,0 +1,101 @@ +======================================= +MongoDB\\Collection::findOneAndDelete() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::findOneAndDelete() + + Finds a single document matching the query and deletes it. + + .. code-block:: php + + function findOneAndDelete($filter = [], array $options = []): object|null + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndDelete-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndDelete-option.rst + +Return Values +------------- + +An array or object for the document that was deleted, or ``null`` if no document +matched the query. The return type will depend on the ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +Examples +-------- + +The following example finds and deletes the document with ``restaurant_id`` of +``"40375376"`` from the ``restaurants`` collection in the ``test`` database: + +.. code-block:: php + + test->restaurants; + + $deletedRestaurant = $collection->findOneAndDelete( + [ 'restaurant_id' => '40375376' ], + [ + 'projection' => [ + 'name' => 1, + 'borough' => 1, + 'restaurant_id' => 1, + ], + ] + ); + + var_dump($deletedRestaurant); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#17 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#11 (1) { + ["oid"]=> + string(24) "594d5ef280a846852a4b3f70" + } + ["borough"]=> + string(9) "Manhattan" + ["name"]=> + string(15) "Agra Restaurant" + ["restaurant_id"]=> + string(8) "40375376" + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::findOneAndReplace()` +- :phpmethod:`MongoDB\\Collection::findOneAndUpdate()` +- :manual:`findAndModify ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndReplace.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndReplace.txt new file mode 100644 index 00000000..6a96a30b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndReplace.txt @@ -0,0 +1,151 @@ +======================================== +MongoDB\\Collection::findOneAndReplace() +======================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::findOneAndReplace() + + Finds a single document matching the query and replaces it. + + .. code-block:: php + + function findOneAndReplace($filter, $replacement, array $options = []): object|null + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndReplace-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndReplace-option.rst + +Return Values +------------- + +An array object for either the original or the replaced document, depending on +the specified value of the ``returnDocument`` option. By default, the original +document is returned. If no document matched the query, ``null`` is returned. +The return type will depend on the ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +Examples +-------- + +Consider the following document in the ``restaurants`` collection in the +``test`` database: + +.. code-block:: javascript + + { + "_id" : ObjectId("576023c7b02fa9281da4139e"), + "address" : { + "building" : "977", + "coord" : [ + -74.06940569999999, + 40.6188443 + ], + "street" : "Bay Street", + "zipcode" : "10305" + }, + "borough" : "Staten Island", + "cuisine" : "French", + "grades" : [ + { + "date" : ISODate("2014-08-15T00:00:00Z"), + "grade" : "A", + "score" : 7 + }, + { + "date" : ISODate("2014-02-13T00:00:00Z"), + "grade" : "A", + "score" : 5 + }, + { + "date" : ISODate("2013-06-07T00:00:00Z"), + "grade" : "A", + "score" : 11 + } + ], + "name" : "Zest", + "restaurant_id" : "41220906" + } + +The following operation replaces the document with ``restaurant_id`` of +``"41220906"`` with a new document: + +.. code-block:: php + + teset->restaurants; + + $replacedRestaurant = $collection->findOneAndReplace( + [ 'restaurant_id' => '41220906' ], + [ + 'Borough' => 'Staten Island', + 'cuisine' => 'Italian', + 'grades' => [], + 'name' => 'Staten Island Pastaria', + 'restaurant_id' => '999999999', + ], + [ 'returnDocument' => MongoDB\Operation\FindOneAndReplace::RETURN_DOCUMENT_AFTER ] + ); + + var_dump($replacedRestaurant); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#18 (1) { + ["storage":"ArrayObject":private]=> + array(6) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#11 (1) { + ["oid"]=> + string(24) "594d5ef380a846852a4b5837" + } + ["Borough"]=> + string(13) "Staten Island" + ["cuisine"]=> + string(7) "Italian" + ["grades"]=> + object(MongoDB\Model\BSONArray)#17 (1) { + ["storage":"ArrayObject":private]=> + array(0) { + } + } + ["name"]=> + string(22) "Staten Island Pastaria" + ["restaurant_id"]=> + string(9) "999999999" + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::findOneAndDelete()` +- :phpmethod:`MongoDB\\Collection::findOneAndUpdate()` +- :manual:`findAndModify ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt new file mode 100644 index 00000000..377d255e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt @@ -0,0 +1,118 @@ +======================================= +MongoDB\\Collection::findOneAndUpdate() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::findOneAndUpdate() + + Finds a single document matching the query and updates it. + + .. code-block:: php + + function findOneAndUpdate($filter, $update, array $options = []): object|null + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndUpdate-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOneAndUpdate-option.rst + +Return Values +------------- + +An array or object for either the original or the updated document, depending on +the specified value of the ``returnDocument`` option. By default, the original +document is returned. If no document matched the query, ``null`` is returned. +The return type will depend on the ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +Examples +-------- + +The following operation updates the restaurant with ``restaurant_id`` of +``"40361708"`` in the ``restaurants`` collection in the ``test`` database by +setting its building number to ``"761"``: + +.. code-block:: php + + test->restaurants; + + $updatedRestaurant = $collection->findOneAndUpdate( + [ 'restaurant_id' => '40361708' ], + [ '$set' => [ 'address.building' => '761' ]], + [ + 'projection' => [ 'address' => 1 ], + 'returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER, + ] + ); + + var_dump($updatedRestaurant); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#20 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#12 (1) { + ["oid"]=> + string(24) "594d5ef280a846852a4b3dee" + } + ["address"]=> + object(MongoDB\Model\BSONDocument)#19 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["building"]=> + string(3) "761" + ["coord"]=> + object(MongoDB\Model\BSONArray)#18 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + float(-73.9925306) + [1]=> + float(40.7309346) + } + } + ["street"]=> + string(8) "Broadway" + ["zipcode"]=> + string(5) "10003" + } + } + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::findOneAndDelete()` +- :phpmethod:`MongoDB\\Collection::findOneAndReplace()` +- :manual:`findAndModify ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getCollectionName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getCollectionName.txt new file mode 100644 index 00000000..86fe3e5e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getCollectionName.txt @@ -0,0 +1,51 @@ +======================================== +MongoDB\\Collection::getCollectionName() +======================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getCollectionName() + + Returns the name of this collection. + + .. code-block:: php + + function getCollectionName(): string + +Return Values +------------- + +The name of this collection as a string. + +Example +------- + +The following returns the collection name for the ``zips`` collection in the +``test`` database. + +.. code-block:: php + + test->zips; + + echo $collection->getCollectionName(); + +The output would then resemble:: + + zips + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::getDatabaseName()` +- :phpmethod:`MongoDB\\Collection::getNamespace()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getDatabaseName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getDatabaseName.txt new file mode 100644 index 00000000..93500c80 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getDatabaseName.txt @@ -0,0 +1,52 @@ +====================================== +MongoDB\\Collection::getDatabaseName() +====================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getDatabaseName() + + Returns the name of the database containing this collection. + + .. code-block:: php + + function getDatabaseName(): string + +Return Values +------------- + +The name of the database containing this collection as a string. + +Example +------- + +The following returns the database name for the ``zips`` collection in the +``test`` database. + +.. code-block:: php + + test->zips; + + echo $collection->getDatabaseName(); + +The output would then resemble:: + + test + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::getCollectionName()` +- :phpmethod:`MongoDB\\Collection::getNamespace()` + diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getManager.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getManager.txt new file mode 100644 index 00000000..e0bbea08 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getManager.txt @@ -0,0 +1,35 @@ +================================= +MongoDB\\Collection::getManager() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getManager() + + Accessor for the + :php:`MongoDB\\Driver\\Manager ` used by this + :phpclass:`Collection `. + + .. code-block:: php + + function getManager(): MongoDB\Manager + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Manager ` object. + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::getManager()` +- :phpmethod:`MongoDB\\Database::getManager()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getNamespace.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getNamespace.txt new file mode 100644 index 00000000..74f1b022 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getNamespace.txt @@ -0,0 +1,52 @@ +=================================== +MongoDB\\Collection::getNamespace() +=================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getNamespace() + + Returns the :term:`namespace` of the collection. A namespace is the canonical + name of an index or collection in MongoDB. + + .. code-block:: php + + function getNamespace(): string + +Return Values +------------- + +The namespace of this collection as a string. + +Example +------- + +The following returns the namespace of the ``zips`` collection in the ``test`` +database. + +.. code-block:: php + + test->zips; + + echo $collection->getNamespace(); + +The output would then resemble:: + + test.zips + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::getCollectionName()` +- :phpmethod:`MongoDB\\Collection::getDatabaseName()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadConcern.txt new file mode 100644 index 00000000..ff1cfeb0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadConcern.txt @@ -0,0 +1,58 @@ +===================================== +MongoDB\\Collection::getReadConcern() +===================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getReadConcern() + + Returns the read concern for this collection. + + .. code-block:: php + + function getReadConcern(): MongoDB\Driver\ReadConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadConcern ` object. + +Example +------- + +.. code-block:: php + + selectCollection('test', 'users', [ + 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY), + ]); + + var_dump($collection->getReadConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadConcern)#5 (1) { + ["level"]=> + string(8) "majority" + } + +See Also +-------- + +- :manual:`Read Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\ReadConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getReadConcern()` +- :phpmethod:`MongoDB\\Database::getReadConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadPreference.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadPreference.txt new file mode 100644 index 00000000..4eac30d3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getReadPreference.txt @@ -0,0 +1,58 @@ +======================================== +MongoDB\\Collection::getReadPreference() +======================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getReadPreference() + + Returns the read preference for this collection. + + .. code-block:: php + + function getReadPreference(): MongoDB\Driver\ReadPreference + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadPreference ` +object. + +Example +------- + +.. code-block:: php + + selectCollection('test', 'users', [ + 'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'), + ]); + + var_dump($collection->getReadPreference()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadPreference)#5 (1) { + ["mode"]=> + string(16) "primaryPreferred" + } + +See Also +-------- + +- :manual:`Read Preference ` in the MongoDB manual +- :phpmethod:`MongoDB\\Client::getReadPreference()` +- :phpmethod:`MongoDB\\Database::getReadPreference()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadPreference()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getTypeMap.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getTypeMap.txt new file mode 100644 index 00000000..11e56426 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getTypeMap.txt @@ -0,0 +1,65 @@ +================================= +MongoDB\\Collection::getTypeMap() +================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getTypeMap() + + Returns the type map for this collection. + + .. code-block:: php + + function getTypeMap(): array + +Return Values +------------- + +A :ref:`type map ` array. + +Example +------- + +.. code-block:: php + + selectCollection('test', 'users', [ + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ]); + + var_dump($collection->getTypeMap()); + +The output would then resemble:: + + array(3) { + ["root"]=> + string(5) "array" + ["document"]=> + string(5) "array" + ["array"]=> + string(5) "array" + } + +See Also +-------- + +- :doc:`/reference/bson` +- :phpmethod:`MongoDB\\Client::getTypeMap()` +- :phpmethod:`MongoDB\\Database::getTypeMap()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getTypeMap()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getWriteConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getWriteConcern.txt new file mode 100644 index 00000000..4fa26ee1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-getWriteConcern.txt @@ -0,0 +1,61 @@ +====================================== +MongoDB\\Collection::getWriteConcern() +====================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::getWriteConcern() + + Returns the write concern for this collection. + + .. code-block:: php + + function getWriteConcern(): MongoDB\Driver\WriteConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\WriteConcern ` +object. + +Example +------- + +.. code-block:: php + + selectCollection('test', 'users', [ + 'writeConcern' => new MongoDB\Driver\WriteConcern(1, 0, true), + ]); + + var_dump($collection->getWriteConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\WriteConcern)#5 (2) { + ["w"]=> + int(1) + ["j"]=> + bool(true) + } + +See Also +-------- + +- :manual:`Write Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\WriteConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getWriteConcern()` +- :phpmethod:`MongoDB\\Database::getWriteConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getWriteConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertMany.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertMany.txt new file mode 100644 index 00000000..8b7eb53b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertMany.txt @@ -0,0 +1,107 @@ +================================= +MongoDB\\Collection::insertMany() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::insertMany() + + Insert multiple documents. + + .. code-block:: php + + function insertMany(array $documents, array $options = []): MongoDB\InsertManyResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-insertMany-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-insertMany-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\InsertManyResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/bulkwriteexception-result.rst +.. include:: /includes/extracts/bulkwriteexception-ordered.rst + +Example +------- + +.. start-crud-include + +The following operation inserts two documents into the ``users`` collection +in the ``test`` database: + +.. code-block:: php + + test->users; + + $insertManyResult = $collection->insertMany([ + [ + 'username' => 'admin', + 'email' => 'admin@example.com', + 'name' => 'Admin User', + ], + [ + 'username' => 'test', + 'email' => 'test@example.com', + 'name' => 'Test User', + ], + ]); + + printf("Inserted %d document(s)\n", $insertManyResult->getInsertedCount()); + + var_dump($insertManyResult->getInsertedIds()); + +The output would then resemble:: + + Inserted 2 document(s) + array(2) { + [0]=> + object(MongoDB\BSON\ObjectId)#11 (1) { + ["oid"]=> + string(24) "579a25921f417dd1e5518141" + } + [1]=> + object(MongoDB\BSON\ObjectId)#12 (1) { + ["oid"]=> + string(24) "579a25921f417dd1e5518142" + } + } + +.. end-crud-include + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::insertOne()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`insert ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertOne.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertOne.txt new file mode 100644 index 00000000..0d25f6d5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-insertOne.txt @@ -0,0 +1,91 @@ +================================ +MongoDB\\Collection::insertOne() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::insertOne() + + Insert one document. + + .. code-block:: php + + function insertOne($document, array $options = []): MongoDB\InsertOneResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-insertOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-insertOne-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\InsertOneResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Example +------- + +.. start-crud-include + +The following operation inserts a document into the ``users`` collection in the +``test`` database: + +.. code-block:: php + + test->users; + + $insertOneResult = $collection->insertOne([ + 'username' => 'admin', + 'email' => 'admin@example.com', + 'name' => 'Admin User', + ]); + + printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); + + var_dump($insertOneResult->getInsertedId()); + +The output would then resemble:: + + Inserted 1 document(s) + object(MongoDB\BSON\ObjectId)#11 (1) { + ["oid"]=> + string(24) "579a25921f417dd1e5518141" + } + +.. end-crud-include + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::insertMany()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`insert ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-listIndexes.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-listIndexes.txt new file mode 100644 index 00000000..e39a9bbb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-listIndexes.txt @@ -0,0 +1,111 @@ +================================== +MongoDB\\Collection::listIndexes() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::listIndexes() + + Returns information for all indexes for this collection. + + .. code-block:: php + + function listIndexes(array $options = []): MongoDB\Model\IndexInfoIterator + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-listIndexes-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-listIndexes-option.rst + +Return Values +------------- + +A traversable :phpclass:`MongoDB\\Model\\IndexInfoIterator`, which contains a +:phpclass:`MongoDB\\Model\\IndexInfo` object for each index for the collection. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example lists all of the indexes for the ``restaurants`` +collection in the ``test`` database: + +.. code-block:: php + + test->restaurants; + + foreach ($collection->listIndexes() as $index) { + var_dump($index); + } + +The output would then resemble:: + + object(MongoDB\Model\IndexInfo)#8 (4) { + ["v"]=> + int(1) + ["key"]=> + array(1) { + ["_id"]=> + int(1) + } + ["name"]=> + string(4) "_id_" + ["ns"]=> + string(16) "test.restaurants" + } + object(MongoDB\Model\IndexInfo)#12 (4) { + ["v"]=> + int(1) + ["key"]=> + array(1) { + ["cuisine"]=> + float(-1) + } + ["name"]=> + string(10) "cuisine_-1" + ["ns"]=> + string(16) "test.restaurants" + } + object(MongoDB\Model\IndexInfo)#8 (4) { + ["v"]=> + int(1) + ["key"]=> + array(1) { + ["borough"]=> + float(1) + } + ["name"]=> + string(9) "borough_1" + ["ns"]=> + string(16) "test.restaurants" + } + +See Also +-------- + +- :doc:`/tutorial/indexes` +- :manual:`listIndexes ` command reference in + the MongoDB manual +- :manual:`Index documentation ` in the MongoDB manual +- `Enumerating Collections + `_ + specification diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-mapReduce.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-mapReduce.txt new file mode 100644 index 00000000..dd413cb5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-mapReduce.txt @@ -0,0 +1,127 @@ +================================= +MongoDB\\Collection::mapReduce() +================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::mapReduce() + + The :manual:`mapReduce ` command allows you to + run map-reduce aggregation operations over a collection. + + .. code-block:: php + + function mapReduce($map, $reduce, $out, array $options = []): MongoDB\MapReduceResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-mapReduce-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-mapReduce-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\MapReduceResult` object, which allows for iteration of +mapReduce results irrespective of the output method (e.g. inline, collection) +via the :php:`IteratorAggregate ` interface. It also +provides access to command statistics. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-unexpectedvalueexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +In MongoDB, the map-reduce operation can write results to a collection +or return the results inline. If you write map-reduce output to a +collection, you can perform subsequent map-reduce operations on the +same input collection that merge replace, merge, or reduce new results +with previous results. See :manual:`Map-Reduce ` and +:manual:`Perform Incremental Map-Reduce ` +for details and examples. + +When returning the results of a map-reduce operation *inline*, the +result documents must be within the :limit:`BSON Document Size` limit, +which is currently 16 megabytes. + +MongoDB supports map-reduce operations on :manual:`sharded collections +`. Map-reduce operations can also output +the results to a sharded collection. See +:manual:`Map-Reduce and Sharded Collections `. + +Example +------- + +This example will use city populations to calculate the overall population of +each state. + +.. code-block:: php + + test->zips; + + $map = new MongoDB\BSON\Javascript('function() { emit(this.state, this.pop); }'); + $reduce = new MongoDB\BSON\Javascript('function(key, values) { return Array.sum(values) }'); + $out = ['inline' => 1]; + + $populations = $collection->mapReduce($map, $reduce, $out); + + foreach ($populations as $pop) { + var_dump($pop); + }; + +The output would then resemble:: + + object(stdClass)#2293 (2) { + ["_id"]=> + string(2) "AK" + ["value"]=> + float(544698) + } + object(stdClass)#2300 (2) { + ["_id"]=> + string(2) "AL" + ["value"]=> + float(4040587) + } + object(stdClass)#2293 (2) { + ["_id"]=> + string(2) "AR" + ["value"]=> + float(2350725) + } + object(stdClass)#2300 (2) { + ["_id"]=> + string(2) "AZ" + ["value"]=> + float(3665228) + } + + +See Also +-------- + +- :manual:`mapReduce ` command reference in the MongoDB + manual +- :manual:`Map-Reduce ` documentation in the MongoDB manual + diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-replaceOne.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-replaceOne.txt new file mode 100644 index 00000000..ba43452b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-replaceOne.txt @@ -0,0 +1,93 @@ +================================= +MongoDB\\Collection::replaceOne() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::replaceOne() + + Replace at most one document that matches the filter criteria. If multiple + documents match the filter criteria, only the :term:`first ` + matching document will be replaced. + + .. code-block:: php + + function replaceOne($filter, $replacement, array $options = []): MongoDB\UpdateResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-replaceOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-replaceOne-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\UpdateResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Example +------- + +The following example replaces the document with ``restaurant_id`` of +``"40356068"`` in the ``restaurants`` collection in the ``test`` database: + +.. code-block:: php + + test->restaurants; + + $updateResult = $collection->replaceOne( + [ 'restaurant_id' => '40356068' ], + [ + 'name' => 'New Restaurant', + 'restaurant_id' => '99988877', + 'borough' => 'Queens', + 'cuisine' => 'Cafe', + 'grades' => [], + ] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +The output would then resemble:: + + Matched 1 document(s) + Modified 1 document(s) + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::updateMany()` +- :phpmethod:`MongoDB\\Collection::updateOne()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`update ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateMany.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateMany.txt new file mode 100644 index 00000000..bd72fdf9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateMany.txt @@ -0,0 +1,83 @@ +================================= +MongoDB\\Collection::updateMany() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::updateMany() + + Update all documents that match the filter criteria. + + .. code-block:: php + + function updateMany($filter, $update, array $options = []): MongoDB\UpdateResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-updateMany-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-updateMany-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\UpdateResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Examples +-------- + +The following example updates all of the documents with the ``borough`` of +``"Queens"`` by setting the ``active`` field to ``true``: + +.. code-block:: php + + $collection = (new MongoDB\Client)->test->restaurants; + + $updateResult = $collection->updateMany( + [ 'borough' => 'Queens' ], + [ '$set' => [ 'active' => 'True' ]] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +The output would then resemble:: + + Matched 5656 document(s) + Modified 5656 document(s) + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::replaceOne()` +- :phpmethod:`MongoDB\\Collection::updateOne()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`update ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateOne.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateOne.txt new file mode 100644 index 00000000..bed657f9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-updateOne.txt @@ -0,0 +1,85 @@ +================================ +MongoDB\\Collection::updateOne() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::updateOne() + + Update at most one document that matches the filter criteria. If multiple + documents match the filter criteria, only the :term:`first ` + matching document will be updated. + + .. code-block:: php + + function updateOne($filter, $update, array $options = []): MongoDB\UpdateResult + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-updateOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-updateOne-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\UpdateResult` object, which encapsulates a +:php:`MongoDB\\Driver\\WriteResult ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-bulkwriteexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst +.. include:: /includes/extracts/bulkwriteexception-result.rst + +Examples +-------- + +The following example updates one document with the ``restaurant_id`` of +``"40356151"`` by setting the ``name`` field to ``"Brunos on Astoria"``: + +.. code-block:: php + + $collection = (new MongoDB\Client)->test->restaurants; + + $updateResult = $collection->updateOne( + [ 'restaurant_id' => '40356151' ], + [ '$set' => [ 'name' => 'Brunos on Astoria' ]] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +The output would then resemble:: + + Matched 1 document(s) + Modified 1 document(s) + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::replaceOne()` +- :phpmethod:`MongoDB\\Collection::updateMany()` +- :phpmethod:`MongoDB\\Collection::bulkWrite()` +- :doc:`/tutorial/crud` +- :manual:`update ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-withOptions.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-withOptions.txt new file mode 100644 index 00000000..92e09f6e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection-withOptions.txt @@ -0,0 +1,61 @@ +================================== +MongoDB\\Collection::withOptions() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::withOptions() + + Returns a clone of the Collection object, but with different options. + + .. code-block:: php + + function withOptions(array $options = []): MongoDB\Collection + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-withOptions-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-withOptions-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Example +------- + +The following example clones an existing Collection object with a new read +preference: + +.. code-block:: php + + selectCollection('test', 'restaurants'); + + $newCollection = $sourceCollection->withOptions([ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ]); + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::__construct()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection__construct.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection__construct.txt new file mode 100644 index 00000000..c3ef0c6b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBCollection__construct.txt @@ -0,0 +1,54 @@ +================================== +MongoDB\\Collection::__construct() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::__construct() + + Constructs a new :phpclass:`Collection ` instance. + + .. code-block:: php + + function __construct(MongoDB\Driver\Manager $manager, $databaseName, $collectionName, array $options = []) + + This constructor has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-construct-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-construct-option.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +If you construct a Collection explicitly, the Collection inherits any options +from the :php:`MongoDB\\Driver\\Manager ` object. +If you select the Collection from a :phpclass:`Client ` or +:phpclass:`Database ` object, the Collection inherits its +options from that object. + +.. todo: add an example + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::withOptions()` +- :phpmethod:`MongoDB\\Client::selectCollection()` +- :phpmethod:`MongoDB\\Database::selectCollection()` +- :phpmethod:`MongoDB\\Database::__get()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-command.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-command.txt new file mode 100644 index 00000000..46b28fbe --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-command.txt @@ -0,0 +1,155 @@ +============================ +MongoDB\\Database::command() +============================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::command() + + Execute a :manual:`command ` on the database. + + .. code-block:: php + + function command($command, array $options = []): MongoDB\Driver\Cursor + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-command-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-command-option.rst + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Cursor ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example executes an :manual:`isMaster +` command, which returns a cursor with a single +result document: + +.. code-block:: php + + test; + + $cursor = $database->command(['isMaster' => 1]); + + var_dump($c->toArray()[0]); + +The output would resemble:: + + object(MongoDB\Model\BSONDocument)#11 (1) { + ["storage":"ArrayObject":private]=> + array(8) { + ["ismaster"]=> + bool(true) + ["maxBsonObjectSize"]=> + int(16777216) + ["maxMessageSizeBytes"]=> + int(48000000) + ["maxWriteBatchSize"]=> + int(1000) + ["localTime"]=> + object(MongoDB\BSON\UTCDateTime)#3 (1) { + ["milliseconds"]=> + string(13) "1477608046464" + } + ["maxWireVersion"]=> + int(4) + ["minWireVersion"]=> + int(0) + ["ok"]=> + float(1) + } + } + +The following example executes a :manual:`listCollections +` command, which returns a cursor with +multiple result documents: + +.. code-block:: php + + test; + + $cursor = $database->command(['isMaster' => 1]); + + var_dump($c->toArray()); + +The output would resemble:: + + array(3) { + [0]=> + object(MongoDB\Model\BSONDocument)#11 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["name"]=> + string(11) "restaurants" + ["options"]=> + object(MongoDB\Model\BSONDocument)#3 (1) { + ["storage":"ArrayObject":private]=> + array(0) { + } + } + } + } + [1]=> + object(MongoDB\Model\BSONDocument)#13 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["name"]=> + string(5) "users" + ["options"]=> + object(MongoDB\Model\BSONDocument)#12 (1) { + ["storage":"ArrayObject":private]=> + array(0) { + } + } + } + } + [2]=> + object(MongoDB\Model\BSONDocument)#15 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["name"]=> + string(6) "restos" + ["options"]=> + object(MongoDB\Model\BSONDocument)#14 (1) { + ["storage":"ArrayObject":private]=> + array(0) { + } + } + } + } + } + +See Also +-------- + +- :doc:`/tutorial/commands` +- :manual:`Database Commands ` in the MongoDB manual +- :php:`MongoDB\\Driver\\Cursor ` +- :php:`MongoDB\\Driver\\Manager::executeCommand() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-createCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-createCollection.txt new file mode 100644 index 00000000..8db6696c --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-createCollection.txt @@ -0,0 +1,99 @@ +===================================== +MongoDB\\Database::createCollection() +===================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::createCollection() + + Explicitly creates a collection. + + .. code-block:: php + + function createCollection($collectionName, array $options = []): array|object + + MongoDB creates collections implicitly when you first reference the + collection in a command, such as when inserting a document into a new + collection. You may also explicitly create a collection with specific options + using the :phpmethod:`MongoDB\\Database::createCollection()` method, or using + :manual:`db.createCollection() ` in + the :program:`mongo` shell. + + Explicitly creating collections enables you to create + :manual:`capped collections `, specify + :manual:`document validation criteria `, + or configure your storage engine or indexing options. + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-createCollection-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-createCollection-option.rst + + Note that not all options are available on all versions of MongoDB. Document + validation, for example, was added in MongoDB 3.2; similarly, the WiredTiger + storage engine is available only for MongoDB 3.0 and later. Refer to the + :manual:`create ` command reference in the MongoDB + manual for compatibility considerations. + +Return Values +------------- + +An array or object with the result document of the :manual:`create +` command. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example creates a ``users`` collection in the ``test`` +database with document validation criteria: + +.. code-block:: php + + test; + + $result = $db->createCollection('users', [ + 'validator' => [ + 'username' => ['$type' => 'string'], + 'email' => ['$regex' => '@mongodb\.com$'], + ], + ]); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#11 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :manual:`create ` command reference in the MongoDB + manual +- :manual:`db.createCollection() ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-drop.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-drop.txt new file mode 100644 index 00000000..bcf6ca88 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-drop.txt @@ -0,0 +1,78 @@ +========================= +MongoDB\\Database::drop() +========================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::drop() + + Drop the database. + + .. code-block:: php + + function drop(array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-drop-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-drop-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`dropDatabase +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example drops the ``test`` database: + +.. code-block:: php + + test; + + $result = $db->drop(); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["dropped"]=> + string(4) "test" + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::dropDatabase()` +- :manual:`dropDatabase ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-dropCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-dropCollection.txt new file mode 100644 index 00000000..fbc005b8 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-dropCollection.txt @@ -0,0 +1,80 @@ +=================================== +MongoDB\\Database::dropCollection() +=================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::dropCollection() + + Drop a collection within the current database. + + .. code-block:: php + + function dropCollection($collectionName, array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-dropCollection-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-dropCollection-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`drop +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example drops the ``users`` collection in the ``test`` database: + +.. code-block:: php + + test; + + $result = $db->dropCollection('users'); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["ns"]=> + string(10) "test.users" + ["nIndexesWas"]=> + int(1) + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::drop()` +- :manual:`drop ` command reference in the MongoDB + manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getDatabaseName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getDatabaseName.txt new file mode 100644 index 00000000..6ff9dcb9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getDatabaseName.txt @@ -0,0 +1,44 @@ +==================================== +MongoDB\\Database::getDatabaseName() +==================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getDatabaseName() + + Returns the name of this database. + + .. code-block:: php + + function getDatabaseName(): string + +Return Values +------------- + +The name of this database as a string. + +Example +------- + +The following example prints the name of a database object: + +.. code-block:: php + + test; + + echo $db->getDatabaseName(); + +The output would then resemble:: + + test diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getManager.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getManager.txt new file mode 100644 index 00000000..72a2b057 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getManager.txt @@ -0,0 +1,35 @@ +=============================== +MongoDB\\Database::getManager() +=============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getManager() + + Accessor for the + :php:`MongoDB\\Driver\\Manager ` used by this + :phpclass:`Database `. + + .. code-block:: php + + function getManager(): MongoDB\Manager + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Manager ` object. + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::getManager()` +- :phpmethod:`MongoDB\\Collection::getManager()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadConcern.txt new file mode 100644 index 00000000..fa277d88 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadConcern.txt @@ -0,0 +1,58 @@ +=================================== +MongoDB\\Database::getReadConcern() +=================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getReadConcern() + + Returns the read concern for this database. + + .. code-block:: php + + function getReadConcern(): MongoDB\Driver\ReadConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadConcern ` object. + +Example +------- + +.. code-block:: php + + selectDatabase('test', [ + 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY), + ]); + + var_dump($database->getReadConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadConcern)#5 (1) { + ["level"]=> + string(8) "majority" + } + +See Also +-------- + +- :manual:`Read Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\ReadConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getReadConcern()` +- :phpmethod:`MongoDB\\Collection::getReadConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadPreference.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadPreference.txt new file mode 100644 index 00000000..c70b4026 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getReadPreference.txt @@ -0,0 +1,58 @@ +====================================== +MongoDB\\Database::getReadPreference() +====================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getReadPreference() + + Returns the read preference for this database. + + .. code-block:: php + + function getReadPreference(): MongoDB\Driver\ReadPreference + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadPreference ` +object. + +Example +------- + +.. code-block:: php + + selectDatabase('test', [ + 'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'), + ]); + + var_dump($database->getReadPreference()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadPreference)#5 (1) { + ["mode"]=> + string(16) "primaryPreferred" + } + +See Also +-------- + +- :manual:`Read Preference ` in the MongoDB manual +- :phpmethod:`MongoDB\\Client::getReadPreference()` +- :phpmethod:`MongoDB\\Collection::getReadPreference()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getReadPreference()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getTypeMap.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getTypeMap.txt new file mode 100644 index 00000000..bc1688d6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getTypeMap.txt @@ -0,0 +1,65 @@ +=============================== +MongoDB\\Database::getTypeMap() +=============================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getTypeMap() + + Returns the type map for this database. + + .. code-block:: php + + function getTypeMap(): array + +Return Values +------------- + +A :ref:`type map ` array. + +Example +------- + +.. code-block:: php + + selectDatabase('test', [ + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ]); + + var_dump($database->getTypeMap()); + +The output would then resemble:: + + array(3) { + ["root"]=> + string(5) "array" + ["document"]=> + string(5) "array" + ["array"]=> + string(5) "array" + } + +See Also +-------- + +- :doc:`/reference/bson` +- :phpmethod:`MongoDB\\Client::getTypeMap()` +- :phpmethod:`MongoDB\\Collection::getTypeMap()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getTypeMap()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getWriteConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getWriteConcern.txt new file mode 100644 index 00000000..31b0ded5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-getWriteConcern.txt @@ -0,0 +1,61 @@ +==================================== +MongoDB\\Database::getWriteConcern() +==================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::getWriteConcern() + + Returns the write concern for this database. + + .. code-block:: php + + function getWriteConcern(): MongoDB\Driver\WriteConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\WriteConcern ` +object. + +Example +------- + +.. code-block:: php + + selectDatabase('test', [ + 'writeConcern' => new MongoDB\Driver\WriteConcern(1, 0, true), + ]); + + var_dump($database->getWriteConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\WriteConcern)#5 (2) { + ["w"]=> + int(1) + ["j"]=> + bool(true) + } + +See Also +-------- + +- :manual:`Write Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\WriteConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getWriteConcern()` +- :phpmethod:`MongoDB\\Collection::getWriteConcern()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::getWriteConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-listCollections.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-listCollections.txt new file mode 100644 index 00000000..99fd69f5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-listCollections.txt @@ -0,0 +1,121 @@ +==================================== +MongoDB\\Database::listCollections() +==================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::listCollections() + + Returns information for all collections in this database. + + .. code-block:: php + + function listCollections(array $options = []): MongoDB\Model\CollectionInfoIterator + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-listCollections-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-listCollections-option.rst + +Return Values +------------- + +A traversable :phpclass:`MongoDB\\Model\\CollectionInfoIterator`, which contains +a :phpclass:`MongoDB\\Model\\CollectionInfo` object for each collection in the +database. + +Example +------- + +The following example lists all of the collections in the ``test`` database: + +.. code-block:: php + + test; + + foreach ($database->listCollections() as $collectionInfo) { + var_dump($collectionInfo); + } + +The output would then resemble:: + + object(MongoDB\Model\CollectionInfo)#3 (2) { + ["name"]=> + string(11) "restaurants" + ["options"]=> + array(0) { + } + } + object(MongoDB\Model\CollectionInfo)#3 (2) { + ["name"]=> + string(5) "users" + ["options"]=> + array(0) { + } + } + object(MongoDB\Model\CollectionInfo)#3 (2) { + ["name"]=> + string(6) "restos" + ["options"]=> + array(0) { + } + } + +The following example lists all collections whose name starts with ``"rest"`` +in the ``test`` database: + +.. code-block:: php + + test; + + $collections = $database->listCollections([ + 'filter' => [ + 'name' => new MongoDB\BSON\Regex('^rest.*'), + ], + ]); + + foreach ($collections as $collectionInfo) { + var_dump($collectionInfo); + } + +The output would then resemble:: + + object(MongoDB\Model\CollectionInfo)#3 (2) { + ["name"]=> + string(11) "restaurants" + ["options"]=> + array(0) { + } + } + object(MongoDB\Model\CollectionInfo)#3 (2) { + ["name"]=> + string(6) "restos" + ["options"]=> + array(0) { + } + } + +See Also +-------- + +- :manual:`listCollections `_ + specification diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectCollection.txt new file mode 100644 index 00000000..8a5a42b2 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectCollection.txt @@ -0,0 +1,83 @@ +===================================== +MongoDB\\Database::selectCollection() +===================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::selectCollection() + + Selects a collection within the database. + + .. code-block:: php + + function selectCollection($collectionName, array $options = []): MongoDB\Collection + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-selectCollection-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-selectCollection-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +The selected collection inherits options such as read preference and type +mapping from the :phpclass:`Database ` object. Options may be +overridden via the ``$options`` parameter. + +Example +------- + +The following example selects the ``users`` collection in the ``test`` database: + +.. code-block:: php + + test; + + $collection = $db->selectCollection('test', 'users'); + +The following example selects the ``users`` collection in the ``test`` +database with a custom read preference: + +.. code-block:: php + + test; + + $users = $db->selectCollection( + 'users', + [ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ] + ); + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::__get()` +- :phpmethod:`MongoDB\\Client::selectCollection()` +- :phpmethod:`MongoDB\\Collection::__construct()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt new file mode 100644 index 00000000..9c63fdf7 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt @@ -0,0 +1,80 @@ +======================================= +MongoDB\\Database::selectGridFSBucket() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::selectGridFSBucket() + + Selects a GridFS bucket within the database. + + .. code-block:: php + + function selectGridFSBucket(array $options = []): MongoDB\GridFS\Bucket + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-selectGridFSBucket-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-selectGridFSBucket-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\GridFS\\Bucket` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +The selected bucket inherits options such as read preference and type +mapping from the :phpclass:`Database ` object. Options may be +overridden via the ``$options`` parameter. + +Example +------- + +The following example selects the default ``fs.files`` bucket in the ``test`` +database: + +.. code-block:: php + + test; + + $bucket = $db->selectGridFSBucket(); + +The following example selects the custom ``images.files`` bucket in the ``test`` +database with a custom read preference: + +.. code-block:: php + + test; + + $imagesBucket = $db->selectGridFSBucket([ + 'bucketName' => 'images', + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ]); + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::__construct()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-withOptions.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-withOptions.txt new file mode 100644 index 00000000..9bc0a82e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase-withOptions.txt @@ -0,0 +1,61 @@ +================================ +MongoDB\\Database::withOptions() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::withOptions() + + Returns a clone of the Database object, but with different options. + + .. code-block:: php + + function withOptions(array $options = []): MongoDB\Database + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-withOptions-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-withOptions-option.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Database` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Example +------- + +The following example clones an existing Database object with a new read +preference: + +.. code-block:: php + + test; + + $newDb = $db->withOptions([ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY), + ]); + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::__construct()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__construct.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__construct.txt new file mode 100644 index 00000000..2d3e7f57 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__construct.txt @@ -0,0 +1,50 @@ +================================ +MongoDB\\Database::__construct() +================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::__construct() + + Constructs a new :phpclass:`Database ` instance. + + .. code-block:: php + + function __construct(MongoDB\Driver\Manager $manager, $databaseName, array $options = []) + + This constructor has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-construct-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-construct-option.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +If you construct a Database explicitly, the Database inherits any options from +the :php:`MongoDB\\Driver\\Manager ` object. If +you select the Database from a :phpclass:`Client ` object, the +Database inherits its options from that object. + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::withOptions()` +- :phpmethod:`MongoDB\\Client::selectDatabase()` +- :phpmethod:`MongoDB\\Client::__get()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__get.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__get.txt new file mode 100644 index 00000000..c41e3981 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDatabase__get.txt @@ -0,0 +1,69 @@ +========================== +MongoDB\\Database::__get() +========================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::__get() + + Select a collection within the database. + + .. code-block:: php + + function __get($collectionName): MongoDB\Collection + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-get-param.rst + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object. + +Behavior +-------- + +The selected collection inherits options such as read preference and type +mapping from the :phpclass:`Database ` object. If you wish to +override any options, use the :phpmethod:`MongoDB\\Database::selectCollection` +method. + +.. note:: + + To select collections whose names contain special characters, such as + ``.``, use complex syntax, as in ``$database->{'that.database'}``. + + Alternatively, :phpmethod:`MongoDB\\Database::selectCollection` supports + selecting collections whose names contain special characters. + +Examples +-------- + +The following example selects the ``users`` and ``system.profile`` +collections from the ``test`` database: + +.. code-block:: php + + test; + + $users = $db->users; + $systemProfile = $db->{'system.profile'}; + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::selectCollection()` +- :phpmethod:`MongoDB\\Client::selectCollection()` +- :php:`Property Overloading ` in the PHP Manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-getDeletedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-getDeletedCount.txt new file mode 100644 index 00000000..dcda2574 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-getDeletedCount.txt @@ -0,0 +1,40 @@ +======================================== +MongoDB\\DeleteResult::getDeletedCount() +======================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\DeleteResult::getDeletedCount() + + Return the number of documents that were deleted. + + .. code-block:: php + + function getDeletedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The number of documents that were deleted. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getDeletedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-isAcknowledged.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-isAcknowledged.txt new file mode 100644 index 00000000..a82fa523 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBDeleteResult-isAcknowledged.txt @@ -0,0 +1,34 @@ +======================================= +MongoDB\\DeleteResult::isAcknowledged() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\DeleteResult::isAcknowledged() + + Return whether the write was acknowledged. + + .. code-block:: php + + function isAcknowledged(): boolean + +Return Values +------------- + +A boolean indicating whether the write was acknowledged. + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::isAcknowledged() + ` +- :manual:`Write Concern ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-delete.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-delete.txt new file mode 100644 index 00000000..6e4eeac5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-delete.txt @@ -0,0 +1,40 @@ +================================= +MongoDB\\GridFS\\Bucket::delete() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::delete() + + Delete a file and its chunks from the GridFS bucket. + + .. code-block:: php + + function delete($id): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-delete-param.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +If the files collection document is not found, this method will still attempt to +delete orphaned chunks. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt new file mode 100644 index 00000000..62009501 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt @@ -0,0 +1,43 @@ +=========================================== +MongoDB\\GridFS\\Bucket::downloadToStream() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::downloadToStream() + + Selects a GridFS file by its ``_id`` and copies its contents to a writable + stream. + + .. code-block:: php + + function downloadToStream($id, $destination): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-downloadToStream-param.rst + +.. todo: add examples + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStreamByName()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStream()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStreamByName()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt new file mode 100644 index 00000000..ca294bc3 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt @@ -0,0 +1,47 @@ +================================================= +MongoDB\\GridFS\\Bucket::downloadToStreamByName() +================================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::downloadToStreamByName() + + Selects a GridFS file by its ``filename`` and copies its contents to a + writable stream. + + .. code-block:: php + + function downloadToStreamByName($filename, $destination, array $options = []): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-downloadToStreamByName-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-downloadToStreamByName-option.rst + +.. todo: add examples + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStream()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStream()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStreamByName()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-drop.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-drop.txt new file mode 100644 index 00000000..a6730fc8 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-drop.txt @@ -0,0 +1,29 @@ +=============================== +MongoDB\\GridFS\\Bucket::drop() +=============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::drop() + + Drops the files and chunks collections associated with this GridFS bucket. + + .. code-block:: php + + function drop(): void + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-find.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-find.txt new file mode 100644 index 00000000..8f40253e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-find.txt @@ -0,0 +1,55 @@ +=============================== +MongoDB\\GridFS\\Bucket::find() +=============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::find() + + Finds documents from the GridFS bucket's files collection matching the query. + + .. code-block:: php + + function find($filter = [], array $options = []): MongoDB\Driver\Cursor + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-find-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-find-option.rst + +Return Values +------------- + +A :php:`MongoDB\\Driver\\Cursor ` object. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::find()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::findOne()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-findOne.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-findOne.txt new file mode 100644 index 00000000..f07a6134 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-findOne.txt @@ -0,0 +1,58 @@ +================================== +MongoDB\\GridFS\\Bucket::findOne() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::findOne() + + Finds a single document from the GridFS bucket's files collection matching + the query. + + .. code-block:: php + + function findOne($filter = [], array $options = []): array|object|null + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-findOne-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-findOne-option.rst + +Return Values +------------- + +An array or object for the :term:`first document ` that matched +the query, or ``null`` if no document matched the query. The return type will +depend on the ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Behavior +-------- + +.. include:: /includes/extracts/note-bson-comparison.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::findOne()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::find()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt new file mode 100644 index 00000000..d8a43a3c --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt @@ -0,0 +1,29 @@ +======================================== +MongoDB\\GridFS\\Bucket::getBucketName() +======================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getBucketName() + + Returns the name of this bucket. + + .. code-block:: php + + function getBucketName(): string + +Return Values +------------- + +The name of this bucket as a string. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt new file mode 100644 index 00000000..3a97aba7 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt @@ -0,0 +1,31 @@ +============================================ +MongoDB\\GridFS\\Bucket::getChunkSizeBytes() +============================================ + +.. versionchanged:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getChunkSizeBytes() + + Returns the chunk size of this bucket in bytes. + + .. code-block:: php + + function getChunkSizeBytes(): integer + +Return Values +------------- + +The chunk size of this bucket in bytes. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt new file mode 100644 index 00000000..cc98abed --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt @@ -0,0 +1,31 @@ +============================================== +MongoDB\\GridFS\\Bucket::getChunksCollection() +============================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getChunksCollection() + + Returns the chunks collection used by the bucket. + + .. code-block:: php + + function getChunksCollection(): MongoDB\Collection + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object for the chunks collection. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt new file mode 100644 index 00000000..dc3ceeaa --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt @@ -0,0 +1,29 @@ +========================================== +MongoDB\\GridFS\\Bucket::getDatabaseName() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getDatabaseName() + + Returns the name of the database containing this bucket. + + .. code-block:: php + + function getDatabaseName(): string + +Return Values +------------- + +The name of the database containing this bucket as a string. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt new file mode 100644 index 00000000..faa58913 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt @@ -0,0 +1,45 @@ +=================================================== +MongoDB\\GridFS\\Bucket::getFileDocumentForStream() +=================================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getFileDocumentForStream() + + Gets the file document of the GridFS file associated with a stream. + + .. code-block:: php + + function getFileDocumentForStream($stream): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-getFileDocumentForStream-param.rst + +Return Values +------------- + +The metadata document associated with the GridFS stream. The return type will +depend on the bucket's ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::getFileIdForStream()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt new file mode 100644 index 00000000..b7ef9964 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt @@ -0,0 +1,46 @@ +============================================= +MongoDB\\GridFS\\Bucket::getFileIdForStream() +============================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getFileIdForStream() + + Gets the file document's ID of the GridFS file associated with a stream. + + .. code-block:: php + + function getFileIdForStream($stream): mixed + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-getFileIdForStream-param.rst + +Return Values +------------- + +The ``_id`` field of the metadata document associated with the GridFS stream. +The return type will depend on the bucket's ``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-corruptfileexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::getFileDocumentForStream()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt new file mode 100644 index 00000000..e989202b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt @@ -0,0 +1,31 @@ +============================================= +MongoDB\\GridFS\\Bucket::getFilesCollection() +============================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getFilesCollection() + + Returns the files collection used by the bucket. + + .. code-block:: php + + function getFilesCollection(): MongoDB\Collection + +Return Values +------------- + +A :phpclass:`MongoDB\\Collection` object for the files collection. + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt new file mode 100644 index 00000000..00517d22 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt @@ -0,0 +1,59 @@ +========================================= +MongoDB\\GridFS\\Bucket::getReadConcern() +========================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getReadConcern() + + Returns the read concern for this GridFS bucket. + + .. code-block:: php + + function getReadConcern(): MongoDB\Driver\ReadConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadConcern ` object. + +Example +------- + +.. code-block:: php + + selectDatabase('test'); + $bucket = $database->selectGridFSBucket([ + 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY), + ]); + + var_dump($bucket->getReadConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadConcern)#3 (1) { + ["level"]=> + string(8) "majority" + } + +See Also +-------- + +- :manual:`Read Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\ReadConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getReadConcern()` +- :phpmethod:`MongoDB\\Collection::getReadConcern()` +- :phpmethod:`MongoDB\\Database::getReadConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt new file mode 100644 index 00000000..94003eea --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt @@ -0,0 +1,59 @@ +============================================ +MongoDB\\GridFS\\Bucket::getReadPreference() +============================================ + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getReadPreference() + + Returns the read preference for this GridFS bucket. + + .. code-block:: php + + function getReadPreference(): MongoDB\Driver\ReadPreference + +Return Values +------------- + +A :php:`MongoDB\\Driver\\ReadPreference ` +object. + +Example +------- + +.. code-block:: php + + selectDatabase('test'); + $bucket = $database->selectGridFSBucket([ + 'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'), + ]); + + var_dump($bucket->getReadPreference()); + +The output would then resemble:: + + object(MongoDB\Driver\ReadPreference)#3 (1) { + ["mode"]=> + string(16) "primaryPreferred" + } + +See Also +-------- + +- :manual:`Read Preference ` in the MongoDB manual +- :phpmethod:`MongoDB\\Client::getReadPreference()` +- :phpmethod:`MongoDB\\Collection::getReadPreference()` +- :phpmethod:`MongoDB\\Database::getReadPreference()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt new file mode 100644 index 00000000..cd9c4a1b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt @@ -0,0 +1,66 @@ +===================================== +MongoDB\\GridFS\\Bucket::getTypeMap() +===================================== + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getTypeMap() + + Returns the type map for this GridFS bucket. + + .. code-block:: php + + function getTypeMap(): array + +Return Values +------------- + +A :ref:`type map ` array. + +Example +------- + +.. code-block:: php + + selectDatabase('test'); + $bucket = $database->selectGridFSBucket([ + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ]); + + var_dump($bucket->getTypeMap()); + +The output would then resemble:: + + array(3) { + ["root"]=> + string(5) "array" + ["document"]=> + string(5) "array" + ["array"]=> + string(5) "array" + } + +See Also +-------- + +- :doc:`/reference/bson` +- :phpmethod:`MongoDB\\Client::getTypeMap()` +- :phpmethod:`MongoDB\\Collection::getTypeMap()` +- :phpmethod:`MongoDB\\Database::getTypeMap()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt new file mode 100644 index 00000000..1b5577e6 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt @@ -0,0 +1,62 @@ +========================================= +MongoDB\\GridFS\Bucket::getWriteConcern() +========================================= + +.. versionadded:: 1.2 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::getWriteConcern() + + Returns the write concern for this GridFS bucket. + + .. code-block:: php + + function getWriteConcern(): MongoDB\Driver\WriteConcern + +Return Values +------------- + +A :php:`MongoDB\\Driver\\WriteConcern ` +object. + +Example +------- + +.. code-block:: php + + selectDatabase('test'); + $bucket = $database->selectGridFSBucket([ + 'writeConcern' => new MongoDB\Driver\WriteConcern(1, 0, true), + ]); + + var_dump($bucket->getWriteConcern()); + +The output would then resemble:: + + object(MongoDB\Driver\WriteConcern)#3 (2) { + ["w"]=> + int(1) + ["j"]=> + bool(true) + } + +See Also +-------- + +- :manual:`Write Concern ` in the MongoDB manual +- :php:`MongoDB\\Driver\\WriteConcern::isDefault() ` +- :phpmethod:`MongoDB\\Client::getWriteConcern()` +- :phpmethod:`MongoDB\\Collection::getWriteConcern()` +- :phpmethod:`MongoDB\\Database::getWriteConcern()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt new file mode 100644 index 00000000..69f6d54f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt @@ -0,0 +1,46 @@ +============================================= +MongoDB\\GridFS\\Bucket::openDownloadStream() +============================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::openDownloadStream() + + Selects a GridFS file by its ``_id`` and opens it as a readable stream. + + .. code-block:: php + + function openDownloadStream($id): resource + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-openDownloadStream-param.rst + +Return Values +------------- + +A readable stream resource. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStream()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStreamByName()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStreamByName()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt new file mode 100644 index 00000000..b4976852 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt @@ -0,0 +1,50 @@ +=================================================== +MongoDB\\GridFS\\Bucket::openDownloadStreamByName() +=================================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::openDownloadStreamByName() + + Selects a GridFS file by its ``filename`` and opens it as a readable stream. + + .. code-block:: php + + function openDownloadStreamByName($filename, array $options = []): resource + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-openDownloadStreamByName-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-openDownloadStreamByName-option.rst + +Return Values +------------- + +A readable stream resource. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStream()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::downloadToStreamByName()` +- :phpmethod:`MongoDB\\GridFS\\Bucket::openDownloadStream()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt new file mode 100644 index 00000000..2ad11c4a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt @@ -0,0 +1,48 @@ +=========================================== +MongoDB\\GridFS\\Bucket::openUploadStream() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::openUploadStream() + + Opens a writable stream for a new GridFS file. + + .. code-block:: php + + function openUploadStream($filename, array $options = []): resource + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-openUploadStream-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-openUploadStream-option.rst + +Return Values +------------- + +A writable stream resource. + +Behavior +-------- + +Chunk documents will be created as data is written to the writable stream. The +metadata document will be created when the writable stream is closed. + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::uploadFromStream()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-rename.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-rename.txt new file mode 100644 index 00000000..77fd899e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-rename.txt @@ -0,0 +1,34 @@ +================================= +MongoDB\\GridFS\\Bucket::rename() +================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::rename() + + Selects a GridFS file by its ``_id`` and alters its ``filename``. + + .. code-block:: php + + function rename($id, $newFilename): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-rename-param.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-gridfs-filenotfoundexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt new file mode 100644 index 00000000..fa26bacc --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt @@ -0,0 +1,51 @@ +=========================================== +MongoDB\\GridFS\\Bucket::uploadFromStream() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::uploadFromStream() + + Creates a new GridFS file and copies the contents of a readable stream to it. + + .. code-block:: php + + function uploadFromStream($filename, $source, array $options = []): mixed + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-uploadFromStream-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-uploadFromStream-option.rst + +Return Values +------------- + +The ``_id`` field of the metadata document associated with the newly created +GridFS file. If the ``_id`` option is not specified, a new +:php:`MongoDB\\BSON\\ObjectId ` object will be used +by default. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +.. todo: add examples + +See Also +-------- + +- :phpmethod:`MongoDB\\GridFS\\Bucket::openUploadStream()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket__construct.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket__construct.txt new file mode 100644 index 00000000..d6c29373 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBGridFSBucket__construct.txt @@ -0,0 +1,50 @@ +====================================== +MongoDB\\GridFS\\Bucket::__construct() +====================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\GridFS\\Bucket::__construct() + + Constructs a new :phpclass:`Bucket ` instance. + + .. code-block:: php + + function __construct(MongoDB\Driver\Manager $manager, $databaseName, $collectionName, array $options = []) + + This constructor has the following parameters: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-construct-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBGridFSBucket-method-construct-option.rst + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +Behavior +-------- + +If you construct a Bucket explicitly, the Bucket inherits any options +from the :php:`MongoDB\\Driver\\Manager ` object. +If you select the Bucket from a :phpclass:`Database ` object, +the Bucket inherits its options from that object. + +.. todo: add an example + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::selectGridFSBucket()` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedCount.txt new file mode 100644 index 00000000..9297008b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedCount.txt @@ -0,0 +1,40 @@ +============================================= +MongoDB\\InsertManyResult::getInsertedCount() +============================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertManyResult::getInsertedCount() + + Return the number of documents that were inserted. + + .. code-block:: php + + function getInsertedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The number of documents that were inserted. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getInsertedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedIds.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedIds.txt new file mode 100644 index 00000000..75c63870 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-getInsertedIds.txt @@ -0,0 +1,36 @@ +=========================================== +MongoDB\\InsertManyResult::getInsertedIds() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertManyResult::getInsertedIds() + + Return a map of IDs (i.e. ``_id`` field values) for the inserted documents. + + .. code-block:: php + + function getInsertedIds(): array + + Since IDs are created by the driver, this method may be called irrespective + of whether the write was acknowledged. + +Return Values +------------- + +A map of IDs (i.e. ``_id`` field values) for the inserted documents. + +The index of each ID in the map corresponds to each document's position in the +bulk operation. If a document had an ID prior to inserting (i.e. the driver did +not generate an ID), the index will contain its ``_id`` field value. Any +driver-generated ID will be a :php:`MongoDB\\BSON\\ObjectId +` instance. diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-isAcknowledged.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-isAcknowledged.txt new file mode 100644 index 00000000..db376e5f --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertManyResult-isAcknowledged.txt @@ -0,0 +1,34 @@ +=========================================== +MongoDB\\InsertManyResult::isAcknowledged() +=========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertManyResult::isAcknowledged() + + Return whether the write was acknowledged. + + .. code-block:: php + + function isAcknowledged(): boolean + +Return Values +------------- + +A boolean indicating whether the write was acknowledged. + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::isAcknowledged() + ` +- :manual:`Write Concern ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedCount.txt new file mode 100644 index 00000000..35508015 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedCount.txt @@ -0,0 +1,41 @@ +============================================ +MongoDB\\InsertOneResult::getInsertedCount() +============================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertOneResult::getInsertedCount() + + Return the number of documents that were inserted. + + .. code-block:: php + + function getInsertedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The number of documents that were inserted. This should be ``1`` for an +acknowledged insert operation. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getInsertedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedId.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedId.txt new file mode 100644 index 00000000..8d4a01dd --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-getInsertedId.txt @@ -0,0 +1,35 @@ +========================================= +MongoDB\\InsertOneResult::getInsertedId() +========================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertOneResult::getInsertedId() + + Return the ID (i.e. ``_id`` field value) for the inserted document. + + .. code-block:: php + + function getInsertedId(): mixed + + Since IDs are created by the driver, this method may be called irrespective + of whether the write was acknowledged. + +Return Values +------------- + +The ID (i.e. ``_id`` field value) of the inserted document. + +If the document had an ID prior to inserting (i.e. the driver did not need to +generate an ID), this will contain its ``_id`` field value. Any driver-generated +ID will be a :php:`MongoDB\\BSON\\ObjectId ` +instance. diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-isAcknowledged.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-isAcknowledged.txt new file mode 100644 index 00000000..921e3a61 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBInsertOneResult-isAcknowledged.txt @@ -0,0 +1,34 @@ +========================================== +MongoDB\\InsertOneResult::isAcknowledged() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\InsertOneResult::isAcknowledged() + + Return whether the write was acknowledged. + + .. code-block:: php + + function isAcknowledged(): boolean + +Return Values +------------- + +A boolean indicating whether the write was acknowledged. + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::isAcknowledged() + ` +- :manual:`Write Concern ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt new file mode 100644 index 00000000..693350f0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt @@ -0,0 +1,39 @@ +============================================== +MongoDB\\Model\\CollectionInfo::getCappedMax() +============================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getCappedMax() + + Return the document limit for the capped collection. This correlates with the + ``max`` option for :phpmethod:`MongoDB\\Database::createCollection()`. + + .. code-block:: php + + function getCappedMax(): integer|null + +Return Values +------------- + +The document limit for the capped collection. If the collection is not capped, +``null`` will be returned. + +See Also +-------- + +- :phpmethod:`MongoDB\\Model\\CollectionInfo::getCappedSize()` +- :phpmethod:`MongoDB\\Model\\CollectionInfo::isCapped()` +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`Capped Collections ` in the MongoDB manual +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt new file mode 100644 index 00000000..cc0bd769 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt @@ -0,0 +1,40 @@ +=============================================== +MongoDB\\Model\\CollectionInfo::getCappedSize() +=============================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getCappedSize() + + Return the size limit for the capped collection in bytes. This correlates + with the ``size`` option for + :phpmethod:`MongoDB\\Database::createCollection()`. + + .. code-block:: php + + function getCappedSize(): integer|null + +Return Values +------------- + +The size limit for the capped collection in bytes. If the collection is not +capped, ``null`` will be returned. + +See Also +-------- + +- :phpmethod:`MongoDB\\Model\\CollectionInfo::getCappedMax()` +- :phpmethod:`MongoDB\\Model\\CollectionInfo::isCapped()` +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`Capped Collections ` in the MongoDB manual +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getName.txt new file mode 100644 index 00000000..cd04ffac --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getName.txt @@ -0,0 +1,34 @@ +========================================= +MongoDB\\Model\\CollectionInfo::getName() +========================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getName() + + Return the collection name. + + .. code-block:: php + + function getName(): string + +Return Values +------------- + +The collection name. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::getCollectionName()` +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt new file mode 100644 index 00000000..e360522b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt @@ -0,0 +1,36 @@ +============================================ +MongoDB\\Model\\CollectionInfo::getOptions() +============================================ + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getOptions() + + Return the collection options. This correlates with the options for + :phpmethod:`MongoDB\\Database::createCollection()`, but may include + additional fields set by the server. + + .. code-block:: php + + function getOptions(): array + +Return Values +------------- + +The collection options. + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt new file mode 100644 index 00000000..abfc387d --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt @@ -0,0 +1,37 @@ +========================================== +MongoDB\\Model\\CollectionInfo::isCapped() +========================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::isCapped() + + Return whether the collection is a :manual:`capped collection + `. + + .. code-block:: php + + function isCapped(): boolean + +Return Values +------------- + +A boolean indicating whether the collection is a capped collection. + +See Also +-------- + +- :phpmethod:`MongoDB\\Model\\CollectionInfo::getCappedMax()` +- :phpmethod:`MongoDB\\Model\\CollectionInfo::getCappedSize()` +- :manual:`Capped Collections ` in the MongoDB manual +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt new file mode 100644 index 00000000..47991f1a --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt @@ -0,0 +1,34 @@ +======================================= +MongoDB\\Model\\DatabaseInfo::getName() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\DatabaseInfo::getName() + + Return the database name. + + .. code-block:: php + + function getName(): string + +Return Values +------------- + +The database name. + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::getDatabaseName()` +- :manual:`listDatabases ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt new file mode 100644 index 00000000..2a8fe5ad --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt @@ -0,0 +1,33 @@ +============================================= +MongoDB\\Model\\DatabaseInfo::getSizeOnDisk() +============================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\DatabaseInfo::getSizeOnDisk() + + Return the total size of the database file on disk in bytes. + + .. code-block:: php + + function getSizeOnDisk(): integer + +Return Values +------------- + +The total size of the database file on disk in bytes. + +See Also +-------- + +- :manual:`listDatabases ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt new file mode 100644 index 00000000..878844d0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt @@ -0,0 +1,33 @@ +======================================= +MongoDB\\Model\\DatabaseInfo::isEmpty() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\DatabaseInfo::isEmpty() + + Return whether the database has any data. + + .. code-block:: php + + function isEmpty(): boolean + +Return Values +------------- + +A boolean indicating whether the database has any data. + +See Also +-------- + +- :manual:`listDatabases ` command reference + in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getKey.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getKey.txt new file mode 100644 index 00000000..6ad0712e --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getKey.txt @@ -0,0 +1,36 @@ +=================================== +MongoDB\\Model\\IndexInfo::getKey() +=================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::getKey() + + Return the index specification (i.e. indexed field(s) and order). This + correlates with the ``$key`` parameter for + :phpmethod:`MongoDB\\Collection::createIndex()`. + + .. code-block:: php + + function getKey(): array + +Return Values +------------- + +The index specification as an associative array. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getName.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getName.txt new file mode 100644 index 00000000..26983790 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getName.txt @@ -0,0 +1,37 @@ +==================================== +MongoDB\\Model\\IndexInfo::getName() +==================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::getName() + + Return the index name. This correlates with the return value of + :phpmethod:`MongoDB\\Collection::createIndex()`. An index name may be derived + from the ``$key`` parameter or or explicitly specified via the ``name`` + option. + + .. code-block:: php + + function getName(): string + +Return Values +------------- + +The index name. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt new file mode 100644 index 00000000..987c8bec --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt @@ -0,0 +1,36 @@ +========================================= +MongoDB\\Model\\IndexInfo::getNamespace() +========================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::getNamespace() + + Return the index namespace, which is the namespace of the collection + containing the index. + + .. code-block:: php + + function getNamespace(): string + +Return Values +------------- + +The index namespace. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :phpmethod:`MongoDB\\Collection::getNamespace()` +- :manual:`listIndexes ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt new file mode 100644 index 00000000..e2480df0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt @@ -0,0 +1,34 @@ +======================================= +MongoDB\\Model\\IndexInfo::getVersion() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::getVersion() + + Return the index version. + + .. code-block:: php + + function getVersion(): integer + +Return Values +------------- + +The index version. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt new file mode 100644 index 00000000..580e2f60 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt @@ -0,0 +1,37 @@ +===================================== +MongoDB\\Model\\IndexInfo::isSparse() +===================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::isSparse() + + Return whether the index is a :manual:`sparse index `. + This correlates with the ``sparse`` option for + :phpmethod:`MongoDB\\Collection::createIndex()`. + + .. code-block:: php + + function isSparse(): boolean + +Return Values +------------- + +A boolean indicating whether the index is a sparse index. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual +- :manual:`Sparse Indexes ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt new file mode 100644 index 00000000..f2f16e02 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt @@ -0,0 +1,37 @@ +================================== +MongoDB\\Model\\IndexInfo::isTtl() +================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::isTtl() + + Return whether the index is a :manual:`TTL index `. This + correlates with the ``expireAfterSeconds`` option for + :phpmethod:`MongoDB\\Collection::createIndex()`. + + .. code-block:: php + + function isTtl(): boolean + +Return Values +------------- + +A boolean indicating whether the index is a TTL index. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual +- :manual:`TTL Indexes ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt new file mode 100644 index 00000000..5fbfa765 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt @@ -0,0 +1,37 @@ +===================================== +MongoDB\\Model\\IndexInfo::isUnique() +===================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\IndexInfo::isUnique() + + Return whether the index is a :manual:`unique index `. + This correlates with the ``unique`` option for + :phpmethod:`MongoDB\\Collection::createIndex()`. + + .. code-block:: php + + function isUnique(): boolean + +Return Values +------------- + +A boolean indicating whether the index is a unique index. + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::createIndex()` +- :manual:`listIndexes ` command reference in + the MongoDB manual +- :manual:`Unique Indexes ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getMatchedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getMatchedCount.txt new file mode 100644 index 00000000..f347a8cf --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getMatchedCount.txt @@ -0,0 +1,49 @@ +======================================== +MongoDB\\UpdateResult::getMatchedCount() +======================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\UpdateResult::getMatchedCount() + + Return the number of documents that were matched. + + .. code-block:: php + + function getMatchedCount(): integer + + This method should only be called if the write was acknowledged. + + .. note:: + + If an update/replace operation results in no change to the document + (e.g. setting the value of a field to its current value), the matched + count may be greater than the value returned by + :phpmethod:`getModifiedCount() + `. + +Return Values +------------- + +The number of documents that were matched. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\UpdateResult::getModifiedCount()` +- :php:`MongoDB\\Driver\\WriteResult::getMatchedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getModifiedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getModifiedCount.txt new file mode 100644 index 00000000..0bd708a0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getModifiedCount.txt @@ -0,0 +1,52 @@ +========================================= +MongoDB\\UpdateResult::getModifiedCount() +========================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\UpdateResult::getModifiedCount() + + Return the number of documents that were modified. + + .. code-block:: php + + function getModifiedCount(): integer|null + + This method should only be called if the write was acknowledged. + + .. note:: + + If an update/replace operation results in no change to the document + (e.g. setting the value of a field to its current value), the modified + count may be less than the value returned by :phpmethod:`getMatchedCount() + `. + +Return Values +------------- + +The number of documents that were modified. + +The modified count is not available on versions of MongoDB before 2.6, which +used the legacy wire protocol version (i.e. ``OP_UPDATE``). If this is the case, +the modified count will be ``null``. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\UpdateResult::getMatchedCount()` +- :php:`MongoDB\\Driver\\WriteResult::getModifiedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedCount.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedCount.txt new file mode 100644 index 00000000..0bbb39fb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedCount.txt @@ -0,0 +1,42 @@ +========================================= +MongoDB\\UpdateResult::getUpsertedCount() +========================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\UpdateResult::getUpsertedCount() + + Return the number of documents that were upserted. + + .. code-block:: php + + function getUpsertedCount(): integer + + This method should only be called if the write was acknowledged. + +Return Values +------------- + +The total number of documents that were upserted. This should be either ``0`` or +``1`` for an acknowledged update or replace operation, depending on whether an +upsert occurred. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getUpsertedCount() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedId.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedId.txt new file mode 100644 index 00000000..52498708 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-getUpsertedId.txt @@ -0,0 +1,44 @@ +====================================== +MongoDB\\UpdateResult::getUpsertedId() +====================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\UpdateResult::getUpsertedId() + + Return the ID (i.e. ``_id`` field value) of the upserted document. + + .. code-block:: php + + function getUpsertedId(): mixed|null + +Return Values +------------- + +The ID (i.e. ``_id`` field value) of the upserted document. If no document was +upserted, ``null`` will be returned. + +If the document had an ID prior to upserting (i.e. the server did not need to +generate an ID), this will contain its ``_id`` field value. Any server-generated +ID will be a :php:`MongoDB\\BSON\\ObjectId ` +instance. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-badmethodcallexception-write-result.rst + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::getUpsertedIds() + ` diff --git a/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-isAcknowledged.txt b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-isAcknowledged.txt new file mode 100644 index 00000000..af15d1f1 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/method/MongoDBUpdateResult-isAcknowledged.txt @@ -0,0 +1,34 @@ +======================================= +MongoDB\\UpdateResult::isAcknowledged() +======================================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\UpdateResult::isAcknowledged() + + Return whether the write was acknowledged. + + .. code-block:: php + + function isAcknowledged(): boolean + +Return Values +------------- + +A boolean indicating whether the write was acknowledged. + +See Also +-------- + +- :php:`MongoDB\\Driver\\WriteResult::isAcknowledged() + ` +- :manual:`Write Concern ` in the MongoDB manual diff --git a/vendor/mongodb/mongodb/docs/reference/write-result-classes.txt b/vendor/mongodb/mongodb/docs/reference/write-result-classes.txt new file mode 100644 index 00000000..f410c083 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/reference/write-result-classes.txt @@ -0,0 +1,143 @@ +==================== +Write Result Classes +==================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +MongoDB\\BulkWriteResult +------------------------ + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\BulkWriteResult + + This class contains information about an executed bulk write operation. It + encapsulates a :php:`MongoDB\\Driver\\WriteResult + ` object and is returned from + :phpmethod:`MongoDB\\Collection::bulkWrite()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBBulkWriteResult-getDeletedCount + /reference/method/MongoDBBulkWriteResult-getInsertedCount + /reference/method/MongoDBBulkWriteResult-getInsertedIds + /reference/method/MongoDBBulkWriteResult-getMatchedCount + /reference/method/MongoDBBulkWriteResult-getModifiedCount + /reference/method/MongoDBBulkWriteResult-getUpsertedCount + /reference/method/MongoDBBulkWriteResult-getUpsertedIds + /reference/method/MongoDBBulkWriteResult-isAcknowledged + +---- + +MongoDB\\DeleteResult +--------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\DeleteResult + + This class contains information about an executed delete operation. It + encapsulates a :php:`MongoDB\\Driver\\WriteResult + ` object and is returned from + :phpmethod:`MongoDB\\Collection::deleteMany()` or + :phpmethod:`MongoDB\\Collection::deleteOne()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBDeleteResult-getDeletedCount + /reference/method/MongoDBDeleteResult-isAcknowledged + +---- + +MongoDB\\InsertManyResult +------------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\InsertManyResult + + This class contains information about an executed bulk insert operation. It + encapsulates a :php:`MongoDB\\Driver\\WriteResult + ` object and is returned from + :phpmethod:`MongoDB\\Collection::insertMany()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBInsertManyResult-getInsertedCount + /reference/method/MongoDBInsertManyResult-getInsertedIds + /reference/method/MongoDBInsertManyResult-isAcknowledged + +---- + +MongoDB\\InsertOneResult +------------------------ + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\InsertOneResult + + This class contains information about an executed insert operation. It + encapsulates a :php:`MongoDB\\Driver\\WriteResult + ` object and is returned from + :phpmethod:`MongoDB\\Collection::insertOne()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBInsertOneResult-getInsertedCount + /reference/method/MongoDBInsertOneResult-getInsertedId + /reference/method/MongoDBInsertOneResult-isAcknowledged + +---- + +MongoDB\\UpdateResult +--------------------- + +Definition +~~~~~~~~~~ + +.. phpclass:: MongoDB\\UpdateResult + + This class contains information about an executed update or replace + operation. It encapsulates a :php:`MongoDB\\Driver\\WriteResult + ` object and is returned from + :phpmethod:`MongoDB\\Collection::replaceOne()`, + :phpmethod:`MongoDB\\Collection::updateMany()`, or + :phpmethod:`MongoDB\\Collection::updateOne()`. + +Methods +~~~~~~~ + +.. toctree:: + :titlesonly: + + /reference/method/MongoDBUpdateResult-getMatchedCount + /reference/method/MongoDBUpdateResult-getModifiedCount + /reference/method/MongoDBUpdateResult-getUpsertedCount + /reference/method/MongoDBUpdateResult-getUpsertedId + /reference/method/MongoDBUpdateResult-isAcknowledged diff --git a/vendor/mongodb/mongodb/docs/tutorial.txt b/vendor/mongodb/mongodb/docs/tutorial.txt new file mode 100644 index 00000000..27f36375 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial.txt @@ -0,0 +1,14 @@ +Tutorials +========= + +.. default-domain:: mongodb + +.. toctree:: + + /tutorial/crud + /tutorial/collation + /tutorial/commands + /tutorial/decimal128 + /tutorial/gridfs + /tutorial/indexes + /tutorial/example-data diff --git a/vendor/mongodb/mongodb/docs/tutorial/collation.txt b/vendor/mongodb/mongodb/docs/tutorial/collation.txt new file mode 100644 index 00000000..71b28a87 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/collation.txt @@ -0,0 +1,373 @@ +========= +Collation +========= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. versionadded:: 1.1 + +Overview +-------- + +MongoDB 3.4 introduced support for :manual:`collations +`, which provide a set of rules to comply with the +conventions of a particular language when comparing strings. + +For example, in Canadian French, the last accent in a given word determines the +sorting order. Consider the following French words: + +.. code-block:: none + + cote < coté < côte < côté + +The sort order using the Canadian French collation would result in the +following: + +.. code-block:: none + + cote < côte < coté < côté + +If collation is unspecified, MongoDB uses simple binary comparison for strings. +As such, the sort order of the words would be: + +.. code-block:: none + + cote < coté < côte < côté + +Usage +----- + +You can specify a default collation for collections and indexes when they are +created, or specify a collation for CRUD operations and aggregations. For +operations that support collation, MongoDB uses the collection's default +collation unless the operation specifies a different collation. + +Collation Parameters +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + 'collation' => [ + 'locale' => , + 'caseLevel' => , + 'caseFirst' => , + 'strength' => , + 'numericOrdering' => , + 'alternate' => , + 'maxVariable' => , + 'normalization' => , + 'backwards' => , + ] + +The only required parameter is ``locale``, which the server parses as an `ICU +format locale ID `_. For example, set +``locale`` to ``en_US`` to represent US English or ``fr_CA`` to represent +Canadian French. + +For a complete description of the available parameters, see :manual:`Collation +Document ` in the MongoDB manual. + +Assign a Default Collation to a Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example creates a new collection called ``contacts`` on the +``test`` database and assigns a default collation with the ``fr_CA`` locale. +Specifying a collation when you create the collection ensures that all +operations involving a query that are run against the ``contacts`` collection +use the ``fr_CA`` collation, unless the query specifies another collation. Any +indexes on the new collection also inherit the default collation, unless the +creation command specifies another collation. + +.. code-block:: php + + test; + + $database->createCollection('contacts', [ + 'collation' => ['locale' => 'fr_CA'], + ]); + +Assign a Collation to an Index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To specify a collation for an index, use the ``collation`` option when you +create the index. + +The following example creates an index on the ``name`` field of the +``address_book`` collection, with the ``unique`` parameter enabled and a default +collation with ``locale`` set to ``en_US``. + +.. code-block:: php + + test->address_book; + + $collection->createIndex( + ['first_name' => 1], + [ + 'collation' => ['locale' => 'en_US'], + 'unique' => true, + ] + ); + +To use this index, make sure your queries also specify the same collation. The +following query uses the above index: + +.. code-block:: php + + test->address_book; + + $cursor = $collection->find( + ['first_name' => 'Adam'], + [ + 'collation' => ['locale' => 'en_US'], + ] + ); + +The following queries do **NOT** use the index. The first query uses no +collation, and the second uses a collation with a different ``strength`` value +than the collation on the index. + +.. code-block:: php + + test->address_book; + + $cursor1 = $collection->find(['first_name' => 'Adam']); + + $cursor2 = $collection->find( + ['first_name' => 'Adam'], + [ + 'collation' => [ + 'locale' => 'en_US', + 'strength' => 2, + ], + ] + ); + +Operations that Support Collation +--------------------------------- + +All reading, updating, and deleting methods support collation. Some examples are +listed below. + +``find()`` with ``sort`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Individual queries can specify a collation to use when matching and sorting +results. The following query and sort operation uses a German collation with the +``locale`` parameter set to ``de``. + +.. code-block:: php + + test->contacts; + + $cursor = $collection->find( + ['city' => 'New York'], + [ + 'collation' => ['locale' => 'de'], + 'sort' => ['name' => 1], + ] + ); + +``findOneAndUpdate()`` +~~~~~~~~~~~~~~~~~~~~~~ + +A collection called ``names`` contains the following documents: + +.. code-block:: javascript + + { "_id" : 1, "first_name" : "Hans" } + { "_id" : 2, "first_name" : "Gunter" } + { "_id" : 3, "first_name" : "Günter" } + { "_id" : 4, "first_name" : "Jürgen" } + +The following :phpmethod:`findOneAndUpdate() +` operation on the collection does not +specify a collation. + +.. code-block:: php + + test->names; + + $document = $collection->findOneAndUpdate( + ['first_name' => ['$lt' =-> 'Gunter']], + ['$set' => ['verified' => true]] + ); + +Because ``Gunter`` is lexically first in the collection, the above operation +returns no results and updates no documents. + +Consider the same :phpmethod:`findOneAndUpdate() +` operation but with a collation +specified, which uses the locale ``de@collation=phonebook``. + +.. note:: + + Some locales have a ``collation=phonebook`` option available for use with + languages which sort proper nouns differently from other words. According to + the ``de@collation=phonebook`` collation, characters with umlauts come before + the same characters without umlauts. + +.. code-block:: php + + test->names; + + $document = $collection->findOneAndUpdate( + ['first_name' => ['$lt' =-> 'Gunter']], + ['$set' => ['verified' => true]], + [ + 'collation' => ['locale' => 'de@collation=phonebook'], + 'returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER, + ] + ); + +The operation returns the following updated document: + +.. code-block:: javascript + + { "_id" => 3, "first_name" => "Günter", "verified" => true } + +``findOneAndDelete()`` +~~~~~~~~~~~~~~~~~~~~~~ + +Set the ``numericOrdering`` collation parameter to ``true`` to compare numeric +strings by their numeric values. + +The collection ``numbers`` contains the following documents: + +.. code-block:: javascript + + { "_id" : 1, "a" : "16" } + { "_id" : 2, "a" : "84" } + { "_id" : 3, "a" : "179" } + +The following example matches the first document in which field ``a`` has a +numeric value greater than 100 and deletes it. + +.. code-block:: php + + test->numbers; + + $document = $collection->findOneAndDelete( + ['a' => ['$gt' =-> '100']], + [ + 'collation' => [ + 'locale' => 'en', + 'numericOrdering' => true, + ], + ] + ); + +After the above operation, the following documents remain in the collection: + +.. code-block:: javascript + + { "_id" : 1, "a" : "16" } + { "_id" : 2, "a" : "84" } + +If you perform the same operation without collation, the server deletes the +first document it finds in which the lexical value of ``a`` is greater than +``"100"``. + +.. code-block:: php + + test->numbers; + + $document = $collection->findOneAndDelete(['a' => ['$gt' =-> '100']]); + +After the above operation is executed, the document in which ``a`` was equal to +``"16"`` has been deleted, and the following documents remain in the collection: + +.. code-block:: javascript + + { "_id" : 2, "a" : "84" } + { "_id" : 3, "a" : "179" } + +``deleteMany()`` +~~~~~~~~~~~~~~~~ + +You can use collations with all the various CRUD operations which exist in the +|php-library|. + +The collection ``recipes`` contains the following documents: + +.. code-block:: javascript + + { "_id" : 1, "dish" : "veggie empanadas", "cuisine" : "Spanish" } + { "_id" : 2, "dish" : "beef bourgignon", "cuisine" : "French" } + { "_id" : 3, "dish" : "chicken molé", "cuisine" : "Mexican" } + { "_id" : 4, "dish" : "chicken paillard", "cuisine" : "french" } + { "_id" : 5, "dish" : "pozole verde", "cuisine" : "Mexican" } + +Setting the ``strength`` parameter of the collation document to ``1`` or ``2`` +causes the server to disregard case in the query filter. The following example +uses a case-insensitive query filter to delete all records in which the +``cuisine`` field matches ``French``. + +.. code-block:: php + + test->recipes; + + $collection->deleteMany( + ['cuisine' => 'French'], + [ + 'collation' => [ + 'locale' => 'en_US', + 'strength' => 1, + ], + ] + ); + +After the above operation runs, the documents with ``_id`` values of ``2`` and +``4`` are deleted from the collection. + +Aggregation +~~~~~~~~~~~ + +To use collation with an :phpmethod:`aggregate() +` operation, specify a collation in the +aggregation options. + +The following aggregation example uses a collection called ``names`` and groups +the ``first_name`` field together, counts the total number of results in each +group, and sorts the results by German phonebook order. + +.. code-block:: php + + test->recipes; + + $cursor = $collection->aggregate( + [ + ['$group' => ['_id' => '$first_name', 'name_count' => ['$sum' => 1]]], + ['$sort' => ['_id' => 1]], + ], + [ + 'collation' => ['locale' => 'de@collation=phonebook'], + ] + ); diff --git a/vendor/mongodb/mongodb/docs/tutorial/commands.txt b/vendor/mongodb/mongodb/docs/tutorial/commands.txt new file mode 100644 index 00000000..88ce5ec9 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/commands.txt @@ -0,0 +1,325 @@ +========================= +Execute Database Commands +========================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +The |php-library| provides helper methods across the :phpclass:`Client +`, :phpclass:`Database `, and +:phpclass:`Collection ` classes for common +:manual:`database commands `. In addition, the +:phpmethod:`MongoDB\\Database::command()` method may be used to run database +commands that do not have a helper method. + +Execute Database Commands +------------------------- + +Basic Command +~~~~~~~~~~~~~ + +To execute a command on a :program:`mongod` instance, use the +:phpmethod:`MongoDB\\Database::command()` method. For instance, the following +operation uses the :manual:`geoNear ` command to +search for the three closest documents to longitude ``-74`` and latitude ``40`` +in the ``restos`` collection in the ``test`` database: + +.. code-block:: php + + test; + + $cursor = $database->command([ + 'geoNear' => 'restos', + 'near' => [ + 'type' => 'Point', + 'coordinates' => [-74.0, 40.0], + ], + 'spherical' => 'true', + 'num' => 3, + ]); + + $results = $cursor->toArray()[0]; + + var_dump($results); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#27 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["waitedMS"]=> + int(0) + ["results"]=> + object(MongoDB\Model\BSONArray)#25 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + object(MongoDB\Model\BSONDocument)#14 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["dis"]=> + float(39463.618389163) + ["obj"]=> + object(MongoDB\Model\BSONDocument)#13 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#3 (1) { + ["oid"]=> + string(24) "55cba2486c522cafdb059bed" + } + ["location"]=> + object(MongoDB\Model\BSONDocument)#12 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["coordinates"]=> + object(MongoDB\Model\BSONArray)#11 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + float(-74.1641319) + [1]=> + float(39.6686512) + } + } + ["type"]=> + string(5) "Point" + } + } + ["name"]=> + string(32) "Soul Food Kitchen Seafood Heaven" + } + } + } + } + [1]=> + object(MongoDB\Model\BSONDocument)#19 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["dis"]=> + float(50686.851650416) + ["obj"]=> + object(MongoDB\Model\BSONDocument)#18 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#15 (1) { + ["oid"]=> + string(24) "55cba2476c522cafdb0544df" + } + ["location"]=> + object(MongoDB\Model\BSONDocument)#17 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["coordinates"]=> + object(MongoDB\Model\BSONArray)#16 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + float(-74.2566332) + [1]=> + float(40.4109872) + } + } + ["type"]=> + string(5) "Point" + } + } + ["name"]=> + string(20) "Seguine Bagel Bakery" + } + } + } + } + [2]=> + object(MongoDB\Model\BSONDocument)#24 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["dis"]=> + float(58398.379630263) + ["obj"]=> + object(MongoDB\Model\BSONDocument)#23 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#20 (1) { + ["oid"]=> + string(24) "55cba2476c522cafdb053c92" + } + ["location"]=> + object(MongoDB\Model\BSONDocument)#22 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["coordinates"]=> + object(MongoDB\Model\BSONArray)#21 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + float(-74.3731727) + [1]=> + float(40.4404759) + } + } + ["type"]=> + string(5) "Point" + } + } + ["name"]=> + string(17) "Water'S Edge Club" + } + } + } + } + } + } + ["stats"]=> + object(MongoDB\Model\BSONDocument)#26 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + ["nscanned"]=> + int(25139) + ["objectsLoaded"]=> + int(25134) + ["avgDistance"]=> + float(49516.283223281) + ["maxDistance"]=> + float(58398.379630263) + ["time"]=> + int(126) + } + } + ["ok"]=> + float(1) + } + } + +Commands with Custom Read Preference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some commands, such as :manual:`createUser `, may +only be executed on a :term:`primary` replica set member or a +:term:`standalone`. + +The command helper methods in the |php-library|, such as +:phpmethod:`MongoDB\\Database::drop()`, know to apply their own :term:`read +preference` if necessary. However, the :phpmethod:`MongoDB\\Database::command()` +method is a generic method and defaults to the read preference of the Database +object on which it is invoked. To execute commands that require a specific read +preference, specify the read preference in the ``$options`` parameter of the +method. + +The following example adds a user to the ``test`` database and specifies a +custom read preference: + +.. code-block:: php + + test; + + $cursor = $db->command( + [ + 'createUser' => 'username', + 'pwd' => 'password', + 'roles' => ['readWrite'], + ], + [ + 'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY), + ] + ); + + var_dump($cursor->toArray()[0]); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["ok"]=> + float(1) + } + } + +View Command Results +-------------------- + +View Single Result Documents +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :phpmethod:`MongoDB\\Database::command()` method returns a +:php:`MongoDB\\Driver\\Cursor ` object. + +Many MongoDB commands return their responses as a single document. To read the +command response, you may either iterate on the cursor and access the first +document, or access the first result in the array, as in the following: + +.. code-block:: php + + test; + + $cursor = $database->command(['ping' => 1]); + + var_dump($cursor->toArray()[0]); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#2 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["ok"]=> + float(1) + } + } + +Iterate Results from a Cursor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some commands, such as :manual:`listCollections +`, return their results via an iterable +cursor. To view the results, iterate through the cursor. + +The following example lists the collections in the ``test`` database by +iterating through the cursor returned by the ``listCollections`` command using a +``foreach`` loop: + +.. code-block:: php + + test; + + $cursor = $database->command(['listCollections' => 1]); + + foreach ($cursor as $collection) { + echo $collection['name'], "\n"; + } + +The output would then be a list of the values for the ``name`` key, for +instance:: + + persons + posts + zips + +.. note:: + + At the *protocol* level, commands that support a cursor return a single + result document with the essential ingredients for constructing the command + cursor (i.e. the cursor's ID, namespace, and the first batch of results). In + the PHP driver implementation, the + :php:`MongoDB\Driver\Manager::executeCommand() + ` method detects such a result and + constructs the iterable command cursor, which is returned rather than the + base result document. diff --git a/vendor/mongodb/mongodb/docs/tutorial/crud.txt b/vendor/mongodb/mongodb/docs/tutorial/crud.txt new file mode 100644 index 00000000..28ba3b6c --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/crud.txt @@ -0,0 +1,746 @@ +=============== +CRUD Operations +=============== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + + +CRUD operations *create*, *read*, *update*, and *delete* documents. The +|php-library|'s :phpclass:`MongoDB\\Collection` class implements MongoDB's +cross-driver `CRUD specification +`_, +providing access to methods for inserting, finding, updating, and deleting +documents in MongoDB. + +This document provides a general introduction to inserting, querying, updating, +and deleting documents using the |php-library|. The MongoDB Manual's +:manual:`CRUD Section ` provides a more thorough introduction to CRUD +operations with MongoDB. + +Insert Documents +---------------- + +Insert One Document +~~~~~~~~~~~~~~~~~~~ + +The :phpmethod:`MongoDB\\Collection::insertOne()` method inserts a single +document into MongoDB and returns an instance of +:phpclass:`MongoDB\\InsertOneResult`, which you can use to access the ID of the +inserted document. + +.. this uses the insertOne example from the method reference: + +.. include:: /reference/method/MongoDBCollection-insertOne.txt + :start-after: start-crud-include + :end-before: end-crud-include + +The output includes the ID of the inserted document. + +If you include an ``_id`` value when inserting a document, MongoDB checks to +ensure that the ``_id`` value is unique for the collection. If the ``_id`` value +is not unique, the insert operation fails due to a duplicate key error. + +The following example inserts a document while specifying the value for the +``_id``: + +.. code-block:: php + + test->users; + + $insertOneResult = $collection->insertOne(['_id' => 1, 'name' => 'Alice']); + + printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); + + var_dump($insertOneResult->getInsertedId()); + +The output would then resemble:: + + Inserted 1 document(s) + int(1) + +.. seealso:: :phpmethod:`MongoDB\\Collection::insertOne()` + +Insert Many Documents +~~~~~~~~~~~~~~~~~~~~~ + +The :phpmethod:`MongoDB\\Collection::insertMany()` method allows you to insert +multiple documents in one write operation and returns an instance of +:phpclass:`MongoDB\\InsertManyResult`, which you can use to access the IDs of +the inserted documents. + +.. this uses the insertMany example from the method reference: + +.. include:: /reference/method/MongoDBCollection-insertMany.txt + :start-after: start-crud-include + :end-before: end-crud-include + +.. seealso:: :phpmethod:`MongoDB\\Collection::insertMany()` + +Query Documents +--------------- + +The |php-library| provides the :phpmethod:`MongoDB\\Collection::findOne()` and +:phpmethod:`MongoDB\\Collection::find()` methods for querying documents and the +:phpmethod:`MongoDB\\Collection::aggregate()` method for performing +:manual:`aggregation operations `. + +.. include:: /includes/extracts/note-bson-comparison.rst + +Find One Document +~~~~~~~~~~~~~~~~~ + +:phpmethod:`MongoDB\\Collection::findOne()` returns the :term:`first document +` that matches the query or ``null`` if no document matches the +query. + +The following example searches for the document with ``_id`` of ``"94301"``: + +.. code-block:: php + + test->zips; + + $document = $collection->findOne(['_id' => '94301']); + + var_dump($document); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#13 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + ["_id"]=> + string(5) "94301" + ["city"]=> + string(9) "PALO ALTO" + ["loc"]=> + object(MongoDB\Model\BSONArray)#12 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + float(-122.149685) + [1]=> + float(37.444324) + } + } + ["pop"]=> + int(15965) + ["state"]=> + string(2) "CA" + } + } + +.. note:: + + The criteria in this example matched an ``_id`` with a string value of + ``"94301"``. The same criteria would not have matched a document with an + integer value of ``94301`` due to MongoDB's :manual:`comparison rules for + BSON types `. Similarly, users should + use a :php:`MongoDB\\BSON\\ObjectId ` object + when matching an ``_id`` with an :manual:`ObjectId ` + value, as strings and ObjectIds are not directly comparable. + +.. seealso:: :phpmethod:`MongoDB\\Collection::findOne()` + +.. _php-find-many-documents: + +Find Many Documents +~~~~~~~~~~~~~~~~~~~ + +:phpmethod:`MongoDB\\Collection::find()` returns a +:php:`MongoDB\\Driver\\Cursor ` object, which you can +iterate upon to access all matched documents. + +The following example lists the documents in the ``zips`` collection with the +specified city and state values: + +.. code-block:: php + + test->zips; + + $cursor = $collection->find(['city' => 'JERSEY CITY', 'state' => 'NJ']); + + foreach ($cursor as $document) { + echo $document['_id'], "\n"; + } + +The output would resemble:: + + 07302 + 07304 + 07305 + 07306 + 07307 + 07310 + +.. seealso:: :phpmethod:`MongoDB\\Collection::find()` + +.. _php-query-projection: + +Query Projection +~~~~~~~~~~~~~~~~ + +By default, queries in MongoDB return all fields in matching documents. To limit +the amount of data that MongoDB sends to applications, you can include a +:manual:`projection document ` in +the query operation. + +.. note:: + + MongoDB includes the ``_id`` field by default unless you explicitly exclude + it in a projection document. + +The following example finds restaurants based on the ``cuisine`` and ``borough`` +fields and uses a :manual:`projection +` to limit the fields that are +returned. It also limits the results to 5 documents. + +.. code-block:: php + + test->restaurants; + + $cursor = $collection->find( + [ + 'cuisine' => 'Italian', + 'borough' => 'Manhattan', + ], + [ + 'projection' => [ + 'name' => 1, + 'borough' => 1, + 'cuisine' => 1, + ], + 'limit' => 4, + ] + ); + + foreach($cursor as $restaurant) { + var_dump($restaurant); + }; + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#10 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#8 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f983" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(23) "Isle Of Capri Resturant" + } + } + object(MongoDB\Model\BSONDocument)#13 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#12 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f98d" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(18) "Marchis Restaurant" + } + } + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#10 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f99b" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(19) "Forlinis Restaurant" + } + } + object(MongoDB\Model\BSONDocument)#12 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#13 (1) { + ["oid"]=> + string(24) "576023c6b02fa9281da3f9a8" + } + ["borough"]=> + string(9) "Manhattan" + ["cuisine"]=> + string(7) "Italian" + ["name"]=> + string(22) "Angelo Of Mulberry St." + } + } + +Limit, Sort, and Skip Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to :ref:`projection criteria `, you can +specify options to limit, sort, and skip documents during queries. + +The following example uses the ``limit`` and ``sort`` options to query for the +five most populous zip codes in the United States: + +.. code-block:: php + + test->zips; + + $cursor = $collection->find( + [], + [ + 'limit' => 5, + 'sort' => ['pop' => -1], + ] + ); + + foreach ($cursor as $document) { + printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); + } + +The output would then resemble:: + + 60623: CHICAGO, IL + 11226: BROOKLYN, NY + 10021: NEW YORK, NY + 10025: NEW YORK, NY + 90201: BELL GARDENS, CA + +Regular Expressions +~~~~~~~~~~~~~~~~~~~ + +Filter criteria may include regular expressions, either by using the +:php:`MongoDB\\BSON\\Regex ` class directory or the +:query:`$regex` operator. + +The following example lists documents in the ``zips`` collection where the city +name starts with "garden" and the state is Texas: + +.. code-block:: php + + test->zips; + + $cursor = $collection->find([ + 'city' => new MongoDB\BSON\Regex('^garden', 'i'), + 'state' => 'TX', + ]); + + foreach ($cursor as $document) { + printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); + } + +The output would then resemble:: + + 78266: GARDEN RIDGE, TX + 79739: GARDEN CITY, TX + 79758: GARDENDALE, TX + +An equivalent filter could be constructed using the :query:`$regex` operator: + +.. code-block:: php + + [ + 'city' => ['$regex' => '^garden', '$options' => 'i'], + 'state' => 'TX', + ] + +.. seealso:: :manual:`$regex ` in the MongoDB manual + +Although MongoDB's regular expression syntax is not exactly the same as PHP's +:php:`PCRE ` syntax, :php:`preg_quote() ` +may be used to escape special characters that should be matched as-is. The +following example finds restaurants whose name starts with "(Library)": + +.. code-block:: php + + test->restaurants; + + $cursor = $collection->find([ + 'name' => new MongoDB\BSON\Regex('^' . preg_quote('(Library)')), + ]); + +.. _php-aggregation: + +Complex Queries with Aggregation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MongoDB's :manual:`Aggregation Framework ` allows +you to issue complex queries that filter, transform, and group collection data. +The |php-library|\'s :phpmethod:`MongoDB\\Collection::aggregate()` method +returns a :php:`Traversable ` object, which you can iterate upon to +access the results of the aggregation operation. Refer to the +:phpmethod:`MongoDB\\Collection::aggregate()` method's :ref:`behavior +reference ` for more about the method's output. + +The following example lists the 5 US states with the most zip codes associated +with them: + +.. code-block:: php + + test->zips; + + $cursor = $collection->aggregate([ + ['$group' => ['_id' => '$state', 'count' => ['$sum' => 1]]], + ['$sort' => ['count' => -1]], + ['$limit' => 5], + ]); + + foreach ($cursor as $state) { + printf("%s has %d zip codes\n", $state['_id'], $state['count']); + } + +The output would then resemble:: + + TX has 1671 zip codes + NY has 1595 zip codes + CA has 1516 zip codes + PA has 1458 zip codes + IL has 1237 zip codes + +.. seealso:: :phpmethod:`MongoDB\\Collection::aggregate()` + +Update Documents +---------------- + +Update One Document +~~~~~~~~~~~~~~~~~~~ + +Use the :phpmethod:`MongoDB\\Collection::updateOne()` method to update a single +document matching a filter. :phpmethod:`MongoDB\\Collection::updateOne()` +returns a :phpclass:`MongoDB\\UpdateResult` object, which you can use to access +statistics about the update operation. + +Update methods have two required parameters: the query filter that identifies +the document or documents to update, and an update document that specifies what +updates to perform. The :phpmethod:`MongoDB\\Collection::updateOne()` reference +describes each parameter in detail. + +The following example inserts two documents into an empty ``users`` collection +in the ``test`` database using the :phpmethod:`MongoDB\\Collection::insertOne()` +method, and then updates the documents where the value for the ``state`` field +is ``"ny"`` to include a ``country`` field set to ``"us"``: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $updateResult = $collection->updateOne( + ['state' => 'ny'], + ['$set' => ['country' => 'us']] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +Since the update operation uses the +:phpmethod:`MongoDB\\Collection::updateOne()` method, which updates the first +document to match the filter criteria, the results would then resemble:: + + Matched 1 document(s) + Modified 1 document(s) + +It is possible for a document to match the filter but *not be modified* by an +update, as is the case where the update sets a field's value to its existing +value, as in this example: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $updateResult = $collection->updateOne( + ['name' => 'Bob'], + ['$set' => ['state' => 'ny']] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +The number of matched documents and the number of *modified* documents would +therefore not be equal, and the output from the operation would resemble:: + + Matched 1 document(s) + Modified 0 document(s) + +.. seealso:: + + - :phpmethod:`MongoDB\\Collection::updateOne()` + - :phpmethod:`MongoDB\\Collection::findOneAndUpdate()` + +Update Many Documents +~~~~~~~~~~~~~~~~~~~~~ + +:phpmethod:`MongoDB\\Collection::updateMany()` updates one or more documents +matching the filter criteria and returns a :phpclass:`MongoDB\\UpdateResult` +object, which you can use to access statistics about the update operation. + +Update methods have two required parameters: the query filter that identifies +the document or documents to update, and an update document that specifies what +updates to perform. The :phpmethod:`MongoDB\\Collection::updateMany()` reference +describes each parameter in detail. + +The following example inserts three documents into an empty ``users`` collection +in the ``test`` database and then uses the :query:`$set` operator to update the +documents matching the filter criteria to include the ``country`` field with +value ``"us"``: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny', 'country' => 'us']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $collection->insertOne(['name' => 'Sam', 'state' => 'ny']); + $updateResult = $collection->updateMany( + ['state' => 'ny'], + ['$set' => ['country' => 'us']] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +If an update operation results in no change to a document, such as setting the +value of the field to its current value, the number of modified documents can be +less than the number of *matched* documents. Since the update document with +``name`` of ``"Bob"`` results in no changes to the document, the output of the +operation therefore resembles:: + + Matched 3 document(s) + Modified 2 document(s) + +.. seealso:: :phpmethod:`MongoDB\\Collection::updateMany()` + +Replace Documents +~~~~~~~~~~~~~~~~~ + +Replacement operations are similar to update operations, but instead of updating +a document to include new fields or new field values, a replacement operation +replaces the entire document with a new document, but retains the original +document's ``_id`` value. + +The :phpmethod:`MongoDB\\Collection::replaceOne()` method replaces a single +document that matches the filter criteria and returns an instance of +:phpclass:`MongoDB\\UpdateResult`, which you can use to access statistics about +the replacement operation. + +:phpmethod:`MongoDB\\Collection::replaceOne()` has two required parameters: the +query filter that identifies the document or documents to replace, and a +replacement document that will replace the original document in MongoDB. The +:phpmethod:`MongoDB\\Collection::replaceOne()` reference describes each +parameter in detail. + +.. important:: + + Replacement operations replace all of the fields in a document except the + ``_id`` value. To avoid accidentally overwriting or deleting desired fields, + use the :phpmethod:`MongoDB\\Collection::updateOne()` or + :phpmethod:`MongoDB\\Collection::updateMany()` methods to update individual + fields in a document rather than replacing the entire document. + +The following example inserts one document into an empty ``users`` collection in +the ``test`` database, and then replaces that document with a new one: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $updateResult = $collection->replaceOne( + ['name' => 'Bob'], + ['name' => 'Robert', 'state' => 'ca'] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + +The output would then resemble:: + + Matched 1 document(s) + Modified 1 document(s) + +.. seealso:: + + - :phpmethod:`MongoDB\\Collection::replaceOne()` + - :phpmethod:`MongoDB\\Collection::findOneAndReplace()` + +Upsert +~~~~~~ + +Update and replace operations support an :manual:`upsert +` option. When ``upsert`` is ``true`` +*and* no documents match the specified filter, the operation creates a new +document and inserts it. If there *are* matching documents, then the operation +modifies or replaces the matching document or documents. + +When a document is upserted, the ID is accessible via +:phpmethod:`MongoDB\\UpdateResult::getUpsertedId()`. + +The following example uses :phpmethod:`MongoDB\\Collection::updateOne()` with +the ``upsert`` option set to ``true`` and an empty ``users`` collection in the +``test`` database, therefore inserting the document into the database: + +.. code-block:: php + + test->users; + $collection->drop(); + + $updateResult = $collection->updateOne( + ['name' => 'Bob'], + ['$set' => ['state' => 'ny']], + ['upsert' => true] + ); + + printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); + printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); + printf("Upserted %d document(s)\n", $updateResult->getUpsertedCount()); + + $upsertedDocument = $collection->findOne([ + '_id' => $updateResult->getUpsertedId(), + ]); + + var_dump($upsertedDocument); + +The output would then resemble:: + + Matched 0 document(s) + Modified 0 document(s) + Upserted 1 document(s) + object(MongoDB\Model\BSONDocument)#16 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectId)#15 (1) { + ["oid"]=> + string(24) "57509c4406d7241dad86e7c3" + } + ["name"]=> + string(3) "Bob" + ["state"]=> + string(2) "ny" + } + } + +Delete Documents +---------------- + +Delete One Document +~~~~~~~~~~~~~~~~~~~ + +The :phpmethod:`MongoDB\\Collection::deleteOne()` method deletes a single +document that matches the filter criteria and returns a +:phpclass:`MongoDB\\DeleteResult`, which you can use to access statistics about +the delete operation. + +If multiple documents match the filter criteria, +:phpmethod:`MongoDB\\Collection::deleteOne()` deletes the :term:`first +` matching document. + +:phpmethod:`MongoDB\\Collection::deleteOne()` has one required parameter: a +query filter that specifies the document to delete. Refer to the +:phpmethod:`MongoDB\\Collection::deleteOne()` reference for full method +documentation. + +The following operation deletes the first document where the ``state`` field's +value is ``"ny"``: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $deleteResult = $collection->deleteOne(['state' => 'ny']); + + printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); + +The output would then resemble:: + + Deleted 1 document(s) + +.. seealso:: :phpmethod:`MongoDB\\Collection::deleteOne()` + +Delete Many Documents +~~~~~~~~~~~~~~~~~~~~~ + +:phpmethod:`MongoDB\\Collection::deleteMany()` deletes all of the documents that +match the filter criteria and returns a :phpclass:`MongoDB\\DeleteResult`, which +you can use to access statistics about the delete operation. + +:phpmethod:`MongoDB\\Collection::deleteMany()` has one required parameter: a +query filter that specifies the document to delete. Refer to the +:phpmethod:`MongoDB\\Collection::deleteMany()` reference for full method +documentation. + +The following operation deletes all of the documents where the ``state`` field's +value is ``"ny"``: + +.. code-block:: php + + test->users; + $collection->drop(); + + $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); + $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); + $deleteResult = $collection->deleteMany(['state' => 'ny']); + + printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); + +The output would then resemble:: + + Deleted 2 document(s) + +.. seealso:: :phpmethod:`MongoDB\\Collection::deleteMany()` diff --git a/vendor/mongodb/mongodb/docs/tutorial/decimal128.txt b/vendor/mongodb/mongodb/docs/tutorial/decimal128.txt new file mode 100644 index 00000000..a94d0ea5 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/decimal128.txt @@ -0,0 +1,124 @@ +========== +Decimal128 +========== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +MongoDB 3.4 introduced support for a :manual:`Decimal128 BSON type +`, which is a 128-bit decimal-based +floating-point value capable of emulating decimal rounding with exact precision. +This functionality is intended for applications that handle :manual:`monetary +data `, such as financial and tax computations. + +The :php:`MongoDB\BSON\Decimal128 ` class, which was +introduced in :php:`PHP driver ` 1.2.0, may be used to work with this +type in PHP. + +Working with Decimal128 Values +------------------------------ + +Inserting a Decimal128 +~~~~~~~~~~~~~~~~~~~~~~ + +The following example inserts a value of type ``Decimal128`` into the ``price`` +field of a collection named ``inventory``: + +.. code-block:: php + + test->inventory; + + $collection->insertOne([ + '_id' => 1, + 'item' => '26-inch monitor', + 'price' => new MongoDB\BSON\Decimal128('428.79'), + ]); + + $item = $collection->findOne(['_id' => 1]); + + var_dump($item); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#9 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + int(1) + ["item"]=> + string(15) "26-inch monitor" + ["price"]=> + object(MongoDB\BSON\Decimal128)#13 (1) { + ["dec"]=> + string(6) "428.79" + } + } + } + +Mathematical Operations with BCMath +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :php:`PHP driver ` does not provide any functionality for working +with ``Decimal128`` values; however, the string representation of a +:php:`MongoDB\BSON\Decimal128 ` object may be used +with PHP's :php:`BCMath ` extension. + +The following example adds two ``Decimal128`` values and creates a new +``Decimal128`` value with the result from :php:`bcadd() `: + +.. code-block:: php + + + string(1) "6" + } + +This does not match the expected result of "6.912". Each operation in the BCMath +API uses a scale to determine the number of decimal digits in the result. The +default scale is zero, which is why the above example produces a result with no +decimal precision. + +In the following example, we use a scale of three for :php:`bcadd() ` to +obtain the expected result: + +.. code-block:: php + + + string(5) "6.912" + } + +In lieu of specifying a scale for each operation, a default scale may be set via +:php:`bcscale() ` or the :php:`bcmath.scale INI setting +`. The ``Decimal128`` type +supports up to 34 decimal digits (i.e. significant digits). diff --git a/vendor/mongodb/mongodb/docs/tutorial/example-data.txt b/vendor/mongodb/mongodb/docs/tutorial/example-data.txt new file mode 100644 index 00000000..e9370f2b --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/example-data.txt @@ -0,0 +1,45 @@ +============ +Example Data +============ + +.. default-domain:: mongodb + +Some examples in this documentation use example data fixtures from +`zips.json `_ and +`primer-dataset.json `_. + +Importing the dataset into MongoDB can be done in several ways. The following +example imports the `zips.json` file into a `test.zips` collection: +:php:`driver ` directly: + +.. code-block:: php + + insert($document); + } + + $manager = new MongoDB\Driver\Manager('mongodb://127.0.0.1/'); + + $result = $manager->executeBulkWrite('test.zips', $bulk); + printf("Inserted %d documents\n", $result->getInsertedCount()); + +The output would then resemble:: + + Inserted 29353 documents + +You may also import the datasets using :manual:`mongoimport +`, which is included with MongoDB: + +.. code-block:: none + + $ mongoimport --db test --collection zips --file zips.json --drop + $ mongoimport --db test --collection restaurants --file primer-dataset.json --drop diff --git a/vendor/mongodb/mongodb/docs/tutorial/gridfs.txt b/vendor/mongodb/mongodb/docs/tutorial/gridfs.txt new file mode 100644 index 00000000..ba9b8368 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/gridfs.txt @@ -0,0 +1,214 @@ +====== +GridFS +====== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +:manual:`GridFS ` is a specification for storing and retrieving +files in MongoDB. GridFS uses two collections to store files. One collection +stores the file chunks (e.g. ``fs.chunks``), and the other stores file metadata +(e.g. ``fs.files``). The :phpclass:`MongoDB\\GridFS\\Bucket` class provides an +interface around these collections for working with the files as PHP +:php:`Streams `. + +Creating a GridFS Bucket +------------------------ + +You can construct a GridFS bucket using the PHP extension's +:php:`MongoDB\\Driver\\Manager ` class, or select +a bucket from the |php-library|'s :phpclass:`MongoDB\\Database` class via the +:phpmethod:`selectGridFSBucket() ` +method. + +The bucket can be constructed with various options: + + - ``bucketName`` determines the prefix for the bucket's metadata and chunk + collections. The default value is ``"fs"``. + - ``chunkSizeBytes`` determines the size of each chunk. GridFS divides the + file into chunks of this length, except for the last, which is only as large + as needed. The default size is ``261120`` (i.e. 255 KiB). + - ``readConcern``, ``readPreference`` and ``writeConcern`` options can be used + to specify defaults for read and write operations, much like the + :phpclass:`MongoDB\\GridFS\\Collection` options. + +Uploading Files with Writable Streams +------------------------------------- + +To upload a file to GridFS using a writable stream, you can either open a stream +and write to it directly or write the entire contents of another readable stream +to GridFS all at once. + +To open an upload stream and write to it: + +.. code-block:: php + + test->selectGridFSBucket(); + + $stream = $bucket->openUploadStream('my-file.txt'); + + $contents = file_get_contents('/path/to/my-file.txt'); + fwrite($stream, $contents); + fclose($stream); + +To upload the entire contents of a readable stream in one call: + +.. code-block:: php + + test->selectGridFSBucket(); + + $file = fopen('/path/to/my-file.txt', 'rb'); + $bucket->uploadFromStream('my-file.txt', $file); + +Downloading Files with Readable Streams +--------------------------------------- + +To download a file from GridFS using a readable stream, you can either open a +stream and read from it directly or download the entire file all at once. + +To open a download stream and read from it: + +.. code-block:: php + + test->selectGridFSBucket(); + + $stream = $bucket->openDownloadStream($fileId); + $contents = stream_get_contents($stream); + +To download the file all at once and write it to a writable stream: + +.. code-block:: php + + test->selectGridFSBucket(); + + $file = fopen('/path/to/my-output-file.txt', 'wb'); + + $bucket->downloadToStream($fileId, $file); + +Selecting Files by Filename and Revision +---------------------------------------- + +You can also download a file specified by filename and (optionally) revision +number. Revision numbers are used to distinguish between files sharing the same +``filename`` metadata field, ordered by date of upload (i.e. the ``uploadDate`` +metadata field). The ``revision`` option accepted by +:phpmethod:`openDownloadStreamByName() +` and +:phpmethod:`downloadToStreamByName() +` can be positive or negative. + +A positive ``revision`` number may be used to select files in order of the +oldest upload date. A revision of ``0`` would denote the file with the oldest +upload date, a revision of ``1`` would denote the second oldest upload, and so +on. + +A negative revision may be used to select files in order of the most recent +upload date. A revision of ``-1`` would denote a file with the most recent +upload date, a revision of ``-2`` would denote the second most recent upload, +and so on. The ``revision`` option defaults to ``-1`` if not specified. + +The following example downloads the contents of the oldest version of a +particular file: + +.. code-block:: php + + test->selectGridFSBucket(); + + $stream = $bucket->openDownloadStreamByName('my-file.txt', ['revision' => 0]); + $contents = stream_get_contents($stream); + +Deleting Files +-------------- + +You can delete a GridFS file by its ``_id``. + +.. code-block:: php + + test->selectGridFSBucket(); + + $bucket->delete($fileId); + +Finding File Metadata +--------------------- + +The :phpmethod:`find() ` method allows you to +retrieve documents from the GridFS files collection, which contain metadata +about the GridFS files. + +.. code-block:: php + + test->selectGridFSBucket(); + + $cursor = $bucket->find(['filename' => 'my-file.txt']); + +Accessing File Metadata for an Existing Stream +---------------------------------------------- + +The :phpmethod:`getFileDocumentForStream() +` method may be used to get +the file document for an existing readable or writable GridFS stream. + +.. code-block:: php + + test->selectGridFSBucket(); + + $stream = $bucket->openDownloadStream($fileId); + $metadata = $bucket->getFileDocumentForStream($stream); + +.. note:: + + Since the file document for a writable stream is not committed to MongoDB + until the stream is closed, + :phpmethod:`getFileDocumentForStream() + ` can only return an + in-memory document, which will be missing some fields (e.g. ``length``, + ``md5``). + +The :phpmethod:`getFileIdForStream() +` method may be used to get the +``_id`` for an existing readable or writable GridFS stream. This is a +convenience for accessing the ``_id`` property of the object returned by +:phpmethod:`getFileDocumentForStream() +`. + +.. code-block:: php + + test->selectGridFSBucket(); + + $stream = $bucket->openDownloadStreamByName('my-file.txt'); + $fileId = $bucket->getFileIdForStream($stream); diff --git a/vendor/mongodb/mongodb/docs/tutorial/indexes.txt b/vendor/mongodb/mongodb/docs/tutorial/indexes.txt new file mode 100644 index 00000000..0ffe7bdb --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/indexes.txt @@ -0,0 +1,133 @@ +======= +Indexes +======= + +.. default-domain:: mongodb + +Indexes support the efficient execution of queries in MongoDB. Without indexes, +MongoDB must perform a *collection scan*, i.e. scan every document in a +collection, to select those documents that match the query statement. If an +appropriate index exists for a query, MongoDB can use the index to limit the +number of documents it must inspect. + +The PHP driver supports managing indexes through the +:phpclass:`MongoDB\\Collection` class, which implements MongoDB's +cross-driver `Index Management +`_ +and `Enumerating Indexes +`_ +specifications. + +This document provides an introduction to creating, listing, and dropping +indexes using the |php-library|. The MongoDB Manual's :manual:`Indexes +` reference provides more thorough information about indexing in +MongoDB. + +Create Indexes +-------------- + +Create indexes with the :phpmethod:`MongoDB\\Collection::createIndex()` or +:phpmethod:`MongoDB\\Collection::createIndexes()` methods. Refer to the method +reference for more details about each method. + +The following example creates an ascending index on the ``state`` field using +the :phpmethod:`createIndex() ` method: + +.. code-block:: php + + test->zips; + + $result = $collection->createIndex(['state' => 1]); + + var_dump($result); + +When you create an index, the method returns its name, which is automatically +generated from its specification. The above example would output something +similar to:: + + string(7) "state_1" + +List Indexes +------------ + +The :phpmethod:`MongoDB\\Collection::listIndexes()` method provides information +about the indexes in a collection. The +:phpmethod:`MongoDB\\Collection::listIndexes()` method returns an iterator of +:phpclass:`MongoDB\\Model\\IndexInfo` objects, which you can use to view +information about each index. Refer to the method reference for more details. + +The following example lists all indexes in the ``zips`` collection in the +``test`` database: + +.. code-block:: php + + test->zips; + + foreach ($collection->listIndexes() as $indexInfo) { + var_dump($indexInfo); + } + +The output would resemble:: + + object(MongoDB\Model\IndexInfo)#10 (4) { + ["v"]=> + int(1) + ["key"]=> + array(1) { + ["_id"]=> + int(1) + } + ["name"]=> + string(4) "_id_" + ["ns"]=> + string(9) "test.zips" + } + object(MongoDB\Model\IndexInfo)#13 (4) { + ["v"]=> + int(1) + ["key"]=> + array(1) { + ["state"]=> + int(1) + } + ["name"]=> + string(7) "state_1" + ["ns"]=> + string(9) "test.zips" + } + +Drop Indexes +------------ + +The :phpmethod:`MongoDB\\Collection::dropIndex()` method lets you drop a single +index while :phpmethod:`MongoDB\\Collection::dropIndexes()` drops all of the +indexes on a collection. Refer to the method reference for more details about +each method. + +The following example drops a single index by its name, ``state_1``: + +.. code-block:: php + + test->zips; + + $result = $collection->dropIndex('state_1'); + + var_dump($result); + +The operation's output would resemble:: + + object(MongoDB\Model\BSONDocument)#11 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["nIndexesWas"]=> + int(2) + ["ok"]=> + float(1) + } + } diff --git a/vendor/mongodb/mongodb/docs/tutorial/install-php-library.txt b/vendor/mongodb/mongodb/docs/tutorial/install-php-library.txt new file mode 100644 index 00000000..0c4098a0 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/tutorial/install-php-library.txt @@ -0,0 +1,58 @@ +========================= +Install the |php-library| +========================= + +.. default-domain:: mongodb + +Prerequisites +------------- + +The |php-library| is a high-level abstraction for the MongoDB PHP driver. As +such, you must install the `mongodb` extension to use the library. + +:php:`Installing the MongoDB PHP Driver ` +describes how to install the `mongodb` extension for PHP. Instructions for +installing the driver for HHVM may be found in the :php:`Installation with HHVM +` article. + +Procedure +--------- + +Install the Library +~~~~~~~~~~~~~~~~~~~ + +The preferred method of installing |php-library| is with `Composer +`_ by running the following from your project +root: + +.. code-block:: sh + + composer require mongodb/mongodb + +While not recommended, you may also manually install the package via +the source tarballs attached to the `GitHub releases +`_. + +Configure Autoloading +~~~~~~~~~~~~~~~~~~~~~ + +Once you have installed the library, ensure that your application +includes Composer's autoloader. The ``require_once`` +statement should point to Composer's autoloader, as in the following example: + +.. code-block:: php + + require_once __DIR__ . "/vendor/autoload.php"; + +Refer to Composer's `autoloading documentation +`_ for more +information about setting up autoloading. + +If you installed the library manually from a source tarball, you +will also need to manually configure autoloading: + +#. Map the top-level ``MongoDB\`` namespace to the ``src/`` directory + using your preferred autoloader implementation. + +#. Manually require the ``src/functions.php`` file, since PHP does not + yet support function autoloading. diff --git a/vendor/mongodb/mongodb/docs/upgrade.txt b/vendor/mongodb/mongodb/docs/upgrade.txt new file mode 100644 index 00000000..6805d630 --- /dev/null +++ b/vendor/mongodb/mongodb/docs/upgrade.txt @@ -0,0 +1,260 @@ +============= +Upgrade Guide +============= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Overview +-------- + +The |php-library| and underlying :php:`mongodb extension ` have notable +API differences from the legacy :php:`mongo extension `. This page will +summarize those differences for the benefit of those upgrading from the legacy +driver. + +Additionally, a community-developed `mongo-php-adapter +`_ library exists, which +implements the `mongo extension `_ API using this library +and the new driver. While this adapter library is not officially supported by +MongoDB, it does bear mentioning. + +Collection API +-------------- + +This library's :phpclass:`MongoDB\\Collection` class implements MongoDB's +cross-driver `CRUD +`_ +and `Index Management +`_ +specifications. Although some method names have changed in accordance with the +new specifications, the new class provides the same functionality as the legacy +driver's :php:`MongoCollection ` class with some notable +exceptions. + +Old and New Methods +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - :php:`MongoCollection ` + - :phpclass:`MongoDB\\Collection` + + * - :php:`MongoCollection::aggregate() ` + - :phpmethod:`MongoDB\\Collection::aggregate()` + + * - :php:`MongoCollection::aggregateCursor() ` + - :phpmethod:`MongoDB\\Collection::aggregate()` + + * - :php:`MongoCollection::batchInsert() ` + - :phpmethod:`MongoDB\\Collection::insertMany()` + + * - :php:`MongoCollection::count() ` + - :phpmethod:`MongoDB\\Collection::count()` + + * - :php:`MongoCollection::createDBRef() ` + - Not yet implemented. See :issue:`PHPLIB-24`. + + * - :php:`MongoCollection::createIndex() ` + - :phpmethod:`MongoDB\\Collection::createIndex()` + + * - :php:`MongoCollection::deleteIndex() ` + - :phpmethod:`MongoDB\\Collection::dropIndex()` + + * - :php:`MongoCollection::deleteIndexes() ` + - :phpmethod:`MongoDB\\Collection::dropIndexes()` + + * - :php:`MongoCollection::drop() ` + - :phpmethod:`MongoDB\\Collection::drop()` + + * - :php:`MongoCollection::distinct() ` + - :phpmethod:`MongoDB\\Collection::distinct()` + + * - :php:`MongoCollection::ensureIndex() ` + - :phpmethod:`MongoDB\\Collection::createIndex()` + + * - :php:`MongoCollection::find() ` + - :phpmethod:`MongoDB\\Collection::find()` + + * - :php:`MongoCollection::findAndModify() ` + - :phpmethod:`MongoDB\\Collection::findOneAndDelete()`, + :phpmethod:`MongoDB\\Collection::findOneAndReplace()`, and + :phpmethod:`MongoDB\\Collection::findOneAndUpdate()` + + * - :php:`MongoCollection::findOne() ` + - :phpmethod:`MongoDB\\Collection::findOne()` + + * - :php:`MongoCollection::getDBRef() ` + - Not implemented. See :issue:`PHPLIB-24`. + + * - :php:`MongoCollection::getIndexInfo() ` + - :phpmethod:`MongoDB\\Collection::listIndexes()` + + * - :php:`MongoCollection::getName() ` + - :phpmethod:`MongoDB\\Collection::getCollectionName()` + + * - :php:`MongoCollection::getReadPreference() ` + - Not implemented. + + * - :php:`MongoCollection::getSlaveOkay() ` + - Not implemented. + + * - :php:`MongoCollection::getWriteConcern() ` + - Not implemented. + + * - :php:`MongoCollection::group() ` + - Not yet implemented. See :issue:`PHPLIB-177`. + Use :phpmethod:`MongoDB\\Database::command()`. + + * - :php:`MongoCollection::insert() ` + - :phpmethod:`MongoDB\\Collection::insertOne()` + + * - :php:`MongoCollection::parallelCollectionScan() ` + - Not implemented. + + * - :php:`MongoCollection::remove() ` + - :phpmethod:`MongoDB\\Collection::deleteMany()` and + :phpmethod:`MongoDB\\Collection::deleteOne()` + + * - :php:`MongoCollection::save() ` + - :phpmethod:`MongoDB\\Collection::insertOne()` or + :phpmethod:`MongoDB\\Collection::replaceOne()` with the ``upsert`` + option. + + * - :php:`MongoCollection::setReadPreference() ` + - Not implemented. Use :phpmethod:`MongoDB\\Collection::withOptions()` + + * - :php:`MongoCollection::setSlaveOkay() ` + - Not implemented. + + * - :php:`MongoCollection::setWriteConcern() ` + - Not implemented. Use :phpmethod:`MongoDB\\Collection::withOptions()` + + * - :php:`MongoCollection::update() ` + - :phpmethod:`MongoDB\\Collection::replaceOne()`, + :phpmethod:`MongoDB\\Collection::updateMany()`, and + :phpmethod:`MongoDB\\Collection::updateOne()`. + + * - :php:`MongoCollection::validate() ` + - Not implemented. + +A guiding principle in designing the new APIs was that explicit method names are +preferable to overloaded terms found in the old API. For instance, +:php:`MongoCollection::save() ` and +:php:`MongoCollection::findAndModify() ` +have different modes of operation, depending on their arguments. Methods were +also split to distinguish between :manual:`updating specific fields +` and :manual:`full-document replacement +`. + +Group Command Helper +-------------------- + +:phpclass:`MongoDB\\Collection` does not yet have a helper method for the +:manual:`group ` command; however, it is planned in +:issue:`PHPLIB-177`. The following example demonstrates how to execute a group +command using the :phpmethod:`MongoDB\\Database::command()` method: + +.. code-block:: php + + selectDatabase('db_name'); + $cursor = $database->command([ + 'group' => [ + 'ns' => 'collection_name', + 'key' => ['field_name' => 1], + 'initial' => ['total' => 0], + '$reduce' => new MongoDB\BSON\Javascript('...'), + ], + ]); + + $resultDocument = $cursor->toArray()[0]; + +MapReduce Command Helper +------------------------ + +:phpclass:`MongoDB\\Collection` does not yet have a helper method for the +:manual:`mapReduce ` command; however, that is +planned in :issue:`PHPLIB-53`. The following example demonstrates how to execute +a mapReduce command using the :phpmethod:`MongoDB\\Database::command()` method: + +.. code-block:: php + + selectDatabase('db_name'); + $cursor = $database->command([ + 'mapReduce' => 'collection_name', + 'map' => new MongoDB\BSON\Javascript('...'), + 'reduce' => new MongoDB\BSON\Javascript('...'), + 'out' => 'output_collection_name', + ]); + + $resultDocument = $cursor->toArray()[0]; + +DBRef Helpers +------------- + +:phpclass:`MongoDB\\Collection` does not yet have helper methods for working +with :manual:`DBRef ` objects; however, that is +planned in :issue:`PHPLIB-24`. + +MongoCollection::save() Removed +------------------------------- + +:php:`MongoCollection::save() `, which was syntactic sugar +for an insert or upsert operation, has been removed in favor of explicitly using +:phpmethod:`MongoDB\\Collection::insertOne` or +:phpmethod:`MongoDB\\Collection::replaceOne` (with the ``upsert`` option). + +.. .. figure:: /images/save-flowchart.png +.. :alt: save() flowchart + +While the ``save`` method does have its uses for interactive environments, such +as the mongo shell, it was intentionally excluded from the `CRUD specification +`_ +for language drivers. Generally, application code should know if the document +has an identifier and be able to explicitly insert or replace the document and +handle the returned :phpclass:`MongoDB\\InsertOneResult` or +:phpclass:`MongoDB\\UpdateResult`, respectively. This also helps avoid +inadvertent and potentially dangerous :manual:`full-document replacements +`. + +Accessing IDs of Inserted Documents +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the legacy driver, :php:`MongoCollection::insert() `, +:php:`MongoCollection::batchInsert() `, and +:php:`MongoCollection::save() ` (when inserting) would +modify their input argument by injecting an ``_id`` key with a generated +ObjectId (i.e. :php:`MongoId ` object). This behavior was a bit +of a hack, as it did not rely on the argument being :php:`passed by reference +`; instead, it directly modified memory through the +extension API and could not be implemented in PHP userland. As such, it is no +longer done in the new driver and library. + +IDs of inserted documents (whether generated or not) may be accessed through the +following methods on the write result objects: + +- :phpmethod:`MongoDB\\InsertOneResult::getInsertedId()` for + :phpmethod:`MongoDB\\Collection::insertOne()` +- :phpmethod:`MongoDB\\InsertManyResult::getInsertedIds()` for + :phpmethod:`MongoDB\\Collection::insertMany()` +- :phpmethod:`MongoDB\\BulkWriteResult::getInsertedIds()` for + :phpmethod:`MongoDB\\Collection::bulkWrite()` + +Bulk Write Operations +--------------------- + +The legacy driver's :php:`MongoWriteBatch ` classes have +been replaced with a general-purpose +:phpmethod:`MongoDB\\Collection::bulkWrite()` method. Whereas the legacy driver +only allowed bulk operations of the same type, the new method allows operations +to be mixed (e.g. inserts, updates, and deletes). diff --git a/vendor/mongodb/mongodb/phpunit.xml.dist b/vendor/mongodb/mongodb/phpunit.xml.dist new file mode 100644 index 00000000..1ec848b3 --- /dev/null +++ b/vendor/mongodb/mongodb/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + + + + + + + + + ./tests/ + + + diff --git a/vendor/mongodb/mongodb/src/BulkWriteResult.php b/vendor/mongodb/mongodb/src/BulkWriteResult.php new file mode 100644 index 00000000..cdf6654e --- /dev/null +++ b/vendor/mongodb/mongodb/src/BulkWriteResult.php @@ -0,0 +1,189 @@ +writeResult = $writeResult; + $this->insertedIds = $insertedIds; + $this->isAcknowledged = $writeResult->isAcknowledged(); + } + + /** + * Return the number of documents that were deleted. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getDeletedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getDeletedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the number of documents that were inserted. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getInsertedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getInsertedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return a map of the inserted documents' IDs. + * + * The index of each ID in the map corresponds to each document's position + * in the bulk operation. If a document had an ID prior to inserting (i.e. + * the driver did not generate an ID), the index will contain its "_id" + * field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId + * instance. + * + * @return mixed[] + */ + public function getInsertedIds() + { + return $this->insertedIds; + } + + /** + * Return the number of documents that were matched by the filter. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getMatchedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getMatchedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the number of documents that were modified. + * + * This value is undefined (i.e. null) if the write executed as a legacy + * operation instead of command. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return integer|null + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getModifiedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getModifiedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the number of documents that were upserted. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getUpsertedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getUpsertedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return a map of the upserted documents' IDs. + * + * The index of each ID in the map corresponds to each document's position + * in bulk operation. If a document had an ID prior to upserting (i.e. the + * server did not need to generate an ID), this will contain its "_id". Any + * server-generated ID will be a MongoDB\BSON\ObjectId instance. + * + * This method should only be called if the write was acknowledged. + * + * @see BulkWriteResult::isAcknowledged() + * @return mixed[] + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getUpsertedIds() + { + if ($this->isAcknowledged) { + return $this->writeResult->getUpsertedIds(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return whether this update was acknowledged by the server. + * + * If the update was not acknowledged, other fields from the WriteResult + * (e.g. matchedCount) will be undefined. + * + * @return boolean + */ + public function isAcknowledged() + { + return $this->isAcknowledged; + } +} diff --git a/vendor/mongodb/mongodb/src/Client.php b/vendor/mongodb/mongodb/src/Client.php new file mode 100644 index 00000000..f08488bc --- /dev/null +++ b/vendor/mongodb/mongodb/src/Client.php @@ -0,0 +1,259 @@ + 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ]; + private static $wireVersionForWritableCommandWriteConcern = 5; + + private $manager; + private $uri; + private $typeMap; + private $writeConcern; + + /** + * Constructs a new Client instance. + * + * This is the preferred class for connecting to a MongoDB server or + * cluster of servers. It serves as a gateway for accessing individual + * databases and collections. + * + * Supported driver-specific options: + * + * * typeMap (array): Default type map for cursors and BSON documents. + * + * Other options are documented in MongoDB\Driver\Manager::__construct(). + * + * @see http://docs.mongodb.org/manual/reference/connection-string/ + * @see http://php.net/manual/en/mongodb-driver-manager.construct.php + * @see http://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps + * @param string $uri MongoDB connection string + * @param array $uriOptions Additional connection string options + * @param array $driverOptions Driver-specific options + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverInvalidArgumentException for parameter/option parsing errors in the driver + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) + { + $driverOptions += ['typeMap' => self::$defaultTypeMap]; + + if (isset($driverOptions['typeMap']) && ! is_array($driverOptions['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" driver option', $driverOptions['typeMap'], 'array'); + } + + $this->uri = (string) $uri; + $this->typeMap = isset($driverOptions['typeMap']) ? $driverOptions['typeMap'] : null; + + unset($driverOptions['typeMap']); + + $this->manager = new Manager($uri, $uriOptions, $driverOptions); + $this->writeConcern = $this->manager->getWriteConcern(); + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'manager' => $this->manager, + 'uri' => $this->uri, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + } + + /** + * Select a database. + * + * Note: databases whose names contain special characters (e.g. "-") may + * be selected with complex syntax (e.g. $client->{"that-database"}) or + * {@link selectDatabase()}. + * + * @see http://php.net/oop5.overloading#object.get + * @see http://php.net/types.string#language.types.string.parsing.complex + * @param string $databaseName Name of the database to select + * @return Database + */ + public function __get($databaseName) + { + return $this->selectDatabase($databaseName); + } + + /** + * Return the connection string (i.e. URI). + * + * @return string + */ + public function __toString() + { + return $this->uri; + } + + /** + * Drop a database. + * + * @see DropDatabase::__construct() for supported options + * @param string $databaseName Database name + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are unsupported on the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function dropDatabase($databaseName, array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropDatabase($databaseName, $options); + + return $operation->execute($server); + } + + /** + * Return the Manager. + * + * @return Manager + */ + public function getManager() + { + return $this->manager; + } + + /** + * Return the read concern for this client. + * + * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @return ReadConcern + */ + public function getReadConcern() + { + return $this->manager->getReadConcern(); + } + + /** + * Return the read preference for this client. + * + * @return ReadPreference + */ + public function getReadPreference() + { + return $this->manager->getReadPreference(); + } + + /** + * Return the type map for this client. + * + * @return array + */ + public function getTypeMap() + { + return $this->typeMap; + } + + /** + * Return the write concern for this client. + * + * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @return WriteConcern + */ + public function getWriteConcern() + { + return $this->writeConcern; + } + + /** + * List databases. + * + * @see ListDatabases::__construct() for supported options + * @return DatabaseInfoIterator + * @throws UnexpectedValueException if the command response was malformed + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function listDatabases(array $options = []) + { + $operation = new ListDatabases($options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Select a collection. + * + * @see Collection::__construct() for supported options + * @param string $databaseName Name of the database containing the collection + * @param string $collectionName Name of the collection to select + * @param array $options Collection constructor options + * @return Collection + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function selectCollection($databaseName, $collectionName, array $options = []) + { + $options += ['typeMap' => $this->typeMap]; + + return new Collection($this->manager, $databaseName, $collectionName, $options); + } + + /** + * Select a database. + * + * @see Database::__construct() for supported options + * @param string $databaseName Name of the database to select + * @param array $options Database constructor options + * @return Database + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function selectDatabase($databaseName, array $options = []) + { + $options += ['typeMap' => $this->typeMap]; + + return new Database($this->manager, $databaseName, $options); + } +} diff --git a/vendor/mongodb/mongodb/src/Collection.php b/vendor/mongodb/mongodb/src/Collection.php new file mode 100644 index 00000000..3b583cec --- /dev/null +++ b/vendor/mongodb/mongodb/src/Collection.php @@ -0,0 +1,973 @@ + 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ]; + private static $wireVersionForFindAndModifyWriteConcern = 4; + private static $wireVersionForReadConcern = 4; + private static $wireVersionForWritableCommandWriteConcern = 5; + + private $collectionName; + private $databaseName; + private $manager; + private $readConcern; + private $readPreference; + private $typeMap; + private $writeConcern; + + /** + * Constructs new Collection instance. + * + * This class provides methods for collection-specific operations, such as + * CRUD (i.e. create, read, update, and delete) and index management. + * + * Supported options: + * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for collection operations. Defaults to the Manager's read concern. + * + * * readPreference (MongoDB\Driver\ReadPreference): The default read + * preference to use for collection operations. Defaults to the Manager's + * read preference. + * + * * typeMap (array): Default type map for cursors and BSON documents. + * + * * writeConcern (MongoDB\Driver\WriteConcern): The default write concern + * to use for collection operations. Defaults to the Manager's write + * concern. + * + * @param Manager $manager Manager instance from the driver + * @param string $databaseName Database name + * @param string $collectionName Collection name + * @param array $options Collection options + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function __construct(Manager $manager, $databaseName, $collectionName, array $options = []) + { + if (strlen($databaseName) < 1) { + throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); + } + + if (strlen($collectionName) < 1) { + throw new InvalidArgumentException('$collectionName is invalid: ' . $collectionName); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + $this->manager = $manager; + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern(); + $this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference(); + $this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap; + $this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern(); + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'collectionName' => $this->collectionName, + 'databaseName' => $this->databaseName, + 'manager' => $this->manager, + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + } + + /** + * Return the collection namespace (e.g. "db.collection"). + * + * @see https://docs.mongodb.org/manual/faq/developers/#faq-dev-namespace + * @return string + */ + public function __toString() + { + return $this->databaseName . '.' . $this->collectionName; + } + + /** + * Executes an aggregation framework pipeline on the collection. + * + * Note: this method's return value depends on the MongoDB server version + * and the "useCursor" option. If "useCursor" is true, a Cursor will be + * returned; otherwise, an ArrayIterator is returned, which wraps the + * "result" array from the command response document. + * + * @see Aggregate::__construct() for supported options + * @param array $pipeline List of pipeline operations + * @param array $options Command options + * @return Traversable + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function aggregate(array $pipeline, array $options = []) + { + $hasOutStage = \MongoDB\is_last_pipeline_operator_out($pipeline); + + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + if ($hasOutStage) { + $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); + } + + $server = $this->manager->selectServer($options['readPreference']); + + /* A "majority" read concern is not compatible with the $out stage, so + * avoid providing the Collection's read concern if it would conflict. + */ + if ( ! isset($options['readConcern']) && + ! ($hasOutStage && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && + \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + if ( ! isset($options['typeMap']) && ( ! isset($options['useCursor']) || $options['useCursor'])) { + $options['typeMap'] = $this->typeMap; + } + + if ($hasOutStage && ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new Aggregate($this->databaseName, $this->collectionName, $pipeline, $options); + + return $operation->execute($server); + } + + /** + * Executes multiple write operations. + * + * @see BulkWrite::__construct() for supported options + * @param array[] $operations List of write operations + * @param array $options Command options + * @return BulkWriteResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function bulkWrite(array $operations, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new BulkWrite($this->databaseName, $this->collectionName, $operations, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Gets the number of documents matching the filter. + * + * @see Count::__construct() for supported options + * @param array|object $filter Query by which to filter documents + * @param array $options Command options + * @return integer + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function count($filter = [], array $options = []) + { + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + $server = $this->manager->selectServer($options['readPreference']); + + if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + $operation = new Count($this->databaseName, $this->collectionName, $filter, $options); + + return $operation->execute($server); + } + + /** + * Create a single index for the collection. + * + * @see Collection::createIndexes() + * @see CreateIndexes::__construct() for supported command options + * @param array|object $key Document containing fields mapped to values, + * which denote order or an index type + * @param array $options Index options + * @return string The name of the created index + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function createIndex($key, array $options = []) + { + $indexOptions = array_diff_key($options, ['writeConcern' => 1]); + $commandOptions = array_intersect_key($options, ['writeConcern' => 1]); + + return current($this->createIndexes([['key' => $key] + $indexOptions], $commandOptions)); + } + + /** + * Create one or more indexes for the collection. + * + * Each element in the $indexes array must have a "key" document, which + * contains fields mapped to an order or type. Other options may follow. + * For example: + * + * $indexes = [ + * // Create a unique index on the "username" field + * [ 'key' => [ 'username' => 1 ], 'unique' => true ], + * // Create a 2dsphere index on the "loc" field with a custom name + * [ 'key' => [ 'loc' => '2dsphere' ], 'name' => 'geo' ], + * ]; + * + * If the "name" option is unspecified, a name will be generated from the + * "key" document. + * + * @see http://docs.mongodb.org/manual/reference/command/createIndexes/ + * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/ + * @see CreateIndexes::__construct() for supported command options + * @param array[] $indexes List of index specifications + * @param array $options Command options + * @return string[] The names of the created indexes + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function createIndexes(array $indexes, array $options = []) + { + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new CreateIndexes($this->databaseName, $this->collectionName, $indexes, $options); + + return $operation->execute($server); + } + + /** + * Deletes all documents matching the filter. + * + * @see DeleteMany::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @param array|object $filter Query by which to delete documents + * @param array $options Command options + * @return DeleteResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function deleteMany($filter, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DeleteMany($this->databaseName, $this->collectionName, $filter, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Deletes at most one document matching the filter. + * + * @see DeleteOne::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @param array|object $filter Query by which to delete documents + * @param array $options Command options + * @return DeleteResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function deleteOne($filter, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DeleteOne($this->databaseName, $this->collectionName, $filter, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Finds the distinct values for a specified field across the collection. + * + * @see Distinct::__construct() for supported options + * @param string $fieldName Field for which to return distinct values + * @param array|object $filter Query by which to filter documents + * @param array $options Command options + * @return mixed[] + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function distinct($fieldName, $filter = [], array $options = []) + { + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + $server = $this->manager->selectServer($options['readPreference']); + + if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + $operation = new Distinct($this->databaseName, $this->collectionName, $fieldName, $filter, $options); + + return $operation->execute($server); + } + + /** + * Drop this collection. + * + * @see DropCollection::__construct() for supported options + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function drop(array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropCollection($this->databaseName, $this->collectionName, $options); + + return $operation->execute($server); + } + + /** + * Drop a single index in the collection. + * + * @see DropIndexes::__construct() for supported options + * @param string $indexName Index name + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function dropIndex($indexName, array $options = []) + { + $indexName = (string) $indexName; + + if ($indexName === '*') { + throw new InvalidArgumentException('dropIndexes() must be used to drop multiple indexes'); + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropIndexes($this->databaseName, $this->collectionName, $indexName, $options); + + return $operation->execute($server); + } + + /** + * Drop all indexes in the collection. + * + * @see DropIndexes::__construct() for supported options + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function dropIndexes(array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropIndexes($this->databaseName, $this->collectionName, '*', $options); + + return $operation->execute($server); + } + + /** + * Finds documents matching the query. + * + * @see Find::__construct() for supported options + * @see http://docs.mongodb.org/manual/core/read-operations-introduction/ + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return Cursor + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function find($filter = [], array $options = []) + { + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + $server = $this->manager->selectServer($options['readPreference']); + + if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new Find($this->databaseName, $this->collectionName, $filter, $options); + + return $operation->execute($server); + } + + /** + * Finds a single document matching the query. + * + * @see FindOne::__construct() for supported options + * @see http://docs.mongodb.org/manual/core/read-operations-introduction/ + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return array|object|null + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function findOne($filter = [], array $options = []) + { + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + $server = $this->manager->selectServer($options['readPreference']); + + if ( ! isset($options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new FindOne($this->databaseName, $this->collectionName, $filter, $options); + + return $operation->execute($server); + } + + /** + * Finds a single document and deletes it, returning the original. + * + * The document to return may be null if no document matched the filter. + * + * @see FindOneAndDelete::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @param array|object $filter Query by which to filter documents + * @param array $options Command options + * @return array|object|null + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function findOneAndDelete($filter, array $options = []) + { + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new FindOneAndDelete($this->databaseName, $this->collectionName, $filter, $options); + + return $operation->execute($server); + } + + /** + * Finds a single document and replaces it, returning either the original or + * the replaced document. + * + * The document to return may be null if no document matched the filter. By + * default, the original document is returned. Specify + * FindOneAndReplace::RETURN_DOCUMENT_AFTER for the "returnDocument" option + * to return the updated document. + * + * @see FindOneAndReplace::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @param array|object $filter Query by which to filter documents + * @param array|object $replacement Replacement document + * @param array $options Command options + * @return array|object|null + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function findOneAndReplace($filter, $replacement, array $options = []) + { + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new FindOneAndReplace($this->databaseName, $this->collectionName, $filter, $replacement, $options); + + return $operation->execute($server); + } + + /** + * Finds a single document and updates it, returning either the original or + * the updated document. + * + * The document to return may be null if no document matched the filter. By + * default, the original document is returned. Specify + * FindOneAndUpdate::RETURN_DOCUMENT_AFTER for the "returnDocument" option + * to return the updated document. + * + * @see FindOneAndReplace::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @param array|object $filter Query by which to filter documents + * @param array|object $update Update to apply to the matched document + * @param array $options Command options + * @return array|object|null + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function findOneAndUpdate($filter, $update, array $options = []) + { + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new FindOneAndUpdate($this->databaseName, $this->collectionName, $filter, $update, $options); + + return $operation->execute($server); + } + + /** + * Return the collection name. + * + * @return string + */ + public function getCollectionName() + { + return $this->collectionName; + } + + /** + * Return the database name. + * + * @return string + */ + public function getDatabaseName() + { + return $this->databaseName; + } + + /** + * Return the Manager. + * + * @return Manager + */ + public function getManager() + { + return $this->manager; + } + + /** + * Return the collection namespace. + * + * @see https://docs.mongodb.org/manual/reference/glossary/#term-namespace + * @return string + */ + public function getNamespace() + { + return $this->databaseName . '.' . $this->collectionName; + } + + /** + * Return the read concern for this collection. + * + * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @return ReadConcern + */ + public function getReadConcern() + { + return $this->readConcern; + } + + /** + * Return the read preference for this collection. + * + * @return ReadPreference + */ + public function getReadPreference() + { + return $this->readPreference; + } + + /** + * Return the type map for this collection. + * + * @return array + */ + public function getTypeMap() + { + return $this->typeMap; + } + + /** + * Return the write concern for this collection. + * + * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @return WriteConcern + */ + public function getWriteConcern() + { + return $this->writeConcern; + } + + /** + * Inserts multiple documents. + * + * @see InsertMany::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @param array[]|object[] $documents The documents to insert + * @param array $options Command options + * @return InsertManyResult + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function insertMany(array $documents, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new InsertMany($this->databaseName, $this->collectionName, $documents, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Inserts one document. + * + * @see InsertOne::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @param array|object $document The document to insert + * @param array $options Command options + * @return InsertOneResult + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function insertOne($document, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new InsertOne($this->databaseName, $this->collectionName, $document, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Returns information for all indexes for the collection. + * + * @see ListIndexes::__construct() for supported options + * @return IndexInfoIterator + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function listIndexes(array $options = []) + { + $operation = new ListIndexes($this->databaseName, $this->collectionName, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Executes a map-reduce aggregation on the collection. + * + * @see MapReduce::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/mapReduce/ + * @param JavascriptInterface $map Map function + * @param JavascriptInterface $reduce Reduce function + * @param string|array|object $out Output specification + * @param array $options Command options + * @return MapReduceResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + * @throws UnexpectedValueException if the command response was malformed + */ + public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = []) + { + $hasOutputCollection = ! $this->isOutInline($out); + + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + // Check if the out option is inline because we will want to coerce a primary read preference if not + if ($hasOutputCollection) { + $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); + } + + $server = $this->manager->selectServer($options['readPreference']); + + /* A "majority" read concern is not compatible with inline output, so + * avoid providing the Collection's read concern if it would conflict. + */ + if ( ! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $options['readConcern'] = $this->readConcern; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + if (! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new MapReduce($this->databaseName, $this->collectionName, $map, $reduce, $out, $options); + + return $operation->execute($server); + } + + /** + * Replaces at most one document matching the filter. + * + * @see ReplaceOne::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/update/ + * @param array|object $filter Query by which to filter documents + * @param array|object $replacement Replacement document + * @param array $options Command options + * @return UpdateResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function replaceOne($filter, $replacement, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new ReplaceOne($this->databaseName, $this->collectionName, $filter, $replacement, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Updates all documents matching the filter. + * + * @see UpdateMany::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/update/ + * @param array|object $filter Query by which to filter documents + * @param array|object $update Update to apply to the matched documents + * @param array $options Command options + * @return UpdateResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function updateMany($filter, $update, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new UpdateMany($this->databaseName, $this->collectionName, $filter, $update, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Updates at most one document matching the filter. + * + * @see UpdateOne::__construct() for supported options + * @see http://docs.mongodb.org/manual/reference/command/update/ + * @param array|object $filter Query by which to filter documents + * @param array|object $update Update to apply to the matched document + * @param array $options Command options + * @return UpdateResult + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function updateOne($filter, $update, array $options = []) + { + if ( ! isset($options['writeConcern'])) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new UpdateOne($this->databaseName, $this->collectionName, $filter, $update, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Get a clone of this collection with different options. + * + * @see Collection::__construct() for supported options + * @param array $options Collection constructor options + * @return Collection + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function withOptions(array $options = []) + { + $options += [ + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + + return new Collection($this->manager, $this->databaseName, $this->collectionName, $options); + } + + private function isOutInline($out) + { + if ( ! is_array($out) && ! is_object($out)) { + return false; + } + + $out = (array) $out; + + if (key($out) === 'inline') { + return true; + } + + return false; + } +} diff --git a/vendor/mongodb/mongodb/src/Database.php b/vendor/mongodb/mongodb/src/Database.php new file mode 100644 index 00000000..ad029d91 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Database.php @@ -0,0 +1,403 @@ + 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ]; + private static $wireVersionForWritableCommandWriteConcern = 5; + + private $databaseName; + private $manager; + private $readConcern; + private $readPreference; + private $typeMap; + private $writeConcern; + + /** + * Constructs new Database instance. + * + * This class provides methods for database-specific operations and serves + * as a gateway for accessing collections. + * + * Supported options: + * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for database operations and selected collections. Defaults to the + * Manager's read concern. + * + * * readPreference (MongoDB\Driver\ReadPreference): The default read + * preference to use for database operations and selected collections. + * Defaults to the Manager's read preference. + * + * * typeMap (array): Default type map for cursors and BSON documents. + * + * * writeConcern (MongoDB\Driver\WriteConcern): The default write concern + * to use for database operations and selected collections. Defaults to + * the Manager's write concern. + * + * @param Manager $manager Manager instance from the driver + * @param string $databaseName Database name + * @param array $options Database options + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function __construct(Manager $manager, $databaseName, array $options = []) + { + if (strlen($databaseName) < 1) { + throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + $this->manager = $manager; + $this->databaseName = (string) $databaseName; + $this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern(); + $this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference(); + $this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap; + $this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern(); + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'databaseName' => $this->databaseName, + 'manager' => $this->manager, + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + } + + /** + * Select a collection within this database. + * + * Note: collections whose names contain special characters (e.g. ".") may + * be selected with complex syntax (e.g. $database->{"system.profile"}) or + * {@link selectCollection()}. + * + * @see http://php.net/oop5.overloading#object.get + * @see http://php.net/types.string#language.types.string.parsing.complex + * @param string $collectionName Name of the collection to select + * @return Collection + */ + public function __get($collectionName) + { + return $this->selectCollection($collectionName); + } + + /** + * Return the database name. + * + * @return string + */ + public function __toString() + { + return $this->databaseName; + } + + /** + * Execute a command on this database. + * + * @see DatabaseCommand::__construct() for supported options + * @param array|object $command Command document + * @param array $options Options for command execution + * @return Cursor + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function command($command, array $options = []) + { + if ( ! isset($options['readPreference'])) { + $options['readPreference'] = $this->readPreference; + } + + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $operation = new DatabaseCommand($this->databaseName, $command, $options); + $server = $this->manager->selectServer($options['readPreference']); + + return $operation->execute($server); + } + + /** + * Create a new collection explicitly. + * + * @see CreateCollection::__construct() for supported options + * @param string $collectionName + * @param array $options + * @return array|object Command result document + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function createCollection($collectionName, array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new CreateCollection($this->databaseName, $collectionName, $options); + + return $operation->execute($server); + } + + /** + * Drop this database. + * + * @see DropDatabase::__construct() for supported options + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are unsupported on the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function drop(array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropDatabase($this->databaseName, $options); + + return $operation->execute($server); + } + + /** + * Drop a collection within this database. + * + * @see DropCollection::__construct() for supported options + * @param string $collectionName Collection name + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are unsupported on the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function dropCollection($collectionName, array $options = []) + { + if ( ! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + if ( ! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new DropCollection($this->databaseName, $collectionName, $options); + + return $operation->execute($server); + } + + /** + * Returns the database name. + * + * @return string + */ + public function getDatabaseName() + { + return $this->databaseName; + } + + /** + * Return the Manager. + * + * @return Manager + */ + public function getManager() + { + return $this->manager; + } + + /** + * Return the read concern for this database. + * + * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @return ReadConcern + */ + public function getReadConcern() + { + return $this->readConcern; + } + + /** + * Return the read preference for this database. + * + * @return ReadPreference + */ + public function getReadPreference() + { + return $this->readPreference; + } + + /** + * Return the type map for this database. + * + * @return array + */ + public function getTypeMap() + { + return $this->typeMap; + } + + /** + * Return the write concern for this database. + * + * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @return WriteConcern + */ + public function getWriteConcern() + { + return $this->writeConcern; + } + + /** + * Returns information for all collections in this database. + * + * @see ListCollections::__construct() for supported options + * @param array $options + * @return CollectionInfoIterator + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function listCollections(array $options = []) + { + $operation = new ListCollections($this->databaseName, $options); + $server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + + return $operation->execute($server); + } + + /** + * Select a collection within this database. + * + * @see Collection::__construct() for supported options + * @param string $collectionName Name of the collection to select + * @param array $options Collection constructor options + * @return Collection + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function selectCollection($collectionName, array $options = []) + { + $options += [ + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + + return new Collection($this->manager, $this->databaseName, $collectionName, $options); + } + + /** + * Select a GridFS bucket within this database. + * + * @see Bucket::__construct() for supported options + * @param array $options Bucket constructor options + * @return Bucket + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function selectGridFSBucket(array $options = []) + { + $options += [ + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + + return new Bucket($this->manager, $this->databaseName, $options); + } + + /** + * Get a clone of this database with different options. + * + * @see Database::__construct() for supported options + * @param array $options Database constructor options + * @return Database + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function withOptions(array $options = []) + { + $options += [ + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + + return new Database($this->manager, $this->databaseName, $options); + } +} diff --git a/vendor/mongodb/mongodb/src/DeleteResult.php b/vendor/mongodb/mongodb/src/DeleteResult.php new file mode 100644 index 00000000..a60137b3 --- /dev/null +++ b/vendor/mongodb/mongodb/src/DeleteResult.php @@ -0,0 +1,72 @@ +writeResult = $writeResult; + $this->isAcknowledged = $writeResult->isAcknowledged(); + } + + /** + * Return the number of documents that were deleted. + * + * This method should only be called if the write was acknowledged. + * + * @see DeleteResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getDeletedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getDeletedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return whether this delete was acknowledged by the server. + * + * If the delete was not acknowledged, other fields from the WriteResult + * (e.g. deletedCount) will be undefined. + * + * @return boolean + */ + public function isAcknowledged() + { + return $this->isAcknowledged; + } +} diff --git a/vendor/mongodb/mongodb/src/Exception/BadMethodCallException.php b/vendor/mongodb/mongodb/src/Exception/BadMethodCallException.php new file mode 100644 index 00000000..f1fe47af --- /dev/null +++ b/vendor/mongodb/mongodb/src/Exception/BadMethodCallException.php @@ -0,0 +1,43 @@ + 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ]; + private static $streamWrapperProtocol = 'gridfs'; + + private $collectionWrapper; + private $databaseName; + private $manager; + private $bucketName; + private $chunkSizeBytes; + private $readConcern; + private $readPreference; + private $typeMap; + private $writeConcern; + + /** + * Constructs a GridFS bucket. + * + * Supported options: + * + * * bucketName (string): The bucket name, which will be used as a prefix + * for the files and chunks collections. Defaults to "fs". + * + * * chunkSizeBytes (integer): The chunk size in bytes. Defaults to + * 261120 (i.e. 255 KiB). + * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. + * + * * readPreference (MongoDB\Driver\ReadPreference): Read preference. + * + * * typeMap (array): Default type map for cursors and BSON documents. + * + * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. + * + * @param Manager $manager Manager instance from the driver + * @param string $databaseName Database name + * @param array $options Bucket options + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function __construct(Manager $manager, $databaseName, array $options = []) + { + $options += [ + 'bucketName' => self::$defaultBucketName, + 'chunkSizeBytes' => self::$defaultChunkSizeBytes, + ]; + + if (isset($options['bucketName']) && ! is_string($options['bucketName'])) { + throw InvalidArgumentException::invalidType('"bucketName" option', $options['bucketName'], 'string'); + } + + if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) { + throw InvalidArgumentException::invalidType('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer'); + } + + if (isset($options['chunkSizeBytes']) && $options['chunkSizeBytes'] < 1) { + throw new InvalidArgumentException(sprintf('Expected "chunkSizeBytes" option to be >= 1, %d given', $options['chunkSizeBytes'])); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + $this->manager = $manager; + $this->databaseName = (string) $databaseName; + $this->bucketName = $options['bucketName']; + $this->chunkSizeBytes = $options['chunkSizeBytes']; + $this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern(); + $this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference(); + $this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap; + $this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern(); + + $collectionOptions = array_intersect_key($options, ['readConcern' => 1, 'readPreference' => 1, 'typeMap' => 1, 'writeConcern' => 1]); + + $this->collectionWrapper = new CollectionWrapper($manager, $databaseName, $options['bucketName'], $collectionOptions); + $this->registerStreamWrapper(); + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'bucketName' => $this->bucketName, + 'databaseName' => $this->databaseName, + 'manager' => $this->manager, + 'chunkSizeBytes' => $this->chunkSizeBytes, + 'readConcern' => $this->readConcern, + 'readPreference' => $this->readPreference, + 'typeMap' => $this->typeMap, + 'writeConcern' => $this->writeConcern, + ]; + } + + /** + * Delete a file from the GridFS bucket. + * + * If the files collection document is not found, this method will still + * attempt to delete orphaned chunks. + * + * @param mixed $id File ID + * @throws FileNotFoundException if no file could be selected + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function delete($id) + { + $file = $this->collectionWrapper->findFileById($id); + $this->collectionWrapper->deleteFileAndChunksById($id); + + if ($file === null) { + throw FileNotFoundException::byId($id, $this->getFilesNamespace()); + } + } + + /** + * Writes the contents of a GridFS file to a writable stream. + * + * @param mixed $id File ID + * @param resource $destination Writable Stream + * @throws FileNotFoundException if no file could be selected + * @throws InvalidArgumentException if $destination is not a stream + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function downloadToStream($id, $destination) + { + if ( ! is_resource($destination) || get_resource_type($destination) != "stream") { + throw InvalidArgumentException::invalidType('$destination', $destination, 'resource'); + } + + stream_copy_to_stream($this->openDownloadStream($id), $destination); + } + + /** + * Writes the contents of a GridFS file, which is selected by name and + * revision, to a writable stream. + * + * Supported options: + * + * * revision (integer): Which revision (i.e. documents with the same + * filename and different uploadDate) of the file to retrieve. Defaults + * to -1 (i.e. the most recent revision). + * + * Revision numbers are defined as follows: + * + * * 0 = the original stored file + * * 1 = the first revision + * * 2 = the second revision + * * etc… + * * -2 = the second most recent revision + * * -1 = the most recent revision + * + * @param string $filename Filename + * @param resource $destination Writable Stream + * @param array $options Download options + * @throws FileNotFoundException if no file could be selected + * @throws InvalidArgumentException if $destination is not a stream + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function downloadToStreamByName($filename, $destination, array $options = []) + { + if ( ! is_resource($destination) || get_resource_type($destination) != "stream") { + throw InvalidArgumentException::invalidType('$destination', $destination, 'resource'); + } + + stream_copy_to_stream($this->openDownloadStreamByName($filename, $options), $destination); + } + + /** + * Drops the files and chunks collections associated with this GridFS + * bucket. + * + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function drop() + { + $this->collectionWrapper->dropCollections(); + } + + /** + * Finds documents from the GridFS bucket's files collection matching the + * query. + * + * @see Find::__construct() for supported options + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return Cursor + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function find($filter = [], array $options = []) + { + return $this->collectionWrapper->findFiles($filter, $options); + } + + /** + * Finds a single document from the GridFS bucket's files collection + * matching the query. + * + * @see FindOne::__construct() for supported options + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return array|object|null + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function findOne($filter = [], array $options = []) + { + return $this->collectionWrapper->findOneFile($filter, $options); + } + + /** + * Return the bucket name. + * + * @return string + */ + public function getBucketName() + { + return $this->bucketName; + } + + /** + * Return the chunks collection. + * + * @return Collection + */ + public function getChunksCollection() + { + return $this->collectionWrapper->getChunksCollection(); + } + + /** + * Return the chunk size in bytes. + * + * @return integer + */ + public function getChunkSizeBytes() + { + return $this->chunkSizeBytes; + } + + /** + * Return the database name. + * + * @return string + */ + public function getDatabaseName() + { + return $this->databaseName; + } + + /** + * Gets the file document of the GridFS file associated with a stream. + * + * @param resource $stream GridFS stream + * @return array|object + * @throws InvalidArgumentException if $stream is not a GridFS stream + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function getFileDocumentForStream($stream) + { + $file = $this->getRawFileDocumentForStream($stream); + + // Filter the raw document through the specified type map + return \MongoDB\apply_type_map_to_document($file, $this->typeMap); + } + + /** + * Gets the file document's ID of the GridFS file associated with a stream. + * + * @param resource $stream GridFS stream + * @return mixed + * @throws CorruptFileException if the file "_id" field does not exist + * @throws InvalidArgumentException if $stream is not a GridFS stream + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function getFileIdForStream($stream) + { + $file = $this->getRawFileDocumentForStream($stream); + + /* Filter the raw document through the specified type map, but override + * the root type so we can reliably access the ID. + */ + $typeMap = ['root' => 'stdClass'] + $this->typeMap; + $file = \MongoDB\apply_type_map_to_document($file, $typeMap); + + if ( ! isset($file->_id) && ! property_exists($file, '_id')) { + throw new CorruptFileException('file._id does not exist'); + } + + return $file->_id; + } + + /** + * Return the files collection. + * + * @return Collection + */ + public function getFilesCollection() + { + return $this->collectionWrapper->getFilesCollection(); + } + + /** + * Return the read concern for this GridFS bucket. + * + * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @return ReadConcern + */ + public function getReadConcern() + { + return $this->readConcern; + } + + /** + * Return the read preference for this GridFS bucket. + * + * @return ReadPreference + */ + public function getReadPreference() + { + return $this->readPreference; + } + + /** + * Return the type map for this GridFS bucket. + * + * @return array + */ + public function getTypeMap() + { + return $this->typeMap; + } + + /** + * Return the write concern for this GridFS bucket. + * + * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @return WriteConcern + */ + public function getWriteConcern() + { + return $this->writeConcern; + } + + /** + * Opens a readable stream for reading a GridFS file. + * + * @param mixed $id File ID + * @return resource + * @throws FileNotFoundException if no file could be selected + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function openDownloadStream($id) + { + $file = $this->collectionWrapper->findFileById($id); + + if ($file === null) { + throw FileNotFoundException::byId($id, $this->getFilesNamespace()); + } + + return $this->openDownloadStreamByFile($file); + } + + /** + * Opens a readable stream stream to read a GridFS file, which is selected + * by name and revision. + * + * Supported options: + * + * * revision (integer): Which revision (i.e. documents with the same + * filename and different uploadDate) of the file to retrieve. Defaults + * to -1 (i.e. the most recent revision). + * + * Revision numbers are defined as follows: + * + * * 0 = the original stored file + * * 1 = the first revision + * * 2 = the second revision + * * etc… + * * -2 = the second most recent revision + * * -1 = the most recent revision + * + * @param string $filename Filename + * @param array $options Download options + * @return resource + * @throws FileNotFoundException if no file could be selected + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function openDownloadStreamByName($filename, array $options = []) + { + $options += ['revision' => -1]; + + $file = $this->collectionWrapper->findFileByFilenameAndRevision($filename, $options['revision']); + + if ($file === null) { + throw FileNotFoundException::byFilenameAndRevision($filename, $options['revision'], $this->getFilesNamespace()); + } + + return $this->openDownloadStreamByFile($file); + } + + /** + * Opens a writable stream for writing a GridFS file. + * + * Supported options: + * + * * _id (mixed): File document identifier. Defaults to a new ObjectId. + * + * * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the + * bucket's chunk size. + * + * * metadata (document): User data for the "metadata" field of the files + * collection document. + * + * @param string $filename Filename + * @param array $options Upload options + * @return resource + */ + public function openUploadStream($filename, array $options = []) + { + $options += ['chunkSizeBytes' => $this->chunkSizeBytes]; + + $path = $this->createPathForUpload(); + $context = stream_context_create([ + self::$streamWrapperProtocol => [ + 'collectionWrapper' => $this->collectionWrapper, + 'filename' => $filename, + 'options' => $options, + ], + ]); + + return fopen($path, 'w', false, $context); + } + + /** + * Renames the GridFS file with the specified ID. + * + * @param mixed $id File ID + * @param string $newFilename New filename + * @throws FileNotFoundException if no file could be selected + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function rename($id, $newFilename) + { + $updateResult = $this->collectionWrapper->updateFilenameForId($id, $newFilename); + + if ($updateResult->getModifiedCount() === 1) { + return; + } + + /* If the update resulted in no modification, it's possible that the + * file did not exist, in which case we must raise an error. Checking + * the write result's matched count will be most efficient, but fall + * back to a findOne operation if necessary (i.e. legacy writes). + */ + $found = $updateResult->getMatchedCount() !== null + ? $updateResult->getMatchedCount() === 1 + : $this->collectionWrapper->findFileById($id) !== null; + + if ( ! $found) { + throw FileNotFoundException::byId($id, $this->getFilesNamespace()); + } + } + + /** + * Writes the contents of a readable stream to a GridFS file. + * + * Supported options: + * + * * _id (mixed): File document identifier. Defaults to a new ObjectId. + * + * * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the + * bucket's chunk size. + * + * * metadata (document): User data for the "metadata" field of the files + * collection document. + * + * @param string $filename Filename + * @param resource $source Readable stream + * @param array $options Stream options + * @return mixed ID of the newly created GridFS file + * @throws InvalidArgumentException if $source is not a GridFS stream + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function uploadFromStream($filename, $source, array $options = []) + { + if ( ! is_resource($source) || get_resource_type($source) != "stream") { + throw InvalidArgumentException::invalidType('$source', $source, 'resource'); + } + + $destination = $this->openUploadStream($filename, $options); + stream_copy_to_stream($source, $destination); + + return $this->getFileIdForStream($destination); + } + + /** + * Creates a path for an existing GridFS file. + * + * @param stdClass $file GridFS file document + * @return string + */ + private function createPathForFile(stdClass $file) + { + if ( ! is_object($file->_id) || method_exists($file->_id, '__toString')) { + $id = (string) $file->_id; + } else { + $id = \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP(['_id' => $file->_id])); + } + + return sprintf( + '%s://%s/%s.files/%s', + self::$streamWrapperProtocol, + urlencode($this->databaseName), + urlencode($this->bucketName), + urlencode($id) + ); + } + + /** + * Creates a path for a new GridFS file, which does not yet have an ID. + * + * @return string + */ + private function createPathForUpload() + { + return sprintf( + '%s://%s/%s.files', + self::$streamWrapperProtocol, + urlencode($this->databaseName), + urlencode($this->bucketName) + ); + } + + /** + * Returns the names of the files collection. + * + * @return string + */ + private function getFilesNamespace() + { + return sprintf('%s.%s.files', $this->databaseName, $this->bucketName); + } + + /** + * Gets the file document of the GridFS file associated with a stream. + * + * This returns the raw document from the StreamWrapper, which does not + * respect the Bucket's type map. + * + * @param resource $stream GridFS stream + * @return stdClass + * @throws InvalidArgumentException + */ + private function getRawFileDocumentForStream($stream) + { + if ( ! is_resource($stream) || get_resource_type($stream) != "stream") { + throw InvalidArgumentException::invalidType('$stream', $stream, 'resource'); + } + + $metadata = stream_get_meta_data($stream); + + if ( ! isset ($metadata['wrapper_data']) || ! $metadata['wrapper_data'] instanceof StreamWrapper) { + throw InvalidArgumentException::invalidType('$stream wrapper data', isset($metadata['wrapper_data']) ? $metadata['wrapper_data'] : null, 'MongoDB\Driver\GridFS\StreamWrapper'); + } + + return $metadata['wrapper_data']->getFile(); + } + + /** + * Opens a readable stream for the GridFS file. + * + * @param stdClass $file GridFS file document + * @return resource + */ + private function openDownloadStreamByFile(stdClass $file) + { + $path = $this->createPathForFile($file); + $context = stream_context_create([ + self::$streamWrapperProtocol => [ + 'collectionWrapper' => $this->collectionWrapper, + 'file' => $file, + ], + ]); + + return fopen($path, 'r', false, $context); + } + + /** + * Registers the GridFS stream wrapper if it is not already registered. + */ + private function registerStreamWrapper() + { + if (in_array(self::$streamWrapperProtocol, stream_get_wrappers())) { + return; + } + + StreamWrapper::register(self::$streamWrapperProtocol); + } +} diff --git a/vendor/mongodb/mongodb/src/GridFS/CollectionWrapper.php b/vendor/mongodb/mongodb/src/GridFS/CollectionWrapper.php new file mode 100644 index 00000000..754fd4b3 --- /dev/null +++ b/vendor/mongodb/mongodb/src/GridFS/CollectionWrapper.php @@ -0,0 +1,338 @@ +databaseName = (string) $databaseName; + $this->bucketName = (string) $bucketName; + + $this->filesCollection = new Collection($manager, $databaseName, sprintf('%s.files', $bucketName), $collectionOptions); + $this->chunksCollection = new Collection($manager, $databaseName, sprintf('%s.chunks', $bucketName), $collectionOptions); + } + + /** + * Deletes all GridFS chunks for a given file ID. + * + * @param mixed $id + */ + public function deleteChunksByFilesId($id) + { + $this->chunksCollection->deleteMany(['files_id' => $id]); + } + + /** + * Deletes a GridFS file and related chunks by ID. + * + * @param mixed $id + */ + public function deleteFileAndChunksById($id) + { + $this->filesCollection->deleteOne(['_id' => $id]); + $this->chunksCollection->deleteMany(['files_id' => $id]); + } + + /** + * Drops the GridFS files and chunks collections. + */ + public function dropCollections() + { + $this->filesCollection->drop(['typeMap' => []]); + $this->chunksCollection->drop(['typeMap' => []]); + } + + /** + * Finds GridFS chunk documents for a given file ID and optional offset. + * + * @param mixed $id File ID + * @param integer $fromChunk Starting chunk (inclusive) + * @return Cursor + */ + public function findChunksByFileId($id, $fromChunk = 0) + { + return $this->chunksCollection->find( + [ + 'files_id' => $id, + 'n' => ['$gte' => $fromChunk], + ], + [ + 'sort' => ['n' => 1], + 'typeMap' => ['root' => 'stdClass'], + ] + ); + } + + /** + * Finds a GridFS file document for a given filename and revision. + * + * Revision numbers are defined as follows: + * + * * 0 = the original stored file + * * 1 = the first revision + * * 2 = the second revision + * * etc… + * * -2 = the second most recent revision + * * -1 = the most recent revision + * + * @see Bucket::downloadToStreamByName() + * @see Bucket::openDownloadStreamByName() + * @param string $filename + * @param integer $revision + * @return stdClass|null + */ + public function findFileByFilenameAndRevision($filename, $revision) + { + $filename = (string) $filename; + $revision = (integer) $revision; + + if ($revision < 0) { + $skip = abs($revision) - 1; + $sortOrder = -1; + } else { + $skip = $revision; + $sortOrder = 1; + } + + return $this->filesCollection->findOne( + ['filename' => $filename], + [ + 'skip' => $skip, + 'sort' => ['uploadDate' => $sortOrder], + 'typeMap' => ['root' => 'stdClass'], + ] + ); + } + + /** + * Finds a GridFS file document for a given ID. + * + * @param mixed $id + * @return stdClass|null + */ + public function findFileById($id) + { + return $this->filesCollection->findOne( + ['_id' => $id], + ['typeMap' => ['root' => 'stdClass']] + ); + } + + /** + * Finds documents from the GridFS bucket's files collection. + * + * @see Find::__construct() for supported options + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return Cursor + */ + public function findFiles($filter, array $options = []) + { + return $this->filesCollection->find($filter, $options); + } + + /** + * Finds a single document from the GridFS bucket's files collection. + * + * @param array|object $filter Query by which to filter documents + * @param array $options Additional options + * @return array|object|null + */ + public function findOneFile($filter, array $options = []) + { + return $this->filesCollection->findOne($filter, $options); + } + + /** + * Return the bucket name. + * + * @return string + */ + public function getBucketName() + { + return $this->bucketName; + } + + /** + * Return the chunks collection. + * + * @return Collection + */ + public function getChunksCollection() + { + return $this->chunksCollection; + } + + /** + * Return the database name. + * + * @return string + */ + public function getDatabaseName() + { + return $this->databaseName; + } + + /** + * Return the files collection. + * + * @return Collection + */ + public function getFilesCollection() + { + return $this->filesCollection; + } + + /** + * Inserts a document into the chunks collection. + * + * @param array|object $chunk Chunk document + */ + public function insertChunk($chunk) + { + if ( ! $this->checkedIndexes) { + $this->ensureIndexes(); + } + + $this->chunksCollection->insertOne($chunk); + } + + /** + * Inserts a document into the files collection. + * + * The file document should be inserted after all chunks have been inserted. + * + * @param array|object $file File document + */ + public function insertFile($file) + { + if ( ! $this->checkedIndexes) { + $this->ensureIndexes(); + } + + $this->filesCollection->insertOne($file); + } + + /** + * Updates the filename field in the file document for a given ID. + * + * @param mixed $id + * @param string $filename + * @return UpdateResult + */ + public function updateFilenameForId($id, $filename) + { + return $this->filesCollection->updateOne( + ['_id' => $id], + ['$set' => ['filename' => (string) $filename]] + ); + } + + /** + * Create an index on the chunks collection if it does not already exist. + */ + private function ensureChunksIndex() + { + foreach ($this->chunksCollection->listIndexes() as $index) { + if ($index->isUnique() && $index->getKey() === ['files_id' => 1, 'n' => 1]) { + return; + } + } + + $this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]); + } + + /** + * Create an index on the files collection if it does not already exist. + */ + private function ensureFilesIndex() + { + foreach ($this->filesCollection->listIndexes() as $index) { + if ($index->getKey() === ['filename' => 1, 'uploadDate' => 1]) { + return; + } + } + + $this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]); + } + + /** + * Ensure indexes on the files and chunks collections exist. + * + * This method is called once before the first write operation on a GridFS + * bucket. Indexes are only be created if the files collection is empty. + */ + private function ensureIndexes() + { + if ($this->checkedIndexes) { + return; + } + + $this->checkedIndexes = true; + + if ( ! $this->isFilesCollectionEmpty()) { + return; + } + + $this->ensureFilesIndex(); + $this->ensureChunksIndex(); + } + + /** + * Returns whether the files collection is empty. + * + * @return boolean + */ + private function isFilesCollectionEmpty() + { + return null === $this->filesCollection->findOne([], [ + 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), + 'projection' => ['_id' => 1], + 'typeMap' => [], + ]); + } +} diff --git a/vendor/mongodb/mongodb/src/GridFS/Exception/CorruptFileException.php b/vendor/mongodb/mongodb/src/GridFS/Exception/CorruptFileException.php new file mode 100644 index 00000000..787c9b88 --- /dev/null +++ b/vendor/mongodb/mongodb/src/GridFS/Exception/CorruptFileException.php @@ -0,0 +1,58 @@ + $id])); + + return new static(sprintf('File "%s" not found in "%s"', $json, $namespace)); + } +} diff --git a/vendor/mongodb/mongodb/src/GridFS/ReadableStream.php b/vendor/mongodb/mongodb/src/GridFS/ReadableStream.php new file mode 100644 index 00000000..5c37f957 --- /dev/null +++ b/vendor/mongodb/mongodb/src/GridFS/ReadableStream.php @@ -0,0 +1,273 @@ +chunkSize) || ! is_integer($file->chunkSize) || $file->chunkSize < 1) { + throw new CorruptFileException('file.chunkSize is not an integer >= 1'); + } + + if ( ! isset($file->length) || ! is_integer($file->length) || $file->length < 0) { + throw new CorruptFileException('file.length is not an integer > 0'); + } + + if ( ! isset($file->_id) && ! property_exists($file, '_id')) { + throw new CorruptFileException('file._id does not exist'); + } + + $this->file = $file; + $this->chunkSize = (integer) $file->chunkSize; + $this->length = (integer) $file->length; + + $this->collectionWrapper = $collectionWrapper; + + if ($this->length > 0) { + $this->numChunks = (integer) ceil($this->length / $this->chunkSize); + $this->expectedLastChunkSize = ($this->length - (($this->numChunks - 1) * $this->chunkSize)); + } + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'bucketName' => $this->collectionWrapper->getBucketName(), + 'databaseName' => $this->collectionWrapper->getDatabaseName(), + 'file' => $this->file, + ]; + } + + public function close() + { + // Nothing to do + } + + /** + * Return the stream's file document. + * + * @return stdClass + */ + public function getFile() + { + return $this->file; + } + + /** + * Return the stream's size in bytes. + * + * @return integer + */ + public function getSize() + { + return $this->length; + } + + /** + * Return whether the current read position is at the end of the stream. + * + * @return boolean + */ + public function isEOF() + { + if ($this->chunkOffset === $this->numChunks - 1) { + return $this->bufferOffset >= $this->expectedLastChunkSize; + } + + return $this->chunkOffset >= $this->numChunks; + } + + /** + * Read bytes from the stream. + * + * Note: this method may return a string smaller than the requested length + * if data is not available to be read. + * + * @param integer $length Number of bytes to read + * @return string + * @throws InvalidArgumentException if $length is negative + */ + public function readBytes($length) + { + if ($length < 0) { + throw new InvalidArgumentException(sprintf('$length must be >= 0; given: %d', $length)); + } + + if ($this->chunksIterator === null) { + $this->initChunksIterator(); + } + + if ($this->buffer === null && ! $this->initBufferFromCurrentChunk()) { + return ''; + } + + $data = ''; + + while (strlen($data) < $length) { + if ($this->bufferOffset >= strlen($this->buffer) && ! $this->initBufferFromNextChunk()) { + break; + } + + $initialDataLength = strlen($data); + $data .= substr($this->buffer, $this->bufferOffset, $length - $initialDataLength); + $this->bufferOffset += strlen($data) - $initialDataLength; + } + + return $data; + } + + /** + * Seeks the chunk and buffer offsets for the next read operation. + * + * @param integer $offset + * @throws InvalidArgumentException if $offset is out of range + */ + public function seek($offset) + { + if ($offset < 0 || $offset > $this->file->length) { + throw new InvalidArgumentException(sprintf('$offset must be >= 0 and <= %d; given: %d', $length, $offset)); + } + + /* Compute the offsets for the chunk and buffer (i.e. chunk data) from + * which we will expect to read after seeking. If the chunk offset + * changed, we'll also need to reset the buffer. + */ + $lastChunkOffset = $this->chunkOffset; + $this->chunkOffset = (integer) floor($offset / $this->chunkSize); + $this->bufferOffset = $offset % $this->chunkSize; + + if ($lastChunkOffset !== $this->chunkOffset) { + $this->buffer = null; + $this->chunksIterator = null; + } + } + + /** + * Return the current position of the stream. + * + * This is the offset within the stream where the next byte would be read. + * + * @return integer + */ + public function tell() + { + return ($this->chunkOffset * $this->chunkSize) + $this->bufferOffset; + } + + /** + * Initialize the buffer to the current chunk's data. + * + * @return boolean Whether there was a current chunk to read + * @throws CorruptFileException if an expected chunk could not be read successfully + */ + private function initBufferFromCurrentChunk() + { + if ($this->chunkOffset === 0 && $this->numChunks === 0) { + return false; + } + + if ( ! $this->chunksIterator->valid()) { + throw CorruptFileException::missingChunk($this->chunkOffset); + } + + $currentChunk = $this->chunksIterator->current(); + + if ($currentChunk->n !== $this->chunkOffset) { + throw CorruptFileException::unexpectedIndex($currentChunk->n, $this->chunkOffset); + } + + $this->buffer = $currentChunk->data->getData(); + + $actualChunkSize = strlen($this->buffer); + + $expectedChunkSize = ($this->chunkOffset === $this->numChunks - 1) + ? $this->expectedLastChunkSize + : $this->chunkSize; + + if ($actualChunkSize !== $expectedChunkSize) { + throw CorruptFileException::unexpectedSize($actualChunkSize, $expectedChunkSize); + } + + return true; + } + + /** + * Advance to the next chunk and initialize the buffer to its data. + * + * @return boolean Whether there was a next chunk to read + * @throws CorruptFileException if an expected chunk could not be read successfully + */ + private function initBufferFromNextChunk() + { + if ($this->chunkOffset === $this->numChunks - 1) { + return false; + } + + $this->bufferOffset = 0; + $this->chunkOffset++; + $this->chunksIterator->next(); + + return $this->initBufferFromCurrentChunk(); + } + + /** + * Initializes the chunk iterator starting from the current offset. + */ + private function initChunksIterator() + { + $cursor = $this->collectionWrapper->findChunksByFileId($this->file->_id, $this->chunkOffset); + + $this->chunksIterator = new IteratorIterator($cursor); + $this->chunksIterator->rewind(); + } +} diff --git a/vendor/mongodb/mongodb/src/GridFS/StreamWrapper.php b/vendor/mongodb/mongodb/src/GridFS/StreamWrapper.php new file mode 100644 index 00000000..00fee874 --- /dev/null +++ b/vendor/mongodb/mongodb/src/GridFS/StreamWrapper.php @@ -0,0 +1,307 @@ +stream->getFile(); + } + + /** + * Register the GridFS stream wrapper. + * + * @param string $protocol Protocol to use for stream_wrapper_register() + */ + public static function register($protocol = 'gridfs') + { + if (in_array($protocol, stream_get_wrappers())) { + stream_wrapper_unregister($protocol); + } + + stream_wrapper_register($protocol, get_called_class(), \STREAM_IS_URL); + } + + /** + * Closes the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-close.php + */ + public function stream_close() + { + $this->stream->close(); + } + + /** + * Returns whether the file pointer is at the end of the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-eof.php + * @return boolean + */ + public function stream_eof() + { + if ( ! $this->stream instanceof ReadableStream) { + return false; + } + + return $this->stream->isEOF(); + } + + /** + * Opens the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-open.php + * @param string $path Path to the file resource + * @param string $mode Mode used to open the file (only "r" and "w" are supported) + * @param integer $options Additional flags set by the streams API + * @param string $openedPath Not used + */ + public function stream_open($path, $mode, $options, &$openedPath) + { + $this->initProtocol($path); + $this->mode = $mode; + + if ($mode === 'r') { + return $this->initReadableStream(); + } + + if ($mode === 'w') { + return $this->initWritableStream(); + } + + return false; + } + + /** + * Read bytes from the stream. + * + * Note: this method may return a string smaller than the requested length + * if data is not available to be read. + * + * @see http://php.net/manual/en/streamwrapper.stream-read.php + * @param integer $length Number of bytes to read + * @return string + */ + public function stream_read($length) + { + if ( ! $this->stream instanceof ReadableStream) { + return ''; + } + + try { + return $this->stream->readBytes($length); + } catch (Exception $e) { + trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), \E_USER_WARNING); + return false; + } + } + + /** + * Return the current position of the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-seek.php + * @param integer $offset Stream offset to seek to + * @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END + * @return boolean True if the position was updated and false otherwise + */ + public function stream_seek($offset, $whence = \SEEK_SET) + { + $size = $this->stream->getSize(); + + if ($whence === \SEEK_CUR) { + $offset += $this->stream->tell(); + } + + if ($whence === \SEEK_END) { + $offset += $size; + } + + // WritableStreams are always positioned at the end of the stream + if ($this->stream instanceof WritableStream) { + return $offset === $size; + } + + if ($offset < 0 || $offset > $size) { + return false; + } + + $this->stream->seek($offset); + + return true; + } + + /** + * Return information about the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-stat.php + * @return array + */ + public function stream_stat() + { + $stat = $this->getStatTemplate(); + + $stat[2] = $stat['mode'] = $this->stream instanceof ReadableStream + ? 0100444 // S_IFREG & S_IRUSR & S_IRGRP & S_IROTH + : 0100222; // S_IFREG & S_IWUSR & S_IWGRP & S_IWOTH + $stat[7] = $stat['size'] = $this->stream->getSize(); + + $file = $this->stream->getFile(); + + if (isset($file->uploadDate) && $file->uploadDate instanceof UTCDateTime) { + $timestamp = $file->uploadDate->toDateTime()->getTimestamp(); + $stat[9] = $stat['mtime'] = $timestamp; + $stat[10] = $stat['ctime'] = $timestamp; + } + + if (isset($file->chunkSize) && is_integer($file->chunkSize)) { + $stat[11] = $stat['blksize'] = $file->chunkSize; + } + + return $stat; + } + + /** + * Return the current position of the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-tell.php + * @return integer The current position of the stream + */ + public function stream_tell() + { + return $this->stream->tell(); + } + + /** + * Write bytes to the stream. + * + * @see http://php.net/manual/en/streamwrapper.stream-write.php + * @param string $data Data to write + * @return integer The number of bytes written + */ + public function stream_write($data) + { + if ( ! $this->stream instanceof WritableStream) { + return 0; + } + + try { + return $this->stream->writeBytes($data); + } catch (Exception $e) { + trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), \E_USER_WARNING); + return false; + } + } + + /** + * Returns a stat template with default values. + * + * @return array + */ + private function getStatTemplate() + { + return [ + 0 => 0, 'dev' => 0, + 1 => 0, 'ino' => 0, + 2 => 0, 'mode' => 0, + 3 => 0, 'nlink' => 0, + 4 => 0, 'uid' => 0, + 5 => 0, 'gid' => 0, + 6 => -1, 'rdev' => -1, + 7 => 0, 'size' => 0, + 8 => 0, 'atime' => 0, + 9 => 0, 'mtime' => 0, + 10 => 0, 'ctime' => 0, + 11 => -1, 'blksize' => -1, + 12 => -1, 'blocks' => -1, + ]; + } + + /** + * Initialize the protocol from the given path. + * + * @see StreamWrapper::stream_open() + * @param string $path + */ + private function initProtocol($path) + { + $parts = explode('://', $path, 2); + $this->protocol = $parts[0] ?: 'gridfs'; + } + + /** + * Initialize the internal stream for reading. + * + * @see StreamWrapper::stream_open() + * @return boolean + */ + private function initReadableStream() + { + $context = stream_context_get_options($this->context); + + $this->stream = new ReadableStream( + $context[$this->protocol]['collectionWrapper'], + $context[$this->protocol]['file'] + ); + + return true; + } + + /** + * Initialize the internal stream for writing. + * + * @see StreamWrapper::stream_open() + * @return boolean + */ + private function initWritableStream() + { + $context = stream_context_get_options($this->context); + + $this->stream = new WritableStream( + $context[$this->protocol]['collectionWrapper'], + $context[$this->protocol]['filename'], + $context[$this->protocol]['options'] + ); + + return true; + } +} diff --git a/vendor/mongodb/mongodb/src/GridFS/WritableStream.php b/vendor/mongodb/mongodb/src/GridFS/WritableStream.php new file mode 100644 index 00000000..84c12b7a --- /dev/null +++ b/vendor/mongodb/mongodb/src/GridFS/WritableStream.php @@ -0,0 +1,266 @@ + new ObjectId, + 'chunkSizeBytes' => self::$defaultChunkSizeBytes, + ]; + + if (isset($options['aliases']) && ! \MongoDB\is_string_array($options['aliases'])) { + throw InvalidArgumentException::invalidType('"aliases" option', $options['aliases'], 'array of strings'); + } + + if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) { + throw InvalidArgumentException::invalidType('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer'); + } + + if (isset($options['chunkSizeBytes']) && $options['chunkSizeBytes'] < 1) { + throw new InvalidArgumentException(sprintf('Expected "chunkSizeBytes" option to be >= 1, %d given', $options['chunkSizeBytes'])); + } + + if (isset($options['contentType']) && ! is_string($options['contentType'])) { + throw InvalidArgumentException::invalidType('"contentType" option', $options['contentType'], 'string'); + } + + if (isset($options['metadata']) && ! is_array($options['metadata']) && ! is_object($options['metadata'])) { + throw InvalidArgumentException::invalidType('"metadata" option', $options['metadata'], 'array or object'); + } + + $this->chunkSize = $options['chunkSizeBytes']; + $this->collectionWrapper = $collectionWrapper; + $this->ctx = hash_init('md5'); + + $this->file = [ + '_id' => $options['_id'], + 'chunkSize' => $this->chunkSize, + 'filename' => (string) $filename, + 'uploadDate' => new UTCDateTime, + ] + array_intersect_key($options, ['aliases' => 1, 'contentType' => 1, 'metadata' => 1]); + } + + /** + * Return internal properties for debugging purposes. + * + * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return [ + 'bucketName' => $this->collectionWrapper->getBucketName(), + 'databaseName' => $this->collectionWrapper->getDatabaseName(), + 'file' => $this->file, + ]; + } + + /** + * Closes an active stream and flushes all buffered data to GridFS. + */ + public function close() + { + if ($this->isClosed) { + // TODO: Should this be an error condition? e.g. BadMethodCallException + return; + } + + if (strlen($this->buffer) > 0) { + $this->insertChunkFromBuffer(); + } + + $this->fileCollectionInsert(); + $this->isClosed = true; + } + + /** + * Return the stream's file document. + * + * @return stdClass + */ + public function getFile() + { + return (object) $this->file; + } + + /** + * Return the stream's size in bytes. + * + * Note: this value will increase as more data is written to the stream. + * + * @return integer + */ + public function getSize() + { + return $this->length + strlen($this->buffer); + } + + /** + * Return the current position of the stream. + * + * This is the offset within the stream where the next byte would be + * written. Since seeking is not supported and writes are appended, this is + * always the end of the stream. + * + * @see WriteableStream::getSize() + * @return integer + */ + public function tell() + { + return $this->getSize(); + } + + /** + * Inserts binary data into GridFS via chunks. + * + * Data will be buffered internally until chunkSizeBytes are accumulated, at + * which point a chunk document will be inserted and the buffer reset. + * + * @param string $data Binary data to write + * @return integer + */ + public function writeBytes($data) + { + if ($this->isClosed) { + // TODO: Should this be an error condition? e.g. BadMethodCallException + return; + } + + $bytesRead = 0; + + while ($bytesRead != strlen($data)) { + $initialBufferLength = strlen($this->buffer); + $this->buffer .= substr($data, $bytesRead, $this->chunkSize - $initialBufferLength); + $bytesRead += strlen($this->buffer) - $initialBufferLength; + + if (strlen($this->buffer) == $this->chunkSize) { + $this->insertChunkFromBuffer(); + } + } + + return $bytesRead; + } + + private function abort() + { + try { + $this->collectionWrapper->deleteChunksByFilesId($this->file['_id']); + } catch (DriverRuntimeException $e) { + // We are already handling an error if abort() is called, so suppress this + } + + $this->isClosed = true; + } + + private function fileCollectionInsert() + { + $md5 = hash_final($this->ctx); + + $this->file['length'] = $this->length; + $this->file['md5'] = $md5; + + try { + $this->collectionWrapper->insertFile($this->file); + } catch (DriverRuntimeException $e) { + $this->abort(); + + throw $e; + } + + return $this->file['_id']; + } + + private function insertChunkFromBuffer() + { + if (strlen($this->buffer) == 0) { + return; + } + + $data = $this->buffer; + $this->buffer = ''; + + $chunk = [ + 'files_id' => $this->file['_id'], + 'n' => $this->chunkOffset, + 'data' => new Binary($data, Binary::TYPE_GENERIC), + ]; + + hash_update($this->ctx, $data); + + try { + $this->collectionWrapper->insertChunk($chunk); + } catch (DriverRuntimeException $e) { + $this->abort(); + + throw $e; + } + + $this->length += strlen($data); + $this->chunkOffset++; + } +} diff --git a/vendor/mongodb/mongodb/src/InsertManyResult.php b/vendor/mongodb/mongodb/src/InsertManyResult.php new file mode 100644 index 00000000..a9ecb693 --- /dev/null +++ b/vendor/mongodb/mongodb/src/InsertManyResult.php @@ -0,0 +1,91 @@ +writeResult = $writeResult; + $this->insertedIds = $insertedIds; + $this->isAcknowledged = $writeResult->isAcknowledged(); + } + + /** + * Return the number of documents that were inserted. + * + * This method should only be called if the write was acknowledged. + * + * @see InsertManyResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getInsertedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getInsertedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return a map of the inserted documents' IDs. + * + * The index of each ID in the map corresponds to each document's position + * in the bulk operation. If a document had an ID prior to inserting (i.e. + * the driver did not generate an ID), the index will contain its "_id" + * field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId + * instance. + * + * @return mixed[] + */ + public function getInsertedIds() + { + return $this->insertedIds; + } + + /** + * Return whether this insert result was acknowledged by the server. + * + * If the insert was not acknowledged, other fields from the WriteResult + * (e.g. insertedCount) will be undefined. + * + * @return boolean + */ + public function isAcknowledged() + { + return $this->writeResult->isAcknowledged(); + } +} diff --git a/vendor/mongodb/mongodb/src/InsertOneResult.php b/vendor/mongodb/mongodb/src/InsertOneResult.php new file mode 100644 index 00000000..5a580bd3 --- /dev/null +++ b/vendor/mongodb/mongodb/src/InsertOneResult.php @@ -0,0 +1,93 @@ +writeResult = $writeResult; + $this->insertedId = $insertedId; + $this->isAcknowledged = $writeResult->isAcknowledged(); + } + + /** + * Return the number of documents that were inserted. + * + * This method should only be called if the write was acknowledged. + * + * @see InsertOneResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getInsertedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getInsertedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the inserted document's ID. + * + * If the document had an ID prior to inserting (i.e. the driver did not + * need to generate an ID), this will contain its "_id". Any + * driver-generated ID will be a MongoDB\BSON\ObjectId instance. + * + * @return mixed + */ + public function getInsertedId() + { + return $this->insertedId; + } + + /** + * Return whether this insert was acknowledged by the server. + * + * If the insert was not acknowledged, other fields from the WriteResult + * (e.g. insertedCount) will be undefined. + * + * If the insert was not acknowledged, other fields from the WriteResult + * (e.g. insertedCount) will be undefined and their getter methods should + * not be invoked. + * + * @return boolean + */ + public function isAcknowledged() + { + return $this->writeResult->isAcknowledged(); + } +} diff --git a/vendor/mongodb/mongodb/src/MapReduceResult.php b/vendor/mongodb/mongodb/src/MapReduceResult.php new file mode 100644 index 00000000..1b50e8f5 --- /dev/null +++ b/vendor/mongodb/mongodb/src/MapReduceResult.php @@ -0,0 +1,99 @@ +getIterator = $getIterator; + $this->executionTimeMS = (integer) $result->timeMillis; + $this->counts = (array) $result->counts; + $this->timing = isset($result->timing) ? (array) $result->timing : []; + } + + /** + * Returns various count statistics from the mapReduce command. + * + * @return array + */ + public function getCounts() + { + return $this->counts; + } + + /** + * Return the command execution time in milliseconds. + * + * @return integer + */ + public function getExecutionTimeMS() + { + return $this->executionTimeMS; + } + + /** + * Return the mapReduce results as a Traversable. + * + * @see http://php.net/iteratoraggregate.getiterator + * @return Traversable + */ + public function getIterator() + { + return call_user_func($this->getIterator); + } + + /** + * Returns various timing statistics from the mapReduce command. + * + * Note: timing statistics are only available if the mapReduce command's + * "verbose" option was true; otherwise, an empty array will be returned. + * + * @return array + */ + public function getTiming() + { + return $this->timing; + } +} diff --git a/vendor/mongodb/mongodb/src/Model/BSONArray.php b/vendor/mongodb/mongodb/src/Model/BSONArray.php new file mode 100644 index 00000000..8474328f --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/BSONArray.php @@ -0,0 +1,89 @@ +exchangeArray($properties); + + return $array; + } + + /** + * Serialize the array to BSON. + * + * The array data will be numerically reindexed to ensure that it is stored + * as a BSON array. + * + * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @return array + */ + public function bsonSerialize() + { + return array_values($this->getArrayCopy()); + } + + /** + * Unserialize the document to BSON. + * + * @see http://php.net/mongodb-bson-unserializable.bsonunserialize + * @param array $data Array data + */ + public function bsonUnserialize(array $data) + { + self::__construct($data); + } + + /** + * Serialize the array to JSON. + * + * The array data will be numerically reindexed to ensure that it is stored + * as a JSON array. + * + * @see http://php.net/jsonserializable.jsonserialize + * @return array + */ + public function jsonSerialize() + { + return array_values($this->getArrayCopy()); + } +} diff --git a/vendor/mongodb/mongodb/src/Model/BSONDocument.php b/vendor/mongodb/mongodb/src/Model/BSONDocument.php new file mode 100644 index 00000000..594c67eb --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/BSONDocument.php @@ -0,0 +1,96 @@ +exchangeArray($properties); + + return $document; + } + + /** + * Serialize the document to BSON. + * + * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @return object + */ + public function bsonSerialize() + { + return (object) $this->getArrayCopy(); + } + + /** + * Unserialize the document to BSON. + * + * @see http://php.net/mongodb-bson-unserializable.bsonunserialize + * @param array $data Array data + */ + public function bsonUnserialize(array $data) + { + parent::__construct($data, ArrayObject::ARRAY_AS_PROPS); + } + + /** + * Serialize the array to JSON. + * + * @see http://php.net/jsonserializable.jsonserialize + * @return object + */ + public function jsonSerialize() + { + return (object) $this->getArrayCopy(); + } +} diff --git a/vendor/mongodb/mongodb/src/Model/CachingIterator.php b/vendor/mongodb/mongodb/src/Model/CachingIterator.php new file mode 100644 index 00000000..560bc388 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/CachingIterator.php @@ -0,0 +1,166 @@ +iterator = $this->wrapTraversable($traversable); + $this->storeCurrentItem(); + } + + /** + * @see http://php.net/countable.count + * @return integer + */ + public function count() + { + $this->exhaustIterator(); + + return count($this->items); + } + + /** + * @see http://php.net/iterator.current + * @return mixed + */ + public function current() + { + return current($this->items); + } + + /** + * @see http://php.net/iterator.mixed + * @return mixed + */ + public function key() + { + return key($this->items); + } + + /** + * @see http://php.net/iterator.next + * @return void + */ + public function next() + { + if ( ! $this->iteratorExhausted) { + $this->iterator->next(); + $this->storeCurrentItem(); + } + + next($this->items); + } + + /** + * @see http://php.net/iterator.rewind + * @return void + */ + public function rewind() + { + /* If the iterator has advanced, exhaust it now so that future iteration + * can rely on the cache. + */ + if ($this->iteratorAdvanced) { + $this->exhaustIterator(); + } + + reset($this->items); + } + + /** + * + * @see http://php.net/iterator.valid + * @return boolean + */ + public function valid() + { + return $this->key() !== null; + } + + /** + * Ensures that the inner iterator is fully consumed and cached. + */ + private function exhaustIterator() + { + while ( ! $this->iteratorExhausted) { + $this->next(); + } + } + + /** + * Stores the current item in the cache. + */ + private function storeCurrentItem() + { + $key = $this->iterator->key(); + + if ($key === null) { + return; + } + + $this->items[$key] = $this->iterator->current(); + } + + /** + * Wraps the Traversable with a Generator. + * + * @param Traversable $traversable + * @return Generator + */ + private function wrapTraversable(Traversable $traversable) + { + foreach ($traversable as $key => $value) { + yield $key => $value; + $this->iteratorAdvanced = true; + } + + $this->iteratorExhausted = true; + } +} diff --git a/vendor/mongodb/mongodb/src/Model/CollectionInfo.php b/vendor/mongodb/mongodb/src/Model/CollectionInfo.php new file mode 100644 index 00000000..70d90dd1 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/CollectionInfo.php @@ -0,0 +1,105 @@ +info = $info; + } + + /** + * Return the collection info as an array. + * + * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return $this->info; + } + + /** + * Return the maximum number of documents to keep in the capped collection. + * + * @return integer|null + */ + public function getCappedMax() + { + return isset($this->info['options']['max']) ? (integer) $this->info['options']['max'] : null; + } + + /** + * Return the maximum size (in bytes) of the capped collection. + * + * @return integer|null + */ + public function getCappedSize() + { + return isset($this->info['options']['size']) ? (integer) $this->info['options']['size'] : null; + } + + /** + * Return the collection name. + * + * @return string + */ + public function getName() + { + return (string) $this->info['name']; + } + + /** + * Return the collection options. + * + * @return array + */ + public function getOptions() + { + return isset($this->info['options']) ? (array) $this->info['options'] : []; + } + + /** + * Return whether the collection is a capped collection. + * + * @return boolean + */ + public function isCapped() + { + return ! empty($this->info['options']['capped']); + } +} diff --git a/vendor/mongodb/mongodb/src/Model/CollectionInfoCommandIterator.php b/vendor/mongodb/mongodb/src/Model/CollectionInfoCommandIterator.php new file mode 100644 index 00000000..c4b7b8da --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/CollectionInfoCommandIterator.php @@ -0,0 +1,46 @@ +info = $info; + } + + /** + * Return the collection info as an array. + * + * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return $this->info; + } + + /** + * Return the database name. + * + * @return string + */ + public function getName() + { + return (string) $this->info['name']; + } + + /** + * Return the databases size on disk (in bytes). + * + * @return integer + */ + public function getSizeOnDisk() + { + return (integer) $this->info['sizeOnDisk']; + } + + /** + * Return whether the database is empty. + * + * @return boolean + */ + public function isEmpty() + { + return (boolean) $this->info['empty']; + } +} diff --git a/vendor/mongodb/mongodb/src/Model/DatabaseInfoIterator.php b/vendor/mongodb/mongodb/src/Model/DatabaseInfoIterator.php new file mode 100644 index 00000000..91576eb1 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/DatabaseInfoIterator.php @@ -0,0 +1,38 @@ +databases = $databases; + } + + /** + * Return the current element as a DatabaseInfo instance. + * + * @see DatabaseInfoIterator::current() + * @see http://php.net/iterator.current + * @return DatabaseInfo + */ + public function current() + { + return new DatabaseInfo(current($this->databases)); + } + + /** + * Return the key of the current element. + * + * @see http://php.net/iterator.key + * @return integer + */ + public function key() + { + return key($this->databases); + } + + /** + * Move forward to next element. + * + * @see http://php.net/iterator.next + */ + public function next() + { + next($this->databases); + } + + /** + * Rewind the Iterator to the first element. + * + * @see http://php.net/iterator.rewind + */ + public function rewind() + { + reset($this->databases); + } + + /** + * Checks if current position is valid. + * + * @see http://php.net/iterator.valid + * @return boolean + */ + public function valid() + { + return key($this->databases) !== null; + } +} diff --git a/vendor/mongodb/mongodb/src/Model/IndexInfo.php b/vendor/mongodb/mongodb/src/Model/IndexInfo.php new file mode 100644 index 00000000..64c37e89 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/IndexInfo.php @@ -0,0 +1,186 @@ +info = $info; + } + + /** + * Return the collection info as an array. + * + * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @return array + */ + public function __debugInfo() + { + return $this->info; + } + + /** + * Return the index key. + * + * @return array + */ + public function getKey() + { + return (array) $this->info['key']; + } + + /** + * Return the index name. + * + * @return string + */ + public function getName() + { + return (string) $this->info['name']; + } + + /** + * Return the index namespace (e.g. "db.collection"). + * + * @return string + */ + public function getNamespace() + { + return (string) $this->info['ns']; + } + + /** + * Return the index version. + * + * @return integer + */ + public function getVersion() + { + return (integer) $this->info['v']; + } + + /** + * Return whether this is a sparse index. + * + * @see http://docs.mongodb.org/manual/core/index-sparse/ + * @return boolean + */ + public function isSparse() + { + return ! empty($this->info['sparse']); + } + + /** + * Return whether this is a TTL index. + * + * @see http://docs.mongodb.org/manual/core/index-ttl/ + * @return boolean + */ + public function isTtl() + { + return array_key_exists('expireAfterSeconds', $this->info); + } + + /** + * Return whether this is a unique index. + * + * @see http://docs.mongodb.org/manual/core/index-unique/ + * @return boolean + */ + public function isUnique() + { + return ! empty($this->info['unique']); + } + + /** + * Check whether a field exists in the index information. + * + * @see http://php.net/arrayaccess.offsetexists + * @param mixed $key + * @return boolean + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->info); + } + + /** + * Return the field's value from the index information. + * + * This method satisfies the Enumerating Indexes specification's requirement + * that index fields be made accessible under their original names. It may + * also be used to access fields that do not have a helper method. + * + * @see http://php.net/arrayaccess.offsetget + * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst#getting-full-index-information + * @param mixed $key + * @return mixed + */ + public function offsetGet($key) + { + return $this->info[$key]; + } + + /** + * Not supported. + * + * @see http://php.net/arrayaccess.offsetset + * @throws BadMethodCallException + */ + public function offsetSet($key, $value) + { + throw BadMethodCallException::classIsImmutable(__CLASS__); + } + + /** + * Not supported. + * + * @see http://php.net/arrayaccess.offsetunset + * @throws BadMethodCallException + */ + public function offsetUnset($key) + { + throw BadMethodCallException::classIsImmutable(__CLASS__); + } +} diff --git a/vendor/mongodb/mongodb/src/Model/IndexInfoIterator.php b/vendor/mongodb/mongodb/src/Model/IndexInfoIterator.php new file mode 100644 index 00000000..5195172c --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/IndexInfoIterator.php @@ -0,0 +1,38 @@ + $order) { + if ( ! is_int($order) && ! is_float($order) && ! is_string($order)) { + throw InvalidArgumentException::invalidType(sprintf('order value for "%s" field within "key" option', $fieldName), $order, 'numeric or string'); + } + } + + if ( ! isset($index['ns'])) { + throw new InvalidArgumentException('Required "ns" option is missing from index specification'); + } + + if ( ! is_string($index['ns'])) { + throw InvalidArgumentException::invalidType('"ns" option', $index['ns'], 'string'); + } + + if ( ! isset($index['name'])) { + $index['name'] = \MongoDB\generate_index_name($index['key']); + } + + if ( ! is_string($index['name'])) { + throw InvalidArgumentException::invalidType('"name" option', $index['name'], 'string'); + } + + $this->index = $index; + } + + /** + * Return the index name. + * + * @param string + */ + public function __toString() + { + return $this->index['name']; + } + + /** + * Serialize the index information to BSON for index creation. + * + * @see \MongoDB\Collection::createIndexes() + * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @return array + */ + public function bsonSerialize() + { + return $this->index; + } +} diff --git a/vendor/mongodb/mongodb/src/Model/TypeMapArrayIterator.php b/vendor/mongodb/mongodb/src/Model/TypeMapArrayIterator.php new file mode 100644 index 00000000..76d2a584 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Model/TypeMapArrayIterator.php @@ -0,0 +1,59 @@ += 2.6). + * + * @internal + */ +class TypeMapArrayIterator extends ArrayIterator +{ + private $typeMap; + + /** + * Constructor. + * + * @param array $documents + * @param array $typeMap + */ + public function __construct(array $documents = [], array $typeMap) + { + parent::__construct($documents); + + $this->typeMap = $typeMap; + } + + /** + * Return the current element with the type map applied to it. + * + * @see http://php.net/arrayiterator.current + * @return array|object + */ + public function current() + { + return \MongoDB\apply_type_map_to_document(parent::current(), $this->typeMap); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Aggregate.php b/vendor/mongodb/mongodb/src/Operation/Aggregate.php new file mode 100644 index 00000000..9aaf76ce --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Aggregate.php @@ -0,0 +1,295 @@ += 2.6, this option allows users to turn off cursors if + * necessary to aid in mongod/mongos upgrades. + * + * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only + * applies when the $out stage is specified. + * + * This is not supported for server versions < 3.4 and will result in an + * exception at execution time if used. + * + * @param string $databaseName Database name + * @param string $collectionName Collection name + * @param array $pipeline List of pipeline operations + * @param array $options Command options + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function __construct($databaseName, $collectionName, array $pipeline, array $options = []) + { + $expectedIndex = 0; + + foreach ($pipeline as $i => $operation) { + if ($i !== $expectedIndex) { + throw new InvalidArgumentException(sprintf('$pipeline is not a list (unexpected index: "%s")', $i)); + } + + if ( ! is_array($operation) && ! is_object($operation)) { + throw InvalidArgumentException::invalidType(sprintf('$pipeline[%d]', $i), $operation, 'array or object'); + } + + $expectedIndex += 1; + } + + $options += [ + 'allowDiskUse' => false, + 'useCursor' => true, + ]; + + if ( ! is_bool($options['allowDiskUse'])) { + throw InvalidArgumentException::invalidType('"allowDiskUse" option', $options['allowDiskUse'], 'boolean'); + } + + if (isset($options['batchSize']) && ! is_integer($options['batchSize'])) { + throw InvalidArgumentException::invalidType('"batchSize" option', $options['batchSize'], 'integer'); + } + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { + throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + } + + if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { + throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if ( ! is_bool($options['useCursor'])) { + throw InvalidArgumentException::invalidType('"useCursor" option', $options['useCursor'], 'boolean'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['batchSize']) && ! $options['useCursor']) { + throw new InvalidArgumentException('"batchSize" option should not be used if "useCursor" is false'); + } + + if (isset($options['typeMap']) && ! $options['useCursor']) { + throw new InvalidArgumentException('"typeMap" option should not be used if "useCursor" is false'); + } + + if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { + unset($options['readConcern']); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->pipeline = $pipeline; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return Traversable + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if collation, read concern, or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + throw UnsupportedException::readConcernNotSupported(); + } + + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $isCursorSupported = \MongoDB\server_supports_feature($server, self::$wireVersionForCursor); + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + + $command = $this->createCommand($server, $isCursorSupported); + $cursor = $server->executeCommand($this->databaseName, $command, $readPreference); + + if ($isCursorSupported && $this->options['useCursor']) { + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return $cursor; + } + + $result = current($cursor->toArray()); + + if ( ! isset($result->result) || ! is_array($result->result)) { + throw new UnexpectedValueException('aggregate command did not return a "result" array'); + } + + if (isset($this->options['typeMap'])) { + return new TypeMapArrayIterator($result->result, $this->options['typeMap']); + } + + return new ArrayIterator($result->result); + } + + /** + * Create the aggregate command. + * + * @param Server $server + * @param boolean $isCursorSupported + * @return Command + */ + private function createCommand(Server $server, $isCursorSupported) + { + $cmd = [ + 'aggregate' => $this->collectionName, + 'pipeline' => $this->pipeline, + ]; + + // Servers < 2.6 do not support any command options + if ( ! $isCursorSupported) { + return new Command($cmd); + } + + $cmd['allowDiskUse'] = $this->options['allowDiskUse']; + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + if (isset($this->options['collation'])) { + $cmd['collation'] = (object) $this->options['collation']; + } + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + if (isset($this->options['readConcern'])) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + if ($this->options['useCursor']) { + $cmd['cursor'] = isset($this->options["batchSize"]) + ? ['batchSize' => $this->options["batchSize"]] + : new stdClass; + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/BulkWrite.php b/vendor/mongodb/mongodb/src/Operation/BulkWrite.php new file mode 100644 index 00000000..525c5d11 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/BulkWrite.php @@ -0,0 +1,329 @@ + [ $filter, $options ] ], + * [ 'deleteOne' => [ $filter, $options ] ], + * [ 'insertOne' => [ $document ] ], + * [ 'replaceOne' => [ $filter, $replacement, $options ] ], + * [ 'updateMany' => [ $filter, $update, $options ] ], + * [ 'updateOne' => [ $filter, $update, $options ] ], + * ] + * + * Arguments correspond to the respective Operation classes; however, the + * writeConcern option is specified for the top-level bulk write operation + * instead of each individual operation. + * + * Supported options for deleteMany and deleteOne operations: + * + * * collation (document): Collation specification. + * + * This is not supported for server versions < 3.4 and will result in an + * exception at execution time if used. + * + * Supported options for replaceOne, updateMany, and updateOne operations: + * + * * collation (document): Collation specification. + * + * This is not supported for server versions < 3.4 and will result in an + * exception at execution time if used. + * + * * upsert (boolean): When true, a new document is created if no document + * matches the query. The default is false. + * + * Supported options for the bulk write operation: + * + * * bypassDocumentValidation (boolean): If true, allows the write to + * circumvent document level validation. The default is false. + * + * For servers < 3.2, this option is ignored as document level validation + * is not available. + * + * * ordered (boolean): If true, when an insert fails, return without + * performing the remaining writes. If false, when a write fails, + * continue with the remaining writes, if any. The default is true. + * + * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. + * + * @param string $databaseName Database name + * @param string $collectionName Collection name + * @param array[] $operations List of write operations + * @param array $options Command options + * @throws InvalidArgumentException for parameter/option parsing errors + */ + public function __construct($databaseName, $collectionName, array $operations, array $options = []) + { + if (empty($operations)) { + throw new InvalidArgumentException('$operations is empty'); + } + + $expectedIndex = 0; + + foreach ($operations as $i => $operation) { + if ($i !== $expectedIndex) { + throw new InvalidArgumentException(sprintf('$operations is not a list (unexpected index: "%s")', $i)); + } + + if ( ! is_array($operation)) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]', $i), $operation, 'array'); + } + + if (count($operation) !== 1) { + throw new InvalidArgumentException(sprintf('Expected one element in $operation[%d], actually: %d', $i, count($operation))); + } + + $type = key($operation); + $args = current($operation); + + if ( ! isset($args[0]) && ! array_key_exists(0, $args)) { + throw new InvalidArgumentException(sprintf('Missing first argument for $operations[%d]["%s"]', $i, $type)); + } + + if ( ! is_array($args[0]) && ! is_object($args[0])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][0]', $i, $type), $args[0], 'array or object'); + } + + switch ($type) { + case self::INSERT_ONE: + break; + + case self::DELETE_MANY: + case self::DELETE_ONE: + if ( ! isset($args[1])) { + $args[1] = []; + } + + if ( ! is_array($args[1])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array'); + } + + $args[1]['limit'] = ($type === self::DELETE_ONE ? 1 : 0); + + if (isset($args[1]['collation'])) { + $this->isCollationUsed = true; + + if ( ! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation'], 'array or object'); + } + } + + $operations[$i][$type][1] = $args[1]; + + break; + + case self::REPLACE_ONE: + if ( ! isset($args[1]) && ! array_key_exists(1, $args)) { + throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type)); + } + + if ( ! is_array($args[1]) && ! is_object($args[1])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object'); + } + + if (\MongoDB\is_first_key_operator($args[1])) { + throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is an update operator', $i, $type)); + } + + if ( ! isset($args[2])) { + $args[2] = []; + } + + if ( ! is_array($args[2])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array'); + } + + $args[2]['multi'] = false; + $args[2] += ['upsert' => false]; + + if (isset($args[2]['collation'])) { + $this->isCollationUsed = true; + + if ( ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); + } + } + + if ( ! is_bool($args[2]['upsert'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean'); + } + + $operations[$i][$type][2] = $args[2]; + + break; + + case self::UPDATE_MANY: + case self::UPDATE_ONE: + if ( ! isset($args[1]) && ! array_key_exists(1, $args)) { + throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type)); + } + + if ( ! is_array($args[1]) && ! is_object($args[1])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object'); + } + + if ( ! \MongoDB\is_first_key_operator($args[1])) { + throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is not an update operator', $i, $type)); + } + + if ( ! isset($args[2])) { + $args[2] = []; + } + + if ( ! is_array($args[2])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]', $i, $type), $args[2], 'array'); + } + + $args[2]['multi'] = ($type === self::UPDATE_MANY); + $args[2] += ['upsert' => false]; + + if (isset($args[2]['collation'])) { + $this->isCollationUsed = true; + + if ( ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); + } + } + + if ( ! is_bool($args[2]['upsert'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["upsert"]', $i, $type), $args[2]['upsert'], 'boolean'); + } + + $operations[$i][$type][2] = $args[2]; + + break; + + default: + throw new InvalidArgumentException(sprintf('Unknown operation type "%s" in $operations[%d]', $type, $i)); + } + + $expectedIndex += 1; + } + + $options += ['ordered' => true]; + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if ( ! is_bool($options['ordered'])) { + throw InvalidArgumentException::invalidType('"ordered" option', $options['ordered'], 'boolean'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->operations = $operations; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return BulkWriteResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + $options = ['ordered' => $this->options['ordered']]; + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + $bulk = new Bulk($options); + $insertedIds = []; + + foreach ($this->operations as $i => $operation) { + $type = key($operation); + $args = current($operation); + + switch ($type) { + case self::DELETE_MANY: + case self::DELETE_ONE: + $bulk->delete($args[0], $args[1]); + break; + + case self::INSERT_ONE: + $insertedIds[$i] = $bulk->insert($args[0]); + break; + + case self::REPLACE_ONE: + case self::UPDATE_MANY: + case self::UPDATE_ONE: + $bulk->update($args[0], $args[1], $args[2]); + } + } + + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern); + + return new BulkWriteResult($writeResult, $insertedIds); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Count.php b/vendor/mongodb/mongodb/src/Operation/Count.php new file mode 100644 index 00000000..cb2180bd --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Count.php @@ -0,0 +1,191 @@ +isDefault()) { + unset($options['readConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->filter = $filter; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return integer + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + throw UnsupportedException::readConcernNotSupported(); + } + + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference); + $result = current($cursor->toArray()); + + // Older server versions may return a float + if ( ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { + throw new UnexpectedValueException('count command did not return a numeric "n" value'); + } + + return (integer) $result->n; + } + + /** + * Create the count command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['count' => $this->collectionName]; + + if ( ! empty($this->filter)) { + $cmd['query'] = (object) $this->filter; + } + + if (isset($this->options['collation'])) { + $cmd['collation'] = (object) $this->options['collation']; + } + + if (isset($this->options['hint'])) { + $cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint']; + } + + foreach (['limit', 'maxTimeMS', 'skip'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } + } + + if (isset($this->options['readConcern'])) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/CreateCollection.php b/vendor/mongodb/mongodb/src/Operation/CreateCollection.php new file mode 100644 index 00000000..7fe44df7 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/CreateCollection.php @@ -0,0 +1,224 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object Command result document + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand()); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create the create command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['create' => $this->collectionName]; + + foreach (['autoIndexId', 'capped', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } + } + + foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'validator'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = (object) $this->options[$option]; + } + } + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/CreateIndexes.php b/vendor/mongodb/mongodb/src/Operation/CreateIndexes.php new file mode 100644 index 00000000..b5083594 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/CreateIndexes.php @@ -0,0 +1,177 @@ + $index) { + if ($i !== $expectedIndex) { + throw new InvalidArgumentException(sprintf('$indexes is not a list (unexpected index: "%s")', $i)); + } + + if ( ! is_array($index)) { + throw InvalidArgumentException::invalidType(sprintf('$index[%d]', $i), $index, 'array'); + } + + if ( ! isset($index['ns'])) { + $index['ns'] = $databaseName . '.' . $collectionName; + } + + if (isset($index['collation'])) { + $this->isCollationUsed = true; + } + + $this->indexes[] = new IndexInput($index); + + $expectedIndex += 1; + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * For servers < 2.6, this will actually perform an insert operation on the + * database's "system.indexes" collection. + * + * @see Executable::execute() + * @param Server $server + * @return string[] The names of the created indexes + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if ($this->isCollationUsed && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + if (\MongoDB\server_supports_feature($server, self::$wireVersionForCommand)) { + $this->executeCommand($server); + } else { + $this->executeLegacy($server); + } + + return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes); + } + + /** + * Create one or more indexes for the collection using the createIndexes + * command. + * + * @param Server $server + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeCommand(Server $server) + { + $cmd = [ + 'createIndexes' => $this->collectionName, + 'indexes' => $this->indexes, + ]; + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + $server->executeCommand($this->databaseName, new Command($cmd)); + } + + /** + * Create one or more indexes for the collection by inserting into the + * "system.indexes" collection (MongoDB <2.6). + * + * @param Server $server + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeLegacy(Server $server) + { + $bulk = new Bulk(['ordered' => true]); + + foreach ($this->indexes as $index) { + $bulk->insert($index); + } + + $server->executeBulkWrite($this->databaseName . '.system.indexes', $bulk, new WriteConcern(1)); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DatabaseCommand.php b/vendor/mongodb/mongodb/src/Operation/DatabaseCommand.php new file mode 100644 index 00000000..967e1b97 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DatabaseCommand.php @@ -0,0 +1,95 @@ +databaseName = (string) $databaseName; + $this->command = ($command instanceof Command) ? $command : new Command($command); + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return Cursor + */ + public function execute(Server $server) + { + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + + $cursor = $server->executeCommand($this->databaseName, $this->command, $readPreference); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return $cursor; + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Delete.php b/vendor/mongodb/mongodb/src/Operation/Delete.php new file mode 100644 index 00000000..4f1afceb --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Delete.php @@ -0,0 +1,125 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->filter = $filter; + $this->limit = $limit; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return DeleteResult + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + $deleteOptions = ['limit' => $this->limit]; + + if (isset($this->options['collation'])) { + $deleteOptions['collation'] = (object) $this->options['collation']; + } + + $bulk = new Bulk(); + $bulk->delete($this->filter, $deleteOptions); + + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern); + + return new DeleteResult($writeResult); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DeleteMany.php b/vendor/mongodb/mongodb/src/Operation/DeleteMany.php new file mode 100644 index 00000000..f515ee3f --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DeleteMany.php @@ -0,0 +1,73 @@ +delete = new Delete($databaseName, $collectionName, $filter, 0, $options); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return DeleteResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->delete->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DeleteOne.php b/vendor/mongodb/mongodb/src/Operation/DeleteOne.php new file mode 100644 index 00000000..fb2d5268 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DeleteOne.php @@ -0,0 +1,73 @@ +delete = new Delete($databaseName, $collectionName, $filter, 1, $options); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return DeleteResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->delete->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Distinct.php b/vendor/mongodb/mongodb/src/Operation/Distinct.php new file mode 100644 index 00000000..04cf7dab --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Distinct.php @@ -0,0 +1,169 @@ +isDefault()) { + unset($options['readConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->fieldName = (string) $fieldName; + $this->filter = $filter; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return mixed[] + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + throw UnsupportedException::readConcernNotSupported(); + } + + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference); + $result = current($cursor->toArray()); + + if ( ! isset($result->values) || ! is_array($result->values)) { + throw new UnexpectedValueException('distinct command did not return a "values" array'); + } + + return $result->values; + } + + /** + * Create the distinct command. + * + * @return Command + */ + private function createCommand() + { + $cmd = [ + 'distinct' => $this->collectionName, + 'key' => $this->fieldName, + ]; + + if ( ! empty($this->filter)) { + $cmd['query'] = (object) $this->filter; + } + + if (isset($this->options['collation'])) { + $cmd['collation'] = (object) $this->options['collation']; + } + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + if (isset($this->options['readConcern'])) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DropCollection.php b/vendor/mongodb/mongodb/src/Operation/DropCollection.php new file mode 100644 index 00000000..6ea1e124 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DropCollection.php @@ -0,0 +1,132 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object Command result document + * @throws UnsupportedException if writeConcern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + try { + $cursor = $server->executeCommand($this->databaseName, $this->createCommand()); + } catch (DriverRuntimeException $e) { + /* The server may return an error if the collection does not exist. + * Check for an error message (unfortunately, there isn't a code) + * and NOP instead of throwing. + */ + if ($e->getMessage() === self::$errorMessageNamespaceNotFound) { + return (object) ['ok' => 0, 'errmsg' => self::$errorMessageNamespaceNotFound]; + } + + throw $e; + } + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create the drop command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['drop' => $this->collectionName]; + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DropDatabase.php b/vendor/mongodb/mongodb/src/Operation/DropDatabase.php new file mode 100644 index 00000000..d35408c6 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DropDatabase.php @@ -0,0 +1,116 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object Command result document + * @throws UnsupportedException if writeConcern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand()); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create the dropDatabase command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['dropDatabase' => 1]; + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/DropIndexes.php b/vendor/mongodb/mongodb/src/Operation/DropIndexes.php new file mode 100644 index 00000000..dc7dbb86 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/DropIndexes.php @@ -0,0 +1,130 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->indexName = $indexName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object Command result document + * @throws UnsupportedException if writeConcern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand()); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create the dropIndexes command. + * + * @return Command + */ + private function createCommand() + { + $cmd = [ + 'dropIndexes' => $this->collectionName, + 'index' => $this->indexName, + ]; + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Executable.php b/vendor/mongodb/mongodb/src/Operation/Executable.php new file mode 100644 index 00000000..eee1b5fd --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Executable.php @@ -0,0 +1,39 @@ +isDefault()) { + unset($options['readConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->filter = $filter; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return Cursor + * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + throw UnsupportedException::readConcernNotSupported(); + } + + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + + $cursor = $server->executeQuery($this->databaseName . '.' . $this->collectionName, $this->createQuery(), $readPreference); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return $cursor; + } + + /** + * Create the find query. + * + * @return Query + */ + private function createQuery() + { + $options = []; + + if (isset($this->options['cursorType'])) { + if ($this->options['cursorType'] === self::TAILABLE) { + $options['tailable'] = true; + } + if ($this->options['cursorType'] === self::TAILABLE_AWAIT) { + $options['tailable'] = true; + $options['awaitData'] = true; + } + } + + foreach (['allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } + } + + foreach (['collation', 'max', 'min'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = (object) $this->options[$option]; + } + } + + $modifiers = empty($this->options['modifiers']) ? [] : (array) $this->options['modifiers']; + + if ( ! empty($modifiers)) { + $options['modifiers'] = $modifiers; + } + + return new Query($this->filter, $options); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/FindAndModify.php b/vendor/mongodb/mongodb/src/Operation/FindAndModify.php new file mode 100644 index 00000000..7535c3fe --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/FindAndModify.php @@ -0,0 +1,255 @@ + false, + 'remove' => false, + 'upsert' => false, + ]; + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { + throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + } + + if (isset($options['fields']) && ! is_array($options['fields']) && ! is_object($options['fields'])) { + throw InvalidArgumentException::invalidType('"fields" option', $options['fields'], 'array or object'); + } + + if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { + throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); + } + + if ( ! is_bool($options['new'])) { + throw InvalidArgumentException::invalidType('"new" option', $options['new'], 'boolean'); + } + + if (isset($options['query']) && ! is_array($options['query']) && ! is_object($options['query'])) { + throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object'); + } + + if ( ! is_bool($options['remove'])) { + throw InvalidArgumentException::invalidType('"remove" option', $options['remove'], 'boolean'); + } + + if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) { + throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if (isset($options['update']) && ! is_array($options['update']) && ! is_object($options['update'])) { + throw InvalidArgumentException::invalidType('"update" option', $options['update'], 'array or object'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if ( ! is_bool($options['upsert'])) { + throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); + } + + if ( ! (isset($options['update']) xor $options['remove'])) { + throw new InvalidArgumentException('The "remove" option must be true or an "update" document must be specified, but not both'); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object|null + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server)); + $result = current($cursor->toArray()); + + if ( ! isset($result->value)) { + return null; + } + + /* Prior to 3.0, findAndModify returns an empty document instead of null + * when an upsert is performed and the pre-modified document was + * requested. + */ + if ($this->options['upsert'] && ! $this->options['new'] && + isset($result->lastErrorObject->updatedExisting) && + ! $result->lastErrorObject->updatedExisting) { + + return null; + } + + if ( ! is_object($result->value)) { + throw new UnexpectedValueException('findAndModify command did not return a "value" document'); + } + + if (isset($this->options['typeMap'])) { + return \MongoDB\apply_type_map_to_document($result->value, $this->options['typeMap']); + } + + return $result->value; + } + + /** + * Create the findAndModify command. + * + * @param Server $server + * @return Command + */ + private function createCommand(Server $server) + { + $cmd = ['findAndModify' => $this->collectionName]; + + if ($this->options['remove']) { + $cmd['remove'] = true; + } else { + $cmd['new'] = $this->options['new']; + $cmd['upsert'] = $this->options['upsert']; + } + + foreach (['collation', 'fields', 'query', 'sort', 'update'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = (object) $this->options[$option]; + } + } + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + if (isset($this->options['writeConcern'])) { + $cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); + } + + return new Command($cmd); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/FindOne.php b/vendor/mongodb/mongodb/src/Operation/FindOne.php new file mode 100644 index 00000000..025857a3 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/FindOne.php @@ -0,0 +1,128 @@ +find = new Find( + $databaseName, + $collectionName, + $filter, + ['limit' => 1] + $options + ); + + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object|null + * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + $cursor = $this->find->execute($server); + $document = current($cursor->toArray()); + + return ($document === false) ? null : $document; + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/FindOneAndDelete.php b/vendor/mongodb/mongodb/src/Operation/FindOneAndDelete.php new file mode 100644 index 00000000..87595658 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/FindOneAndDelete.php @@ -0,0 +1,104 @@ +findAndModify = new FindAndModify( + $databaseName, + $collectionName, + ['query' => $filter, 'remove' => true] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object|null + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->findAndModify->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/FindOneAndReplace.php b/vendor/mongodb/mongodb/src/Operation/FindOneAndReplace.php new file mode 100644 index 00000000..79542758 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/FindOneAndReplace.php @@ -0,0 +1,147 @@ + self::RETURN_DOCUMENT_BEFORE, + 'upsert' => false, + ]; + + if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { + throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + } + + if ( ! is_integer($options['returnDocument'])) { + throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); + } + + if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && + $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) { + throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']); + } + + if (isset($options['projection'])) { + $options['fields'] = $options['projection']; + } + + $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + + unset($options['projection'], $options['returnDocument']); + + $this->findAndModify = new FindAndModify( + $databaseName, + $collectionName, + ['query' => $filter, 'update' => $replacement] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object|null + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->findAndModify->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/FindOneAndUpdate.php b/vendor/mongodb/mongodb/src/Operation/FindOneAndUpdate.php new file mode 100644 index 00000000..4d188f25 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/FindOneAndUpdate.php @@ -0,0 +1,147 @@ + self::RETURN_DOCUMENT_BEFORE, + 'upsert' => false, + ]; + + if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { + throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + } + + if ( ! is_integer($options['returnDocument'])) { + throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); + } + + if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && + $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) { + throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']); + } + + if (isset($options['projection'])) { + $options['fields'] = $options['projection']; + } + + $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + + unset($options['projection'], $options['returnDocument']); + + $this->findAndModify = new FindAndModify( + $databaseName, + $collectionName, + ['query' => $filter, 'update' => $update] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object|null + * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->findAndModify->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/InsertMany.php b/vendor/mongodb/mongodb/src/Operation/InsertMany.php new file mode 100644 index 00000000..be33d511 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/InsertMany.php @@ -0,0 +1,138 @@ + $document) { + if ($i !== $expectedIndex) { + throw new InvalidArgumentException(sprintf('$documents is not a list (unexpected index: "%s")', $i)); + } + + if ( ! is_array($document) && ! is_object($document)) { + throw InvalidArgumentException::invalidType(sprintf('$documents[%d]', $i), $document, 'array or object'); + } + + $expectedIndex += 1; + } + + $options += ['ordered' => true]; + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if ( ! is_bool($options['ordered'])) { + throw InvalidArgumentException::invalidType('"ordered" option', $options['ordered'], 'boolean'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->documents = $documents; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return InsertManyResult + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + $options = ['ordered' => $this->options['ordered']]; + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + $bulk = new Bulk($options); + $insertedIds = []; + + foreach ($this->documents as $i => $document) { + $insertedIds[$i] = $bulk->insert($document); + } + + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern); + + return new InsertManyResult($writeResult, $insertedIds); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/InsertOne.php b/vendor/mongodb/mongodb/src/Operation/InsertOne.php new file mode 100644 index 00000000..c11fd3a1 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/InsertOne.php @@ -0,0 +1,110 @@ +isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->document = $document; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return InsertOneResult + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + $options = []; + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + $bulk = new Bulk($options); + $insertedId = $bulk->insert($this->document); + + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern); + + return new InsertOneResult($writeResult, $insertedId); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/ListCollections.php b/vendor/mongodb/mongodb/src/Operation/ListCollections.php new file mode 100644 index 00000000..cfbed632 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/ListCollections.php @@ -0,0 +1,144 @@ +databaseName = (string) $databaseName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return CollectionInfoIterator + * @throws InvalidArgumentException if filter.name is not a string for legacy execution + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return \MongoDB\server_supports_feature($server, self::$wireVersionForCommand) + ? $this->executeCommand($server) + : $this->executeLegacy($server); + } + + /** + * Returns information for all collections in this database using the + * listCollections command. + * + * @param Server $server + * @return CollectionInfoCommandIterator + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeCommand(Server $server) + { + $cmd = ['listCollections' => 1]; + + if ( ! empty($this->options['filter'])) { + $cmd['filter'] = (object) $this->options['filter']; + } + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + $cursor = $server->executeCommand($this->databaseName, new Command($cmd)); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + + return new CollectionInfoCommandIterator(new CachingIterator($cursor)); + } + + /** + * Returns information for all collections in this database by querying the + * "system.namespaces" collection (MongoDB <3.0). + * + * @param Server $server + * @return CollectionInfoLegacyIterator + * @throws InvalidArgumentException if filter.name is not a string + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeLegacy(Server $server) + { + $filter = empty($this->options['filter']) ? [] : (array) $this->options['filter']; + + if (array_key_exists('name', $filter)) { + if ( ! is_string($filter['name'])) { + throw InvalidArgumentException::invalidType('filter name for MongoDB <3.0', $filter['name'], 'string'); + } + + $filter['name'] = $this->databaseName . '.' . $filter['name']; + } + + $options = isset($this->options['maxTimeMS']) + ? ['modifiers' => ['$maxTimeMS' => $this->options['maxTimeMS']]] + : []; + + $cursor = $server->executeQuery($this->databaseName . '.system.namespaces', new Query($filter, $options)); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + + return new CollectionInfoLegacyIterator(new CachingIterator($cursor)); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/ListDatabases.php b/vendor/mongodb/mongodb/src/Operation/ListDatabases.php new file mode 100644 index 00000000..b9f17a76 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/ListDatabases.php @@ -0,0 +1,92 @@ +options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return DatabaseInfoIterator + * @throws UnexpectedValueException if the command response was malformed + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + $cmd = ['listDatabases' => 1]; + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + $cursor = $server->executeCommand('admin', new Command($cmd)); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + $result = current($cursor->toArray()); + + if ( ! isset($result['databases']) || ! is_array($result['databases'])) { + throw new UnexpectedValueException('listDatabases command did not return a "databases" array'); + } + + /* Return an Iterator instead of an array in case listDatabases is + * eventually changed to return a command cursor, like the collection + * and index enumeration commands. This makes the "totalSize" command + * field inaccessible, but users can manually invoke the command if they + * need that value. + */ + return new DatabaseInfoLegacyIterator($result['databases']); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/ListIndexes.php b/vendor/mongodb/mongodb/src/Operation/ListIndexes.php new file mode 100644 index 00000000..e91422d7 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/ListIndexes.php @@ -0,0 +1,142 @@ +databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return IndexInfoIterator + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return \MongoDB\server_supports_feature($server, self::$wireVersionForCommand) + ? $this->executeCommand($server) + : $this->executeLegacy($server); + } + + /** + * Returns information for all indexes for this collection using the + * listIndexes command. + * + * @param Server $server + * @return IndexInfoIteratorIterator + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeCommand(Server $server) + { + $cmd = ['listIndexes' => $this->collectionName]; + + if (isset($this->options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + } + + try { + $cursor = $server->executeCommand($this->databaseName, new Command($cmd)); + } catch (DriverRuntimeException $e) { + /* The server may return an error if the collection does not exist. + * Check for possible error codes (see: SERVER-20463) and return an + * empty iterator instead of throwing. + */ + if ($e->getCode() === self::$errorCodeNamespaceNotFound || $e->getCode() === self::$errorCodeDatabaseNotFound) { + return new IndexInfoIteratorIterator(new EmptyIterator); + } + + throw $e; + } + + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + + return new IndexInfoIteratorIterator(new CachingIterator($cursor)); + } + + /** + * Returns information for all indexes for this collection by querying the + * "system.indexes" collection (MongoDB <3.0). + * + * @param Server $server + * @return IndexInfoIteratorIterator + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + private function executeLegacy(Server $server) + { + $filter = ['ns' => $this->databaseName . '.' . $this->collectionName]; + + $options = isset($this->options['maxTimeMS']) + ? ['modifiers' => ['$maxTimeMS' => $this->options['maxTimeMS']]] + : []; + + $cursor = $server->executeQuery($this->databaseName . '.system.indexes', new Query($filter, $options)); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + + return new IndexInfoIteratorIterator(new CachingIterator($cursor)); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/MapReduce.php b/vendor/mongodb/mongodb/src/Operation/MapReduce.php new file mode 100644 index 00000000..deffe224 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/MapReduce.php @@ -0,0 +1,326 @@ + false, + 'verbose' => true, + ]; + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { + throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + } + + if (isset($options['finalize']) && ! $options['finalize'] instanceof Javascript) { + throw InvalidArgumentException::invalidType('"finalize" option', $options['finalize'], 'MongoDB\Driver\Javascript'); + } + + if (isset($options['jsMode']) && ! is_bool($options['jsMode'])) { + throw InvalidArgumentException::invalidType('"jsMode" option', $options['jsMode'], 'boolean'); + } + + if (isset($options['limit']) && ! is_integer($options['limit'])) { + throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer'); + } + + if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { + throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); + } + + if (isset($options['query']) && ! is_array($options['query']) && ! is_object($options['query'])) { + throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object'); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); + } + + if (isset($options['scope']) && ! is_array($options['scope']) && ! is_object($options['scope'])) { + throw InvalidArgumentException::invalidType('"scope" option', $options['scope'], 'array or object'); + } + + if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) { + throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object'); + } + + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { + throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); + } + + if (isset($options['verbose']) && ! is_bool($options['verbose'])) { + throw InvalidArgumentException::invalidType('"verbose" option', $options['verbose'], 'boolean'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { + unset($options['readConcern']); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->map = $map; + $this->reduce = $reduce; + $this->out = $out; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return MapReduceResult + * @throws UnexpectedValueException if the command response was malformed + * @throws UnsupportedException if collation, read concern, or write concern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + if (isset($this->options['readConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + throw UnsupportedException::readConcernNotSupported(); + } + + if (isset($this->options['writeConcern']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; + $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $readPreference); + $result = current($cursor->toArray()); + + $getIterator = $this->createGetIteratorCallable($result, $server); + + return new MapReduceResult($getIterator, $result); + } + + /** + * Create the mapReduce command. + * + * @param Server $server + * @return Command + */ + private function createCommand(Server $server) + { + $cmd = [ + 'mapReduce' => $this->collectionName, + 'map' => $this->map, + 'reduce' => $this->reduce, + 'out' => $this->out, + ]; + + foreach (['finalize', 'jsMode', 'limit', 'maxTimeMS', 'readConcern', 'verbose', 'writeConcern'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } + } + + foreach (['collation', 'query', 'scope', 'sort'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = (object) $this->options[$option]; + } + } + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + return new Command($cmd); + } + + /** + * Creates a callable for MapReduceResult::getIterator(). + * + * @param stdClass $result + * @param Server $server + * @return callable + * @throws UnexpectedValueException if the command response was malformed + */ + private function createGetIteratorCallable(stdClass $result, Server $server) + { + // Inline results can be wrapped with an ArrayIterator + if (isset($result->results) && is_array($result->results)) { + $results = $result->results; + + return function() use ($results) { + if (isset($this->options['typeMap'])) { + return new TypeMapArrayIterator($results, $this->options['typeMap']); + } + + return new ArrayIterator($results); + }; + } + + if (isset($result->result) && (is_string($result->result) || is_object($result->result))) { + $options = isset($this->options['typeMap']) ? ['typeMap' => $this->options['typeMap']] : []; + + $find = is_string($result->result) + ? new Find($this->databaseName, $result->result, [], $options) + : new Find($result->result->db, $result->result->collection, [], $options); + + return function() use ($find, $server) { + return $find->execute($server); + }; + } + + throw new UnexpectedValueException('mapReduce command did not return inline results or an output collection'); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/ReplaceOne.php b/vendor/mongodb/mongodb/src/Operation/ReplaceOne.php new file mode 100644 index 00000000..3f6a477e --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/ReplaceOne.php @@ -0,0 +1,97 @@ +update = new Update( + $databaseName, + $collectionName, + $filter, + $replacement, + ['multi' => false] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return UpdateResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->update->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/Update.php b/vendor/mongodb/mongodb/src/Operation/Update.php new file mode 100644 index 00000000..f0c1419b --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/Update.php @@ -0,0 +1,169 @@ + false, + 'upsert' => false, + ]; + + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { + throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); + } + + if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { + throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + } + + if ( ! is_bool($options['multi'])) { + throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean'); + } + + if ($options['multi'] && ! \MongoDB\is_first_key_operator($update)) { + throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document'); + } + + if ( ! is_bool($options['upsert'])) { + throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); + } + + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { + throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern'); + } + + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { + unset($options['writeConcern']); + } + + $this->databaseName = (string) $databaseName; + $this->collectionName = (string) $collectionName; + $this->filter = $filter; + $this->update = $update; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return UpdateResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['collation']) && ! \MongoDB\server_supports_feature($server, self::$wireVersionForCollation)) { + throw UnsupportedException::collationNotSupported(); + } + + $updateOptions = [ + 'multi' => $this->options['multi'], + 'upsert' => $this->options['upsert'], + ]; + + if (isset($this->options['collation'])) { + $updateOptions['collation'] = (object) $this->options['collation']; + } + + $bulkOptions = []; + + if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) { + $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + $bulk = new Bulk($bulkOptions); + $bulk->update($this->filter, $this->update, $updateOptions); + + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern); + + return new UpdateResult($writeResult); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/UpdateMany.php b/vendor/mongodb/mongodb/src/Operation/UpdateMany.php new file mode 100644 index 00000000..e6a934d6 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/UpdateMany.php @@ -0,0 +1,97 @@ +update = new Update( + $databaseName, + $collectionName, + $filter, + $update, + ['multi' => true] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return UpdateResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->update->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/Operation/UpdateOne.php b/vendor/mongodb/mongodb/src/Operation/UpdateOne.php new file mode 100644 index 00000000..401139c2 --- /dev/null +++ b/vendor/mongodb/mongodb/src/Operation/UpdateOne.php @@ -0,0 +1,97 @@ +update = new Update( + $databaseName, + $collectionName, + $filter, + $update, + ['multi' => false] + $options + ); + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return UpdateResult + * @throws UnsupportedException if collation is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + return $this->update->execute($server); + } +} diff --git a/vendor/mongodb/mongodb/src/UpdateResult.php b/vendor/mongodb/mongodb/src/UpdateResult.php new file mode 100644 index 00000000..a19173f9 --- /dev/null +++ b/vendor/mongodb/mongodb/src/UpdateResult.php @@ -0,0 +1,140 @@ +writeResult = $writeResult; + $this->isAcknowledged = $writeResult->isAcknowledged(); + } + + /** + * Return the number of documents that were matched by the filter. + * + * This method should only be called if the write was acknowledged. + * + * @see UpdateResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getMatchedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getMatchedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the number of documents that were modified. + * + * This value is undefined (i.e. null) if the write executed as a legacy + * operation instead of command. + * + * This method should only be called if the write was acknowledged. + * + * @see UpdateResult::isAcknowledged() + * @return integer|null + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getModifiedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getModifiedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the number of documents that were upserted. + * + * This method should only be called if the write was acknowledged. + * + * @see UpdateResult::isAcknowledged() + * @return integer + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getUpsertedCount() + { + if ($this->isAcknowledged) { + return $this->writeResult->getUpsertedCount(); + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return the ID of the document inserted by an upsert operation. + * + * If the document had an ID prior to upserting (i.e. the server did not + * need to generate an ID), this will contain its "_id". Any + * server-generated ID will be a MongoDB\BSON\ObjectId instance. + * + * This value is undefined (i.e. null) if an upsert did not take place. + * + * This method should only be called if the write was acknowledged. + * + * @see UpdateResult::isAcknowledged() + * @return mixed|null + * @throws BadMethodCallException is the write result is unacknowledged + */ + public function getUpsertedId() + { + if ($this->isAcknowledged) { + foreach ($this->writeResult->getUpsertedIds() as $id) { + return $id; + } + + return null; + } + + throw BadMethodCallException::unacknowledgedWriteResultAccess(__METHOD__); + } + + /** + * Return whether this update was acknowledged by the server. + * + * If the update was not acknowledged, other fields from the WriteResult + * (e.g. matchedCount) will be undefined and their getter methods should not + * be invoked. + * + * @return boolean + */ + public function isAcknowledged() + { + return $this->isAcknowledged; + } +} diff --git a/vendor/mongodb/mongodb/src/functions.php b/vendor/mongodb/mongodb/src/functions.php new file mode 100644 index 00000000..4fc305ec --- /dev/null +++ b/vendor/mongodb/mongodb/src/functions.php @@ -0,0 +1,207 @@ +bsonSerialize(); + } + + if (is_object($document)) { + $document = get_object_vars($document); + } + + if ( ! is_array($document)) { + throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + } + + $name = ''; + + foreach ($document as $field => $type) { + $name .= ($name != '' ? '_' : '') . $field . '_' . $type; + } + + return $name; +} + +/** + * Return whether the first key in the document starts with a "$" character. + * + * This is used for differentiating update and replacement documents. + * + * @internal + * @param array|object $document Update or replacement document + * @return boolean + * @throws InvalidArgumentException + */ +function is_first_key_operator($document) +{ + if ($document instanceof Serializable) { + $document = $document->bsonSerialize(); + } + + if (is_object($document)) { + $document = get_object_vars($document); + } + + if ( ! is_array($document)) { + throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + } + + reset($document); + $firstKey = (string) key($document); + + return (isset($firstKey[0]) && $firstKey[0] === '$'); +} + +/** + * Return whether the aggregation pipeline ends with an $out operator. + * + * This is used for determining whether the aggregation pipeline msut be + * executed against a primary server. + * + * @internal + * @param array $pipeline List of pipeline operations + * @return boolean + */ +function is_last_pipeline_operator_out(array $pipeline) +{ + $lastOp = end($pipeline); + + if ($lastOp === false) { + return false; + } + + $lastOp = (array) $lastOp; + + return key($lastOp) === '$out'; +} + +/** + * Converts a ReadConcern instance to a stdClass for use in a BSON document. + * + * @internal + * @see https://jira.mongodb.org/browse/PHPC-498 + * @param ReadConcern $readConcern Read concern + * @return stdClass + */ +function read_concern_as_document(ReadConcern $readConcern) +{ + $document = []; + + if ($readConcern->getLevel() !== null) { + $document['level'] = $readConcern->getLevel(); + } + + return (object) $document; +} + +/** + * Return whether the server supports a particular feature. + * + * @internal + * @param Server $server Server to check + * @param integer $feature Feature constant (i.e. wire protocol version) + * @return boolean + */ +function server_supports_feature(Server $server, $feature) +{ + $info = $server->getInfo(); + $maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0; + $minWireVersion = isset($info['minWireVersion']) ? (integer) $info['minWireVersion'] : 0; + + return ($minWireVersion <= $feature && $maxWireVersion >= $feature); +} + +function is_string_array($input) { + if (!is_array($input)){ + return false; + } + foreach($input as $item) { + if (!is_string($item)) { + return false; + } + } + return true; +} + +/** + * Converts a WriteConcern instance to a stdClass for use in a BSON document. + * + * @internal + * @see https://jira.mongodb.org/browse/PHPC-498 + * @param WriteConcern $writeConcern Write concern + * @return stdClass + */ +function write_concern_as_document(WriteConcern $writeConcern) +{ + $document = []; + + if ($writeConcern->getW() !== null) { + $document['w'] = $writeConcern->getW(); + } + + if ($writeConcern->getJournal() !== null) { + $document['j'] = $writeConcern->getJournal(); + } + + if ($writeConcern->getWtimeout() !== 0) { + $document['wtimeout'] = $writeConcern->getWtimeout(); + } + + return (object) $document; +} diff --git a/vendor/mongodb/mongodb/tests/ClientFunctionalTest.php b/vendor/mongodb/mongodb/tests/ClientFunctionalTest.php new file mode 100644 index 00000000..e197a601 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/ClientFunctionalTest.php @@ -0,0 +1,100 @@ +client = new Client($this->getUri()); + $this->client->dropDatabase($this->getDatabaseName()); + } + + public function testGetManager() + { + $this->assertInstanceOf('MongoDB\Driver\Manager', $this->client->getManager()); + } + + public function testDropDatabase() + { + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['x' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->client->dropDatabase($this->getDatabaseName()); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionCount($this->getNamespace(), 0); + } + + public function testListDatabases() + { + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['x' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $databases = $this->client->listDatabases(); + + $this->assertInstanceOf('MongoDB\Model\DatabaseInfoIterator', $databases); + + foreach ($databases as $database) { + $this->assertInstanceOf('MongoDB\Model\DatabaseInfo', $database); + } + + $that = $this; + $this->assertDatabaseExists($this->getDatabaseName(), function(DatabaseInfo $info) use ($that) { + $that->assertFalse($info->isEmpty()); + $that->assertGreaterThan(0, $info->getSizeOnDisk()); + }); + } + + /** + * Asserts that a database with the given name exists on the server. + * + * An optional $callback may be provided, which should take a DatabaseInfo + * argument as its first and only parameter. If a DatabaseInfo matching + * the given name is found, it will be passed to the callback, which may + * perform additional assertions. + * + * @param string $databaseName + * @param callable $callback + */ + private function assertDatabaseExists($databaseName, $callback = null) + { + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $databases = $this->client->listDatabases(); + + $foundDatabase = null; + + foreach ($databases as $database) { + if ($database->getName() === $databaseName) { + $foundDatabase = $database; + break; + } + } + + $this->assertNotNull($foundDatabase, sprintf('Database %s does not exist on the server', $databaseName)); + + if ($callback !== null) { + call_user_func($callback, $foundDatabase); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/ClientTest.php b/vendor/mongodb/mongodb/tests/ClientTest.php new file mode 100644 index 00000000..07a68bbf --- /dev/null +++ b/vendor/mongodb/mongodb/tests/ClientTest.php @@ -0,0 +1,163 @@ +assertEquals('mongodb://127.0.0.1/', (string) $client); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorDriverOptions + */ + public function testConstructorDriverOptionTypeChecks(array $driverOptions) + { + new Client($this->getUri(), [], $driverOptions); + } + + public function provideInvalidConstructorDriverOptions() + { + $options = []; + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + return $options; + } + + public function testToString() + { + $client = new Client($this->getUri()); + + $this->assertSame($this->getUri(), (string) $client); + } + + public function testSelectCollectionInheritsOptions() + { + $this->markTestSkipped('Depends on https://jira.mongodb.org/browse/PHPC-523'); + + $uriOptions = [ + 'readConcernLevel' => ReadConcern::LOCAL, + 'readPreference' => 'secondaryPreferred', + 'w' => WriteConcern::MAJORITY, + ]; + + $driverOptions = [ + 'typeMap' => ['root' => 'array'], + ]; + + $client = new Client($this->getUri(), $uriOptions, $driverOptions); + $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName()); + $debug = $collection->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectCollectionPassesOptions() + { + $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $client = new Client($this->getUri()); + $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName(), $collectionOptions); + $debug = $collection->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testGetSelectsDatabaseAndInheritsOptions() + { + $uriOptions = ['w' => WriteConcern::MAJORITY]; + + $client = new Client($this->getUri(), $uriOptions); + $database = $client->{$this->getDatabaseName()}; + $debug = $database->__debugInfo(); + + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectDatabaseInheritsOptions() + { + $this->markTestSkipped('Depends on https://jira.mongodb.org/browse/PHPC-523'); + + $uriOptions = [ + 'readConcernLevel' => ReadConcern::LOCAL, + 'readPreference' => 'secondaryPreferred', + 'w' => WriteConcern::MAJORITY, + ]; + + $driverOptions = [ + 'typeMap' => ['root' => 'array'], + ]; + + $client = new Client($this->getUri(), $uriOptions, $driverOptions); + $database = $client->selectDatabase($this->getDatabaseName()); + $debug = $database->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectDatabasePassesOptions() + { + $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $client = new Client($this->getUri()); + $database = $client->selectDatabase($this->getDatabaseName(), $databaseOptions); + $debug = $database->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Collection/CollectionFunctionalTest.php b/vendor/mongodb/mongodb/tests/Collection/CollectionFunctionalTest.php new file mode 100644 index 00000000..c6c7cd74 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/CollectionFunctionalTest.php @@ -0,0 +1,227 @@ +manager, $databaseName, $this->getCollectionName()); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDatabaseAndCollectionNames + */ + public function testConstructorCollectionNameArgument($collectionName) + { + // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) + new Collection($this->manager, $this->getDatabaseName(), $collectionName); + } + + public function provideInvalidDatabaseAndCollectionNames() + { + return [ + [null], + [''], + ]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + public function testGetManager() + { + $this->assertSame($this->manager, $this->collection->getManager()); + } + + public function testToString() + { + $this->assertEquals($this->getNamespace(), (string) $this->collection); + } + + public function getGetCollectionName() + { + $this->assertEquals($this->getCollectionName(), $this->collection->getCollectionName()); + } + + public function getGetDatabaseName() + { + $this->assertEquals($this->getDatabaseName(), $this->collection->getDatabaseName()); + } + + public function testGetNamespace() + { + $this->assertEquals($this->getNamespace(), $this->collection->getNamespace()); + } + + public function testDrop() + { + $writeResult = $this->collection->insertOne(['x' => 1]); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->collection->drop(); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionCount($this->getNamespace(), 0); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @todo Move this to a unit test once Manager can be mocked + */ + public function testDropIndexShouldNotAllowWildcardCharacter() + { + $this->collection->dropIndex('*'); + } + + public function testFindOne() + { + $this->createFixtures(5); + + $filter = ['_id' => ['$lt' => 5]]; + $options = [ + 'skip' => 1, + 'sort' => ['x' => -1], + ]; + + $expected = ['_id' => 3, 'x' => 33]; + + $this->assertSameDocument($expected, $this->collection->findOne($filter, $options)); + } + + public function testWithOptionsInheritsOptions() + { + $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $collectionOptions); + $clone = $collection->withOptions(); + $debug = $clone->__debugInfo(); + + $this->assertSame($this->manager, $debug['manager']); + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertSame($this->getCollectionName(), $debug['collectionName']); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testWithOptionsPassesOptions() + { + $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $clone = $this->collection->withOptions($collectionOptions); + $debug = $clone->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testMapReduce() + { + $this->createFixtures(3); + + $map = new Javascript('function() { emit(1, this.x); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = ['inline' => 1]; + + $result = $this->collection->mapReduce($map, $reduce, $out); + + $this->assertInstanceOf('MongoDB\MapReduceResult', $result); + $expected = [ + [ '_id' => 1.0, 'value' => 66.0 ], + ]; + + $this->assertSameDocuments($expected, $result); + + $this->assertGreaterThanOrEqual(0, $result->getExecutionTimeMS()); + $this->assertNotEmpty($result->getCounts()); + $this->assertNotEmpty($result->getTiming()); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (integer) ($i . $i), + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Collection/CrudSpecFunctionalTest.php b/vendor/mongodb/mongodb/tests/Collection/CrudSpecFunctionalTest.php new file mode 100644 index 00000000..0461851d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/CrudSpecFunctionalTest.php @@ -0,0 +1,353 @@ +expectedCollection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName() . '.expected'); + $this->expectedCollection->drop(); + } + + /** + * @dataProvider provideSpecificationTests + */ + public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion) + { + $this->setName(str_replace(' ', '_', $test['description'])); + + if (isset($minServerVersion) || isset($maxServerVersion)) { + $this->checkServerVersion($minServerVersion, $maxServerVersion); + } + + $expectedData = isset($test['outcome']['collection']['data']) ? $test['outcome']['collection']['data'] : null; + $this->initializeData($initialData, $expectedData); + + $result = $this->executeOperation($test['operation']); + $this->executeOutcome($test['operation'], $test['outcome'], $result); + } + + public function provideSpecificationTests() + { + $testArgs = []; + + foreach (glob(__DIR__ . '/spec-tests/*/*.json') as $filename) { + $json = json_decode(file_get_contents($filename), true); + + $minServerVersion = isset($json['minServerVersion']) ? $json['minServerVersion'] : null; + $maxServerVersion = isset($json['maxServerVersion']) ? $json['maxServerVersion'] : null; + + foreach ($json['tests'] as $test) { + $testArgs[] = [$json['data'], $test, $minServerVersion, $maxServerVersion]; + } + } + + return $testArgs; + } + + /** + * Assert that the collections contain equivalent documents. + * + * @param Collection $expectedCollection + * @param Collection $actualCollection + */ + private function assertEquivalentCollections($expectedCollection, $actualCollection) + { + $mi = new MultipleIterator; + $mi->attachIterator(new IteratorIterator($expectedCollection->find())); + $mi->attachIterator(new IteratorIterator($actualCollection->find())); + + foreach ($mi as $documents) { + list($expectedDocument, $actualDocument) = $documents; + $this->assertSameDocument($expectedDocument, $actualDocument); + } + } + + /** + * Checks that the server version is within the allowed bounds (if any). + * + * @param string|null $minServerVersion + * @param string|null $maxServerVersion + * @throws \PHPUnit_Framework_SkippedTestError + */ + private function checkServerVersion($minServerVersion, $maxServerVersion) + { + $serverVersion = $this->getServerVersion(); + + if (isset($minServerVersion) && version_compare($serverVersion, $minServerVersion, '<')) { + $this->markTestSkipped(sprintf('Server version "%s" < minServerVersion "%s"', $serverVersion, $minServerVersion)); + } + + if (isset($maxServerVersion) && version_compare($serverVersion, $maxServerVersion, '>=')) { + $this->markTestSkipped(sprintf('Server version "%s" >= maxServerVersion "%s"', $serverVersion, $maxServerVersion)); + } + } + + /** + * Executes an "operation" block. + * + * @param array $operation + * @return mixed + * @throws LogicException if the operation is unsupported + */ + private function executeOperation(array $operation) + { + switch ($operation['name']) { + case 'aggregate': + return $this->collection->aggregate( + $operation['arguments']['pipeline'], + array_diff_key($operation['arguments'], ['pipeline' => 1]) + ); + + case 'count': + case 'find': + return $this->collection->{$operation['name']}( + isset($operation['arguments']['filter']) ? $operation['arguments']['filter'] : [], + array_diff_key($operation['arguments'], ['filter' => 1]) + ); + + case 'deleteMany': + case 'deleteOne': + case 'findOneAndDelete': + return $this->collection->{$operation['name']}( + $operation['arguments']['filter'], + array_diff_key($operation['arguments'], ['filter' => 1]) + ); + + case 'distinct': + return $this->collection->distinct( + $operation['arguments']['fieldName'], + isset($operation['arguments']['filter']) ? $operation['arguments']['filter'] : [], + array_diff_key($operation['arguments'], ['fieldName' => 1, 'filter' => 1]) + ); + + case 'findOneAndReplace': + $operation['arguments'] = $this->prepareFindAndModifyArguments($operation['arguments']); + // Fall through + + case 'replaceOne': + return $this->collection->{$operation['name']}( + $operation['arguments']['filter'], + $operation['arguments']['replacement'], + array_diff_key($operation['arguments'], ['filter' => 1, 'replacement' => 1]) + ); + + case 'findOneAndUpdate': + $operation['arguments'] = $this->prepareFindAndModifyArguments($operation['arguments']); + // Fall through + + case 'updateMany': + case 'updateOne': + return $this->collection->{$operation['name']}( + $operation['arguments']['filter'], + $operation['arguments']['update'], + array_diff_key($operation['arguments'], ['filter' => 1, 'update' => 1]) + ); + + case 'insertMany': + return $this->collection->insertMany( + $operation['arguments']['documents'], + array_diff_key($operation['arguments'], ['documents' => 1]) + ); + + case 'insertOne': + return $this->collection->insertOne( + $operation['arguments']['document'], + array_diff_key($operation['arguments'], ['document' => 1]) + ); + + default: + throw new LogicException('Unsupported operation: ' . $operation['name']); + } + } + + /** + * Executes an "outcome" block. + * + * @param array $operation + * @param array $outcome + * @param mixed $actualResult + * @return mixed + * @throws LogicException if the operation is unsupported + */ + private function executeOutcome(array $operation, array $outcome, $actualResult) + { + if (array_key_exists('result', $outcome)) { + $this->executeAssertResult($operation, $outcome['result'], $actualResult); + } + + if (isset($outcome['collection'])) { + $actualCollection = isset($outcome['collection']['name']) + ? new Collection($this->manager, $this->getDatabaseName(), $outcome['collection']['name']) + : $this->collection; + + $this->assertEquivalentCollections($this->expectedCollection, $actualCollection); + } + } + + /** + * Executes the "result" section of an "outcome" block. + * + * @param array $operation + * @param mixed $expectedResult + * @param mixed $actualResult + * @throws LogicException if the operation is unsupported + */ + private function executeAssertResult(array $operation, $expectedResult, $actualResult) + { + switch ($operation['name']) { + case 'aggregate': + /* Returning a cursor for the $out collection is optional per + * the CRUD specification and is not implemented in the library + * since we have no concept of lazy cursors. We will not assert + * the result here; however, assertEquivalentCollections() will + * assert the output collection's contents later. + */ + if ( ! \MongoDB\is_last_pipeline_operator_out($operation['arguments']['pipeline'])) { + $this->assertSameDocuments($expectedResult, $actualResult); + } + break; + + case 'count': + $this->assertSame($expectedResult, $actualResult); + break; + + case 'distinct': + $this->assertSameDocument( + ['values' => $expectedResult], + ['values' => $actualResult] + ); + break; + + case 'find': + $this->assertSameDocuments($expectedResult, $actualResult); + break; + + case 'deleteMany': + case 'deleteOne': + $this->assertInstanceOf('MongoDB\DeleteResult', $actualResult); + + if (isset($expectedResult['deletedCount'])) { + $this->assertSame($expectedResult['deletedCount'], $actualResult->getDeletedCount()); + } + break; + + case 'findOneAndDelete': + case 'findOneAndReplace': + case 'findOneAndUpdate': + $this->assertSameDocument( + ['result' => $expectedResult], + ['result' => $actualResult] + ); + break; + + case 'insertMany': + $this->assertInstanceOf('MongoDB\InsertManyResult', $actualResult); + + if (isset($expectedResult['insertedCount'])) { + $this->assertSame($expectedResult['insertedCount'], $actualResult->getInsertedCount()); + } + + if (isset($expectedResult['insertedIds'])) { + $this->assertSameDocument( + ['insertedIds' => $expectedResult['insertedIds']], + ['insertedIds' => $actualResult->getInsertedIds()] + ); + } + break; + + case 'insertOne': + $this->assertInstanceOf('MongoDB\InsertOneResult', $actualResult); + + if (isset($expectedResult['insertedCount'])) { + $this->assertSame($expectedResult['insertedCount'], $actualResult->getInsertedCount()); + } + + if (isset($expectedResult['insertedId'])) { + $this->assertSameDocument( + ['insertedId' => $expectedResult['insertedId']], + ['insertedId' => $actualResult->getInsertedId()] + ); + } + break; + + case 'replaceOne': + case 'updateMany': + case 'updateOne': + $this->assertInstanceOf('MongoDB\UpdateResult', $actualResult); + + if (isset($expectedResult['matchedCount'])) { + $this->assertSame($expectedResult['matchedCount'], $actualResult->getMatchedCount()); + } + + if (isset($expectedResult['modifiedCount'])) { + $this->assertSame($expectedResult['modifiedCount'], $actualResult->getModifiedCount()); + } + + if (isset($expectedResult['upsertedCount'])) { + $this->assertSame($expectedResult['upsertedCount'], $actualResult->getUpsertedCount()); + } + + if (array_key_exists('upsertedId', $expectedResult)) { + $this->assertSameDocument( + ['upsertedId' => $expectedResult['upsertedId']], + ['upsertedId' => $actualResult->getUpsertedId()] + ); + } + break; + + default: + throw new LogicException('Unsupported operation: ' . $operationName); + } + } + + /** + * Initializes data in the test collections. + * + * @param array $initialData + * @param array $expectedData + */ + private function initializeData(array $initialData, array $expectedData = null) + { + if ( ! empty($initialData)) { + $this->collection->insertMany($initialData); + } + + if ( ! empty($expectedData)) { + $this->expectedCollection->insertMany($expectedData); + } + } + + /** + * Prepares arguments for findOneAndReplace and findOneAndUpdate operations. + * + * @param array $arguments + * @return array + */ + private function prepareFindAndModifyArguments($arguments) + { + if (isset($arguments['returnDocument'])) { + $arguments['returnDocument'] = ('after' === strtolower($arguments['returnDocument'])) + ? FindOneAndReplace::RETURN_DOCUMENT_AFTER + : FindOneAndReplace::RETURN_DOCUMENT_BEFORE; + } + + return $arguments; + } +} diff --git a/vendor/mongodb/mongodb/tests/Collection/FunctionalTestCase.php b/vendor/mongodb/mongodb/tests/Collection/FunctionalTestCase.php new file mode 100644 index 00000000..66c94b81 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/FunctionalTestCase.php @@ -0,0 +1,34 @@ +collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName()); + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + public function tearDown() + { + if ($this->hasFailed()) { + return; + } + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-collation.json new file mode 100644 index 00000000..903a5834 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-collation.json @@ -0,0 +1,38 @@ +{ + "data": [ + { + "_id": 1, + "x": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "Aggregate with collation", + "operation": { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "x": "PING" + } + } + ], + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": "ping" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-out.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-out.json new file mode 100644 index 00000000..cbc8ca47 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate-out.json @@ -0,0 +1,70 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "Aggregate with $out", + "operation": { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "collection": { + "name": "other_test_collection", + "data": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate.json new file mode 100644 index 00000000..479fcb9b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/aggregate.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Aggregate with multiple stages", + "operation": { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count-collation.json new file mode 100644 index 00000000..46212094 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count-collation.json @@ -0,0 +1,29 @@ +{ + "data": [ + { + "_id": 1, + "x": "PING" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "Count with collation", + "operation": { + "name": "count", + "arguments": { + "filter": { + "x": "ping" + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": 1 + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count.json new file mode 100644 index 00000000..85c17e11 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/count.json @@ -0,0 +1,60 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Count without a filter", + "operation": { + "name": "count", + "arguments": { + "filter": {} + } + }, + "outcome": { + "result": 3 + } + }, + { + "description": "Count with a filter", + "operation": { + "name": "count", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": 2 + } + }, + { + "description": "Count with skip and limit", + "operation": { + "name": "count", + "arguments": { + "filter": {}, + "skip": 1, + "limit": 3 + } + }, + "outcome": { + "result": 2 + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct-collation.json new file mode 100644 index 00000000..4d688cc3 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct-collation.json @@ -0,0 +1,33 @@ +{ + "data": [ + { + "_id": 1, + "string": "PING" + }, + { + "_id": 2, + "string": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "Distinct with a collation", + "operation": { + "name": "distinct", + "arguments": { + "fieldName": "string", + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": [ + "PING" + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct.json new file mode 100644 index 00000000..408d8a48 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/distinct.json @@ -0,0 +1,55 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Distinct without a filter", + "operation": { + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": {} + } + }, + "outcome": { + "result": [ + 11, + 22, + 33 + ] + } + }, + { + "description": "Distinct with a filter", + "operation": { + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": [ + 22, + 33 + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find-collation.json new file mode 100644 index 00000000..b2d268ae --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find-collation.json @@ -0,0 +1,34 @@ +{ + "data": [ + { + "_id": 1, + "x": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "Find with a collation", + "operation": { + "name": "find", + "arguments": { + "filter": { + "x": "PING" + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": "ping" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find.json new file mode 100644 index 00000000..d92081d5 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/read/find.json @@ -0,0 +1,105 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ], + "tests": [ + { + "description": "Find with filter", + "operation": { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": 11 + } + ] + } + }, + { + "description": "Find with filter, sort, skip, and limit", + "operation": { + "name": "find", + "arguments": { + "filter": { + "_id": { + "$gt": 2 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2, + "limit": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 5, + "x": 55 + } + ] + } + }, + { + "description": "Find with limit, sort, and batchsize", + "operation": { + "name": "find", + "arguments": { + "filter": {}, + "sort": { + "_id": 1 + }, + "limit": 4, + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany-collation.json new file mode 100644 index 00000000..593ad685 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany-collation.json @@ -0,0 +1,47 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + }, + { + "_id": 3, + "x": "pINg" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "DeleteMany when many documents match with collation", + "operation": { + "name": "deleteMany", + "arguments": { + "filter": { + "x": "PING" + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "deletedCount": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany.json new file mode 100644 index 00000000..885ebd20 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteMany.json @@ -0,0 +1,76 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "DeleteMany when many documents match", + "operation": { + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": { + "deletedCount": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } + }, + { + "description": "DeleteMany when no document matches", + "operation": { + "name": "deleteMany", + "arguments": { + "filter": { + "_id": 4 + } + } + }, + "outcome": { + "result": { + "deletedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne-collation.json new file mode 100644 index 00000000..9f22b112 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne-collation.json @@ -0,0 +1,51 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + }, + { + "_id": 3, + "x": "pINg" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "DeleteOne when many documents matches with collation", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "x": "PING" + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": "pINg" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne.json new file mode 100644 index 00000000..50226bdd --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/deleteOne.json @@ -0,0 +1,96 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "DeleteOne when many documents match", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + } + } + }, + { + "description": "DeleteOne when one document matches", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 2 + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "DeleteOne when no documents match", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 4 + } + } + }, + "outcome": { + "result": { + "deletedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete-collation.json new file mode 100644 index 00000000..e848d754 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete-collation.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + }, + { + "_id": 3, + "x": "pINg" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "FindOneAndDelete when one document matches with collation", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 2, + "x": "PING" + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "x": "ping" + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": "pINg" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete.json new file mode 100644 index 00000000..2bfcc32c --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndDelete.json @@ -0,0 +1,127 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndDelete when many documents match", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndDelete when one document matches", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 2 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndDelete when no documents match", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 4 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-collation.json new file mode 100644 index 00000000..5227b0f8 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-collation.json @@ -0,0 +1,58 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "FindOneAndReplace when one document matches with collation returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "x": "PING" + }, + "replacement": { + "x": "pong" + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "x": "pong" + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "pong" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert.json new file mode 100644 index 00000000..e13eb9c2 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert.json @@ -0,0 +1,201 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "FindOneAndReplace when no documents match without id specified with upsert returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match without id specified with upsert returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 44 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match with id specified with upsert returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match with id specified with upsert returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 44 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert_pre_2.6.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert_pre_2.6.json new file mode 100644 index 00000000..613c664b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace-upsert_pre_2.6.json @@ -0,0 +1,161 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "maxServerVersion": "2.4.99", + "tests": [ + { + "description": "FindOneAndReplace when no documents match without id specified with upsert returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "upsert": true + } + }, + "outcome": { + "result": null + } + }, + { + "description": "FindOneAndReplace when no documents match without id specified with upsert returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 44 + } + } + }, + { + "description": "FindOneAndReplace when no documents match with id specified with upsert returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match with id specified with upsert returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 44 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace.json new file mode 100644 index 00000000..f8eb5ebb --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndReplace.json @@ -0,0 +1,273 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndReplace when many documents match returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when many documents match returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 32 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when one document matches returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when one document matches returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 32 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json new file mode 100644 index 00000000..172149ac --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json @@ -0,0 +1,67 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + }, + { + "_id": 3, + "x": "pINg" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "FindOneAndUpdate when many documents match with collation returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "x": "PING" + }, + "update": { + "$set": { + "x": "pong" + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "_id": 1 + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "x": "ping" + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "pong" + }, + { + "_id": 3, + "x": "pINg" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate.json new file mode 100644 index 00000000..c257b740 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/findOneAndUpdate.json @@ -0,0 +1,379 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndUpdate when many documents match returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when many documents match returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 23 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when one document matches returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when one document matches returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 23 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match with upsert returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match with upsert returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertMany.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertMany.json new file mode 100644 index 00000000..f604ef75 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertMany.json @@ -0,0 +1,52 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + } + ], + "tests": [ + { + "description": "InsertMany with non-existing documents", + "operation": { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + }, + "outcome": { + "result": { + "insertedIds": [ + 2, + 3 + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertOne.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertOne.json new file mode 100644 index 00000000..83597fca --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/insertOne.json @@ -0,0 +1,39 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + } + ], + "tests": [ + { + "description": "InsertOne with a non-existing document", + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "x": 22 + } + } + }, + "outcome": { + "result": { + "insertedId": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-collation.json new file mode 100644 index 00000000..c2a08c9b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-collation.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "ReplaceOne when one document matches with collation", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "x": "PING" + }, + "replacement": { + "_id": 2, + "x": "pong" + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "pong" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-pre_2.6.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-pre_2.6.json new file mode 100644 index 00000000..363bad50 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-pre_2.6.json @@ -0,0 +1,179 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "maxServerVersion": "2.4.99", + "tests": [ + { + "description": "ReplaceOne when many documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "upsertedCount": 0 + } + } + }, + { + "description": "ReplaceOne when one document matches", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 111 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne when no documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match without an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 1 + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match with an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-upsert.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-upsert.json new file mode 100644 index 00000000..f3040dcc --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne-upsert.json @@ -0,0 +1,104 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "ReplaceOne with upsert when no documents match without an id specified", + "operation": { + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 1 + }, + "upsert": true + }, + "name": "replaceOne" + }, + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + }, + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match with an id specified", + "operation": { + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + }, + "upsert": true + }, + "name": "replaceOne" + }, + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + }, + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + } + } + } + ] +} diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne.json new file mode 100644 index 00000000..580e3b93 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/replaceOne.json @@ -0,0 +1,205 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "ReplaceOne when many documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + }, + { + "description": "ReplaceOne when one document matches", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 111 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne when no documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match without an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match with an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-collation.json new file mode 100644 index 00000000..d88ce60f --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-collation.json @@ -0,0 +1,62 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + }, + { + "_id": 3, + "x": "pINg" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "UpdateMany when many documents match with collation", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "x": "ping" + }, + "update": { + "$set": { + "x": "pong" + } + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "pong" + }, + { + "_id": 3, + "x": "pong" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-pre_2.6.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-pre_2.6.json new file mode 100644 index 00000000..89e8a5c9 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany-pre_2.6.json @@ -0,0 +1,179 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "maxServerVersion": "2.4.99", + "tests": [ + { + "description": "UpdateMany when many documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 2, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 34 + } + ] + } + } + }, + { + "description": "UpdateMany when one document matches", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany with upsert when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany.json new file mode 100644 index 00000000..533e3f30 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateMany.json @@ -0,0 +1,183 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "UpdateMany when many documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 34 + } + ] + } + } + }, + { + "description": "UpdateMany when one document matches", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany with upsert when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-collation.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-collation.json new file mode 100644 index 00000000..8e45ff32 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-collation.json @@ -0,0 +1,54 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "ping" + } + ], + "minServerVersion": "3.4", + "tests": [ + { + "description": "UpdateOne when one document matches with collation", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "x": "PING" + }, + "update": { + "$set": { + "x": "pong" + } + }, + "collation": { + "locale": "en_US", + "strength": 2 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": "pong" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-pre_2.6.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-pre_2.6.json new file mode 100644 index 00000000..de15c616 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne-pre_2.6.json @@ -0,0 +1,163 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "maxServerVersion": "2.4.99", + "tests": [ + { + "description": "UpdateOne when many documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "upsertedCount": 0 + } + } + }, + { + "description": "UpdateOne when one document matches", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne with upsert when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne.json b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne.json new file mode 100644 index 00000000..1a51dff1 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Collection/spec-tests/write/updateOne.json @@ -0,0 +1,167 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "minServerVersion": "2.6", + "tests": [ + { + "description": "UpdateOne when many documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + }, + { + "description": "UpdateOne when one document matches", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne with upsert when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 1, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/CommandObserver.php b/vendor/mongodb/mongodb/tests/CommandObserver.php new file mode 100644 index 00000000..9c38b153 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/CommandObserver.php @@ -0,0 +1,44 @@ +commands = []; + + \MongoDB\Driver\Monitoring\addSubscriber($this); + + call_user_func($execution); + + \MongoDB\Driver\Monitoring\removeSubscriber($this); + + foreach ($this->commands as $command) { + call_user_func($commandCallback, $command); + } + } + + public function commandStarted(CommandStartedEvent $event) + { + $this->commands[] = $event->getCommand(); + } + + public function commandSucceeded(CommandSucceededEvent $event) + { + } + + public function commandFailed(CommandFailedEvent $event) + { + } +} diff --git a/vendor/mongodb/mongodb/tests/Database/CollectionManagementFunctionalTest.php b/vendor/mongodb/mongodb/tests/Database/CollectionManagementFunctionalTest.php new file mode 100644 index 00000000..893c46c9 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Database/CollectionManagementFunctionalTest.php @@ -0,0 +1,117 @@ +getCollectionName() . '.basic'; + + $commandResult = $this->database->createCollection($basicCollectionName); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionExists($basicCollectionName, function(CollectionInfo $info) use ($that) { + $that->assertFalse($info->isCapped()); + }); + + $cappedCollectionName = $this->getCollectionName() . '.capped'; + $cappedCollectionOptions = [ + 'capped' => true, + 'max' => 100, + 'size' => 1048576, + ]; + + $commandResult = $this->database->createCollection($cappedCollectionName, $cappedCollectionOptions); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionExists($cappedCollectionName, function(CollectionInfo $info) use ($that) { + $that->assertTrue($info->isCapped()); + $that->assertEquals(100, $info->getCappedMax()); + $that->assertEquals(1048576, $info->getCappedSize()); + }); + } + + public function testDropCollection() + { + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['x' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->database->dropCollection($this->getCollectionName()); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionCount($this->getNamespace(), 0); + } + + public function testListCollections() + { + $commandResult = $this->database->createCollection($this->getCollectionName()); + $this->assertCommandSucceeded($commandResult); + + $collections = $this->database->listCollections(); + $this->assertInstanceOf('MongoDB\Model\CollectionInfoIterator', $collections); + + foreach ($collections as $collection) { + $this->assertInstanceOf('MongoDB\Model\CollectionInfo', $collection); + } + } + + public function testListCollectionsWithFilter() + { + $commandResult = $this->database->createCollection($this->getCollectionName()); + $this->assertCommandSucceeded($commandResult); + + $collectionName = $this->getCollectionName(); + $options = ['filter' => ['name' => $collectionName]]; + + $collections = $this->database->listCollections($options); + $this->assertInstanceOf('MongoDB\Model\CollectionInfoIterator', $collections); + + foreach ($collections as $collection) { + $this->assertInstanceOf('MongoDB\Model\CollectionInfo', $collection); + $this->assertEquals($collectionName, $collection->getName()); + } + } + + /** + * Asserts that a collection with the given name exists in the database. + * + * An optional $callback may be provided, which should take a CollectionInfo + * argument as its first and only parameter. If a CollectionInfo matching + * the given name is found, it will be passed to the callback, which may + * perform additional assertions. + * + * @param callable $callback + */ + private function assertCollectionExists($collectionName, $callback = null) + { + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $collections = $this->database->listCollections(); + + $foundCollection = null; + + foreach ($collections as $collection) { + if ($collection->getName() === $collectionName) { + $foundCollection = $collection; + break; + } + } + + $this->assertNotNull($foundCollection, sprintf('Found %s collection in the database', $collectionName)); + + if ($callback !== null) { + call_user_func($callback, $foundCollection); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/Database/DatabaseFunctionalTest.php b/vendor/mongodb/mongodb/tests/Database/DatabaseFunctionalTest.php new file mode 100644 index 00000000..78237d02 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Database/DatabaseFunctionalTest.php @@ -0,0 +1,297 @@ +manager, $databaseName); + } + + public function provideInvalidDatabaseNames() + { + return [ + [null], + [''], + ]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Database($this->manager, $this->getDatabaseName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + public function testGetManager() + { + $this->assertSame($this->manager, $this->database->getManager()); + } + + public function testToString() + { + $this->assertEquals($this->getDatabaseName(), (string) $this->database); + } + + public function getGetDatabaseName() + { + $this->assertEquals($this->getDatabaseName(), $this->database->getDatabaseName()); + } + + public function testCommand() + { + $command = ['isMaster' => 1]; + $options = [ + 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), + ]; + + $cursor = $this->database->command($command, $options); + + $this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor); + $commandResult = current($cursor->toArray()); + + $this->assertCommandSucceeded($commandResult); + $this->assertTrue(isset($commandResult->ismaster)); + $this->assertTrue($commandResult->ismaster); + } + + public function testCommandAppliesTypeMapToCursor() + { + $command = ['isMaster' => 1]; + $options = [ + 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), + 'typeMap' => ['root' => 'array'], + ]; + + $cursor = $this->database->command($command, $options); + + $this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor); + $commandResult = current($cursor->toArray()); + + $this->assertCommandSucceeded($commandResult); + $this->assertInternalType('array', $commandResult); + $this->assertTrue(isset($commandResult['ismaster'])); + $this->assertTrue($commandResult['ismaster']); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testCommandCommandArgumentTypeCheck($command) + { + $this->database->command($command); + } + + public function testDrop() + { + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['x' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->database->drop(); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionCount($this->getNamespace(), 0); + } + + public function testGetSelectsCollectionAndInheritsOptions() + { + $databaseOptions = ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; + + $database = new Database($this->manager, $this->getDatabaseName(), $databaseOptions); + $collection = $database->{$this->getCollectionName()}; + $debug = $collection->__debugInfo(); + + $this->assertSame($this->manager, $debug['manager']); + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertSame($this->getCollectionName(), $debug['collectionName']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectCollectionInheritsOptions() + { + $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $database = new Database($this->manager, $this->getDatabaseName(), $databaseOptions); + $collection = $database->selectCollection($this->getCollectionName()); + $debug = $collection->__debugInfo(); + + $this->assertSame($this->manager, $debug['manager']); + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertSame($this->getCollectionName(), $debug['collectionName']); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectCollectionPassesOptions() + { + $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $collection = $this->database->selectCollection($this->getCollectionName(), $collectionOptions); + $debug = $collection->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectGridFSBucketInheritsOptions() + { + $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $database = new Database($this->manager, $this->getDatabaseName(), $databaseOptions); + $bucket = $database->selectGridFSBucket(); + $debug = $bucket->__debugInfo(); + + $this->assertSame($this->manager, $debug['manager']); + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertSame('fs', $debug['bucketName']); + $this->assertSame(261120, $debug['chunkSizeBytes']); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testSelectGridFSBucketPassesOptions() + { + $bucketOptions = [ + 'bucketName' => 'custom_fs', + 'chunkSizeBytes' => 8192, + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $database = new Database($this->manager, $this->getDatabaseName()); + $bucket = $database->selectGridFSBucket($bucketOptions); + $debug = $bucket->__debugInfo(); + + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertSame('custom_fs', $debug['bucketName']); + $this->assertSame(8192, $debug['chunkSizeBytes']); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testWithOptionsInheritsOptions() + { + $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $database = new Database($this->manager, $this->getDatabaseName(), $databaseOptions); + $clone = $database->withOptions(); + $debug = $clone->__debugInfo(); + + $this->assertSame($this->manager, $debug['manager']); + $this->assertSame($this->getDatabaseName(), $debug['databaseName']); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } + + public function testWithOptionsPassesOptions() + { + $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'typeMap' => ['root' => 'array'], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ]; + + $clone = $this->database->withOptions($databaseOptions); + $debug = $clone->__debugInfo(); + + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); + $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); + $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); + $this->assertInternalType('array', $debug['typeMap']); + $this->assertSame(['root' => 'array'], $debug['typeMap']); + $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); + $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Database/FunctionalTestCase.php b/vendor/mongodb/mongodb/tests/Database/FunctionalTestCase.php new file mode 100644 index 00000000..2b84bbbd --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Database/FunctionalTestCase.php @@ -0,0 +1,22 @@ +database = new Database($this->manager, $this->getDatabaseName()); + $this->database->drop(); + } +} diff --git a/vendor/mongodb/mongodb/tests/DocumentationExamplesTest.php b/vendor/mongodb/mongodb/tests/DocumentationExamplesTest.php new file mode 100644 index 00000000..9a7502fc --- /dev/null +++ b/vendor/mongodb/mongodb/tests/DocumentationExamplesTest.php @@ -0,0 +1,947 @@ +getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + public function tearDown() + { + if ($this->hasFailed()) { + return; + } + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + public function testExample_1_2() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 1 + $insertOneResult = $db->inventory->insertOne([ + 'item' => 'canvas', + 'qty' => 100, + 'tags' => ['cotton'], + 'size' => ['h' => 28, 'w' => 35.5, 'uom' => 'cm'], + ]); + // End Example 1 + + $this->assertSame(1, $insertOneResult->getInsertedCount()); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $insertOneResult->getInsertedId()); + $this->assertInventoryCount(1); + + // Start Example 2 + $cursor = $db->inventory->find(['item' => 'canvas']); + // End Example 2 + + $this->assertCursorCount(1, $cursor); + } + + public function testExample_3() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 3 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'qty' => 25, + 'tags' => ['blank', 'red'], + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + ], + [ + 'item' => 'mat', + 'qty' => 85, + 'tags' => ['gray'], + 'size' => ['h' => 27.9, 'w' => 35.5, 'uom' => 'cm'], + ], + [ + 'item' => 'mousepad', + 'qty' => 25, + 'tags' => ['gel', 'blue'], + 'size' => ['h' => 19, 'w' => 22.85, 'uom' => 'cm'], + ], + ]); + // End Example 3 + + $this->assertSame(3, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(3); + } + + public function testExample_6_13() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 6 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'qty' => 25, + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'notebook', + 'qty' => 50, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'A', + ], + [ + 'item' => 'paper', + 'qty' => 100, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'D', + ], + [ + 'item' => 'planner', + 'qty' => 75, + 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], + 'status' => 'D', + ], + [ + 'item' => 'postcard', + 'qty' => 45, + 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], + 'status' => 'A', + ], + ]); + // End Example 6 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 7 + $cursor = $db->inventory->find([]); + // End Example 7 + + $this->assertCursorCount(5, $cursor); + + // Start Example 8 + $cursor = $db->inventory->find(); + // End Example 8 + + $this->assertCursorCount(5, $cursor); + + // Start Example 9 + $cursor = $db->inventory->find(['status' => 'D']); + // End Example 9 + + $this->assertCursorCount(2, $cursor); + + // Start Example 10 + $cursor = $db->inventory->find(['status' => ['$in' => ['A', 'D']]]); + // End Example 10 + + $this->assertCursorCount(5, $cursor); + + // Start Example 11 + $cursor = $db->inventory->find([ + 'status' => 'A', + 'qty' => ['$lt' => 30], + ]); + // End Example 11 + + $this->assertCursorCount(1, $cursor); + + // Start Example 12 + $cursor = $db->inventory->find([ + '$or' => [ + ['status' => 'A'], + ['qty' => ['$lt' => 30]], + ], + ]); + // End Example 12 + + $this->assertCursorCount(3, $cursor); + + // Start Example 13 + $cursor = $db->inventory->find([ + 'status' => 'A', + '$or' => [ + ['qty' => ['$lt' => 30]], + // Alternatively: ['item' => new \MongoDB\BSON\Regex('^p')] + ['item' => ['$regex' => '^p']], + ], + ]); + // End Example 13 + + $this->assertCursorCount(2, $cursor); + } + + public function testExample_14_19() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 14 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'qty' => 25, + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'notebook', + 'qty' => 50, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'A', + ], + [ + 'item' => 'paper', + 'qty' => 100, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'D', + ], + [ + 'item' => 'planner', + 'qty' => 75, + 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], + 'status' => 'D', + ], + [ + 'item' => 'postcard', + 'qty' => 45, + 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], + 'status' => 'A', + ], + ]); + // End Example 14 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 15 + $cursor = $db->inventory->find(['size' => ['h' => 14, 'w' => 21, 'uom' => 'cm']]); + // End Example 15 + + $this->assertCursorCount(1, $cursor); + + // Start Example 16 + $cursor = $db->inventory->find(['size' => ['w' => 21, 'h' => 14, 'uom' => 'cm']]); + // End Example 16 + + $this->assertCursorCount(0, $cursor); + + // Start Example 17 + $cursor = $db->inventory->find(['size.uom' => 'in']); + // End Example 17 + + $this->assertCursorCount(2, $cursor); + + // Start Example 18 + $cursor = $db->inventory->find(['size.h' => ['$lt' => 15]]); + // End Example 18 + + $this->assertCursorCount(4, $cursor); + + // Start Example 19 + $cursor = $db->inventory->find([ + 'size.h' => ['$lt' => 15], + 'size.uom' => 'in', + 'status' => 'D', + ]); + // End Example 19 + + $this->assertCursorCount(1, $cursor); + } + + public function testExample_20_28() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 20 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'qty' => 25, + 'tags' => ['blank', 'red'], + 'dim_cm' => [14, 21], + ], + [ + 'item' => 'notebook', + 'qty' => 50, + 'tags' => ['red', 'blank'], + 'dim_cm' => [14, 21], + ], + [ + 'item' => 'paper', + 'qty' => 100, + 'tags' => ['red', 'blank', 'plain'], + 'dim_cm' => [14, 21], + ], + [ + 'item' => 'planner', + 'qty' => 75, + 'tags' => ['blank', 'red'], + 'dim_cm' => [22.85, 30], + ], + [ + 'item' => 'postcard', + 'qty' => 45, + 'tags' => ['blue'], + 'dim_cm' => [10, 15.25], + ], + ]); + // End Example 20 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 21 + $cursor = $db->inventory->find(['tags' => ['red', 'blank']]); + // End Example 21 + + $this->assertCursorCount(1, $cursor); + + // Start Example 22 + $cursor = $db->inventory->find(['tags' => ['$all' => ['red', 'blank']]]); + // End Example 22 + + $this->assertCursorCount(4, $cursor); + + // Start Example 23 + $cursor = $db->inventory->find(['tags' => 'red']); + // End Example 23 + + $this->assertCursorCount(4, $cursor); + + // Start Example 24 + $cursor = $db->inventory->find(['dim_cm' => ['$gt' => 25]]); + // End Example 24 + + $this->assertCursorCount(1, $cursor); + + // Start Example 25 + $cursor = $db->inventory->find([ + 'dim_cm' => [ + '$gt' => 15, + '$lt' => 20, + ], + ]); + // End Example 25 + + $this->assertCursorCount(4, $cursor); + + // Start Example 26 + $cursor = $db->inventory->find([ + 'dim_cm' => [ + '$elemMatch' => [ + '$gt' => 22, + '$lt' => 30, + ], + ], + ]); + // End Example 26 + + $this->assertCursorCount(1, $cursor); + + // Start Example 27 + $cursor = $db->inventory->find(['dim_cm.1' => ['$gt' => 25]]); + // End Example 27 + + $this->assertCursorCount(1, $cursor); + + // Start Example 28 + $cursor = $db->inventory->find(['tags' => ['$size' => 3]]); + // End Example 28 + + $this->assertCursorCount(1, $cursor); + } + + public function testExample_29_37() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 29 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'instock' => [ + ['warehouse' => 'A', 'qty' => 5], + ['warehouse' => 'C', 'qty' => 15], + ], + ], + [ + 'item' => 'notebook', + 'instock' => [ + ['warehouse' => 'C', 'qty' => 5], + ], + ], + [ + 'item' => 'paper', + 'instock' => [ + ['warehouse' => 'A', 'qty' => 60], + ['warehouse' => 'B', 'qty' => 15], + ], + ], + [ + 'item' => 'planner', + 'instock' => [ + ['warehouse' => 'A', 'qty' => 40], + ['warehouse' => 'B', 'qty' => 5], + ], + ], + [ + 'item' => 'postcard', + 'instock' => [ + ['warehouse' => 'B', 'qty' => 15], + ['warehouse' => 'C', 'qty' => 35], + ], + ], + ]); + // End Example 29 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 30 + $cursor = $db->inventory->find(['instock' => ['warehouse' => 'A', 'qty' => 5]]); + // End Example 30 + + $this->assertCursorCount(1, $cursor); + + // Start Example 31 + $cursor = $db->inventory->find(['instock' => ['qty' => 5, 'warehouse' => 'A']]); + // End Example 31 + + $this->assertCursorCount(0, $cursor); + + // Start Example 32 + $cursor = $db->inventory->find(['instock.0.qty' => ['$lte' => 20]]); + // End Example 32 + + $this->assertCursorCount(3, $cursor); + + // Start Example 33 + $cursor = $db->inventory->find(['instock.qty' => ['$lte' => 20]]); + // End Example 33 + + $this->assertCursorCount(5, $cursor); + + // Start Example 34 + $cursor = $db->inventory->find(['instock' => ['$elemMatch' => ['qty' => 5, 'warehouse' => 'A']]]); + // End Example 34 + + $this->assertCursorCount(1, $cursor); + + // Start Example 35 + $cursor = $db->inventory->find(['instock' => ['$elemMatch' => ['qty' => ['$gt' => 10, '$lte' => 20]]]]); + // End Example 35 + + $this->assertCursorCount(3, $cursor); + + // Start Example 36 + $cursor = $db->inventory->find(['instock.qty' => ['$gt' => 10, '$lte' => 20]]); + // End Example 36 + + $this->assertCursorCount(4, $cursor); + + // Start Example 37 + $cursor = $db->inventory->find(['instock.qty' => 5, 'instock.warehouse' => 'A']); + // End Example 37 + + $this->assertCursorCount(2, $cursor); + } + + public function testExample_38_41() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 38 + $insertManyResult = $db->inventory->insertMany([ + ['_id' => 1, 'item' => null], + ['_id' => 2], + ]); + // End Example 38 + + $this->assertSame(2, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInternalType('int', $id); + } + $this->assertInventoryCount(2); + + // Start Example 39 + $cursor = $db->inventory->find(['item' => null]); + // End Example 39 + + $this->assertCursorCount(2, $cursor); + + // Start Example 40 + $cursor = $db->inventory->find(['item' => ['$type' => 10]]); + // End Example 40 + + $this->assertCursorCount(1, $cursor); + + // Start Example 41 + $cursor = $db->inventory->find(['item' => ['$exists' => false]]); + // End Example 41 + + $this->assertCursorCount(1, $cursor); + } + + public function testExample_42_50() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 42 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'status' => 'A', + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'instock' => [ + ['warehouse' => 'A', 'qty' => 5], + ], + ], + [ + 'item' => 'notebook', + 'status' => 'A', + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'instock' => [ + ['warehouse' => 'C', 'qty' => 5], + ], + ], + [ + 'item' => 'paper', + 'status' => 'D', + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'instock' => [ + ['warehouse' => 'A', 'qty' => 60], + ], + ], + [ + 'item' => 'planner', + 'status' => 'D', + 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], + 'instock' => [ + ['warehouse' => 'A', 'qty' => 40], + ], + ], + [ + 'item' => 'postcard', + 'status' => 'A', + 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], + 'instock' => [ + ['warehouse' => 'B', 'qty' => 15], + ['warehouse' => 'C', 'qty' => 35], + ], + ], + ]); + // End Example 42 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 43 + $cursor = $db->inventory->find(['status' => 'A']); + // End Example 43 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status', 'size', 'instock'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + } + + // Start Example 44 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['item' => 1, 'status' => 1]] + ); + // End Example 44 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + foreach (['size', 'instock'] as $field) { + $this->assertObjectNotHasAttribute($field, $document); + } + } + + // Start Example 45 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['item' => 1, 'status' => 1, '_id' => 0]] + ); + // End Example 45 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['item', 'status'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + foreach (['_id', 'size', 'instock'] as $field) { + $this->assertObjectNotHasAttribute($field, $document); + } + } + + // Start Example 46 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['status' => 0, 'instock' => 0]] + ); + // End Example 46 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'size'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + foreach (['status', 'instock'] as $field) { + $this->assertObjectNotHasAttribute($field, $document); + } + } + + // Start Example 47 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['item' => 1, 'status' => 1, 'size.uom' => 1]] + ); + // End Example 47 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status', 'size'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + $this->assertObjectNotHasAttribute('instock', $document); + $this->assertObjectHasAttribute('uom', $document->size); + $this->assertObjectNotHasAttribute('h', $document->size); + $this->assertObjectNotHasAttribute('w', $document->size); + } + + // Start Example 48 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['size.uom' => 0]] + ); + // End Example 48 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status', 'size', 'instock'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + $this->assertObjectHasAttribute('h', $document->size); + $this->assertObjectHasAttribute('w', $document->size); + $this->assertObjectNotHasAttribute('uom', $document->size); + } + + // Start Example 49 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['item' => 1, 'status' => 1, 'instock.qty' => 1]] + ); + // End Example 49 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status', 'instock'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + $this->assertObjectNotHasAttribute('size', $document); + foreach ($document->instock as $instock) { + $this->assertObjectHasAttribute('qty', $instock); + $this->assertObjectNotHasAttribute('warehouse', $instock); + } + } + + // Start Example 50 + $cursor = $db->inventory->find( + ['status' => 'A'], + ['projection' => ['item' => 1, 'status' => 1, 'instock' => ['$slice' => -1]]] + ); + // End Example 50 + + $documents = $cursor->toArray(); + $this->assertCount(3, $documents); + foreach ($documents as $document) { + foreach (['_id', 'item', 'status', 'instock'] as $field) { + $this->assertObjectHasAttribute($field, $document); + } + $this->assertObjectNotHasAttribute('size', $document); + $this->assertCount(1, $document->instock); + } + } + + public function testExample_51_54() + { + if (version_compare($this->getServerVersion(), '2.6.0', '<')) { + $this->markTestSkipped('$currentDate update operator is not supported'); + } + + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 51 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'canvas', + 'qty' => 100, + 'size' => ['h' => 28, 'w' => 35.5, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'journal', + 'qty' => 25, + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'mat', + 'qty' => 85, + 'size' => ['h' => 27.9, 'w' => 35.5, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'mousepad', + 'qty' => 25, + 'size' => ['h' => 19, 'w' => 22.85, 'uom' => 'cm'], + 'status' => 'P', + ], + [ + 'item' => 'notebook', + 'qty' => 50, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'P', + ], + [ + 'item' => 'paper', + 'qty' => 100, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'D', + ], + [ + 'item' => 'planner', + 'qty' => 75, + 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], + 'status' => 'D', + ], + [ + 'item' => 'postcard', + 'qty' => 45, + 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'sketchbook', + 'qty' => 80, + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'sketch pad', + 'qty' => 95, + 'size' => ['h' => 22.85, 'w' => 30.5, 'uom' => 'cm'], + 'status' => 'A', + ], + ]); + // End Example 51 + + $this->assertSame(10, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(10); + + // Start Example 52 + $updateResult = $db->inventory->updateOne( + ['item' => 'paper'], + [ + '$set' => ['size.uom' => 'cm', 'status' => 'P'], + '$currentDate' => ['lastModified' => true], + ] + ); + // End Example 52 + + $this->assertSame(1, $updateResult->getMatchedCount()); + $this->assertSame(1, $updateResult->getModifiedCount()); + $cursor = $db->inventory->find([ + 'item' => 'paper', + 'size.uom' => 'cm', + 'status' => 'P', + 'lastModified' => ['$type' => 9], + ]); + $this->assertCursorCount(1, $cursor); + + // Start Example 53 + $updateResult = $db->inventory->updateMany( + ['qty' => ['$lt' => 50]], + [ + '$set' => ['size.uom' => 'cm', 'status' => 'P'], + '$currentDate' => ['lastModified' => true], + ] + ); + // End Example 53 + + $this->assertSame(3, $updateResult->getMatchedCount()); + $this->assertSame(3, $updateResult->getModifiedCount()); + $cursor = $db->inventory->find([ + 'qty' => ['$lt' => 50], + 'size.uom' => 'cm', + 'status' => 'P', + 'lastModified' => ['$type' => 9], + ]); + $this->assertCursorCount(3, $cursor); + + // Start Example 54 + $updateResult = $db->inventory->replaceOne( + ['item' => 'paper'], + [ + 'item' => 'paper', + 'instock' => [ + ['warehouse' => 'A', 'qty' => 60], + ['warehouse' => 'B', 'qty' => 40], + ], + ] + ); + // End Example 54 + + $this->assertSame(1, $updateResult->getMatchedCount()); + $this->assertSame(1, $updateResult->getModifiedCount()); + $cursor = $db->inventory->find([ + 'item' => 'paper', + 'instock' => [ + ['warehouse' => 'A', 'qty' => 60], + ['warehouse' => 'B', 'qty' => 40], + ], + ]); + $this->assertCursorCount(1, $cursor); + } + + + + public function testExample_55_58() + { + $db = new Database($this->manager, $this->getDatabaseName()); + + // Start Example 55 + $insertManyResult = $db->inventory->insertMany([ + [ + 'item' => 'journal', + 'qty' => 25, + 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], + 'status' => 'A', + ], + [ + 'item' => 'notebook', + 'qty' => 50, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'P', + ], + [ + 'item' => 'paper', + 'qty' => 100, + 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], + 'status' => 'D', + ], + [ + 'item' => 'planner', + 'qty' => 75, + 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], + 'status' => 'D', + ], + [ + 'item' => 'postcard', + 'qty' => 45, + 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], + 'status' => 'A', + ], + ]); + // End Example 55 + + $this->assertSame(5, $insertManyResult->getInsertedCount()); + foreach ($insertManyResult->getInsertedIds() as $id) { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $id); + } + $this->assertInventoryCount(5); + + // Start Example 57 + $deleteResult = $db->inventory->deleteMany(['status' => 'A']); + // End Example 57 + + $this->assertSame(2, $deleteResult->getDeletedCount()); + $cursor = $db->inventory->find(['status' => 'A']); + $this->assertCursorCount(0, $cursor); + + // Start Example 58 + $deleteResult = $db->inventory->deleteOne(['status' => 'D']); + // End Example 58 + + $this->assertSame(1, $deleteResult->getDeletedCount()); + $cursor = $db->inventory->find(['status' => 'D']); + $this->assertCursorCount(1, $cursor); + + // Start Example 56 + $deleteResult = $db->inventory->deleteMany([]); + // End Example 56 + + $this->assertSame(2, $deleteResult->getDeletedCount()); + $this->assertInventoryCount(0); + } + + /** + * Return the test collection name. + * + * @return string + */ + protected function getCollectionName() + { + return 'inventory'; + } + + private function assertCursorCount($count, Cursor $cursor) + { + $this->assertCount($count, $cursor->toArray()); + } + + private function assertInventoryCount($count) + { + $this->assertCollectionCount($this->getDatabaseName() . '.' . $this->getCollectionName(), $count); + } +} diff --git a/vendor/mongodb/mongodb/tests/FooTest.php b/vendor/mongodb/mongodb/tests/FooTest.php new file mode 100644 index 00000000..e69de29b diff --git a/vendor/mongodb/mongodb/tests/FunctionalTestCase.php b/vendor/mongodb/mongodb/tests/FunctionalTestCase.php new file mode 100644 index 00000000..d12335ed --- /dev/null +++ b/vendor/mongodb/mongodb/tests/FunctionalTestCase.php @@ -0,0 +1,141 @@ +manager = new Manager($this->getUri()); + } + + protected function assertCollectionCount($namespace, $count) + { + list($databaseName, $collectionName) = explode('.', $namespace, 2); + + $cursor = $this->manager->executeCommand($databaseName, new Command(['count' => $collectionName])); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + $document = current($cursor->toArray()); + + $this->assertArrayHasKey('n', $document); + $this->assertEquals($count, $document['n']); + } + + protected function assertCommandSucceeded($document) + { + $document = is_object($document) ? (array) $document : $document; + + $this->assertArrayHasKey('ok', $document); + $this->assertEquals(1, $document['ok']); + } + + protected function assertSameObjectId($expectedObjectId, $actualObjectId) + { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $expectedObjectId); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $actualObjectId); + $this->assertEquals((string) $expectedObjectId, (string) $actualObjectId); + } + + protected function assertSameDocument($expectedDocument, $actualDocument) + { + $this->assertEquals( + \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP($this->normalizeBSON($expectedDocument))), + \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP($this->normalizeBSON($actualDocument))) + ); + } + + protected function assertSameDocuments(array $expectedDocuments, $actualDocuments) + { + if ($actualDocuments instanceof Traversable) { + $actualDocuments = iterator_to_array($actualDocuments); + } + + if ( ! is_array($actualDocuments)) { + throw new InvalidArgumentException('$actualDocuments is not an array or Traversable'); + } + + $normalizeRootDocuments = function($document) { + return \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP($this->normalizeBSON($document))); + }; + + $this->assertEquals( + array_map($normalizeRootDocuments, $expectedDocuments), + array_map($normalizeRootDocuments, $actualDocuments) + ); + } + + protected function getPrimaryServer() + { + return $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); + } + + protected function getServerVersion(ReadPreference $readPreference = null) + { + $cursor = $this->manager->executeCommand( + $this->getDatabaseName(), + new Command(['buildInfo' => 1]), + $readPreference ?: new ReadPreference(ReadPreference::RP_PRIMARY) + ); + + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + $document = current($cursor->toArray()); + + return $document['version']; + } + + /** + * Normalizes a BSON document or array for use with assertEquals(). + * + * The argument will be converted to a BSONArray or BSONDocument based on + * its type and keys. Document fields will be sorted alphabetically. Each + * value within the array or document will then be normalized recursively. + * + * @param array|object $bson + * @return BSONDocument|BSONArray + * @throws InvalidArgumentException if $bson is not an array or object + */ + private function normalizeBSON($bson) + { + if ( ! is_array($bson) && ! is_object($bson)) { + throw new InvalidArgumentException('$bson is not an array or object'); + } + + if ($bson instanceof BSONArray || (is_array($bson) && $bson === array_values($bson))) { + if ( ! $bson instanceof BSONArray) { + $bson = new BSONArray($bson); + } + } else { + if ( ! $bson instanceof BSONDocument) { + $bson = new BSONDocument((array) $bson); + } + + $bson->ksort(); + } + + foreach ($bson as $key => $value) { + if ($value instanceof BSONArray || (is_array($value) && $value === array_values($value))) { + $bson[$key] = $this->normalizeBSON($value); + continue; + } + + if ($value instanceof stdClass || $value instanceof BSONDocument || is_array($value)) { + $bson[$key] = $this->normalizeBSON($value); + continue; + } + } + + return $bson; + } +} diff --git a/vendor/mongodb/mongodb/tests/FunctionsTest.php b/vendor/mongodb/mongodb/tests/FunctionsTest.php new file mode 100644 index 00000000..f23b6821 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/FunctionsTest.php @@ -0,0 +1,164 @@ +assertEquals($expectedDocument, \MongoDB\apply_type_map_to_document($document, $typeMap)); + } + + public function provideDocumentAndTypeMap() + { + return [ + [ + [ + 'x' => 1, + 'y' => (object) ['foo' => 'bar'], + 'z' => [1, 2, 3], + ], + [ + 'root' => 'object', + 'document' => 'stdClass', + 'array' => 'array', + ], + (object) [ + 'x' => 1, + 'y' => (object) ['foo' => 'bar'], + 'z' => [1, 2, 3], + ], + ], + [ + [ + 'x' => 1, + 'y' => (object) ['foo' => 'bar'], + 'z' => [1, 2, 3], + ], + [ + 'root' => 'MongoDB\Model\BSONDocument', + 'document' => 'MongoDB\Model\BSONDocument', + 'array' => 'MongoDB\Model\BSONArray', + ], + new BSONDocument([ + 'x' => 1, + 'y' => new BSONDocument(['foo' => 'bar']), + 'z' => new BSONArray([1, 2, 3]), + ]), + ], + ]; + } + + /** + * @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames + */ + public function testGenerateIndexName($document, $expectedName) + { + $this->assertSame($expectedName, \MongoDB\generate_index_name($document)); + } + + public function provideIndexSpecificationDocumentsAndGeneratedNames() + { + return [ + [ ['x' => 1], 'x_1' ], + [ ['x' => -1, 'y' => 1], 'x_-1_y_1' ], + [ ['x' => '2dsphere', 'y' => 1 ], 'x_2dsphere_y_1' ], + [ (object) ['x' => 1], 'x_1' ], + [ new BSONDocument(['x' => 1]), 'x_1' ], + ]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testGenerateIndexNameArgumentTypeCheck($document) + { + \MongoDB\generate_index_name($document); + } + + /** + * @dataProvider provideIsFirstKeyOperatorDocuments + */ + public function testIsFirstKeyOperator($document, $isFirstKeyOperator) + { + $this->assertSame($isFirstKeyOperator, \MongoDB\is_first_key_operator($document)); + } + + public function provideIsFirstKeyOperatorDocuments() + { + return [ + [ ['y' => 1], false ], + [ (object) ['y' => 1], false ], + [ new BSONDocument(['y' => 1]), false ], + [ ['$set' => ['y' => 1]], true ], + [ (object) ['$set' => ['y' => 1]], true ], + [ new BSONDocument(['$set' => ['y' => 1]]), true ], + ]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testIsFirstKeyOperatorArgumentTypeCheck($document) + { + \MongoDB\is_first_key_operator($document); + } + + /** + * @dataProvider provideReadConcernsAndDocuments + */ + public function testReadConcernAsDocument(ReadConcern $readConcern, $expectedDocument) + { + $this->assertEquals($expectedDocument, \MongoDB\read_concern_as_document($readConcern)); + } + + public function provideReadConcernsAndDocuments() + { + return [ + [ new ReadConcern, (object) [] ], + [ new ReadConcern(ReadConcern::LOCAL), (object) ['level' => ReadConcern::LOCAL] ], + [ new ReadConcern(ReadConcern::MAJORITY), (object) ['level' => ReadConcern::MAJORITY] ], + ]; + } + + /** + * @dataProvider provideWriteConcernsAndDocuments + */ + public function testWriteConcernAsDocument(WriteConcern $writeConcern, $expectedDocument) + { + $this->assertEquals($expectedDocument, \MongoDB\write_concern_as_document($writeConcern)); + } + + public function provideWriteConcernsAndDocuments() + { + return [ + [ new WriteConcern(-3), (object) ['w' => 'majority'] ], // MONGOC_WRITE_CONCERN_W_MAJORITY + [ new WriteConcern(-2), (object) [] ], // MONGOC_WRITE_CONCERN_W_DEFAULT + [ new WriteConcern(-1), (object) ['w' => -1] ], + [ new WriteConcern(0), (object) ['w' => 0] ], + [ new WriteConcern(1), (object) ['w' => 1] ], + [ new WriteConcern('majority'), (object) ['w' => 'majority'] ], + [ new WriteConcern('tag'), (object) ['w' => 'tag'] ], + [ new WriteConcern(1, 0), (object) ['w' => 1] ], + [ new WriteConcern(1, 0, false), (object) ['w' => 1, 'j' => false] ], + [ new WriteConcern(1, 1000), (object) ['w' => 1, 'wtimeout' => 1000] ], + [ new WriteConcern(1, 1000, true), (object) ['w' => 1, 'wtimeout' => 1000, 'j' => true] ], + [ new WriteConcern(-2, 0, true), (object) ['j' => true] ], + // Note: wtimeout is only applicable applies for w > 1 + [ new WriteConcern(-2, 1000), (object) ['wtimeout' => 1000] ], + ]; + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/BucketFunctionalTest.php b/vendor/mongodb/mongodb/tests/GridFS/BucketFunctionalTest.php new file mode 100644 index 00000000..b03d0fa9 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/BucketFunctionalTest.php @@ -0,0 +1,761 @@ +manager, $this->getDatabaseName(), [ + 'bucketName' => 'test', + 'chunkSizeBytes' => 8192, + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY, 1000), + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Bucket($this->manager, $this->getDatabaseName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['bucketName' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['chunkSizeBytes' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected "chunkSizeBytes" option to be >= 1, 0 given + */ + public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive() + { + new Bucket($this->manager, $this->getDatabaseName(), ['chunkSizeBytes' => 0]); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testDelete($input, $expectedChunks) + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); + + $this->assertCollectionCount($this->filesCollection, 1); + $this->assertCollectionCount($this->chunksCollection, $expectedChunks); + + $this->bucket->delete($id); + + $this->assertCollectionCount($this->filesCollection, 0); + $this->assertCollectionCount($this->chunksCollection, 0); + } + + public function provideInputDataAndExpectedChunks() + { + return [ + ['', 0], + ['foobar', 1], + [str_repeat('a', 261120), 1], + [str_repeat('a', 261121), 2], + [str_repeat('a', 522240), 2], + [str_repeat('a', 522241), 3], + [str_repeat('foobar', 43520), 1], + [str_repeat('foobar', 43521), 2], + [str_repeat('foobar', 87040), 2], + [str_repeat('foobar', 87041), 3], + ]; + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + */ + public function testDeleteShouldRequireFileToExist() + { + $this->bucket->delete('nonexistent-id'); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expectedChunks) + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); + + $this->assertCollectionCount($this->filesCollection, 1); + $this->assertCollectionCount($this->chunksCollection, $expectedChunks); + + $this->filesCollection->deleteOne(['_id' => $id]); + + try { + $this->bucket->delete($id); + $this->fail('FileNotFoundException was not thrown'); + } catch (FileNotFoundException $e) {} + + $this->assertCollectionCount($this->chunksCollection, 0); + } + + /** + * @expectedException PHPUnit_Framework_Error_Warning + */ + public function testDownloadingFileWithMissingChunk() + { + $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); + + $this->chunksCollection->deleteOne(['files_id' => $id, 'n' => 0]); + + stream_get_contents($this->bucket->openDownloadStream($id)); + } + + /** + * @expectedException PHPUnit_Framework_Error_Warning + */ + public function testDownloadingFileWithUnexpectedChunkIndex() + { + $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); + + $this->chunksCollection->updateOne( + ['files_id' => $id, 'n' => 0], + ['$set' => ['n' => 1]] + ); + + stream_get_contents($this->bucket->openDownloadStream($id)); + } + + /** + * @expectedException PHPUnit_Framework_Error_Warning + */ + public function testDownloadingFileWithUnexpectedChunkSize() + { + $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); + + $this->chunksCollection->updateOne( + ['files_id' => $id, 'n' => 0], + ['$set' => ['data' => new Binary('fooba', Binary::TYPE_GENERIC)]] + ); + + stream_get_contents($this->bucket->openDownloadStream($id)); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testDownloadToStream($input) + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); + $destination = $this->createStream(); + $this->bucket->downloadToStream($id, $destination); + + $this->assertStreamContents($input, $destination); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidStreamValues + */ + public function testDownloadToStreamShouldRequireDestinationStream($destination) + { + $this->bucket->downloadToStream('id', $destination); + } + + public function provideInvalidStreamValues() + { + return $this->wrapValuesForDataProvider($this->getInvalidStreamValues()); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + */ + public function testDownloadToStreamShouldRequireFileToExist() + { + $this->bucket->downloadToStream('nonexistent-id', $this->createStream()); + } + + public function testDownloadToStreamByName() + { + $this->bucket->uploadFromStream('filename', $this->createStream('foo')); + $this->bucket->uploadFromStream('filename', $this->createStream('bar')); + $this->bucket->uploadFromStream('filename', $this->createStream('baz')); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination); + $this->assertStreamContents('baz', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -3]); + $this->assertStreamContents('foo', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -2]); + $this->assertStreamContents('bar', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -1]); + $this->assertStreamContents('baz', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 0]); + $this->assertStreamContents('foo', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 1]); + $this->assertStreamContents('bar', $destination); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 2]); + $this->assertStreamContents('baz', $destination); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidStreamValues + */ + public function testDownloadToStreamByNameShouldRequireDestinationStream($destination) + { + $this->bucket->downloadToStreamByName('filename', $destination); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + * @dataProvider provideNonexistentFilenameAndRevision + */ + public function testDownloadToStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision) + { + $this->bucket->uploadFromStream('filename', $this->createStream('foo')); + $this->bucket->uploadFromStream('filename', $this->createStream('bar')); + + $destination = $this->createStream(); + $this->bucket->downloadToStreamByName($filename, $destination, ['revision' => $revision]); + } + + public function provideNonexistentFilenameAndRevision() + { + return [ + ['filename', 2], + ['filename', -3], + ['nonexistent-filename', 0], + ['nonexistent-filename', -1], + ]; + } + + public function testDrop() + { + $this->bucket->uploadFromStream('filename', $this->createStream('foobar')); + + $this->assertCollectionCount($this->filesCollection, 1); + $this->assertCollectionCount($this->chunksCollection, 1); + + $this->bucket->drop(); + + $this->assertCollectionDoesNotExist($this->filesCollection->getCollectionName()); + $this->assertCollectionDoesNotExist($this->chunksCollection->getCollectionName()); + } + + public function testFind() + { + $this->bucket->uploadFromStream('a', $this->createStream('foo')); + $this->bucket->uploadFromStream('b', $this->createStream('foobar')); + $this->bucket->uploadFromStream('c', $this->createStream('foobarbaz')); + + $cursor = $this->bucket->find( + ['length' => ['$lte' => 6]], + [ + 'projection' => [ + 'filename' => 1, + 'length' => 1, + '_id' => 0, + ], + 'sort' => ['length' => -1], + ] + ); + + $expected = [ + ['filename' => 'b', 'length' => 6], + ['filename' => 'a', 'length' => 3], + ]; + + $this->assertSameDocuments($expected, $cursor); + } + + public function testFindUsesTypeMap() + { + $this->bucket->uploadFromStream('a', $this->createStream('foo')); + + $cursor = $this->bucket->find(); + $fileDocument = current($cursor->toArray()); + + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $fileDocument); + } + + public function testFindOne() + { + $this->bucket->uploadFromStream('a', $this->createStream('foo')); + $this->bucket->uploadFromStream('b', $this->createStream('foobar')); + $this->bucket->uploadFromStream('c', $this->createStream('foobarbaz')); + + $fileDocument = $this->bucket->findOne( + ['length' => ['$lte' => 6]], + [ + 'projection' => [ + 'filename' => 1, + 'length' => 1, + '_id' => 0, + ], + 'sort' => ['length' => -1], + ] + ); + + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $fileDocument); + $this->assertSameDocument(['filename' => 'b', 'length' => 6], $fileDocument); + } + + public function testGetBucketNameWithCustomValue() + { + $bucket = new Bucket($this->manager, $this->getDatabaseName(), ['bucketName' => 'custom_fs']); + + $this->assertEquals('custom_fs', $bucket->getBucketName()); + } + + public function testGetBucketNameWithDefaultValue() + { + $this->assertEquals('fs', $this->bucket->getBucketName()); + } + + public function testGetChunksCollection() + { + $chunksCollection = $this->bucket->getChunksCollection(); + + $this->assertInstanceOf('MongoDB\Collection', $chunksCollection); + $this->assertEquals('fs.chunks', $chunksCollection->getCollectionName()); + } + + public function testGetChunkSizeBytesWithCustomValue() + { + $bucket = new Bucket($this->manager, $this->getDatabaseName(), ['chunkSizeBytes' => 8192]); + + $this->assertEquals(8192, $bucket->getChunkSizeBytes()); + } + + public function testGetChunkSizeBytesWithDefaultValue() + { + $this->assertEquals(261120, $this->bucket->getChunkSizeBytes()); + } + + public function testGetDatabaseName() + { + $this->assertEquals($this->getDatabaseName(), $this->bucket->getDatabaseName()); + } + + public function testGetFileDocumentForStreamUsesTypeMap() + { + $metadata = ['foo' => 'bar']; + $stream = $this->bucket->openUploadStream('filename', ['_id' => 1, 'metadata' => $metadata]); + + $fileDocument = $this->bucket->getFileDocumentForStream($stream); + + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $fileDocument); + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $fileDocument['metadata']); + $this->assertSame(['foo' => 'bar'], $fileDocument['metadata']->getArrayCopy()); + } + + public function testGetFileDocumentForStreamWithReadableStream() + { + $metadata = ['foo' => 'bar']; + $id = $this->bucket->uploadFromStream('filename', $this->createStream('foobar'), ['metadata' => $metadata]); + $stream = $this->bucket->openDownloadStream($id); + + $fileDocument = $this->bucket->getFileDocumentForStream($stream); + + $this->assertSameObjectId($id, $fileDocument->_id); + $this->assertSame('filename', $fileDocument->filename); + $this->assertSame(6, $fileDocument->length); + $this->assertSameDocument($metadata, $fileDocument->metadata); + } + + public function testGetFileDocumentForStreamWithWritableStream() + { + $metadata = ['foo' => 'bar']; + $stream = $this->bucket->openUploadStream('filename', ['_id' => 1, 'metadata' => $metadata]); + + $fileDocument = $this->bucket->getFileDocumentForStream($stream); + + $this->assertEquals(1, $fileDocument->_id); + $this->assertSame('filename', $fileDocument->filename); + $this->assertSameDocument($metadata, $fileDocument->metadata); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidGridFSStreamValues + */ + public function testGetFileDocumentForStreamShouldRequireGridFSStreamResource($stream) + { + $this->bucket->getFileDocumentForStream($stream); + } + + public function provideInvalidGridFSStreamValues() + { + return $this->wrapValuesForDataProvider(array_merge($this->getInvalidStreamValues(), [$this->createStream()])); + } + + public function testGetFileIdForStreamUsesTypeMap() + { + $stream = $this->bucket->openUploadStream('filename', ['_id' => ['x' => 1]]); + + $id = $this->bucket->getFileIdForStream($stream); + + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $id); + $this->assertSame(['x' => 1], $id->getArrayCopy()); + } + + public function testGetFileIdForStreamWithReadableStream() + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream('foobar')); + $stream = $this->bucket->openDownloadStream($id); + + $this->assertSameObjectId($id, $this->bucket->getFileIdForStream($stream)); + } + + public function testGetFileIdForStreamWithWritableStream() + { + $stream = $this->bucket->openUploadStream('filename', ['_id' => 1]); + + $this->assertEquals(1, $this->bucket->getFileIdForStream($stream)); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidGridFSStreamValues + */ + public function testGetFileIdForStreamShouldRequireGridFSStreamResource($stream) + { + $this->bucket->getFileIdForStream($stream); + } + + public function testGetFilesCollection() + { + $filesCollection = $this->bucket->getFilesCollection(); + + $this->assertInstanceOf('MongoDB\Collection', $filesCollection); + $this->assertEquals('fs.files', $filesCollection->getCollectionName()); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testOpenDownloadStream($input) + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); + + $this->assertStreamContents($input, $this->bucket->openDownloadStream($id)); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testOpenDownloadStreamAndMultipleReadOperations($input) + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); + $stream = $this->bucket->openDownloadStream($id); + $buffer = ''; + + while (strlen($buffer) < strlen($input)) { + $expectedReadLength = min(4096, strlen($input) - strlen($buffer)); + $buffer .= $read = fread($stream, 4096); + + $this->assertInternalType('string', $read); + $this->assertEquals($expectedReadLength, strlen($read)); + } + + $this->assertTrue(fclose($stream)); + $this->assertEquals($input, $buffer); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + */ + public function testOpenDownloadStreamShouldRequireFileToExist() + { + $this->bucket->openDownloadStream('nonexistent-id'); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + */ + public function testOpenDownloadStreamByNameShouldRequireFilenameToExist() + { + $this->bucket->openDownloadStream('nonexistent-filename'); + } + + public function testOpenDownloadStreamByName() + { + $this->bucket->uploadFromStream('filename', $this->createStream('foo')); + $this->bucket->uploadFromStream('filename', $this->createStream('bar')); + $this->bucket->uploadFromStream('filename', $this->createStream('baz')); + + $this->assertStreamContents('baz', $this->bucket->openDownloadStreamByName('filename')); + $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('filename', ['revision' => -3])); + $this->assertStreamContents('bar', $this->bucket->openDownloadStreamByName('filename', ['revision' => -2])); + $this->assertStreamContents('baz', $this->bucket->openDownloadStreamByName('filename', ['revision' => -1])); + $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('filename', ['revision' => 0])); + $this->assertStreamContents('bar', $this->bucket->openDownloadStreamByName('filename', ['revision' => 1])); + $this->assertStreamContents('baz', $this->bucket->openDownloadStreamByName('filename', ['revision' => 2])); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + * @dataProvider provideNonexistentFilenameAndRevision + */ + public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision) + { + $this->bucket->uploadFromStream('filename', $this->createStream('foo')); + $this->bucket->uploadFromStream('filename', $this->createStream('bar')); + + $this->bucket->openDownloadStream($filename, ['revision' => $revision]); + } + + public function testOpenUploadStream() + { + $stream = $this->bucket->openUploadStream('filename'); + + fwrite($stream, 'foobar'); + fclose($stream); + + $this->assertStreamContents('foobar', $this->bucket->openDownloadStreamByName('filename')); + } + + /** + * @dataProvider provideInputDataAndExpectedChunks + */ + public function testOpenUploadStreamAndMultipleWriteOperations($input) + { + $stream = $this->bucket->openUploadStream('filename'); + $offset = 0; + + while ($offset < strlen($input)) { + $expectedWriteLength = min(4096, strlen($input) - $offset); + $writeLength = fwrite($stream, substr($input, $offset, 4096)); + $offset += $writeLength; + + $this->assertEquals($expectedWriteLength, $writeLength); + } + + $this->assertTrue(fclose($stream)); + $this->assertStreamContents($input, $this->bucket->openDownloadStreamByName('filename')); + } + + public function testRename() + { + $id = $this->bucket->uploadFromStream('a', $this->createStream('foo')); + $this->bucket->rename($id, 'b'); + + $fileDocument = $this->filesCollection->findOne( + ['_id' => $id], + ['projection' => ['filename' => 1, '_id' => 0]] + ); + + $this->assertSameDocument(['filename' => 'b'], $fileDocument); + $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('b')); + } + + public function testRenameShouldNotRequireFileToBeModified() + { + $id = $this->bucket->uploadFromStream('a', $this->createStream('foo')); + $this->bucket->rename($id, 'a'); + + $fileDocument = $this->filesCollection->findOne( + ['_id' => $id], + ['projection' => ['filename' => 1, '_id' => 0]] + ); + + $this->assertSameDocument(['filename' => 'a'], $fileDocument); + $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('a')); + } + + /** + * @expectedException MongoDB\GridFS\Exception\FileNotFoundException + */ + public function testRenameShouldRequireFileToExist() + { + $this->bucket->rename('nonexistent-id', 'b'); + } + + public function testUploadFromStream() + { + $options = [ + '_id' => 'custom-id', + 'chunkSizeBytes' => 2, + 'metadata' => ['foo' => 'bar'], + ]; + + $id = $this->bucket->uploadFromStream('filename', $this->createStream('foobar'), $options); + + $this->assertCollectionCount($this->filesCollection, 1); + $this->assertCollectionCount($this->chunksCollection, 3); + $this->assertSame('custom-id', $id); + + $fileDocument = $this->filesCollection->findOne(['_id' => $id]); + + $this->assertSameDocument(['foo' => 'bar'], $fileDocument['metadata']); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidStreamValues + */ + public function testUploadFromStreamShouldRequireSourceStream($source) + { + $this->bucket->uploadFromStream('filename', $source); + } + + public function testUploadingAnEmptyFile() + { + $id = $this->bucket->uploadFromStream('filename', $this->createStream('')); + $destination = $this->createStream(); + $this->bucket->downloadToStream($id, $destination); + + $this->assertStreamContents('', $destination); + $this->assertCollectionCount($this->filesCollection, 1); + $this->assertCollectionCount($this->chunksCollection, 0); + + $fileDocument = $this->filesCollection->findOne( + ['_id' => $id], + [ + 'projection' => [ + 'length' => 1, + 'md5' => 1, + '_id' => 0, + ], + ] + ); + + $expected = [ + 'length' => 0, + 'md5' => 'd41d8cd98f00b204e9800998ecf8427e', + ]; + + $this->assertSameDocument($expected, $fileDocument); + } + + public function testUploadingFirstFileCreatesIndexes() + { + $this->bucket->uploadFromStream('filename', $this->createStream('foo')); + + $this->assertIndexExists($this->filesCollection->getCollectionName(), 'filename_1_uploadDate_1'); + $this->assertIndexExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1', function(IndexInfo $info) { + $this->assertTrue($info->isUnique()); + }); + } + + /** + * Asserts that a collection with the given name does not exist on the + * server. + * + * @param string $collectionName + */ + private function assertCollectionDoesNotExist($collectionName) + { + $operation = new ListCollections($this->getDatabaseName()); + $collections = $operation->execute($this->getPrimaryServer()); + + $foundCollection = null; + + foreach ($collections as $collection) { + if ($collection->getName() === $collectionName) { + $foundCollection = $collection; + break; + } + } + + $this->assertNull($foundCollection, sprintf('Collection %s exists', $collectionName)); + } + + /** + * Asserts that an index with the given name exists for the collection. + * + * An optional $callback may be provided, which should take an IndexInfo + * argument as its first and only parameter. If an IndexInfo matching the + * given name is found, it will be passed to the callback, which may perform + * additional assertions. + * + * @param string $collectionName + * @param string $indexName + * @param callable $callback + */ + private function assertIndexExists($collectionName, $indexName, $callback = null) + { + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $operation = new ListIndexes($this->getDatabaseName(), $collectionName); + $indexes = $operation->execute($this->getPrimaryServer()); + + $foundIndex = null; + + foreach ($indexes as $index) { + if ($index->getName() === $indexName) { + $foundIndex = $index; + break; + } + } + + $this->assertNotNull($foundIndex, sprintf('Index %s does not exist', $indexName)); + + if ($callback !== null) { + call_user_func($callback, $foundIndex); + } + } + + /** + * Return a list of invalid stream values. + * + * @return array + */ + private function getInvalidStreamValues() + { + return [null, 123, 'foo', [], hash_init('md5')]; + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/FunctionalTestCase.php b/vendor/mongodb/mongodb/tests/GridFS/FunctionalTestCase.php new file mode 100644 index 00000000..4b31b672 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/FunctionalTestCase.php @@ -0,0 +1,58 @@ +bucket = new Bucket($this->manager, $this->getDatabaseName()); + $this->bucket->drop(); + + $this->chunksCollection = new Collection($this->manager, $this->getDatabaseName(), 'fs.chunks'); + $this->filesCollection = new Collection($this->manager, $this->getDatabaseName(), 'fs.files'); + } + + /** + * Asserts that a variable is a stream containing the expected data. + * + * Note: this will seek to the beginning of the stream before reading. + * + * @param string $expectedContents + * @param resource $stream + */ + protected function assertStreamContents($expectedContents, $stream) + { + $this->assertInternalType('resource', $stream); + $this->assertSame('stream', get_resource_type($stream)); + $this->assertEquals($expectedContents, stream_get_contents($stream, -1, 0)); + } + + /** + * Creates an in-memory stream with the given data. + * + * @param string $data + * @return resource + */ + protected function createStream($data = '') + { + $stream = fopen('php://temp', 'w+b'); + fwrite($stream, $data); + rewind($stream); + + return $stream; + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/ReadableStreamFunctionalTest.php b/vendor/mongodb/mongodb/tests/GridFS/ReadableStreamFunctionalTest.php new file mode 100644 index 00000000..8b7d3204 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/ReadableStreamFunctionalTest.php @@ -0,0 +1,180 @@ +collectionWrapper = new CollectionWrapper($this->manager, $this->getDatabaseName(), 'fs'); + + $this->filesCollection->insertMany([ + ['_id' => 'length-0', 'length' => 0, 'chunkSize' => 4], + ['_id' => 'length-0-with-empty-chunk', 'length' => 0, 'chunkSize' => 4], + ['_id' => 'length-2', 'length' => 2, 'chunkSize' => 4], + ['_id' => 'length-8', 'length' => 8, 'chunkSize' => 4], + ['_id' => 'length-10', 'length' => 10, 'chunkSize' => 4], + ]); + + $this->chunksCollection->insertMany([ + ['_id' => 1, 'files_id' => 'length-0-with-empty-chunk', 'n' => 0, 'data' => new Binary('', Binary::TYPE_GENERIC)], + ['_id' => 2, 'files_id' => 'length-2', 'n' => 0, 'data' => new Binary('ab', Binary::TYPE_GENERIC)], + ['_id' => 3, 'files_id' => 'length-8', 'n' => 0, 'data' => new Binary('abcd', Binary::TYPE_GENERIC)], + ['_id' => 4, 'files_id' => 'length-8', 'n' => 1, 'data' => new Binary('efgh', Binary::TYPE_GENERIC)], + ['_id' => 5, 'files_id' => 'length-10', 'n' => 0, 'data' => new Binary('abcd', Binary::TYPE_GENERIC)], + ['_id' => 6, 'files_id' => 'length-10', 'n' => 1, 'data' => new Binary('efgh', Binary::TYPE_GENERIC)], + ['_id' => 7, 'files_id' => 'length-10', 'n' => 2, 'data' => new Binary('ij', Binary::TYPE_GENERIC)], + ]); + } + + public function testValidConstructorFileDocument() + { + new ReadableStream($this->collectionWrapper, (object) ['_id' => null, 'chunkSize' => 1, 'length' => 0]); + } + + /** + * @expectedException MongoDB\GridFS\Exception\CorruptFileException + * @dataProvider provideInvalidConstructorFileDocuments + */ + public function testConstructorFileDocumentChecks($file) + { + new ReadableStream($this->collectionWrapper, $file); + } + + public function provideInvalidConstructorFileDocuments() + { + $options = []; + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = (object) ['_id' => 1, 'chunkSize' => $value, 'length' => 0]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = (object) ['_id' => 1, 'chunkSize' => 1, 'length' => $value]; + } + + $options[][] = (object) ['_id' => 1, 'chunkSize' => 0, 'length' => 0]; + $options[][] = (object) ['_id' => 1, 'chunkSize' => 1, 'length' => -1]; + $options[][] = (object) ['chunkSize' => 1, 'length' => 0]; + + return $options; + } + + /** + * @dataProvider provideFileIdAndExpectedBytes + */ + public function testReadBytes($fileId, $length, $expectedBytes) + { + $fileDocument = $this->collectionWrapper->findFileById($fileId); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + $this->assertSame($expectedBytes, $stream->readBytes($length)); + } + + public function provideFileIdAndExpectedBytes() + { + return [ + ['length-0', 0, ''], + ['length-0', 2, ''], + ['length-0-with-empty-chunk', 0, ''], + ['length-0-with-empty-chunk', 2, ''], + ['length-2', 0, ''], + ['length-2', 2, 'ab'], + ['length-2', 4, 'ab'], + ['length-8', 0, ''], + ['length-8', 2, 'ab'], + ['length-8', 4, 'abcd'], + ['length-8', 6, 'abcdef'], + ['length-8', 8, 'abcdefgh'], + ['length-8', 10, 'abcdefgh'], + ['length-10', 0, ''], + ['length-10', 2, 'ab'], + ['length-10', 4, 'abcd'], + ['length-10', 6, 'abcdef'], + ['length-10', 8, 'abcdefgh'], + ['length-10', 10, 'abcdefghij'], + ['length-10', 12, 'abcdefghij'], + ]; + } + + /** + * @dataProvider provideFileIdAndExpectedBytes + */ + public function testReadBytesCalledMultipleTimes($fileId, $length, $expectedBytes) + { + $fileDocument = $this->collectionWrapper->findFileById($fileId); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + for ($i = 0; $i < $length; $i++) { + $expectedByte = isset($expectedBytes[$i]) ? $expectedBytes[$i] : ''; + $this->assertSame($expectedByte, $stream->readBytes(1)); + } + } + + /** + * @expectedException MongoDB\GridFS\Exception\CorruptFileException + * @expectedExceptionMessage Chunk not found for index "2" + */ + public function testReadBytesWithMissingChunk() + { + $this->chunksCollection->deleteOne(['files_id' => 'length-10', 'n' => 2]); + + $fileDocument = $this->collectionWrapper->findFileById('length-10'); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + $stream->readBytes(10); + } + + /** + * @expectedException MongoDB\GridFS\Exception\CorruptFileException + * @expectedExceptionMessage Expected chunk to have index "1" but found "2" + */ + public function testReadBytesWithUnexpectedChunkIndex() + { + $this->chunksCollection->deleteOne(['files_id' => 'length-10', 'n' => 1]); + + $fileDocument = $this->collectionWrapper->findFileById('length-10'); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + $stream->readBytes(10); + } + + /** + * @expectedException MongoDB\GridFS\Exception\CorruptFileException + * @expectedExceptionMessage Expected chunk to have size "2" but found "1" + */ + public function testReadBytesWithUnexpectedChunkSize() + { + $this->chunksCollection->updateOne( + ['files_id' => 'length-10', 'n' => 2], + ['$set' => ['data' => new Binary('i', Binary::TYPE_GENERIC)]] + ); + + $fileDocument = $this->collectionWrapper->findFileById('length-10'); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + $stream->readBytes(10); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + */ + public function testReadBytesWithNegativeLength() + { + $fileDocument = $this->collectionWrapper->findFileById('length-0'); + $stream = new ReadableStream($this->collectionWrapper, $fileDocument); + + $stream->readBytes(-1); + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/SpecFunctionalTest.php b/vendor/mongodb/mongodb/tests/GridFS/SpecFunctionalTest.php new file mode 100644 index 00000000..94bc4588 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/SpecFunctionalTest.php @@ -0,0 +1,359 @@ +expectedFilesCollection = new Collection($this->manager, $this->getDatabaseName(), 'expected.files'); + $this->expectedFilesCollection->drop(); + + $this->expectedChunksCollection = new Collection($this->manager, $this->getDatabaseName(), 'expected.chunks'); + $this->expectedChunksCollection->drop(); + } + + /** + * @dataProvider provideSpecificationTests + */ + public function testSpecification(array $initialData, array $test) + { + $this->setName(str_replace(' ', '_', $test['description'])); + $this->initializeData($initialData); + + if (isset($test['arrange'])) { + foreach ($test['arrange']['data'] as $dataModification) { + $this->executeDataModification($dataModification); + } + } + + try { + $result = $this->executeAct($test['act']); + } catch (Exception $e) { + $result = $e; + } + + if (isset($test['assert'])) { + $this->executeAssert($test['assert'], $result); + } + } + + public function provideSpecificationTests() + { + $testArgs = []; + + foreach (glob(__DIR__ . '/spec-tests/*.json') as $filename) { + $json = json_decode(file_get_contents($filename), true); + + foreach ($json['tests'] as $test) { + $testArgs[] = [$json['data'], $test]; + } + } + + return $testArgs; + } + + /** + * Assert that the collections contain equivalent documents. + * + * This method will resolve references within the expected collection's + * documents before comparing documents. Occurrences of "*result" in the + * expected collection's documents will be replaced with the actual result. + * Occurrences of "*actual" in the expected collection's documents will be + * replaced with the corresponding value in the actual collection's document + * being compared. + * + * @param Collection $expectedCollection + * @param Collection $actualCollection + * @param mixed $actualResult + */ + private function assertEquivalentCollections($expectedCollection, $actualCollection, $actualResult) + { + $mi = new MultipleIterator; + $mi->attachIterator(new IteratorIterator($expectedCollection->find())); + $mi->attachIterator(new IteratorIterator($actualCollection->find())); + + foreach ($mi as $documents) { + list($expectedDocument, $actualDocument) = $documents; + + foreach ($expectedDocument as $key => $value) { + if ( ! is_string($value)) { + continue; + } + + if ($value === '*result') { + $expectedDocument[$key] = $actualResult; + } + + if ( ! strncmp($value, '*actual_', 8)) { + $expectedDocument[$key] = $actualDocument[$key]; + } + } + + $this->assertSameDocument($expectedDocument, $actualDocument); + } + } + + /** + * Convert encoded types in the array and return the modified array. + * + * Nested arrays with "$oid" and "$date" keys will be converted to ObjectId + * and UTCDateTime instances, respectively. Nested arrays with "$hex" keys + * will be converted to a string or Binary object. + * + * @param param $data + * @param boolean $createBinary If true, convert "$hex" values to a Binary + * @return array + */ + private function convertTypes(array $data, $createBinary = true) + { + /* array_walk_recursive() only visits leaf nodes within the array, so we + * need to manually recurse. + */ + array_walk($data, function(&$value) use ($createBinary) { + if ( ! is_array($value)) { + return; + } + + if (isset($value['$oid'])) { + $value = new ObjectId($value['$oid']); + return; + } + + if (isset($value['$hex'])) { + $value = $createBinary + ? new Binary(hex2bin($value['$hex']), Binary::TYPE_GENERIC) + : hex2bin($value['$hex']); + + return; + } + + if (isset($value['$date'])) { + $value = new UTCDateTime(new DateTime($value['$date'])); + return; + } + + $value = $this->convertTypes($value, $createBinary); + }); + + return $data; + } + + /** + * Executes an "act" block. + * + * @param array $act + * @return mixed + * @throws LogicException if the operation is unsupported + */ + private function executeAct(array $act) + { + $act = $this->convertTypes($act, false); + + switch ($act['operation']) { + case 'delete': + return $this->bucket->delete($act['arguments']['id']); + + case 'download': + return stream_get_contents($this->bucket->openDownloadStream($act['arguments']['id'])); + + case 'download_by_name': + return stream_get_contents($this->bucket->openDownloadStreamByName( + $act['arguments']['filename'], + isset($act['arguments']['options']) ? $act['arguments']['options'] : [] + )); + + case 'upload': + return $this->bucket->uploadFromStream( + $act['arguments']['filename'], + $this->createStream($act['arguments']['source']), + isset($act['arguments']['options']) ? $act['arguments']['options'] : [] + ); + + default: + throw new LogicException('Unsupported act: ' . $act['operation']); + } + } + + /** + * Executes an "assert" block. + * + * @param array $assert + * @param mixed $actualResult + * @return mixed + * @throws LogicException if the operation is unsupported + */ + private function executeAssert(array $assert, $actualResult) + { + if (isset($assert['error'])) { + $this->assertInstanceOf($this->getExceptionClassForError($assert['error']), $actualResult); + } + + if (isset($assert['result'])) { + $this->executeAssertResult($assert['result'], $actualResult); + } + + if ( ! isset($assert['data'])) { + return; + } + + /* Since "*actual" may be used for an expected document's "_id", append + * a unique value to avoid duplicate key exceptions. + */ + array_walk_recursive($assert['data'], function(&$value) { + if ($value === '*actual') { + $value .= '_' . new ObjectId; + } + }); + + foreach ($assert['data'] as $dataModification) { + $this->executeDataModification($dataModification); + } + + $this->assertEquivalentCollections($this->expectedFilesCollection, $this->filesCollection, $actualResult); + $this->assertEquivalentCollections($this->expectedChunksCollection, $this->chunksCollection, $actualResult); + } + + /** + * Executes the "result" section of an "assert" block. + * + * @param mixed $expectedResult + * @param mixed $actualResult + * @throws LogicException if the result assertion is unsupported + */ + private function executeAssertResult($expectedResult, $actualResult) + { + if ($expectedResult === 'void') { + return $this->assertNull($actualResult); + } + + if ($expectedResult === '&result') { + // Do nothing; assertEquivalentCollections() will handle this + return; + } + + if (isset($expectedResult['$hex'])) { + return $this->assertSame(hex2bin($expectedResult['$hex']), $actualResult); + } + + throw new LogicException('Unsupported result assertion: ' . var_export($expectedResult, true)); + } + + /** + * Executes a data modification from an "arrange" or "assert" block. + * + * @param array $dataModification + * @return mixed + * @throws LogicException if the operation or collection is unsupported + */ + private function executeDataModification(array $dataModification) + { + foreach ($dataModification as $type => $collectionName) { + break; + } + + if ( ! in_array($collectionName, ['fs.files', 'fs.chunks', 'expected.files', 'expected.chunks'])) { + throw new LogicException('Unsupported collection: ' . $collectionName); + } + + $dataModification = $this->convertTypes($dataModification); + $operations = []; + + switch ($type) { + case 'delete': + foreach ($dataModification['deletes'] as $delete) { + $operations[] = [ ($delete['limit'] === 1 ? 'deleteOne' : 'deleteMany') => [ $delete['q'] ] ]; + } + + break; + + case 'insert': + foreach ($dataModification['documents'] as $document) { + $operations[] = [ 'insertOne' => [ $document ] ]; + } + + break; + + case 'update': + foreach ($dataModification['updates'] as $update) { + $operations[] = [ 'updateOne' => [ $update['q'], $update['u'] ] ]; + } + + break; + + default: + throw new LogicException('Unsupported arrangement: ' . $type); + } + + $bulk = new BulkWrite($this->getDatabaseName(), $collectionName, $operations); + + return $bulk->execute($this->getPrimaryServer()); + } + + /** + * Returns the exception class for the "error" section of an "assert" block. + * + * @param string $error + * @return string + * @throws LogicException if the error is unsupported + */ + private function getExceptionClassForError($error) + { + switch ($error) { + case 'FileNotFound': + case 'RevisionNotFound': + return 'MongoDB\GridFS\Exception\FileNotFoundException'; + + case 'ChunkIsMissing': + case 'ChunkIsWrongSize': + /* Although ReadableStream throws a CorruptFileException, the + * stream wrapper will convert it to a PHP error of type + * E_USER_WARNING. */ + return 'PHPUnit_Framework_Error_Warning'; + + default: + throw new LogicException('Unsupported error: ' . $error); + } + } + + /** + * Initializes data in the files and chunks collections. + * + * @param array $data + */ + private function initializeData(array $data) + { + $data = $this->convertTypes($data); + + if ( ! empty($data['files'])) { + $this->filesCollection->insertMany($data['files']); + $this->expectedFilesCollection->insertMany($data['files']); + } + + if ( ! empty($data['chunks'])) { + $this->chunksCollection->insertMany($data['chunks']); + $this->expectedChunksCollection->insertMany($data['chunks']); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/StreamWrapperFunctionalTest.php b/vendor/mongodb/mongodb/tests/GridFS/StreamWrapperFunctionalTest.php new file mode 100644 index 00000000..808ebc4a --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/StreamWrapperFunctionalTest.php @@ -0,0 +1,180 @@ +filesCollection->insertMany([ + ['_id' => 'length-10', 'length' => 10, 'chunkSize' => 4, 'uploadDate' => new UTCDateTime('1484202200000')], + ]); + + $this->chunksCollection->insertMany([ + ['_id' => 1, 'files_id' => 'length-10', 'n' => 0, 'data' => new Binary('abcd', Binary::TYPE_GENERIC)], + ['_id' => 2, 'files_id' => 'length-10', 'n' => 1, 'data' => new Binary('efgh', Binary::TYPE_GENERIC)], + ['_id' => 3, 'files_id' => 'length-10', 'n' => 2, 'data' => new Binary('ij', Binary::TYPE_GENERIC)], + ]); + } + + public function testReadableStreamClose() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $this->assertTrue(fclose($stream)); + } + + public function testReadableStreamEof() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $this->assertFalse(feof($stream)); + $this->assertStreamContents('abcdefghij', $stream); + $this->assertTrue(feof($stream)); + } + + public function testReadableStreamRead() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $this->assertSame('abc', fread($stream, 3)); + $this->assertSame('defghij', fread($stream, 10)); + $this->assertSame('', fread($stream, 3)); + } + + public function testReadableStreamSeek() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $this->assertSame(0, fseek($stream, 2, \SEEK_SET)); + $this->assertSame('cde', fread($stream, 3)); + $this->assertSame(0, fseek($stream, 10, \SEEK_SET)); + $this->assertSame('', fread($stream, 3)); + $this->assertSame(-1, fseek($stream, -1, \SEEK_SET)); + $this->assertSame(-1, fseek($stream, 11, \SEEK_SET)); + + $this->assertSame(0, fseek($stream, -5, \SEEK_CUR)); + $this->assertSame('fgh', fread($stream, 3)); + $this->assertSame(0, fseek($stream, 1, \SEEK_CUR)); + $this->assertSame('j', fread($stream, 3)); + $this->assertSame(-1, fseek($stream, 1, \SEEK_CUR)); + $this->assertSame(-1, fseek($stream, -11, \SEEK_CUR)); + + $this->assertSame(0, fseek($stream, 0, \SEEK_END)); + $this->assertSame('', fread($stream, 3)); + $this->assertSame(0, fseek($stream, -8, \SEEK_END)); + $this->assertSame('cde', fread($stream, 3)); + $this->assertSame(-1, fseek($stream, -11, \SEEK_END)); + $this->assertSame(-1, fseek($stream, 1, \SEEK_END)); + } + + public function testReadableStreamStat() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $stat = fstat($stream); + $this->assertSame(0100444, $stat[2]); + $this->assertSame(0100444, $stat['mode']); + $this->assertSame(10, $stat[7]); + $this->assertSame(10, $stat['size']); + $this->assertSame(1484202200, $stat[9]); + $this->assertSame(1484202200, $stat['mtime']); + $this->assertSame(1484202200, $stat[10]); + $this->assertSame(1484202200, $stat['ctime']); + $this->assertSame(4, $stat[11]); + $this->assertSame(4, $stat['blksize']); + } + + public function testReadableStreamWrite() + { + $stream = $this->bucket->openDownloadStream('length-10'); + + $this->assertSame(0, fwrite($stream, 'foobar')); + } + + public function testWritableStreamClose() + { + $stream = $this->bucket->openUploadStream('filename'); + + $this->assertSame(6, fwrite($stream, 'foobar')); + $this->assertTrue(fclose($stream)); + + $this->assertStreamContents('foobar', $this->bucket->openDownloadStreamByName('filename')); + } + + public function testWritableStreamEof() + { + $stream = $this->bucket->openUploadStream('filename'); + + $this->assertFalse(feof($stream)); + $this->assertSame(6, fwrite($stream, 'foobar')); + $this->assertFalse(feof($stream)); + } + + public function testWritableStreamRead() + { + $stream = $this->bucket->openUploadStream('filename'); + + $this->assertSame('', fread($stream, 8192)); + $this->assertSame(6, fwrite($stream, 'foobar')); + $this->assertSame('', fread($stream, 8192)); + } + + public function testWritableStreamSeek() + { + $stream = $this->bucket->openUploadStream('filename'); + + $this->assertSame(6, fwrite($stream, 'foobar')); + + $this->assertSame(-1, fseek($stream, 0, \SEEK_SET)); + $this->assertSame(-1, fseek($stream, 7, \SEEK_SET)); + $this->assertSame(0, fseek($stream, 6, \SEEK_SET)); + + $this->assertSame(0, fseek($stream, 0, \SEEK_CUR)); + $this->assertSame(-1, fseek($stream, -1, \SEEK_CUR)); + $this->assertSame(-1, fseek($stream, 1, \SEEK_CUR)); + + $this->assertSame(0, fseek($stream, 0, \SEEK_END)); + $this->assertSame(-1, fseek($stream, -1, \SEEK_END)); + $this->assertSame(-1, fseek($stream, 1, \SEEK_END)); + } + + public function testWritableStreamStat() + { + $currentTimestamp = time(); + $stream = $this->bucket->openUploadStream('filename', ['chunkSizeBytes' => 1024]); + + $stat = fstat($stream); + $this->assertSame(0100222, $stat[2]); + $this->assertSame(0100222, $stat['mode']); + $this->assertSame(0, $stat[7]); + $this->assertSame(0, $stat['size']); + $this->assertGreaterThanOrEqual($currentTimestamp, $stat[9]); + $this->assertGreaterThanOrEqual($currentTimestamp, $stat['mtime']); + $this->assertGreaterThanOrEqual($currentTimestamp, $stat[10]); + $this->assertGreaterThanOrEqual($currentTimestamp, $stat['ctime']); + $this->assertSame(1024, $stat[11]); + $this->assertSame(1024, $stat['blksize']); + + $this->assertSame(6, fwrite($stream, 'foobar')); + + $stat = fstat($stream); + $this->assertSame(6, $stat[7]); + $this->assertSame(6, $stat['size']); + } + + public function testWritableStreamWrite() + { + $stream = $this->bucket->openUploadStream('filename'); + + $this->assertSame(6, fwrite($stream, 'foobar')); + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/WritableStreamFunctionalTest.php b/vendor/mongodb/mongodb/tests/GridFS/WritableStreamFunctionalTest.php new file mode 100644 index 00000000..6a1ce899 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/WritableStreamFunctionalTest.php @@ -0,0 +1,108 @@ +collectionWrapper = new CollectionWrapper($this->manager, $this->getDatabaseName(), 'fs'); + } + + public function testValidConstructorOptions() + { + new WritableStream($this->collectionWrapper, 'filename', [ + '_id' => 'custom-id', + 'chunkSizeBytes' => 2, + 'metadata' => ['foo' => 'bar'], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new WritableStream($this->collectionWrapper, 'filename', $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['chunkSizeBytes' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['metadata' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected "chunkSizeBytes" option to be >= 1, 0 given + */ + public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive() + { + new WritableStream($this->collectionWrapper, 'filename', ['chunkSizeBytes' => 0]); + } + + public function testWriteBytesAlwaysUpdatesFileSize() + { + $stream = new WritableStream($this->collectionWrapper, 'filename', ['chunkSizeBytes' => 1024]); + + $this->assertSame(0, $stream->getSize()); + $this->assertSame(512, $stream->writeBytes(str_repeat('a', 512))); + $this->assertSame(512, $stream->getSize()); + $this->assertSame(512, $stream->writeBytes(str_repeat('a', 512))); + $this->assertSame(1024, $stream->getSize()); + $this->assertSame(512, $stream->writeBytes(str_repeat('a', 512))); + $this->assertSame(1536, $stream->getSize()); + + $stream->close(); + $this->assertSame(1536, $stream->getSize()); + } + + /** + * @dataProvider provideInputDataAndExpectedMD5 + */ + public function testWriteBytesCalculatesMD5($input, $expectedMD5) + { + $stream = new WritableStream($this->collectionWrapper, 'filename'); + $stream->writeBytes($input); + $stream->close(); + + $fileDocument = $this->filesCollection->findOne( + ['_id' => $stream->getFile()->_id], + ['projection' => ['md5' => 1, '_id' => 0]] + ); + + $this->assertSameDocument(['md5' => $expectedMD5], $fileDocument); + } + + public function provideInputDataAndExpectedMD5() + { + return [ + ['', 'd41d8cd98f00b204e9800998ecf8427e'], + ['foobar', '3858f62230ac3c915f300c664312c63f'], + [str_repeat('foobar', 43520), '88ff0e5fcb0acb27947d736b5d69cb73'], + [str_repeat('foobar', 43521), '8ff86511c95a06a611842ceb555d8454'], + [str_repeat('foobar', 87040), '45bfa1a9ec36728ee7338d15c5a30c13'], + [str_repeat('foobar', 87041), '95e78f624f8e745bcfd2d11691fa601e'], + ]; + } +} diff --git a/vendor/mongodb/mongodb/tests/GridFS/spec-tests/delete.json b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/delete.json new file mode 100644 index 00000000..f1b98306 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/delete.json @@ -0,0 +1,316 @@ +{ + "data": { + "files": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + } + ], + "chunks": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$hex": "" + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$hex": "1122" + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$hex": "11223344" + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$hex": "55667788" + } + } + ] + }, + "tests": [ + { + "description": "Delete when length is 0", + "act": { + "operation": "delete", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + } + } + }, + "assert": { + "result": "void", + "data": [ + { + "delete": "expected.files", + "deletes": [ + { + "q": { + "_id": { + "$oid": "000000000000000000000001" + } + }, + "limit": 1 + } + ] + } + ] + } + }, + { + "description": "Delete when length is 0 and there is one extra empty chunk", + "act": { + "operation": "delete", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + } + } + }, + "assert": { + "result": "void", + "data": [ + { + "delete": "expected.files", + "deletes": [ + { + "q": { + "_id": { + "$oid": "000000000000000000000002" + } + }, + "limit": 1 + } + ] + }, + { + "delete": "expected.chunks", + "deletes": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000002" + } + }, + "limit": 0 + } + ] + } + ] + } + }, + { + "description": "Delete when length is 8", + "act": { + "operation": "delete", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + } + }, + "assert": { + "result": "void", + "data": [ + { + "delete": "expected.files", + "deletes": [ + { + "q": { + "_id": { + "$oid": "000000000000000000000004" + } + }, + "limit": 1 + } + ] + }, + { + "delete": "expected.chunks", + "deletes": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000004" + } + }, + "limit": 0 + } + ] + } + ] + } + }, + { + "description": "Delete when files entry does not exist", + "act": { + "operation": "delete", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + } + } + }, + "assert": { + "error": "FileNotFound" + } + }, + { + "description": "Delete when files entry does not exist and there are orphaned chunks", + "arrange": { + "data": [ + { + "delete": "fs.files", + "deletes": [ + { + "q": { + "_id": { + "$oid": "000000000000000000000004" + } + }, + "limit": 1 + } + ] + } + ] + }, + "act": { + "operation": "delete", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + } + }, + "assert": { + "error": "FileNotFound", + "data": [ + { + "delete": "expected.files", + "deletes": [ + { + "q": { + "_id": { + "$oid": "000000000000000000000004" + } + }, + "limit": 1 + } + ] + }, + { + "delete": "expected.chunks", + "deletes": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000004" + } + }, + "limit": 0 + } + ] + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download.json b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download.json new file mode 100644 index 00000000..f0bee2e0 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download.json @@ -0,0 +1,445 @@ +{ + "data": { + "files": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 10, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "57d83cd477bfb1ccd975ab33d827a92b", + "filename": "length-10", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + } + ], + "chunks": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$hex": "" + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$hex": "1122" + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$hex": "11223344" + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$hex": "55667788" + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$hex": "11223344" + } + }, + { + "_id": { + "$oid": "000000000000000000000006" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1, + "data": { + "$hex": "55667788" + } + }, + { + "_id": { + "$oid": "000000000000000000000007" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2, + "data": { + "$hex": "99aa" + } + } + ] + }, + "tests": [ + { + "description": "Download when length is zero", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + }, + "options": { + } + } + }, + "assert": { + "result": { + "$hex": "" + } + } + }, + { + "description": "Download when length is zero and there is one empty chunk", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + }, + "options": { + } + } + }, + "assert": { + "result": { + "$hex": "" + } + } + }, + { + "description": "Download when there is one chunk", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000003" + }, + "options": { + } + } + }, + "assert": { + "result": { + "$hex": "1122" + } + } + }, + { + "description": "Download when there are two chunks", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + }, + "options": { + } + } + }, + "assert": { + "result": { + "$hex": "1122334455667788" + } + } + }, + { + "description": "Download when there are three chunks", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + }, + "options": { + } + } + }, + "assert": { + "result": { + "$hex": "112233445566778899aa" + } + } + }, + { + "description": "Download when files entry does not exist", + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + }, + "options": { + } + } + }, + "assert": { + "error": "FileNotFound" + } + }, + { + "description": "Download when an intermediate chunk is missing", + "arrange": { + "data": [ + { + "delete": "fs.chunks", + "deletes": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + }, + "limit": 1 + } + ] + } + ] + }, + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + } + }, + "assert": { + "error": "ChunkIsMissing" + } + }, + { + "description": "Download when final chunk is missing", + "arrange": { + "data": [ + { + "delete": "fs.chunks", + "deletes": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + }, + "limit": 1 + } + ] + } + ] + }, + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + } + }, + "assert": { + "error": "ChunkIsMissing" + } + }, + { + "description": "Download when an intermediate chunk is the wrong size", + "arrange": { + "data": [ + { + "update": "fs.chunks", + "updates": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + }, + "u": { + "$set": { + "data": { + "$hex": "556677" + } + } + } + }, + { + "q": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "u": { + "$set": { + "data": { + "$hex": "8899aa" + } + } + } + } + ] + } + ] + }, + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + } + }, + "assert": { + "error": "ChunkIsWrongSize" + } + }, + { + "description": "Download when final chunk is the wrong size", + "arrange": { + "data": [ + { + "update": "fs.chunks", + "updates": [ + { + "q": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "u": { + "$set": { + "data": { + "$hex": "99" + } + } + } + } + ] + } + ] + }, + "act": { + "operation": "download", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + } + }, + "assert": { + "error": "ChunkIsWrongSize" + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download_by_name.json b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download_by_name.json new file mode 100644 index 00000000..7f4d46bb --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/download_by_name.json @@ -0,0 +1,255 @@ +{ + "data": { + "files": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-02T00:00:00.000Z" + }, + "md5": "b15835f133ff2e27c7cb28117bfae8f4", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-03T00:00:00.000Z" + }, + "md5": "eccbc87e4b5ce2fe28308fd9f2a7baf3", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-04T00:00:00.000Z" + }, + "md5": "f623e75af30e62bbd73d6df5b50bb7b5", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-05T00:00:00.000Z" + }, + "md5": "4c614360da93c0a041b22e537de151eb", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [ + + ], + "metadata": { + } + } + ], + "chunks": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000001" + }, + "n": 0, + "data": { + "$hex": "11" + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$hex": "22" + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$hex": "33" + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$hex": "44" + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$hex": "55" + } + } + ] + }, + "tests": [ + { + "description": "Download_by_name when revision is 0", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "abc", + "options": { + "revision": 0 + } + } + }, + "assert": { + "result": { + "$hex": "11" + } + } + }, + { + "description": "Download_by_name when revision is 1", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "abc", + "options": { + "revision": 1 + } + } + }, + "assert": { + "result": { + "$hex": "22" + } + } + }, + { + "description": "Download_by_name when revision is -2", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "abc", + "options": { + "revision": -2 + } + } + }, + "assert": { + "result": { + "$hex": "44" + } + } + }, + { + "description": "Download_by_name when revision is -1", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "abc", + "options": { + "revision": -1 + } + } + }, + "assert": { + "result": { + "$hex": "55" + } + } + }, + { + "description": "Download_by_name when files entry does not exist", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "xyz" + } + }, + "assert": { + "error": "FileNotFound" + } + }, + { + "description": "Download_by_name when revision does not exist", + "act": { + "operation": "download_by_name", + "arguments": { + "filename": "abc", + "options": { + "revision": 999 + } + } + }, + "assert": { + "error": "RevisionNotFound" + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/GridFS/spec-tests/upload.json b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/upload.json new file mode 100644 index 00000000..95dfd79e --- /dev/null +++ b/vendor/mongodb/mongodb/tests/GridFS/spec-tests/upload.json @@ -0,0 +1,391 @@ +{ + "data": { + "files": [ + + ], + "chunks": [ + + ] + }, + "tests": [ + { + "description": "Upload when length is 0", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 0, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "filename" + } + ] + } + ] + } + }, + { + "description": "Upload when length is 1", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "11" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 1, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "filename" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11" + } + } + ] + } + ] + } + }, + { + "description": "Upload when length is 3", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "112233" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 3, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "bafae3a174ab91fc70db7a6aa50f4f52", + "filename": "filename" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "112233" + } + } + ] + } + ] + } + }, + { + "description": "Upload when length is 4", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "11223344" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 4, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "7e7c77cff5705d1f7574a25ef6662117", + "filename": "filename" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11223344" + } + } + ] + } + ] + } + }, + { + "description": "Upload when length is 5", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "1122334455" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 5, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "283d4fea5dded59cf837d3047328f5af", + "filename": "filename" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11223344" + } + }, + { + "_id": "*actual", + "files_id": "*result", + "n": 1, + "data": { + "$hex": "55" + } + } + ] + } + ] + } + }, + { + "description": "Upload when length is 8", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "1122334455667788" + }, + "options": { + "chunkSizeBytes": 4 + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 8, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "filename" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11223344" + } + }, + { + "_id": "*actual", + "files_id": "*result", + "n": 1, + "data": { + "$hex": "55667788" + } + } + ] + } + ] + } + }, + { + "description": "Upload when contentType is provided", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "11" + }, + "options": { + "chunkSizeBytes": 4, + "contentType": "image/jpeg" + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 1, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "filename", + "contentType": "image/jpeg" + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11" + } + } + ] + } + ] + } + }, + { + "description": "Upload when metadata is provided", + "act": { + "operation": "upload", + "arguments": { + "filename": "filename", + "source": { + "$hex": "11" + }, + "options": { + "chunkSizeBytes": 4, + "metadata": { + "x": 1 + } + } + } + }, + "assert": { + "result": "&result", + "data": [ + { + "insert": "expected.files", + "documents": [ + { + "_id": "*result", + "length": 1, + "chunkSize": 4, + "uploadDate": "*actual", + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "filename", + "metadata": { + "x": 1 + } + } + ] + }, + { + "insert": "expected.chunks", + "documents": [ + { + "_id": "*actual", + "files_id": "*result", + "n": 0, + "data": { + "$hex": "11" + } + } + ] + } + ] + } + } + ] +} \ No newline at end of file diff --git a/vendor/mongodb/mongodb/tests/Model/BSONArrayTest.php b/vendor/mongodb/mongodb/tests/Model/BSONArrayTest.php new file mode 100644 index 00000000..9f4191e7 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/BSONArrayTest.php @@ -0,0 +1,50 @@ + 'foo', 2 => 'bar']; + + $array = new BSONArray($data); + $this->assertSame($data, $array->getArrayCopy()); + $this->assertSame(['foo', 'bar'], $array->bsonSerialize()); + } + + public function testJsonSerialize() + { + $document = new BSONArray([ + 'foo', + new BSONArray(['foo' => 1, 'bar' => 2, 'baz' => 3]), + new BSONDocument(['foo' => 1, 'bar' => 2, 'baz' => 3]), + new BSONArray([new BSONArray([new BSONArray])]), + ]); + + $expectedJson = '["foo",[1,2,3],{"foo":1,"bar":2,"baz":3},[[[]]]]'; + + $this->assertSame($expectedJson, json_encode($document)); + } + + public function testJsonSerializeReindexesKeys() + { + $data = [0 => 'foo', 2 => 'bar']; + + $array = new BSONArray($data); + $this->assertSame($data, $array->getArrayCopy()); + $this->assertSame(['foo', 'bar'], $array->jsonSerialize()); + } + + public function testSetState() + { + $data = ['foo', 'bar']; + + $array = BSONArray::__set_state($data); + $this->assertInstanceOf('MongoDB\Model\BSONArray', $array); + $this->assertSame($data, $array->getArrayCopy()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/BSONDocumentTest.php b/vendor/mongodb/mongodb/tests/Model/BSONDocumentTest.php new file mode 100644 index 00000000..2f13e2fb --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/BSONDocumentTest.php @@ -0,0 +1,58 @@ + 'bar']); + $this->assertEquals(ArrayObject::ARRAY_AS_PROPS, $document->getFlags()); + $this->assertSame('bar', $document->foo); + } + + public function testBsonSerializeCastsToObject() + { + $data = [0 => 'foo', 2 => 'bar']; + + $document = new BSONDocument($data); + $this->assertSame($data, $document->getArrayCopy()); + $this->assertEquals((object) [0 => 'foo', 2 => 'bar'], $document->bsonSerialize()); + } + + public function testJsonSerialize() + { + $document = new BSONDocument([ + 'foo' => 'bar', + 'array' => new BSONArray([1, 2, 3]), + 'object' => new BSONDocument([1, 2, 3]), + 'nested' => new BSONDocument([new BSONDocument([new BSONDocument])]), + ]); + + $expectedJson = '{"foo":"bar","array":[1,2,3],"object":{"0":1,"1":2,"2":3},"nested":{"0":{"0":{}}}}'; + + $this->assertSame($expectedJson, json_encode($document)); + } + + public function testJsonSerializeCastsToObject() + { + $data = [0 => 'foo', 2 => 'bar']; + + $document = new BSONDocument($data); + $this->assertSame($data, $document->getArrayCopy()); + $this->assertEquals((object) [0 => 'foo', 2 => 'bar'], $document->jsonSerialize()); + } + + public function testSetState() + { + $data = ['foo' => 'bar']; + + $document = BSONDocument::__set_state($data); + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $document); + $this->assertSame($data, $document->getArrayCopy()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/CachingIteratorTest.php b/vendor/mongodb/mongodb/tests/Model/CachingIteratorTest.php new file mode 100644 index 00000000..c16c2f84 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/CachingIteratorTest.php @@ -0,0 +1,130 @@ +getTraversable([1, 2, 3]); + $this->assertSame([1, 2, 3], iterator_to_array($iterator)); + $this->assertSame([1, 2, 3], iterator_to_array($iterator)); + } + + public function testConstructorRewinds() + { + $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); + + $this->assertTrue($iterator->valid()); + $this->assertSame(0, $iterator->key()); + $this->assertSame(1, $iterator->current()); + } + + public function testIteration() + { + $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); + + $expectedKey = 0; + $expectedItem = 1; + + foreach ($iterator as $key => $item) { + $this->assertSame($expectedKey++, $key); + $this->assertSame($expectedItem++, $item); + } + + $this->assertFalse($iterator->valid()); + } + + public function testIterationWithEmptySet() + { + $iterator = new CachingIterator($this->getTraversable([])); + + $iterator->rewind(); + $this->assertFalse($iterator->valid()); + } + + public function testPartialIterationDoesNotExhaust() + { + $traversable = $this->getTraversableThatThrows([1, 2, new Exception]); + $iterator = new CachingIterator($traversable); + + $expectedKey = 0; + $expectedItem = 1; + + foreach ($iterator as $key => $item) { + $this->assertSame($expectedKey++, $key); + $this->assertSame($expectedItem++, $item); + + if ($key === 1) { + break; + } + } + + $this->assertTrue($iterator->valid()); + } + + public function testRewindAfterPartialIteration() + { + $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); + + $iterator->rewind(); + $this->assertTrue($iterator->valid()); + $this->assertSame(0, $iterator->key()); + $this->assertSame(1, $iterator->current()); + + $iterator->next(); + $this->assertSame([1, 2, 3], iterator_to_array($iterator)); + } + + public function testCount() + { + $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); + $this->assertCount(3, $iterator); + } + + public function testCountAfterPartialIteration() + { + $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); + + $iterator->rewind(); + $this->assertTrue($iterator->valid()); + $this->assertSame(0, $iterator->key()); + $this->assertSame(1, $iterator->current()); + + $iterator->next(); + $this->assertCount(3, $iterator); + } + + public function testCountWithEmptySet() + { + $iterator = new CachingIterator($this->getTraversable([])); + $this->assertCount(0, $iterator); + } + + private function getTraversable($items) + { + foreach ($items as $item) { + yield $item; + } + } + + private function getTraversableThatThrows($items) + { + foreach ($items as $item) { + if ($item instanceof Exception) { + throw $item; + } else { + yield $item; + } + } + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/CollectionInfoTest.php b/vendor/mongodb/mongodb/tests/Model/CollectionInfoTest.php new file mode 100644 index 00000000..4cef402b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/CollectionInfoTest.php @@ -0,0 +1,53 @@ + 'foo']); + $this->assertSame('foo', $info->getName()); + } + + public function testGetOptions() + { + $info = new CollectionInfo(['name' => 'foo']); + $this->assertSame([], $info->getOptions()); + + $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576]]); + $this->assertSame(['capped' => true, 'size' => 1048576], $info->getOptions()); + } + + public function testCappedCollectionMethods() + { + $info = new CollectionInfo(['name' => 'foo']); + $this->assertFalse($info->isCapped()); + $this->assertNull($info->getCappedMax()); + $this->assertNull($info->getCappedSize()); + + $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576]]); + $this->assertTrue($info->isCapped()); + $this->assertNull($info->getCappedMax()); + $this->assertSame(1048576, $info->getCappedSize()); + + $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576, 'max' => 100]]); + $this->assertTrue($info->isCapped()); + $this->assertSame(100, $info->getCappedMax()); + $this->assertSame(1048576, $info->getCappedSize()); + } + + public function testDebugInfo() + { + $expectedInfo = [ + 'name' => 'foo', + 'options' => ['capped' => true, 'size' => 1048576], + ]; + + $info = new CollectionInfo($expectedInfo); + $this->assertSame($expectedInfo, $info->__debugInfo()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/DatabaseInfoTest.php b/vendor/mongodb/mongodb/tests/Model/DatabaseInfoTest.php new file mode 100644 index 00000000..3e779c2d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/DatabaseInfoTest.php @@ -0,0 +1,42 @@ + 'foo']); + $this->assertSame('foo', $info->getName()); + } + + public function testGetSizeOnDisk() + { + $info = new DatabaseInfo(['sizeOnDisk' => 1048576]); + $this->assertSame(1048576, $info->getSizeOnDisk()); + } + + public function testIsEmpty() + { + $info = new DatabaseInfo(['empty' => false]); + $this->assertFalse($info->isEmpty()); + + $info = new DatabaseInfo(['empty' => true]); + $this->assertTrue($info->isEmpty()); + } + + public function testDebugInfo() + { + $expectedInfo = [ + 'name' => 'foo', + 'sizeOnDisk' => 1048576, + 'empty' => false, + ]; + + $info = new DatabaseInfo($expectedInfo); + $this->assertSame($expectedInfo, $info->__debugInfo()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/IndexInfoTest.php b/vendor/mongodb/mongodb/tests/Model/IndexInfoTest.php new file mode 100644 index 00000000..1aa5f11f --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/IndexInfoTest.php @@ -0,0 +1,145 @@ + 1, + 'key' => ['x' => 1], + 'name' => 'x_1', + 'ns' => 'foo.bar', + ]); + + $this->assertSame(1, $info->getVersion()); + $this->assertSame(['x' => 1], $info->getKey()); + $this->assertSame('x_1', $info->getName()); + $this->assertSame('foo.bar', $info->getNamespace()); + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isTtl()); + $this->assertFalse($info->isUnique()); + } + + public function testSparseIndex() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['y' => 1], + 'name' => 'y_sparse', + 'ns' => 'foo.bar', + 'sparse' => true, + ]); + + $this->assertSame(1, $info->getVersion()); + $this->assertSame(['y' => 1], $info->getKey()); + $this->assertSame('y_sparse', $info->getName()); + $this->assertSame('foo.bar', $info->getNamespace()); + $this->assertTrue($info->isSparse()); + $this->assertFalse($info->isTtl()); + $this->assertFalse($info->isUnique()); + } + + public function testUniqueIndex() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['z' => 1], + 'name' => 'z_unique', + 'ns' => 'foo.bar', + 'unique' => true, + ]); + + $this->assertSame(1, $info->getVersion()); + $this->assertSame(['z' => 1], $info->getKey()); + $this->assertSame('z_unique', $info->getName()); + $this->assertSame('foo.bar', $info->getNamespace()); + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isTtl()); + $this->assertTrue($info->isUnique()); + } + + public function testTtlIndex() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['z' => 1], + 'name' => 'z_unique', + 'ns' => 'foo.bar', + 'expireAfterSeconds' => 100, + ]); + + $this->assertSame(1, $info->getVersion()); + $this->assertSame(['z' => 1], $info->getKey()); + $this->assertSame('z_unique', $info->getName()); + $this->assertSame('foo.bar', $info->getNamespace()); + $this->assertFalse($info->isSparse()); + $this->assertTrue($info->isTtl()); + $this->assertFalse($info->isUnique()); + $this->assertTrue(isset($info['expireAfterSeconds'])); + $this->assertSame(100, $info['expireAfterSeconds']); + } + + public function testDebugInfo() + { + $expectedInfo = [ + 'v' => 1, + 'key' => ['x' => 1], + 'name' => 'x_1', + 'ns' => 'foo.bar', + ]; + + $info = new IndexInfo($expectedInfo); + $this->assertSame($expectedInfo, $info->__debugInfo()); + } + + public function testImplementsArrayAccess() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['x' => 1], + 'name' => 'x_1', + 'ns' => 'foo.bar', + ]); + + $this->assertInstanceOf('ArrayAccess', $info); + $this->assertTrue(isset($info['name'])); + $this->assertSame('x_1', $info['name']); + } + + /** + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessage MongoDB\Model\IndexInfo is immutable + */ + public function testOffsetSetCannotBeCalled() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['x' => 1], + 'name' => 'x_1', + 'ns' => 'foo.bar', + ]); + + $info['v'] = 2; + } + + /** + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessage MongoDB\Model\IndexInfo is immutable + */ + public function testOffsetUnsetCannotBeCalled() + { + $info = new IndexInfo([ + 'v' => 1, + 'key' => ['x' => 1], + 'name' => 'x_1', + 'ns' => 'foo.bar', + ]); + + unset($info['v']); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/IndexInputTest.php b/vendor/mongodb/mongodb/tests/Model/IndexInputTest.php new file mode 100644 index 00000000..35df36c3 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/IndexInputTest.php @@ -0,0 +1,100 @@ + 'foo']); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidFieldOrderValues + */ + public function testConstructorShouldRequireKeyFieldOrderToBeNumericOrString($order) + { + new IndexInput(['key' => ['x' => $order]]); + } + + public function provideInvalidFieldOrderValues() + { + return $this->wrapValuesForDataProvider([true, [], new stdClass]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + */ + public function testConstructorShouldRequireNamespace() + { + new IndexInput(['key' => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + */ + public function testConstructorShouldRequireNamespaceToBeString() + { + new IndexInput(['key' => ['x' => 1], 'ns' => 1]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + */ + public function testConstructorShouldRequireNameToBeString() + { + new IndexInput(['key' => ['x' => 1], 'ns' => 'foo.bar', 'name' => 1]); + } + + /** + * @dataProvider provideExpectedNameAndKey + */ + public function testNameGeneration($expectedName, array $key) + { + $this->assertSame($expectedName, (string) new IndexInput(['key' => $key, 'ns' => 'foo.bar'])); + } + + public function provideExpectedNameAndKey() + { + return [ + ['x_1', ['x' => 1]], + ['x_1_y_-1', ['x' => 1, 'y' => -1]], + ['loc_2dsphere', ['loc' => '2dsphere']], + ['loc_2dsphere_x_1', ['loc' => '2dsphere', 'x' => 1]], + ['doc_text', ['doc' => 'text']], + ]; + } + + public function testBsonSerialization() + { + $expected = [ + 'key' => ['x' => 1], + 'ns' => 'foo.bar', + 'name' => 'x_1', + ]; + + $indexInput = new IndexInput([ + 'key' => ['x' => 1], + 'ns' => 'foo.bar', + ]); + + $this->assertInstanceOf('MongoDB\BSON\Serializable', $indexInput); + $this->assertEquals($expected, $indexInput->bsonSerialize()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Model/TypeMapArrayIteratorTest.php b/vendor/mongodb/mongodb/tests/Model/TypeMapArrayIteratorTest.php new file mode 100644 index 00000000..e15061bb --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Model/TypeMapArrayIteratorTest.php @@ -0,0 +1,33 @@ + [1, 2, 3], + 'object' => ['foo' => 'bar'], + ]; + + $typeMap = [ + 'root' => 'object', + 'document' => 'object', + 'array' => 'array', + ]; + + $iterator = new TypeMapArrayIterator([$document], $typeMap); + + $expectedDocument = (object) [ + 'array' => [1, 2, 3], + 'object' => (object) ['foo' => 'bar'], + ]; + + $iterator->rewind(); + + $this->assertEquals($expectedDocument, $iterator->current()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/AggregateFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/AggregateFunctionalTest.php new file mode 100644 index 00000000..989d556a --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/AggregateFunctionalTest.php @@ -0,0 +1,147 @@ +observe( + function() { + $operation = new Aggregate( + $this->getDatabaseName(), + $this->getCollectionName(), + [['$match' => ['x' => 1]]], + ['readConcern' => $this->createDefaultReadConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('readConcern', $command); + } + ); + } + + public function testDefaultWriteConcernIsOmitted() + { + if (version_compare($this->getServerVersion(), '2.6.0', '<')) { + $this->markTestSkipped('$out pipeline operator is not supported'); + } + + (new CommandObserver)->observe( + function() { + $operation = new Aggregate( + $this->getDatabaseName(), + $this->getCollectionName(), + [['$out' => $this->getCollectionName() . '.output']], + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + public function testEmptyPipelineReturnsAllDocuments() + { + $this->createFixtures(3); + + $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), []); + $results = iterator_to_array($operation->execute($this->getPrimaryServer())); + + $expectedDocuments = [ + (object) ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + (object) ['_id' => 2, 'x' => (object) ['foo' => 'bar']], + (object) ['_id' => 3, 'x' => (object) ['foo' => 'bar']], + ]; + + $this->assertEquals($expectedDocuments, $results); + } + + /** + * @expectedException MongoDB\Driver\Exception\RuntimeException + */ + public function testUnrecognizedPipelineState() + { + $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [['$foo' => 1]]); + $operation->execute($this->getPrimaryServer()); + } + + /** + * @dataProvider provideTypeMapOptionsAndExpectedDocuments + */ + public function testTypeMapOption(array $typeMap = null, array $expectedDocuments) + { + $this->createFixtures(3); + + $pipeline = [['$match' => ['_id' => ['$ne' => 2]]]]; + $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), $pipeline, ['typeMap' => $typeMap]); + $results = iterator_to_array($operation->execute($this->getPrimaryServer())); + + $this->assertEquals($expectedDocuments, $results); + } + + public function provideTypeMapOptionsAndExpectedDocuments() + { + return [ + [ + null, + [ + (object) ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + (object) ['_id' => 3, 'x' => (object) ['foo' => 'bar']], + ], + ], + [ + ['root' => 'array', 'document' => 'array'], + [ + ['_id' => 1, 'x' => ['foo' => 'bar']], + ['_id' => 3, 'x' => ['foo' => 'bar']], + ], + ], + [ + ['root' => 'object', 'document' => 'array'], + [ + (object) ['_id' => 1, 'x' => ['foo' => 'bar']], + (object) ['_id' => 3, 'x' => ['foo' => 'bar']], + ], + ], + [ + ['root' => 'array', 'document' => 'stdClass'], + [ + ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + ['_id' => 3, 'x' => (object) ['foo' => 'bar']], + ], + ], + ]; + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (object) ['foo' => 'bar'], + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/AggregateTest.php b/vendor/mongodb/mongodb/tests/Operation/AggregateTest.php new file mode 100644 index 00000000..b1f3fdc8 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/AggregateTest.php @@ -0,0 +1,101 @@ +getDatabaseName(), $this->getCollectionName(), [1 => ['$match' => ['x' => 1]]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [['$match' => ['x' => 1]]], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['allowDiskUse' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['batchSize' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['useCursor' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage "batchSize" option should not be used if "useCursor" is false + */ + public function testConstructorBatchSizeOptionRequiresUseCursor() + { + new Aggregate( + $this->getDatabaseName(), + $this->getCollectionName(), + [['$match' => ['x' => 1]]], + ['batchSize' => 100, 'useCursor' => false] + ); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage "typeMap" option should not be used if "useCursor" is false + */ + public function testConstructorTypeMapOptionRequiresUseCursor() + { + new Aggregate( + $this->getDatabaseName(), + $this->getCollectionName(), + [['$match' => ['x' => 1]]], + ['typeMap' => ['root' => 'array'], 'useCursor' => false] + ); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/BulkWriteFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/BulkWriteFunctionalTest.php new file mode 100644 index 00000000..cbd5aace --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/BulkWriteFunctionalTest.php @@ -0,0 +1,308 @@ +omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<'); + } + + public function testInserts() + { + $ops = [ + ['insertOne' => [['_id' => 1, 'x' => 11]]], + ['insertOne' => [['x' => 22]]], + ['insertOne' => [(object) ['_id' => 'foo', 'x' => 33]]], + ['insertOne' => [new BSONDocument(['_id' => 'bar', 'x' => 44])]], + ]; + + $operation = new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\BulkWriteResult', $result); + $this->assertSame(4, $result->getInsertedCount()); + + $insertedIds = $result->getInsertedIds(); + $this->assertSame(1, $insertedIds[0]); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $insertedIds[1]); + $this->assertSame('foo', $insertedIds[2]); + $this->assertSame('bar', $insertedIds[3]); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => $insertedIds[1], 'x' => 22], + ['_id' => 'foo', 'x' => 33], + ['_id' => 'bar', 'x' => 44], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUpdates() + { + $this->createFixtures(4); + + $ops = [ + ['updateOne' => [['_id' => 2], ['$inc' => ['x' => 1]]]], + ['updateMany' => [['_id' => ['$gt' => 2]], ['$inc' => ['x' => -1]]]], + ['updateOne' => [['_id' => 5], ['$set' => ['x' => 55]], ['upsert' => true]]], + ['updateOne' => [['x' => 66], ['$set' => ['x' => 66]], ['upsert' => true]]], + ['updateMany' => [['x' => ['$gt' => 50]], ['$inc' => ['x' => 1]]]], + ]; + + $operation = new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\BulkWriteResult', $result); + $this->assertSame(5, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(5, $result->getModifiedCount()); + $this->assertSame(2, $result->getUpsertedCount()); + + $upsertedIds = $result->getUpsertedIds(); + $this->assertSame(5, $upsertedIds[2]); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $upsertedIds[3]); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => 2, 'x' => 23], + ['_id' => 3, 'x' => 32], + ['_id' => 4, 'x' => 43], + ['_id' => 5, 'x' => 56], + ['_id' => $upsertedIds[3], 'x' => 67], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testDeletes() + { + $this->createFixtures(4); + + $ops = [ + ['deleteOne' => [['_id' => 1]]], + ['deleteMany' => [['_id' => ['$gt' => 2]]]], + ]; + + $operation = new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\BulkWriteResult', $result); + $this->assertSame(3, $result->getDeletedCount()); + + $expected = [ + ['_id' => 2, 'x' => 22], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testMixedOrderedOperations() + { + $this->createFixtures(3); + + $ops = [ + ['updateOne' => [['_id' => ['$gt' => 1]], ['$inc' => ['x' => 1]]]], + ['updateMany' => [['_id' => ['$gt' => 1]], ['$inc' => ['x' => 1]]]], + ['insertOne' => [['_id' => 4, 'x' => 44]]], + ['deleteMany' => [['x' => ['$nin' => [24, 34]]]]], + ['replaceOne' => [['_id' => 4], ['_id' => 4, 'x' => 44], ['upsert' => true]]], + ]; + + $operation = new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\BulkWriteResult', $result); + + $this->assertSame(1, $result->getInsertedCount()); + $this->assertSame([2 => 4], $result->getInsertedIds()); + + $this->assertSame(3, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(3, $result->getModifiedCount()); + $this->assertSame(1, $result->getUpsertedCount()); + $this->assertSame([4 => 4], $result->getUpsertedIds()); + + $this->assertSame(2, $result->getDeletedCount()); + + $expected = [ + ['_id' => 2, 'x' => 24], + ['_id' => 3, 'x' => 34], + ['_id' => 4, 'x' => 44], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUnacknowledgedWriteConcern() + { + $ops = [['insertOne' => [['_id' => 1]]]]; + $options = ['writeConcern' => new WriteConcern(0)]; + $operation = new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertFalse($result->isAcknowledged()); + + return $result; + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResult $result) + { + $result->getDeletedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResult $result) + { + $result->getInsertedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResult $result) + { + $result->getMatchedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteResult $result) + { + $result->getModifiedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteResult $result) + { + $result->getUpsertedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesUpsertedIds(BulkWriteResult $result) + { + $result->getUpsertedIds(); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Unknown operation type "foo" in $operations[0] + */ + public function testUnknownOperation() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + ['foo' => [['_id' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Missing (first|second) argument for \$operations\[\d+\]\["\w+\"]/ + * @dataProvider provideOpsWithMissingArguments + */ + public function testMissingArguments(array $ops) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), $ops); + } + + public function provideOpsWithMissingArguments() + { + return [ + [[['insertOne' => []]]], + [[['updateOne' => []]]], + [[['updateOne' => [['_id' => 1]]]]], + [[['updateMany' => []]]], + [[['updateMany' => [['_id' => 1]]]]], + [[['replaceOne' => []]]], + [[['replaceOne' => [['_id' => 1]]]]], + [[['deleteOne' => []]]], + [[['deleteMany' => []]]], + ]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["updateOne"][1] is not an update operator + */ + public function testUpdateOneRequiresUpdateOperators() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + ['updateOne' => [['_id' => 1], ['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["updateMany"][1] is not an update operator + */ + public function testUpdateManyRequiresUpdateOperators() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + ['updateMany' => [['_id' => ['$gt' => 1]], ['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["replaceOne"][1] is an update operator + */ + public function testReplaceOneRequiresReplacementDocument() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + ['replaceOne' => [['_id' => 1], ['$inc' => ['x' => 1]]]], + ]); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new Bulk(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (integer) ($i . $i), + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/BulkWriteTest.php b/vendor/mongodb/mongodb/tests/Operation/BulkWriteTest.php new file mode 100644 index 00000000..7fc73b81 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/BulkWriteTest.php @@ -0,0 +1,432 @@ +getDatabaseName(), $this->getCollectionName(), []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage $operations is not a list (unexpected index: "1") + */ + public function testOperationsMustBeAList() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + 1 => [BulkWrite::INSERT_ONE => [['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected one element in $operation[0], actually: 2 + */ + public function testMultipleOperationsInOneElement() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [ + BulkWrite::INSERT_ONE => [['x' => 1]], + BulkWrite::DELETE_ONE => [['x' => 1]], + ], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Unknown operation type "foo" in $operations[0] + */ + public function testUnknownOperation() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + ['foo' => [['_id' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["insertOne"] + */ + public function testInsertOneDocumentArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::INSERT_ONE => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["insertOne"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testInsertOneDocumentArgumentTypeCheck($document) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::INSERT_ONE => [$document]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["deleteMany"] + */ + public function testDeleteManyFilterArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_MANY => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["deleteMany"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testDeleteManyFilterArgumentTypeCheck($document) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_MANY => [$document]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["deleteMany"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testDeleteManyCollationOptionTypeCheck($collation) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_MANY => [['x' => 1], ['collation' => $collation]]], + ]); + } + + public function provideInvalidDocumentValues() + { + return $this->wrapValuesForDataProvider($this->getInvalidDocumentValues()); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["deleteOne"] + */ + public function testDeleteOneFilterArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_ONE => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["deleteOne"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testDeleteOneFilterArgumentTypeCheck($document) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_ONE => [$document]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["deleteOne"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testDeleteOneCollationOptionTypeCheck($collation) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::DELETE_ONE => [['x' => 1], ['collation' => $collation]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["replaceOne"] + */ + public function testReplaceOneFilterArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["replaceOne"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testReplaceOneFilterArgumentTypeCheck($filter) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [$filter, ['y' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing second argument for $operations[0]["replaceOne"] + */ + public function testReplaceOneReplacementArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["replaceOne"\]\[1\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testReplaceOneReplacementArgumentTypeCheck($replacement) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["replaceOne"][1] is an update operator + */ + public function testReplaceOneReplacementArgumentRequiresNoOperators() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [['_id' => 1], ['$inc' => ['x' => 1]]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["replaceOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testReplaceOneCollationOptionTypeCheck($collation) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [['x' => 1], ['y' => 1], ['collation' => $collation]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["replaceOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/ + * @dataProvider provideInvalidBooleanValues + */ + public function testReplaceOneUpsertOptionTypeCheck($upsert) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::REPLACE_ONE => [['x' => 1], ['y' => 1], ['upsert' => $upsert]]], + ]); + } + + public function provideInvalidBooleanValues() + { + return $this->wrapValuesForDataProvider($this->getInvalidBooleanValues()); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["updateMany"] + */ + public function testUpdateManyFilterArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateMany"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateManyFilterArgumentTypeCheck($filter) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [$filter, ['$set' => ['x' => 1]]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing second argument for $operations[0]["updateMany"] + */ + public function testUpdateManyUpdateArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateMany"\]\[1\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateManyUpdateArgumentTypeCheck($update) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [['x' => 1], $update]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["updateMany"][1] is not an update operator + */ + public function testUpdateManyUpdateArgumentRequiresOperators() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [['_id' => ['$gt' => 1]], ['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateMany"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateManyCollationOptionTypeCheck($collation) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [['x' => 1], ['$set' => ['x' => 1]], ['collation' => $collation]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateMany"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/ + * @dataProvider provideInvalidBooleanValues + */ + public function testUpdateManyUpsertOptionTypeCheck($upsert) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_MANY => [['x' => 1], ['$set' => ['x' => 1]], ['upsert' => $upsert]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing first argument for $operations[0]["updateOne"] + */ + public function testUpdateOneFilterArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => []], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateOne"\]\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateOneFilterArgumentTypeCheck($filter) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [$filter, ['$set' => ['x' => 1]]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage Missing second argument for $operations[0]["updateOne"] + */ + public function testUpdateOneUpdateArgumentMissing() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateOne"\]\[1\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateOneUpdateArgumentTypeCheck($update) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [['x' => 1], $update]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $operations[0]["updateOne"][1] is not an update operator + */ + public function testUpdateOneUpdateArgumentRequiresOperators() + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [['_id' => 1], ['x' => 1]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testUpdateOneCollationOptionTypeCheck($collation) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [['x' => 1], ['$set' => ['x' => 1]], ['collation' => $collation]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$operations\[0\]\["updateOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/ + * @dataProvider provideInvalidBooleanValues + */ + public function testUpdateOneUpsertOptionTypeCheck($upsert) + { + new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ + [BulkWrite::UPDATE_ONE => [['x' => 1], ['$set' => ['x' => 1]], ['upsert' => $upsert]]], + ]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new BulkWrite( + $this->getDatabaseName(), + $this->getCollectionName(), + [[BulkWrite::INSERT_ONE => [['x' => 1]]]], + $options + ); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['ordered' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CountFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/CountFunctionalTest.php new file mode 100644 index 00000000..cc0fbc1d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CountFunctionalTest.php @@ -0,0 +1,76 @@ +observe( + function() { + $operation = new Count( + $this->getDatabaseName(), + $this->getCollectionName(), + [], + ['readConcern' => $this->createDefaultReadConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('readConcern', $command); + } + ); + } + + public function testHintOption() + { + if (version_compare($this->getServerVersion(), '2.6.0', '<')) { + $this->markTestSkipped('count command does not support "hint" option'); + } + + $insertMany = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [ + ['x' => 1], + ['x' => 2], + ['y' => 3], + ]); + $insertMany->execute($this->getPrimaryServer()); + + $createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [ + ['key' => ['x' => 1], 'sparse' => true, 'name' => 'sparse_x'], + ['key' => ['y' => 1]], + ]); + $createIndexes->execute($this->getPrimaryServer()); + + $hintsUsingSparseIndex = [ + ['x' => 1], + 'sparse_x', + ]; + + /* Per SERVER-22041, the count command in server versions before 3.3.2 + * may ignore the hint option if its query predicate is empty. */ + $filter = ['_id' => ['$exists' => true]]; + + foreach ($hintsUsingSparseIndex as $hint) { + $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), $filter, ['hint' => $hint]); + $this->assertEquals(2, $operation->execute($this->getPrimaryServer())); + } + + $hintsNotUsingSparseIndex = [ + ['_id' => 1], + ['y' => 1], + 'y_1', + ]; + + foreach ($hintsNotUsingSparseIndex as $hint) { + $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), $filter, ['hint' => $hint]); + $this->assertEquals(3, $operation->execute($this->getPrimaryServer())); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CountTest.php b/vendor/mongodb/mongodb/tests/Operation/CountTest.php new file mode 100644 index 00000000..1bd52d50 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CountTest.php @@ -0,0 +1,66 @@ +getDatabaseName(), $this->getCollectionName(), $filter); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Count($this->getDatabaseName(), $this->getCollectionName(), [], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidHintValues() as $value) { + $options[][] = ['hint' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['limit' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['skip' => $value]; + } + + return $options; + } + + private function getInvalidHintValues() + { + return [123, 3.14, true]; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CreateCollectionFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/CreateCollectionFunctionalTest.php new file mode 100644 index 00000000..bfe42ccc --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CreateCollectionFunctionalTest.php @@ -0,0 +1,28 @@ +observe( + function() { + $operation = new CreateCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CreateCollectionTest.php b/vendor/mongodb/mongodb/tests/Operation/CreateCollectionTest.php new file mode 100644 index 00000000..09cc5536 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CreateCollectionTest.php @@ -0,0 +1,80 @@ +getDatabaseName(), $this->getCollectionName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['autoIndexId' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['capped' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['flags' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['indexOptionDefaults' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['max' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['size' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['storageEngine' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['validationAction' => $value]; + } + + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['validationLevel' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['validator' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CreateIndexesFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/CreateIndexesFunctionalTest.php new file mode 100644 index 00000000..1064a19d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CreateIndexesFunctionalTest.php @@ -0,0 +1,223 @@ + ['x' => 1], 'sparse' => true, 'unique' => true]]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('x_1', $createdIndexNames[0]); + $this->assertIndexExists('x_1', function(IndexInfo $info) { + $this->assertTrue($info->isSparse()); + $this->assertTrue($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + } + + public function testCreateCompoundIndex() + { + $indexes = [['key' => ['y' => -1, 'z' => 1]]]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('y_-1_z_1', $createdIndexNames[0]); + $this->assertIndexExists('y_-1_z_1', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + } + + public function testCreateGeospatialIndex() + { + $indexes = [['key' => ['g' => '2dsphere', 'z' => 1]]]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('g_2dsphere_z_1', $createdIndexNames[0]); + $this->assertIndexExists('g_2dsphere_z_1', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + } + + public function testCreateTTLIndex() + { + $indexes = [['key' => ['t' => 1], 'expireAfterSeconds' => 0, 'name' => 'my_ttl']]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('my_ttl', $createdIndexNames[0]); + $this->assertIndexExists('my_ttl', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertTrue($info->isTtl()); + }); + } + + public function testCreateIndexes() + { + $expectedNames = ['x_1', 'y_-1_z_1', 'g_2dsphere_z_1', 'my_ttl']; + + $indexes = [ + ['key' => ['x' => 1], 'sparse' => true, 'unique' => true], + ['key' => ['y' => -1, 'z' => 1]], + ['key' => ['g' => '2dsphere', 'z' => 1]], + ['key' => ['t' => 1], 'expireAfterSeconds' => 0, 'name' => 'my_ttl'], + ]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame($expectedNames, $createdIndexNames); + + $this->assertIndexExists('x_1', function(IndexInfo $info) { + $this->assertTrue($info->isSparse()); + $this->assertTrue($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + + $this->assertIndexExists('y_-1_z_1', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + + $this->assertIndexExists('g_2dsphere_z_1', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + + $this->assertIndexExists('my_ttl', function(IndexInfo $info) { + $this->assertFalse($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertTrue($info->isTtl()); + }); + } + + /** + * @expectedException MongoDB\Driver\Exception\RuntimeException + */ + public function testCreateConflictingIndexesWithCommand() + { + if ( ! \MongoDB\server_supports_feature($this->getPrimaryServer(), self::$wireVersionForCommand)) { + $this->markTestSkipped('createIndexes command is not supported'); + } + + $indexes = [ + ['key' => ['x' => 1], 'sparse' => true, 'unique' => false], + ['key' => ['x' => 1], 'sparse' => false, 'unique' => true], + ]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + } + + public function testCreateConflictingIndexesWithLegacyInsert() + { + if (\MongoDB\server_supports_feature($this->getPrimaryServer(), self::$wireVersionForCommand)) { + $this->markTestSkipped('Index creation does not use legacy insertion'); + } + + $indexes = [ + ['key' => ['x' => 1], 'sparse' => true, 'unique' => false], + ['key' => ['x' => 1], 'sparse' => false, 'unique' => true], + ]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + /* When creating indexes with legacy insert operations, the server + * ignores conflicting index specifications and leaves the original + * index in place. + */ + $this->assertSame('x_1', $createdIndexNames[0]); + $this->assertIndexExists('x_1', function(IndexInfo $info) { + $this->assertTrue($info->isSparse()); + $this->assertFalse($info->isUnique()); + $this->assertFalse($info->isTtl()); + }); + } + + public function testDefaultWriteConcernIsOmitted() + { + /* Earlier server versions do not support the createIndexes command. Per + * the Index Management specification, inserts on system.indexes must + * use the write concern {w:1}. */ + if ( ! \MongoDB\server_supports_feature($this->getPrimaryServer(), self::$wireVersionForCommand)) { + $this->markTestSkipped('createIndexes command is not supported'); + } + + (new CommandObserver)->observe( + function() { + $operation = new CreateIndexes( + $this->getDatabaseName(), + $this->getCollectionName(), + [['key' => ['x' => 1]]], + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + /** + * Asserts that an index with the given name exists for the collection. + * + * An optional $callback may be provided, which should take an IndexInfo + * argument as its first and only parameter. If an IndexInfo matching the + * given name is found, it will be passed to the callback, which may perform + * additional assertions. + * + * @param string $indexName + * @param callable $callback + */ + private function assertIndexExists($indexName, $callback = null) + { + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + $foundIndex = null; + + foreach ($indexes as $index) { + if ($index->getName() === $indexName) { + $foundIndex = $index; + break; + } + } + + $this->assertNotNull($foundIndex, sprintf('Index %s does not exist', $indexName)); + + if ($callback !== null) { + call_user_func($callback, $foundIndex); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/CreateIndexesTest.php b/vendor/mongodb/mongodb/tests/Operation/CreateIndexesTest.php new file mode 100644 index 00000000..a347fa7d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/CreateIndexesTest.php @@ -0,0 +1,60 @@ +getDatabaseName(), $this->getCollectionName(), [1 => ['key' => ['x' => 1]]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1]]], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage $indexes is empty + */ + public function testConstructorRequiresAtLeastOneIndex() + { + new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidIndexSpecificationTypes + */ + public function testConstructorRequiresIndexSpecificationsToBeAnArray($index) + { + new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [$index]); + } + + public function provideInvalidIndexSpecificationTypes() + { + return $this->wrapValuesForDataProvider($this->getInvalidArrayValues()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DatabaseCommandTest.php b/vendor/mongodb/mongodb/tests/Operation/DatabaseCommandTest.php new file mode 100644 index 00000000..fddeb3a6 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DatabaseCommandTest.php @@ -0,0 +1,41 @@ +getDatabaseName(), $command); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new DatabaseCommand($this->getDatabaseName(), ['ping' => 1], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DeleteFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/DeleteFunctionalTest.php new file mode 100644 index 00000000..588083f1 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DeleteFunctionalTest.php @@ -0,0 +1,94 @@ +createFixtures(3); + + $filter = ['_id' => 1]; + + $operation = new Delete($this->getDatabaseName(), $this->getCollectionName(), $filter, 1); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\DeleteResult', $result); + $this->assertSame(1, $result->getDeletedCount()); + + $expected = [ + ['_id' => 2, 'x' => 22], + ['_id' => 3, 'x' => 33], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testDeleteMany() + { + $this->createFixtures(3); + + $filter = ['_id' => ['$gt' => 1]]; + + $operation = new Delete($this->getDatabaseName(), $this->getCollectionName(), $filter, 0); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\DeleteResult', $result); + $this->assertSame(2, $result->getDeletedCount()); + + $expected = [ + ['_id' => 1, 'x' => 11], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUnacknowledgedWriteConcern() + { + $filter = ['_id' => 1]; + $options = ['writeConcern' => new WriteConcern(0)]; + + $operation = new Delete($this->getDatabaseName(), $this->getCollectionName(), $filter, 0, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertFalse($result->isAcknowledged()); + + return $result; + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult $result) + { + $result->getDeletedCount(); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (integer) ($i . $i), + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DeleteTest.php b/vendor/mongodb/mongodb/tests/Operation/DeleteTest.php new file mode 100644 index 00000000..0af26dc2 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DeleteTest.php @@ -0,0 +1,56 @@ +getDatabaseName(), $this->getCollectionName(), $filter, 0); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage $limit must be 0 or 1 + * @dataProvider provideInvalidLimitValues + */ + public function testConstructorLimitArgumentMustBeOneOrZero($limit) + { + new Delete($this->getDatabaseName(), $this->getCollectionName(), [], $limit); + } + + public function provideInvalidLimitValues() + { + return $this->wrapValuesForDataProvider(array_merge($this->getInvalidIntegerValues(), [-1, 2])); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Delete($this->getDatabaseName(), $this->getCollectionName(), [], 1, $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DistinctFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/DistinctFunctionalTest.php new file mode 100644 index 00000000..4430c6f7 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DistinctFunctionalTest.php @@ -0,0 +1,30 @@ +observe( + function() { + $operation = new Distinct( + $this->getDatabaseName(), + $this->getCollectionName(), + 'x', + [], + ['readConcern' => $this->createDefaultReadConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('readConcern', $command); + } + ); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DistinctTest.php b/vendor/mongodb/mongodb/tests/Operation/DistinctTest.php new file mode 100644 index 00000000..8d6eec1c --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DistinctTest.php @@ -0,0 +1,49 @@ +getDatabaseName(), $this->getCollectionName(), 'x', $filter); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', [], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropCollectionFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/DropCollectionFunctionalTest.php new file mode 100644 index 00000000..270e1a42 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropCollectionFunctionalTest.php @@ -0,0 +1,78 @@ +observe( + function() { + $operation = new DropCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + public function testDropExistingCollection() + { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($server); + + $this->assertCollectionDoesNotExist($this->getCollectionName()); + } + + /** + * @depends testDropExistingCollection + */ + public function testDropNonexistentCollection() + { + $this->assertCollectionDoesNotExist($this->getCollectionName()); + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + /** + * Asserts that a collection with the given name does not exist on the + * server. + * + * @param string $collectionName + */ + private function assertCollectionDoesNotExist($collectionName) + { + $operation = new ListCollections($this->getDatabaseName()); + $collections = $operation->execute($this->getPrimaryServer()); + + $foundCollection = null; + + foreach ($collections as $collection) { + if ($collection->getName() === $collectionName) { + $foundCollection = $collection; + break; + } + } + + $this->assertNull($foundCollection, sprintf('Collection %s exists', $collectionName)); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropCollectionTest.php b/vendor/mongodb/mongodb/tests/Operation/DropCollectionTest.php new file mode 100644 index 00000000..097fe9fd --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropCollectionTest.php @@ -0,0 +1,32 @@ +getDatabaseName(), $this->getCollectionName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropDatabaseFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/DropDatabaseFunctionalTest.php new file mode 100644 index 00000000..8be8f61b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropDatabaseFunctionalTest.php @@ -0,0 +1,83 @@ +observe( + function() { + $operation = new DropDatabase( + $this->getDatabaseName(), + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + public function testDropExistingDatabase() + { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new DropDatabase($this->getDatabaseName()); + $operation->execute($server); + + $this->assertDatabaseDoesNotExist($server, $this->getDatabaseName()); + } + + /** + * @depends testDropExistingDatabase + */ + public function testDropNonexistentDatabase() + { + $server = $this->getPrimaryServer(); + + $operation = new DropDatabase($this->getDatabaseName()); + $operation->execute($server); + + $this->assertDatabaseDoesNotExist($server, $this->getDatabaseName()); + + $operation = new DropDatabase($this->getDatabaseName()); + $operation->execute($server); + } + + /** + * Asserts that a database with the given name does not exist on the server. + * + * @param Server $server + * @param string $databaseName + */ + private function assertDatabaseDoesNotExist(Server $server, $databaseName) + { + $operation = new ListDatabases(); + $databases = $operation->execute($server); + + $foundDatabase = null; + + foreach ($databases as $database) { + if ($database->getName() === $databaseName) { + $foundDatabase = $database; + break; + } + } + + $this->assertNull($foundDatabase, sprintf('Database %s exists on the server', $databaseName)); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropDatabaseTest.php b/vendor/mongodb/mongodb/tests/Operation/DropDatabaseTest.php new file mode 100644 index 00000000..424cf31d --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropDatabaseTest.php @@ -0,0 +1,32 @@ +getDatabaseName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropIndexesFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/DropIndexesFunctionalTest.php new file mode 100644 index 00000000..1806290b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropIndexesFunctionalTest.php @@ -0,0 +1,125 @@ +getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1]]]); + $operation->execute($this->getPrimaryServer()); + + (new CommandObserver)->observe( + function() { + $operation = new DropIndexes( + $this->getDatabaseName(), + $this->getCollectionName(), + 'x_1', + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + public function testDropOneIndexByName() + { + $indexes = [['key' => ['x' => 1]]]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('x_1', $createdIndexNames[0]); + $this->assertIndexExists('x_1'); + + $operation = new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), 'x_1'); + $this->assertCommandSucceeded($operation->execute($this->getPrimaryServer())); + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + foreach ($indexes as $index) { + if ($index->getName() === 'x_1') { + $this->fail('The "x_1" index should have been deleted'); + } + } + } + + public function testDropAllIndexesByWildcard() + { + $indexes = [ + ['key' => ['x' => 1]], + ['key' => ['y' => 1]], + ]; + + $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes); + $createdIndexNames = $operation->execute($this->getPrimaryServer()); + + $this->assertSame('x_1', $createdIndexNames[0]); + $this->assertSame('y_1', $createdIndexNames[1]); + $this->assertIndexExists('x_1'); + $this->assertIndexExists('y_1'); + + $operation = new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), '*'); + $this->assertCommandSucceeded($operation->execute($this->getPrimaryServer())); + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + foreach ($indexes as $index) { + if ($index->getName() === 'x_1') { + $this->fail('The "x_1" index should have been deleted'); + } + + if ($index->getName() === 'y_1') { + $this->fail('The "y_1" index should have been deleted'); + } + } + } + + /** + * Asserts that an index with the given name exists for the collection. + * + * An optional $callback may be provided, which should take an IndexInfo + * argument as its first and only parameter. If an IndexInfo matching the + * given name is found, it will be passed to the callback, which may perform + * additional assertions. + * + * @param callable $callback + */ + private function assertIndexExists($indexName, $callback = null) + { + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + $foundIndex = null; + + foreach ($indexes as $index) { + if ($index->getName() === $indexName) { + $foundIndex = $index; + break; + } + } + + $this->assertNotNull($foundIndex, sprintf('Found %s index for the collection', $indexName)); + + if ($callback !== null) { + call_user_func($callback, $foundIndex); + } + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/DropIndexesTest.php b/vendor/mongodb/mongodb/tests/Operation/DropIndexesTest.php new file mode 100644 index 00000000..dd1cf8e3 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/DropIndexesTest.php @@ -0,0 +1,40 @@ +getDatabaseName(), $this->getCollectionName(), ''); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), '*', $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindAndModifyFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/FindAndModifyFunctionalTest.php new file mode 100644 index 00000000..549a9e2c --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindAndModifyFunctionalTest.php @@ -0,0 +1,97 @@ +observe( + function() { + $operation = new FindAndModify( + $this->getDatabaseName(), + $this->getCollectionName(), + ['remove' => true, 'writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + } + + /** + * @dataProvider provideTypeMapOptionsAndExpectedDocument + */ + public function testTypeMapOption(array $typeMap = null, $expectedDocument) + { + $this->createFixtures(1); + + $operation = new FindAndModify( + $this->getDatabaseName(), + $this->getCollectionName(), + [ + 'remove' => true, + 'typeMap' => $typeMap, + ] + ); + $document = $operation->execute($this->getPrimaryServer()); + + $this->assertEquals($expectedDocument, $document); + } + + public function provideTypeMapOptionsAndExpectedDocument() + { + return [ + [ + null, + (object) ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + ], + [ + ['root' => 'array', 'document' => 'array'], + ['_id' => 1, 'x' => ['foo' => 'bar']], + ], + [ + ['root' => 'object', 'document' => 'array'], + (object) ['_id' => 1, 'x' => ['foo' => 'bar']], + ], + [ + ['root' => 'array', 'document' => 'stdClass'], + ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + ], + [ + ['root' => 'MongoDB\Model\BSONDocument', 'document' => 'object'], + new BSONDocument(['_id' => 1, 'x' => (object) ['foo' => 'bar']]), + ], + ]; + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (object) ['foo' => 'bar'], + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindAndModifyTest.php b/vendor/mongodb/mongodb/tests/Operation/FindAndModifyTest.php new file mode 100644 index 00000000..9c8378db --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindAndModifyTest.php @@ -0,0 +1,81 @@ +getDatabaseName(), $this->getCollectionName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['fields' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['new' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['query' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['remove' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['sort' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['update' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['upsert' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage The "remove" option must be true or an "update" document must be specified, but not both + */ + public function testConstructorUpdateAndRemoveOptionsAreMutuallyExclusive() + { + new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), ['remove' => true, 'update' => []]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/FindFunctionalTest.php new file mode 100644 index 00000000..3d524931 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindFunctionalTest.php @@ -0,0 +1,185 @@ +observe( + function() { + $operation = new Find( + $this->getDatabaseName(), + $this->getCollectionName(), + [], + ['readConcern' => $this->createDefaultReadConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('readConcern', $command); + } + ); + } + + public function testHintOption() + { + $bulkWrite = new BulkWrite; + $bulkWrite->insert(['_id' => 1, 'x' => 1]); + $bulkWrite->insert(['_id' => 2, 'x' => 2]); + $bulkWrite->insert(['_id' => 3, 'y' => 3]); + $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [ + ['key' => ['x' => 1], 'sparse' => true, 'name' => 'sparse_x'], + ['key' => ['y' => 1]], + ]); + $createIndexes->execute($this->getPrimaryServer()); + + $hintsUsingSparseIndex = [ + ['x' => 1], + 'sparse_x', + ]; + + foreach ($hintsUsingSparseIndex as $hint) { + $operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]); + $cursor = $operation->execute($this->getPrimaryServer()); + + $expectedDocuments = [ + (object) ['_id' => 1, 'x' => 1], + (object) ['_id' => 2, 'x' => 2], + ]; + + $this->assertEquals($expectedDocuments, $cursor->toArray()); + } + + $hintsNotUsingSparseIndex = [ + ['_id' => 1], + ['y' => 1], + 'y_1', + ]; + + foreach ($hintsNotUsingSparseIndex as $hint) { + $operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]); + $cursor = $operation->execute($this->getPrimaryServer()); + + $expectedDocuments = [ + (object) ['_id' => 1, 'x' => 1], + (object) ['_id' => 2, 'x' => 2], + (object) ['_id' => 3, 'y' => 3], + ]; + + $this->assertEquals($expectedDocuments, $cursor->toArray()); + } + } + + /** + * @dataProvider provideTypeMapOptionsAndExpectedDocuments + */ + public function testTypeMapOption(array $typeMap, array $expectedDocuments) + { + $this->createFixtures(3); + + $operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['typeMap' => $typeMap]); + $cursor = $operation->execute($this->getPrimaryServer()); + + $this->assertEquals($expectedDocuments, $cursor->toArray()); + } + + public function provideTypeMapOptionsAndExpectedDocuments() + { + return [ + [ + ['root' => 'array', 'document' => 'array'], + [ + ['_id' => 1, 'x' => ['foo' => 'bar']], + ['_id' => 2, 'x' => ['foo' => 'bar']], + ['_id' => 3, 'x' => ['foo' => 'bar']], + ], + ], + [ + ['root' => 'object', 'document' => 'array'], + [ + (object) ['_id' => 1, 'x' => ['foo' => 'bar']], + (object) ['_id' => 2, 'x' => ['foo' => 'bar']], + (object) ['_id' => 3, 'x' => ['foo' => 'bar']], + ], + ], + [ + ['root' => 'array', 'document' => 'stdClass'], + [ + ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + ['_id' => 2, 'x' => (object) ['foo' => 'bar']], + ['_id' => 3, 'x' => (object) ['foo' => 'bar']], + ], + ], + ]; + } + + public function testMaxAwaitTimeMS() + { + if (version_compare($this->getServerVersion(), '3.2.0', '<')) { + $this->markTestSkipped('maxAwaitTimeMS option is not supported'); + } + + $maxAwaitTimeMS = 10; + + // Create a capped collection. + $databaseName = $this->getDatabaseName(); + $cappedCollectionName = $this->getCollectionName(); + $cappedCollectionOptions = [ + 'capped' => true, + 'max' => 100, + 'size' => 1048576, + ]; + + $operation = new CreateCollection($databaseName, $cappedCollectionName, $cappedCollectionOptions); + $operation->execute($this->getPrimaryServer()); + + // Insert documents into the capped collection. + $bulkWrite = new BulkWrite(['ordered' => true]); + $bulkWrite->insert(['_id' => 1]); + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $operation = new Find($databaseName, $cappedCollectionName, [], ['cursorType' => Find::TAILABLE_AWAIT, 'maxAwaitTimeMS' => $maxAwaitTimeMS]); + $cursor = $operation->execute($this->getPrimaryServer()); + $it = new \IteratorIterator($cursor); + + // Make sure we await results for no more than the maxAwaitTimeMS. + $it->rewind(); + $it->next(); + $startTime = microtime(true); + $it->next(); + $this->assertGreaterThanOrEqual($maxAwaitTimeMS * 0.001, microtime(true) - $startTime); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (object) ['foo' => 'bar'], + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindOneAndDeleteTest.php b/vendor/mongodb/mongodb/tests/Operation/FindOneAndDeleteTest.php new file mode 100644 index 00000000..af040677 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindOneAndDeleteTest.php @@ -0,0 +1,37 @@ +getDatabaseName(), $this->getCollectionName(), $filter); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), [], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['projection' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindOneAndReplaceTest.php b/vendor/mongodb/mongodb/tests/Operation/FindOneAndReplaceTest.php new file mode 100644 index 00000000..201b5078 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindOneAndReplaceTest.php @@ -0,0 +1,73 @@ +getDatabaseName(), $this->getCollectionName(), $filter, []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorReplacementArgumentTypeCheck($replacement) + { + new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $replacement argument is an update operator + */ + public function testConstructorReplacementArgumentRequiresNoOperators() + { + new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], ['$set' => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], [], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['projection' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['returnDocument' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorReturnDocumentOptions + */ + public function testConstructorReturnDocumentOption($returnDocument) + { + new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], [], ['returnDocument' => $returnDocument]); + } + + public function provideInvalidConstructorReturnDocumentOptions() + { + return $this->wrapValuesForDataProvider([-1, 0, 3]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindOneAndUpdateTest.php b/vendor/mongodb/mongodb/tests/Operation/FindOneAndUpdateTest.php new file mode 100644 index 00000000..317ed5cf --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindOneAndUpdateTest.php @@ -0,0 +1,73 @@ +getDatabaseName(), $this->getCollectionName(), $filter, []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorUpdateArgumentTypeCheck($update) + { + new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $update argument is not an update operator + */ + public function testConstructorUpdateArgumentRequiresOperators() + { + new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], ['$set' => ['x' => 1]], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['projection' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['returnDocument' => $value]; + } + + return $options; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorReturnDocumentOptions + */ + public function testConstructorReturnDocumentOption($returnDocument) + { + new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], [], ['returnDocument' => $returnDocument]); + } + + public function provideInvalidConstructorReturnDocumentOptions() + { + return $this->wrapValuesForDataProvider([-1, 0, 3]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindOneFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/FindOneFunctionalTest.php new file mode 100644 index 00000000..62fac828 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindOneFunctionalTest.php @@ -0,0 +1,61 @@ +createFixtures(1); + + $operation = new FindOne($this->getDatabaseName(), $this->getCollectionName(), [], ['typeMap' => $typeMap]); + $document = $operation->execute($this->getPrimaryServer()); + + $this->assertEquals($expectedDocument, $document); + } + + public function provideTypeMapOptionsAndExpectedDocument() + { + return [ + [ + ['root' => 'array', 'document' => 'array'], + ['_id' => 1, 'x' => ['foo' => 'bar']], + ], + [ + ['root' => 'object', 'document' => 'array'], + (object) ['_id' => 1, 'x' => ['foo' => 'bar']], + ], + [ + ['root' => 'array', 'document' => 'stdClass'], + ['_id' => 1, 'x' => (object) ['foo' => 'bar']], + ], + ]; + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (object) ['foo' => 'bar'], + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FindTest.php b/vendor/mongodb/mongodb/tests/Operation/FindTest.php new file mode 100644 index 00000000..379a35ff --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FindTest.php @@ -0,0 +1,144 @@ +getDatabaseName(), $this->getCollectionName(), $filter); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Find($this->getDatabaseName(), $this->getCollectionName(), [], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['allowPartialResults' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['batchSize' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['comment' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['cursorType' => $value]; + } + + foreach ($this->getInvalidHintValues() as $value) { + $options[][] = ['hint' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['limit' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['max' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxAwaitTimeMS' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxScan' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['min' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['modifiers' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['oplogReplay' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['projection' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['returnKey' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['showRecordId' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['skip' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['snapshot' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['sort' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + return $options; + } + + private function getInvalidHintValues() + { + return [123, 3.14, true]; + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorCursorTypeOptions + */ + public function testConstructorCursorTypeOption($cursorType) + { + new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['cursorType' => $cursorType]); + } + + public function provideInvalidConstructorCursorTypeOptions() + { + return $this->wrapValuesForDataProvider([-1, 0, 4]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/FunctionalTestCase.php b/vendor/mongodb/mongodb/tests/Operation/FunctionalTestCase.php new file mode 100644 index 00000000..3c100cb1 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/FunctionalTestCase.php @@ -0,0 +1,44 @@ +getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + public function tearDown() + { + if ($this->hasFailed()) { + return; + } + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + } + + protected function createDefaultReadConcern() + { + return new ReadConcern; + } + + protected function createDefaultWriteConcern() + { + return new WriteConcern(-2); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/InsertManyFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/InsertManyFunctionalTest.php new file mode 100644 index 00000000..fb7a535e --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/InsertManyFunctionalTest.php @@ -0,0 +1,73 @@ + 'foo', 'x' => 11], + ['x' => 22], + (object) ['_id' => 'bar', 'x' => 33], + new BSONDocument(['_id' => 'baz', 'x' => 44]), + ]; + + $operation = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), $documents); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\InsertManyResult', $result); + $this->assertSame(4, $result->getInsertedCount()); + + $insertedIds = $result->getInsertedIds(); + $this->assertSame('foo', $insertedIds[0]); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $insertedIds[1]); + $this->assertSame('bar', $insertedIds[2]); + $this->assertSame('baz', $insertedIds[3]); + + $expected = [ + ['_id' => 'foo', 'x' => 11], + ['_id' => $insertedIds[1], 'x' => 22], + ['_id' => 'bar', 'x' => 33], + ['_id' => 'baz', 'x' => 44], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUnacknowledgedWriteConcern() + { + $documents = [['x' => 11]]; + $options = ['writeConcern' => new WriteConcern(0)]; + + $operation = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), $documents, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertFalse($result->isAcknowledged()); + + return $result; + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyResult $result) + { + $result->getInsertedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + */ + public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertManyResult $result) + { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $result->getInsertedIds()[0]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/InsertManyTest.php b/vendor/mongodb/mongodb/tests/Operation/InsertManyTest.php new file mode 100644 index 00000000..66fa4ba1 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/InsertManyTest.php @@ -0,0 +1,64 @@ +getDatabaseName(), $this->getCollectionName(), []); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage $documents is not a list (unexpected index: "1") + */ + public function testConstructorDocumentsMustBeAList() + { + new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [1 => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$documents\[0\] to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorDocumentsArgumentElementTypeChecks($document) + { + new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [$document]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [['x' => 1]], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['ordered' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/InsertOneFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/InsertOneFunctionalTest.php new file mode 100644 index 00000000..f7f362cd --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/InsertOneFunctionalTest.php @@ -0,0 +1,88 @@ +getDatabaseName(), $this->getCollectionName(), $document); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\InsertOneResult', $result); + $this->assertSame(1, $result->getInsertedCount()); + $this->assertSame('foo', $result->getInsertedId()); + + $expected = [ + ['_id' => 'foo', 'x' => 11], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function provideDocumentWithExistingId() + { + return [ + [['_id' => 'foo', 'x' => 11]], + [(object) ['_id' => 'foo', 'x' => 11]], + [new BSONDocument(['_id' => 'foo', 'x' => 11])], + ]; + } + + public function testInsertOneWithGeneratedId() + { + $document = ['x' => 11]; + + $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\InsertOneResult', $result); + $this->assertSame(1, $result->getInsertedCount()); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $result->getInsertedId()); + + $expected = [ + ['_id' => $result->getInsertedId(), 'x' => 11], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUnacknowledgedWriteConcern() + { + $document = ['x' => 11]; + $options = ['writeConcern' => new WriteConcern(0)]; + + $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertFalse($result->isAcknowledged()); + + return $result; + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneResult $result) + { + $result->getInsertedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + */ + public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertOneResult $result) + { + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $result->getInsertedId()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/InsertOneTest.php b/vendor/mongodb/mongodb/tests/Operation/InsertOneTest.php new file mode 100644 index 00000000..ba1ae90b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/InsertOneTest.php @@ -0,0 +1,41 @@ +getDatabaseName(), $this->getCollectionName(), $document); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/ListCollectionsFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/ListCollectionsFunctionalTest.php new file mode 100644 index 00000000..b597e42c --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/ListCollectionsFunctionalTest.php @@ -0,0 +1,47 @@ +getPrimaryServer(); + + $operation = new DropDatabase($this->getDatabaseName()); + $operation->execute($server); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new ListCollections($this->getDatabaseName(), ['filter' => ['name' => $this->getCollectionName()]]); + $collections = $operation->execute($server); + + $this->assertInstanceOf('MongoDB\Model\CollectionInfoIterator', $collections); + + $this->assertCount(1, $collections); + + foreach ($collections as $collection) { + $this->assertInstanceOf('MongoDB\Model\CollectionInfo', $collection); + $this->assertEquals($this->getCollectionName(), $collection->getName()); + } + } + + public function testListCollectionsForNonexistentDatabase() + { + $server = $this->getPrimaryServer(); + + $operation = new DropDatabase($this->getDatabaseName()); + $operation->execute($server); + + $operation = new ListCollections($this->getDatabaseName()); + $collections = $operation->execute($server); + + $this->assertCount(0, $collections); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/ListDatabasesTest.php b/vendor/mongodb/mongodb/tests/Operation/ListDatabasesTest.php new file mode 100644 index 00000000..302676da --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/ListDatabasesTest.php @@ -0,0 +1,28 @@ +getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/ListIndexesFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/ListIndexesFunctionalTest.php new file mode 100644 index 00000000..33f9f079 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/ListIndexesFunctionalTest.php @@ -0,0 +1,43 @@ +getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($this->getPrimaryServer()); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\Model\IndexInfoIterator', $indexes); + + $this->assertCount(1, $indexes); + + foreach ($indexes as $index) { + $this->assertInstanceOf('MongoDB\Model\IndexInfo', $index); + $this->assertEquals(['_id' => 1], $index->getKey()); + } + } + + public function testListIndexesForNonexistentCollection() + { + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + + $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName()); + $indexes = $operation->execute($this->getPrimaryServer()); + + $this->assertCount(0, $indexes); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/ListIndexesTest.php b/vendor/mongodb/mongodb/tests/Operation/ListIndexesTest.php new file mode 100644 index 00000000..c6f6ea74 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/ListIndexesTest.php @@ -0,0 +1,28 @@ +getDatabaseName(), $this->getCollectionName(), $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/MapReduceFunctionalTest.php b/vendor/mongodb/mongodb/tests/Operation/MapReduceFunctionalTest.php new file mode 100644 index 00000000..15fb0895 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/MapReduceFunctionalTest.php @@ -0,0 +1,191 @@ +getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + + (new CommandObserver)->observe( + function() { + $operation = new MapReduce( + $this->getDatabaseName(), + $this->getCollectionName(), + new Javascript('function() { emit(this.x, this.y); }'), + new Javascript('function(key, values) { return Array.sum(values); }'), + ['inline' => 1], + ['readConcern' => $this->createDefaultReadConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('readConcern', $command); + } + ); + } + + public function testDefaultWriteConcernIsOmitted() + { + $operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName()); + $operation->execute($this->getPrimaryServer()); + + (new CommandObserver)->observe( + function() { + $operation = new MapReduce( + $this->getDatabaseName(), + $this->getCollectionName(), + new Javascript('function() { emit(this.x, this.y); }'), + new Javascript('function(key, values) { return Array.sum(values); }'), + $this->getCollectionName() . '.output', + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function(stdClass $command) { + $this->assertObjectNotHasAttribute('writeConcern', $command); + } + ); + + $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName() . '.output'); + $operation->execute($this->getPrimaryServer()); + } + + public function testResult() + { + $this->createFixtures(3); + + $map = new Javascript('function() { emit(this.x, this.y); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = ['inline' => 1]; + + $operation = new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\MapReduceResult', $result); + $this->assertGreaterThanOrEqual(0, $result->getExecutionTimeMS()); + $this->assertNotEmpty($result->getCounts()); + $this->assertNotEmpty($result->getTiming()); + } + + public function testResultDoesNotIncludeTimingWithoutVerboseOption() + { + $this->createFixtures(3); + + $map = new Javascript('function() { emit(this.x, this.y); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = ['inline' => 1]; + + $operation = new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out, ['verbose' => false]); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\MapReduceResult', $result); + $this->assertGreaterThanOrEqual(0, $result->getExecutionTimeMS()); + $this->assertNotEmpty($result->getCounts()); + $this->assertEmpty($result->getTiming()); + } + + /** + * @dataProvider provideTypeMapOptionsAndExpectedDocuments + */ + public function testTypeMapOptionWithInlineResults(array $typeMap = null, array $expectedDocuments) + { + $this->createFixtures(3); + + $map = new Javascript('function() { emit(this.x, this.y); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = ['inline' => 1]; + + $operation = new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out, ['typeMap' => $typeMap]); + $results = iterator_to_array($operation->execute($this->getPrimaryServer())); + + $this->assertEquals($expectedDocuments, $results); + } + + public function provideTypeMapOptionsAndExpectedDocuments() + { + return [ + [ + null, + [ + (object) ['_id' => 1, 'value' => 3], + (object) ['_id' => 2, 'value' => 6], + (object) ['_id' => 3, 'value' => 9], + ], + ], + [ + ['root' => 'array'], + [ + ['_id' => 1, 'value' => 3], + ['_id' => 2, 'value' => 6], + ['_id' => 3, 'value' => 9], + ], + ], + [ + ['root' => 'object'], + [ + (object) ['_id' => 1, 'value' => 3], + (object) ['_id' => 2, 'value' => 6], + (object) ['_id' => 3, 'value' => 9], + ], + ], + ]; + } + + /** + * @dataProvider provideTypeMapOptionsAndExpectedDocuments + */ + public function testTypeMapOptionWithOutputCollection(array $typeMap = null, array $expectedDocuments) + { + $this->createFixtures(3); + + $map = new Javascript('function() { emit(this.x, this.y); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = $this->getCollectionName() . '.output'; + + $operation = new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out, ['typeMap' => $typeMap]); + $results = iterator_to_array($operation->execute($this->getPrimaryServer())); + + $this->assertEquals($expectedDocuments, $results); + + $operation = new Find($this->getDatabaseName(), $out, [], ['typeMap' => $typeMap]); + $cursor = $operation->execute($this->getPrimaryServer()); + + $this->assertEquals($expectedDocuments, iterator_to_array($cursor)); + + $operation = new DropCollection($this->getDatabaseName(), $out); + $operation->execute($this->getPrimaryServer()); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert(['x' => $i, 'y' => $i]); + $bulkWrite->insert(['x' => $i, 'y' => $i * 2]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n * 2, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/MapReduceTest.php b/vendor/mongodb/mongodb/tests/Operation/MapReduceTest.php new file mode 100644 index 00000000..2dc2fb4c --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/MapReduceTest.php @@ -0,0 +1,109 @@ +getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out); + } + + public function provideInvalidOutValues() + { + return $this->wrapValuesForDataProvider([123, 3.14, true]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + $map = new Javascript('function() { emit(this.x, this.y); }'); + $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); + $out = ['inline' => 1]; + + new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out, $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidJavascriptValues() as $value) { + $options[][] = ['finalize' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['jsMode' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['limit' => $value]; + } + + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['maxTimeMS' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['query' => $value]; + } + + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + + foreach ($this->getInvalidReadPreferenceValues() as $value) { + $options[][] = ['readPreference' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['scope' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['sort' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['verbose' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } + + private function getInvalidJavascriptValues() + { + return [123, 3.14, 'foo', true, [], new stdClass, new ObjectId]; + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/ReplaceOneTest.php b/vendor/mongodb/mongodb/tests/Operation/ReplaceOneTest.php new file mode 100644 index 00000000..3b70b832 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/ReplaceOneTest.php @@ -0,0 +1,63 @@ +getDatabaseName(), $this->getCollectionName(), $filter, ['y' => 1]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorReplacementArgumentTypeCheck($replacement) + { + new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); + } + + /** + * @dataProvider provideReplacementDocuments + */ + public function testConstructorReplacementArgument($replacement) + { + new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $replacement argument is an update operator + * @dataProvider provideUpdateDocuments + */ + public function testConstructorReplacementArgumentRequiresNoOperators($replacement) + { + new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); + } + + public function provideReplacementDocuments() + { + return $this->wrapValuesForDataProvider([ + ['y' => 1], + (object) ['y' => 1], + new BSONDocument(['y' => 1]), + ]); + } + + public function provideUpdateDocuments() + { + return $this->wrapValuesForDataProvider([ + ['$set' => ['y' => 1]], + (object) ['$set' => ['y' => 1]], + new BSONDocument(['$set' => ['y' => 1]]), + ]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/TestCase.php b/vendor/mongodb/mongodb/tests/Operation/TestCase.php new file mode 100644 index 00000000..2de8b0e6 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/TestCase.php @@ -0,0 +1,12 @@ +omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<'); + } + + public function testUpdateOne() + { + $this->createFixtures(3); + + $filter = ['_id' => ['$gt' => 1]]; + $update = ['$inc' => ['x' => 1]]; + + $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, $update); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\UpdateResult', $result); + $this->assertSame(1, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount()); + $this->assertSame(0, $result->getUpsertedCount()); + $this->assertNull($result->getUpsertedId()); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => 2, 'x' => 23], + ['_id' => 3, 'x' => 33], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUpdateMany() + { + $this->createFixtures(3); + + $filter = ['_id' => ['$gt' => 1]]; + $update = ['$inc' => ['x' => 1]]; + $options = ['multi' => true]; + + $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, $update, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\UpdateResult', $result); + $this->assertSame(2, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(2, $result->getModifiedCount()); + $this->assertSame(0, $result->getUpsertedCount()); + $this->assertNull($result->getUpsertedId()); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => 2, 'x' => 23], + ['_id' => 3, 'x' => 34], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUpdateManyWithExistingId() + { + $this->createFixtures(3); + + $filter = ['_id' => 5]; + $update = ['$set' => ['x' => 55]]; + $options = ['upsert' => true]; + + $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, $update, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\UpdateResult', $result); + $this->assertSame(0, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount()); + $this->assertSame(1, $result->getUpsertedCount()); + $this->assertSame(5, $result->getUpsertedId()); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => 2, 'x' => 22], + ['_id' => 3, 'x' => 33], + ['_id' => 5, 'x' => 55], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUpdateManyWithGeneratedId() + { + $this->createFixtures(3); + + $filter = ['x' => 66]; + $update = ['$set' => ['x' => 66]]; + $options = ['upsert' => true]; + + $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, $update, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertInstanceOf('MongoDB\UpdateResult', $result); + $this->assertSame(0, $result->getMatchedCount()); + $this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount()); + $this->assertSame(1, $result->getUpsertedCount()); + $this->assertInstanceOf('MongoDB\BSON\ObjectId', $result->getUpsertedId()); + + $expected = [ + ['_id' => 1, 'x' => 11], + ['_id' => 2, 'x' => 22], + ['_id' => 3, 'x' => 33], + ['_id' => $result->getUpsertedId(), 'x' => 66], + ]; + + $this->assertSameDocuments($expected, $this->collection->find()); + } + + public function testUnacknowledgedWriteConcern() + { + $filter = ['_id' => 1]; + $update = ['$set' => ['x' => 1]]; + $options = ['writeConcern' => new WriteConcern(0)]; + $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, $update, $options); + $result = $operation->execute($this->getPrimaryServer()); + + $this->assertFalse($result->isAcknowledged()); + + return $result; + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult $result) + { + $result->getMatchedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult $result) + { + $result->getModifiedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult $result) + { + $result->getUpsertedCount(); + } + + /** + * @depends testUnacknowledgedWriteConcern + * @expectedException MongoDB\Exception\BadMethodCallException + * @expectedExceptionMessageRegExp /[\w:\\]+ should not be called for an unacknowledged write result/ + */ + public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $result) + { + $result->getUpsertedId(); + } + + /** + * Create data fixtures. + * + * @param integer $n + */ + private function createFixtures($n) + { + $bulkWrite = new BulkWrite(['ordered' => true]); + + for ($i = 1; $i <= $n; $i++) { + $bulkWrite->insert([ + '_id' => $i, + 'x' => (integer) ($i . $i), + ]); + } + + $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + + $this->assertEquals($n, $result->getInsertedCount()); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/UpdateManyTest.php b/vendor/mongodb/mongodb/tests/Operation/UpdateManyTest.php new file mode 100644 index 00000000..acf816d5 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/UpdateManyTest.php @@ -0,0 +1,63 @@ +getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorUpdateArgumentTypeCheck($update) + { + new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); + } + + /** + * @dataProvider provideUpdateDocuments + */ + public function testConstructorUpdateArgument($update) + { + new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $update argument is not an update operator + * @dataProvider provideReplacementDocuments + */ + public function testConstructorUpdateArgumentRequiresOperators($replacement) + { + new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); + } + + public function provideReplacementDocuments() + { + return $this->wrapValuesForDataProvider([ + ['y' => 1], + (object) ['y' => 1], + new BSONDocument(['y' => 1]), + ]); + } + + public function provideUpdateDocuments() + { + return $this->wrapValuesForDataProvider([ + ['$set' => ['y' => 1]], + (object) ['$set' => ['y' => 1]], + new BSONDocument(['$set' => ['y' => 1]]), + ]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/UpdateOneTest.php b/vendor/mongodb/mongodb/tests/Operation/UpdateOneTest.php new file mode 100644 index 00000000..cdddcc83 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/UpdateOneTest.php @@ -0,0 +1,63 @@ +getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorUpdateArgumentTypeCheck($update) + { + new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); + } + + /** + * @dataProvider provideUpdateDocuments + */ + public function testConstructorUpdateArgument($update) + { + new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessage First key in $update argument is not an update operator + * @dataProvider provideReplacementDocuments + */ + public function testConstructorUpdateArgumentRequiresOperators($replacement) + { + new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); + } + + public function provideReplacementDocuments() + { + return $this->wrapValuesForDataProvider([ + ['y' => 1], + (object) ['y' => 1], + new BSONDocument(['y' => 1]), + ]); + } + + public function provideUpdateDocuments() + { + return $this->wrapValuesForDataProvider([ + ['$set' => ['y' => 1]], + (object) ['$set' => ['y' => 1]], + new BSONDocument(['$set' => ['y' => 1]]), + ]); + } +} diff --git a/vendor/mongodb/mongodb/tests/Operation/UpdateTest.php b/vendor/mongodb/mongodb/tests/Operation/UpdateTest.php new file mode 100644 index 00000000..49fee8f8 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/Operation/UpdateTest.php @@ -0,0 +1,64 @@ +getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /Expected \$update to have type "array or object" but found "[\w ]+"/ + * @dataProvider provideInvalidDocumentValues + */ + public function testConstructorUpdateArgumentTypeCheck($update) + { + new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); + } + + /** + * @expectedException MongoDB\Exception\InvalidArgumentException + * @dataProvider provideInvalidConstructorOptions + */ + public function testConstructorOptionTypeChecks(array $options) + { + new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], ['y' => 1], $options); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['bypassDocumentValidation' => $value]; + } + + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['collation' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['multi' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['upsert' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + return $options; + } +} diff --git a/vendor/mongodb/mongodb/tests/PedantryTest.php b/vendor/mongodb/mongodb/tests/PedantryTest.php new file mode 100644 index 00000000..1dd07dca --- /dev/null +++ b/vendor/mongodb/mongodb/tests/PedantryTest.php @@ -0,0 +1,79 @@ +getMethods(); + + $methods = array_filter( + $methods, + function(ReflectionMethod $method) use ($class) { + return $method->getDeclaringClass() == $class; + } + ); + + $getSortValue = function(ReflectionMethod $method) { + if ($method->getModifiers() & ReflectionMethod::IS_PRIVATE) { + return '2' . $method->getName(); + } + if ($method->getModifiers() & ReflectionMethod::IS_PROTECTED) { + return '1' . $method->getName(); + } + if ($method->getModifiers() & ReflectionMethod::IS_PUBLIC) { + return '0' . $method->getName(); + } + }; + + $sortedMethods = $methods; + usort( + $sortedMethods, + function(ReflectionMethod $a, ReflectionMethod $b) use ($getSortValue) { + return strcasecmp($getSortValue($a), $getSortValue($b)); + } + ); + + $methods = array_map(function(ReflectionMethod $method) { return $method->getName(); }, $methods); + $sortedMethods = array_map(function(ReflectionMethod $method) { return $method->getName(); }, $sortedMethods); + + $this->assertEquals($sortedMethods, $methods); + } + + public function provideProjectClassNames() + { + $classNames = []; + $srcDir = realpath(__DIR__ . '/../src/'); + + $files = new RegexIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($srcDir)), '/\.php$/i'); + + foreach ($files as $file) { + if ($file->getFilename() === 'functions.php') { + continue; + } + + /* autoload.php added downstream (e.g. Fedora) */ + if ($file->getFilename() === 'autoload.php') { + continue; + } + + $classNames[][] = 'MongoDB\\' . str_replace(DIRECTORY_SEPARATOR, '\\', substr($file->getRealPath(), strlen($srcDir) + 1, -4)); + } + + return $classNames; + } +} diff --git a/vendor/mongodb/mongodb/tests/TestCase.php b/vendor/mongodb/mongodb/tests/TestCase.php new file mode 100644 index 00000000..a83c501b --- /dev/null +++ b/vendor/mongodb/mongodb/tests/TestCase.php @@ -0,0 +1,150 @@ +wrapValuesForDataProvider($this->getInvalidDocumentValues()); + } + + /** + * Return the test collection name. + * + * @return string + */ + protected function getCollectionName() + { + $class = new ReflectionClass($this); + + return sprintf('%s.%s', $class->getShortName(), hash('crc32b', $this->getName())); + } + + /** + * Return the test database name. + * + * @return string + */ + protected function getDatabaseName() + { + return getenv('MONGODB_DATABASE') ?: 'phplib_test'; + } + + /** + * Return a list of invalid array values. + * + * @return array + */ + protected function getInvalidArrayValues() + { + return [123, 3.14, 'foo', true, new stdClass]; + } + + /** + * Return a list of invalid boolean values. + * + * @return array + */ + protected function getInvalidBooleanValues() + { + return [123, 3.14, 'foo', [], new stdClass]; + } + + /** + * Return a list of invalid document values. + * + * @return array + */ + protected function getInvalidDocumentValues() + { + return [123, 3.14, 'foo', true]; + } + + /** + * Return a list of invalid integer values. + * + * @return array + */ + protected function getInvalidIntegerValues() + { + return [3.14, 'foo', true, [], new stdClass]; + } + + /** + * Return a list of invalid ReadPreference values. + * + * @return array + */ + protected function getInvalidReadConcernValues() + { + return [123, 3.14, 'foo', true, [], new stdClass, new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)]; + } + + /** + * Return a list of invalid ReadPreference values. + * + * @return array + */ + protected function getInvalidReadPreferenceValues() + { + return [123, 3.14, 'foo', true, [], new stdClass, new ReadConcern, new WriteConcern(1)]; + } + + /** + * Return a list of invalid string values. + * + * @return array + */ + protected function getInvalidStringValues() + { + return [123, 3.14, true, [], new stdClass]; + } + + /** + * Return a list of invalid WriteConcern values. + * + * @return array + */ + protected function getInvalidWriteConcernValues() + { + return [123, 3.14, 'foo', true, [], new stdClass, new ReadConcern, new ReadPreference(ReadPreference::RP_PRIMARY)]; + } + + /** + * Return the test namespace. + * + * @return string + */ + protected function getNamespace() + { + return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName()); + } + + /** + * Return the connection URI. + * + * @return string + */ + protected function getUri() + { + return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017'; + } + + /** + * Wrap a list of values for use as a single-argument data provider. + * + * @param array $values List of values + * @return array + */ + protected function wrapValuesForDataProvider(array $values) + { + return array_map(function($value) { return [$value]; }, $values); + } +} diff --git a/vendor/mongodb/mongodb/tests/bootstrap.php b/vendor/mongodb/mongodb/tests/bootstrap.php new file mode 100644 index 00000000..fd711e00 --- /dev/null +++ b/vendor/mongodb/mongodb/tests/bootstrap.php @@ -0,0 +1,11 @@ + 7.1, you can omit it on PHP 7.0. + +## Usage + +```php +$action = new Action(Action::VIEW); + +// or +$action = Action::VIEW(); +``` + +As you can see, static methods are automatically implemented to provide quick access to an enum value. + +One advantage over using class constants is to be able to type-hint enum values: + +```php +function setAction(Action $action) { + // ... +} +``` + +## Documentation + +- `__construct()` The constructor checks that the value exist in the enum +- `__toString()` You can `echo $myValue`, it will display the enum value (value of the constant) +- `getValue()` Returns the current value of the enum +- `getKey()` Returns the key of the current value on Enum +- `equals()` Tests whether enum instances are equal (returns `true` if enum values are equal, `false` otherwise) + +Static methods: + +- `toArray()` method Returns all possible values as an array (constant name in key, constant value in value) +- `keys()` Returns the names (keys) of all constants in the Enum class +- `values()` Returns instances of the Enum class of all Enum constants (constant name in key, Enum instance in value) +- `isValid()` Check if tested value is valid on enum set +- `isValidKey()` Check if tested key is valid on enum set +- `search()` Return key for searched value + +### Static methods + +```php +class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} + +// Static method: +$action = Action::VIEW(); +$action = Action::EDIT(); +``` + +Static method helpers are implemented using [`__callStatic()`](http://www.php.net/manual/en/language.oop5.overloading.php#object.callstatic). + +If you care about IDE autocompletion, you can either implement the static methods yourself: + +```php +class Action extends Enum +{ + private const VIEW = 'view'; + + /** + * @return Action + */ + public static function VIEW() { + return new Action(self::VIEW); + } +} +``` + +or you can use phpdoc (this is supported in PhpStorm for example): + +```php +/** + * @method static Action VIEW() + * @method static Action EDIT() + */ +class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} +``` + +## Related projects + +- [Doctrine enum mapping](https://github.com/acelaya/doctrine-enum-type) +- [Symfony 2/3 ParamConverter integration](https://github.com/Ex3v/MyCLabsEnumParamConverter) diff --git a/vendor/myclabs/php-enum/composer.json b/vendor/myclabs/php-enum/composer.json new file mode 100755 index 00000000..88bbe16b --- /dev/null +++ b/vendor/myclabs/php-enum/composer.json @@ -0,0 +1,32 @@ +{ + "name": "myclabs/php-enum", + "type": "library", + "description": "PHP Enum implementation", + "keywords": ["enum"], + "homepage": "http://github.com/myclabs/php-enum", + "license": "MIT", + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "MyCLabs\\Tests\\Enum\\": "tests/" + } + }, + "require": { + "php": ">=5.4", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.7|^6.0", + "squizlabs/php_codesniffer": "1.*" + } +} diff --git a/vendor/myclabs/php-enum/src/Enum.php b/vendor/myclabs/php-enum/src/Enum.php new file mode 100755 index 00000000..aa36c428 --- /dev/null +++ b/vendor/myclabs/php-enum/src/Enum.php @@ -0,0 +1,204 @@ + + * @author Daniel Costa + * @author Mirosław Filip + */ +abstract class Enum implements \JsonSerializable +{ + /** + * Enum value + * + * @var mixed + */ + protected $value; + + /** + * Store existing constants in a static cache per object. + * + * @var array + */ + protected static $cache = []; + + /** + * Creates a new value of some type + * + * @param mixed $value + * + * @throws \UnexpectedValueException if incompatible type is given. + */ + public function __construct($value) + { + if ($value instanceof static) { + $this->value = $value->getValue(); + + return; + } + + if (!$this->isValid($value)) { + throw new \UnexpectedValueException("Value '$value' is not part of the enum " . \get_called_class()); + } + + $this->value = $value; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the enum key (i.e. the constant name). + * + * @return mixed + */ + public function getKey() + { + return static::search($this->value); + } + + /** + * @return string + */ + public function __toString() + { + return (string)$this->value; + } + + /** + * Compares one Enum with another. + * + * This method is final, for more information read https://github.com/myclabs/php-enum/issues/4 + * + * @return bool True if Enums are equal, false if not equal + */ + final public function equals(Enum $enum = null) + { + return $enum !== null && $this->getValue() === $enum->getValue() && \get_called_class() === \get_class($enum); + } + + /** + * Returns the names (keys) of all constants in the Enum class + * + * @return array + */ + public static function keys() + { + return \array_keys(static::toArray()); + } + + /** + * Returns instances of the Enum class of all Enum constants + * + * @return static[] Constant name in key, Enum instance in value + */ + public static function values() + { + $values = array(); + + foreach (static::toArray() as $key => $value) { + $values[$key] = new static($value); + } + + return $values; + } + + /** + * Returns all possible values as an array + * + * @return array Constant name in key, constant value in value + */ + public static function toArray() + { + $class = \get_called_class(); + if (!isset(static::$cache[$class])) { + $reflection = new \ReflectionClass($class); + static::$cache[$class] = $reflection->getConstants(); + } + + return static::$cache[$class]; + } + + /** + * Check if is valid enum value + * + * @param $value + * + * @return bool + */ + public static function isValid($value) + { + return \in_array($value, static::toArray(), true); + } + + /** + * Check if is valid enum key + * + * @param $key + * + * @return bool + */ + public static function isValidKey($key) + { + $array = static::toArray(); + + return isset($array[$key]) || \array_key_exists($key, $array); + } + + /** + * Return key for value + * + * @param $value + * + * @return mixed + */ + public static function search($value) + { + return \array_search($value, static::toArray(), true); + } + + /** + * Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a class constant + * + * @param string $name + * @param array $arguments + * + * @return static + * @throws \BadMethodCallException + */ + public static function __callStatic($name, $arguments) + { + $array = static::toArray(); + if (isset($array[$name]) || \array_key_exists($name, $array)) { + return new static($array[$name]); + } + + throw new \BadMethodCallException("No static method or enum constant '$name' in class " . \get_called_class()); + } + + /** + * Specify data which should be serialized to JSON. This method returns data that can be serialized by json_encode() + * natively. + * + * @return mixed + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + */ + public function jsonSerialize() + { + return $this->getValue(); + } +} diff --git a/vendor/picqer/php-barcode-generator/.gitignore b/vendor/picqer/php-barcode-generator/.gitignore new file mode 100755 index 00000000..2e3beb6f --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.gitignore @@ -0,0 +1,4 @@ +.idea +.DS_Store +vendor +composer.lock \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/.travis.yml b/vendor/picqer/php-barcode-generator/.travis.yml new file mode 100755 index 00000000..93e4bfa8 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.travis.yml @@ -0,0 +1,12 @@ +language: php + +php: + - 5.6 + - 7.0 + - hhvm + +sudo: false + +install: composer install --no-interaction --prefer-source + +script: vendor/bin/phpunit \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/LICENSE.md b/vendor/picqer/php-barcode-generator/LICENSE.md new file mode 100755 index 00000000..65c5ca88 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/LICENSE.md @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/vendor/picqer/php-barcode-generator/Readme.md b/vendor/picqer/php-barcode-generator/Readme.md new file mode 100755 index 00000000..0dccb4df --- /dev/null +++ b/vendor/picqer/php-barcode-generator/Readme.md @@ -0,0 +1,78 @@ +# PHP Barcode Generator [![Build Status](https://travis-ci.org/picqer/php-barcode-generator.svg?branch=master)](https://travis-ci.org/picqer/php-barcode-generator) [![Total Downloads](https://poser.pugx.org/picqer/php-barcode-generator/downloads)](https://packagist.org/packages/picqer/php-barcode-generator) +This is an easy to use, non-bloated, framework independent, barcode generator in PHP. + +It creates SVG, PNG, JPG and HTML images, from the most used 1D barcode standards. + +*The codebase is largely from the [TCPDF barcode generator](https://github.com/tecnickcom/TCPDF) by Nicola Asuni. This code is therefor licensed under LGPLv3. It is still a bit of a mess, bit I will clean it in the future. I do not expect the interface of this class will change during the clean ups.* + +## Installation +Install through [composer](https://getcomposer.org/doc/00-intro.md): + +``` +composer require picqer/php-barcode-generator +``` + +If you want to generate PNG or JPG images, you need the GD library or Imagick installed on your system as well. + +## Usage +Initiate the barcode generator for the output you want, then call the ->getBarcode() routine as many times as you want. + +```php +$generator = new Picqer\Barcode\BarcodeGeneratorHTML(); +echo $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); +``` + +The ->getBarcode() routine accepts the following: +- $code Data for the barcode +- $type Type of barcode, use the constants defined in the class +- $widthFactor Width is based on the length of the data, with this factor you can make the barcode bars wider than default +- $totalHeight The total height of the barcode +- $color Hex code of the foreground color + +## Image types +```php +$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); +$generatorPNG = new Picqer\Barcode\BarcodeGeneratorPNG(); +$generatorJPG = new Picqer\Barcode\BarcodeGeneratorJPG(); +$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); +``` + +## Accepted types +- TYPE_CODE_39 +- TYPE_CODE_39_CHECKSUM +- TYPE_CODE_39E +- TYPE_CODE_39E_CHECKSUM +- TYPE_CODE_93 +- TYPE_STANDARD_2_5 +- TYPE_STANDARD_2_5_CHECKSUM +- TYPE_INTERLEAVED_2_5 +- TYPE_INTERLEAVED_2_5_CHECKSUM +- TYPE_CODE_128 +- TYPE_CODE_128_A +- TYPE_CODE_128_B +- TYPE_CODE_128_C +- TYPE_EAN_2 +- TYPE_EAN_5 +- TYPE_EAN_8 +- TYPE_EAN_13 +- TYPE_UPC_A +- TYPE_UPC_E +- TYPE_MSI +- TYPE_MSI_CHECKSUM +- TYPE_POSTNET +- TYPE_PLANET +- TYPE_RMS4CC +- TYPE_KIX +- TYPE_IMB +- TYPE_CODABAR +- TYPE_CODE_11 +- TYPE_PHARMA_CODE +- TYPE_PHARMA_CODE_TWO_TRACKS + +## Examples +Embedded PNG image in HTML: + +```php +$generator = new \Picqer\Barcode\BarcodeGeneratorPNG(); +echo ''; +``` diff --git a/vendor/picqer/php-barcode-generator/composer.json b/vendor/picqer/php-barcode-generator/composer.json new file mode 100755 index 00000000..22f4c42d --- /dev/null +++ b/vendor/picqer/php-barcode-generator/composer.json @@ -0,0 +1,30 @@ +{ + "name": "picqer/php-barcode-generator", + "type": "library", + "description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", + "keywords": [ "php", "barcode", "barcode generator", "EAN", "EAN13", "UPC", "Code39", "Code128", "Code93", "Standard 2 of 5", "MSI", "POSTNET", "KIX", "KIXCODE", "CODABAR", "PHARMA", "Code11", "SVG", "PNG", "HTML", "JPG", "JPEG" ], + "homepage": "http://github.com/picqer/php-barcode-generator", + "license": "LGPLv3", + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + }, + { + "name": "Casper Bakker", + "email": "info@picqer.com" + } + ], + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.3" + }, + "autoload": { + "psr-4": { + "Picqer\\Barcode\\": "src" + } + } +} diff --git a/vendor/picqer/php-barcode-generator/generate-verified-files.php b/vendor/picqer/php-barcode-generator/generate-verified-files.php new file mode 100755 index 00000000..b035d873 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/generate-verified-files.php @@ -0,0 +1,16 @@ +getBarcode('081231723897', $generatorSVG::TYPE_EAN_13)); + +$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); +file_put_contents('tests/verified-files/081231723897-code128.html', $generatorHTML->getBarcode('081231723897', $generatorHTML::TYPE_CODE_128)); + +$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); +file_put_contents('tests/verified-files/0049000004632-ean13.svg', $generatorSVG->getBarcode('0049000004632', $generatorSVG::TYPE_EAN_13)); diff --git a/vendor/picqer/php-barcode-generator/phpunit.xml b/vendor/picqer/php-barcode-generator/phpunit.xml new file mode 100755 index 00000000..0d549dc3 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/phpunit.xml @@ -0,0 +1,24 @@ + + + + + ./tests/ + + + + + ./src + + + \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php b/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php new file mode 100755 index 00000000..33e6fa02 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php @@ -0,0 +1,2861 @@ +. +// +// See LICENSE.TXT file for more information. + +namespace Picqer\Barcode; + +use Picqer\Barcode\Exceptions\BarcodeException; +use Picqer\Barcode\Exceptions\InvalidCharacterException; +use Picqer\Barcode\Exceptions\InvalidCheckDigitException; +use Picqer\Barcode\Exceptions\InvalidFormatException; +use Picqer\Barcode\Exceptions\InvalidLengthException; +use Picqer\Barcode\Exceptions\UnknownTypeException; + +abstract class BarcodeGenerator +{ + const TYPE_CODE_39 = 'C39'; + const TYPE_CODE_39_CHECKSUM = 'C39+'; + const TYPE_CODE_39E = 'C39E'; + const TYPE_CODE_39E_CHECKSUM = 'C39E+'; + const TYPE_CODE_93 = 'C93'; + const TYPE_STANDARD_2_5 = 'S25'; + const TYPE_STANDARD_2_5_CHECKSUM = 'S25+'; + const TYPE_INTERLEAVED_2_5 = 'I25'; + const TYPE_INTERLEAVED_2_5_CHECKSUM = 'I25+'; + const TYPE_CODE_128 = 'C128'; + const TYPE_CODE_128_A = 'C128A'; + const TYPE_CODE_128_B = 'C128B'; + const TYPE_CODE_128_C = 'C128C'; + const TYPE_EAN_2 = 'EAN2'; + const TYPE_EAN_5 = 'EAN5'; + const TYPE_EAN_8 = 'EAN8'; + const TYPE_EAN_13 = 'EAN13'; + const TYPE_UPC_A = 'UPCA'; + const TYPE_UPC_E = 'UPCE'; + const TYPE_MSI = 'MSI'; + const TYPE_MSI_CHECKSUM = 'MSI+'; + const TYPE_POSTNET = 'POSTNET'; + const TYPE_PLANET = 'PLANET'; + const TYPE_RMS4CC = 'RMS4CC'; + const TYPE_KIX = 'KIX'; + const TYPE_IMB = 'IMB'; + const TYPE_CODABAR = 'CODABAR'; + const TYPE_CODE_11 = 'CODE11'; + const TYPE_PHARMA_CODE = 'PHARMA'; + const TYPE_PHARMA_CODE_TWO_TRACKS = 'PHARMA2T'; + + /** + * Get the barcode data + * + * @param string $code code to print + * @param string $type type of barcode + * @return array barcode array + * @public + */ + protected function getBarcodeData($code, $type) + { + switch (strtoupper($type)) { + case self::TYPE_CODE_39: { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + $arrcode = $this->barcode_code39($code, false, false); + break; + } + case self::TYPE_CODE_39_CHECKSUM: { // CODE 39 with checksum + $arrcode = $this->barcode_code39($code, false, true); + break; + } + case self::TYPE_CODE_39E: { // CODE 39 EXTENDED + $arrcode = $this->barcode_code39($code, true, false); + break; + } + case self::TYPE_CODE_39E_CHECKSUM: { // CODE 39 EXTENDED + CHECKSUM + $arrcode = $this->barcode_code39($code, true, true); + break; + } + case self::TYPE_CODE_93: { // CODE 93 - USS-93 + $arrcode = $this->barcode_code93($code); + break; + } + case self::TYPE_STANDARD_2_5: { // Standard 2 of 5 + $arrcode = $this->barcode_s25($code, false); + break; + } + case self::TYPE_STANDARD_2_5_CHECKSUM: { // Standard 2 of 5 + CHECKSUM + $arrcode = $this->barcode_s25($code, true); + break; + } + case self::TYPE_INTERLEAVED_2_5: { // Interleaved 2 of 5 + $arrcode = $this->barcode_i25($code, false); + break; + } + case self::TYPE_INTERLEAVED_2_5_CHECKSUM: { // Interleaved 2 of 5 + CHECKSUM + $arrcode = $this->barcode_i25($code, true); + break; + } + case self::TYPE_CODE_128: { // CODE 128 + $arrcode = $this->barcode_c128($code, ''); + break; + } + case self::TYPE_CODE_128_A: { // CODE 128 A + $arrcode = $this->barcode_c128($code, 'A'); + break; + } + case self::TYPE_CODE_128_B: { // CODE 128 B + $arrcode = $this->barcode_c128($code, 'B'); + break; + } + case self::TYPE_CODE_128_C: { // CODE 128 C + $arrcode = $this->barcode_c128($code, 'C'); + break; + } + case self::TYPE_EAN_2: { // 2-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 2); + break; + } + case self::TYPE_EAN_5: { // 5-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 5); + break; + } + case self::TYPE_EAN_8: { // EAN 8 + $arrcode = $this->barcode_eanupc($code, 8); + break; + } + case self::TYPE_EAN_13: { // EAN 13 + $arrcode = $this->barcode_eanupc($code, 13); + break; + } + case self::TYPE_UPC_A: { // UPC-A + $arrcode = $this->barcode_eanupc($code, 12); + break; + } + case self::TYPE_UPC_E: { // UPC-E + $arrcode = $this->barcode_eanupc($code, 6); + break; + } + case self::TYPE_MSI: { // MSI (Variation of Plessey code) + $arrcode = $this->barcode_msi($code, false); + break; + } + case self::TYPE_MSI_CHECKSUM: { // MSI + CHECKSUM (modulo 11) + $arrcode = $this->barcode_msi($code, true); + break; + } + case self::TYPE_POSTNET: { // POSTNET + $arrcode = $this->barcode_postnet($code, false); + break; + } + case self::TYPE_PLANET: { // PLANET + $arrcode = $this->barcode_postnet($code, true); + break; + } + case self::TYPE_RMS4CC: { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) + $arrcode = $this->barcode_rms4cc($code, false); + break; + } + case self::TYPE_KIX: { // KIX (Klant index - Customer index) + $arrcode = $this->barcode_rms4cc($code, true); + break; + } + case self::TYPE_IMB: { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + $arrcode = $this->barcode_imb($code); + break; + } + case self::TYPE_CODABAR: { // CODABAR + $arrcode = $this->barcode_codabar($code); + break; + } + case self::TYPE_CODE_11: { // CODE 11 + $arrcode = $this->barcode_code11($code); + break; + } + case self::TYPE_PHARMA_CODE: { // PHARMACODE + $arrcode = $this->barcode_pharmacode($code); + break; + } + case self::TYPE_PHARMA_CODE_TWO_TRACKS: { // PHARMACODE TWO-TRACKS + $arrcode = $this->barcode_pharmacode2t($code); + break; + } + default: { + throw new UnknownTypeException(); + break; + } + } + + if ( ! isset($arrcode['maxWidth'])) { + $arrcode = $this->convertBarcodeArrayToNewStyle($arrcode); + } + + return $arrcode; + } + + /** + * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + * General-purpose code in very wide use world-wide + * + * @param $code (string) code to represent. + * @param $extended (boolean) if true uses the extended mode. + * @param $checksum (boolean) if true add a checksum to the code. + * @return array barcode representation. + * @protected + */ + protected function barcode_code39($code, $extended = false, $checksum = false) + { + $chr = []; + $chr['0'] = '111331311'; + $chr['1'] = '311311113'; + $chr['2'] = '113311113'; + $chr['3'] = '313311111'; + $chr['4'] = '111331113'; + $chr['5'] = '311331111'; + $chr['6'] = '113331111'; + $chr['7'] = '111311313'; + $chr['8'] = '311311311'; + $chr['9'] = '113311311'; + $chr['A'] = '311113113'; + $chr['B'] = '113113113'; + $chr['C'] = '313113111'; + $chr['D'] = '111133113'; + $chr['E'] = '311133111'; + $chr['F'] = '113133111'; + $chr['G'] = '111113313'; + $chr['H'] = '311113311'; + $chr['I'] = '113113311'; + $chr['J'] = '111133311'; + $chr['K'] = '311111133'; + $chr['L'] = '113111133'; + $chr['M'] = '313111131'; + $chr['N'] = '111131133'; + $chr['O'] = '311131131'; + $chr['P'] = '113131131'; + $chr['Q'] = '111111333'; + $chr['R'] = '311111331'; + $chr['S'] = '113111331'; + $chr['T'] = '111131331'; + $chr['U'] = '331111113'; + $chr['V'] = '133111113'; + $chr['W'] = '333111111'; + $chr['X'] = '131131113'; + $chr['Y'] = '331131111'; + $chr['Z'] = '133131111'; + $chr['-'] = '131111313'; + $chr['.'] = '331111311'; + $chr[' '] = '133111311'; + $chr['$'] = '131313111'; + $chr['/'] = '131311131'; + $chr['+'] = '131113131'; + $chr['%'] = '111313131'; + $chr['*'] = '131131311'; + + $code = strtoupper($code); + + if ($extended) { + // extended mode + $code = $this->encode_code39_ext($code); + } + + if ($checksum) { + // checksum + $code .= $this->checksum_code39($code); + } + + // add start and stop codes + $code = '*' . $code . '*'; + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = $code{$i}; + if ( ! isset($chr[$char])) { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + for ($j = 0; $j < 9; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char]{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + // intercharacter gap + $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + ++$k; + } + + return $bararray; + } + + /** + * Encode a string to be used for CODE 39 Extended mode. + * + * @param string $code code to represent. + * @return bool|string encoded string. + * @protected + */ + protected function encode_code39_ext($code) + { + $encode = array( + chr(0) => '%U', + chr(1) => '$A', + chr(2) => '$B', + chr(3) => '$C', + chr(4) => '$D', + chr(5) => '$E', + chr(6) => '$F', + chr(7) => '$G', + chr(8) => '$H', + chr(9) => '$I', + chr(10) => '$J', + chr(11) => '£K', + chr(12) => '$L', + chr(13) => '$M', + chr(14) => '$N', + chr(15) => '$O', + chr(16) => '$P', + chr(17) => '$Q', + chr(18) => '$R', + chr(19) => '$S', + chr(20) => '$T', + chr(21) => '$U', + chr(22) => '$V', + chr(23) => '$W', + chr(24) => '$X', + chr(25) => '$Y', + chr(26) => '$Z', + chr(27) => '%A', + chr(28) => '%B', + chr(29) => '%C', + chr(30) => '%D', + chr(31) => '%E', + chr(32) => ' ', + chr(33) => '/A', + chr(34) => '/B', + chr(35) => '/C', + chr(36) => '/D', + chr(37) => '/E', + chr(38) => '/F', + chr(39) => '/G', + chr(40) => '/H', + chr(41) => '/I', + chr(42) => '/J', + chr(43) => '/K', + chr(44) => '/L', + chr(45) => '-', + chr(46) => '.', + chr(47) => '/O', + chr(48) => '0', + chr(49) => '1', + chr(50) => '2', + chr(51) => '3', + chr(52) => '4', + chr(53) => '5', + chr(54) => '6', + chr(55) => '7', + chr(56) => '8', + chr(57) => '9', + chr(58) => '/Z', + chr(59) => '%F', + chr(60) => '%G', + chr(61) => '%H', + chr(62) => '%I', + chr(63) => '%J', + chr(64) => '%V', + chr(65) => 'A', + chr(66) => 'B', + chr(67) => 'C', + chr(68) => 'D', + chr(69) => 'E', + chr(70) => 'F', + chr(71) => 'G', + chr(72) => 'H', + chr(73) => 'I', + chr(74) => 'J', + chr(75) => 'K', + chr(76) => 'L', + chr(77) => 'M', + chr(78) => 'N', + chr(79) => 'O', + chr(80) => 'P', + chr(81) => 'Q', + chr(82) => 'R', + chr(83) => 'S', + chr(84) => 'T', + chr(85) => 'U', + chr(86) => 'V', + chr(87) => 'W', + chr(88) => 'X', + chr(89) => 'Y', + chr(90) => 'Z', + chr(91) => '%K', + chr(92) => '%L', + chr(93) => '%M', + chr(94) => '%N', + chr(95) => '%O', + chr(96) => '%W', + chr(97) => '+A', + chr(98) => '+B', + chr(99) => '+C', + chr(100) => '+D', + chr(101) => '+E', + chr(102) => '+F', + chr(103) => '+G', + chr(104) => '+H', + chr(105) => '+I', + chr(106) => '+J', + chr(107) => '+K', + chr(108) => '+L', + chr(109) => '+M', + chr(110) => '+N', + chr(111) => '+O', + chr(112) => '+P', + chr(113) => '+Q', + chr(114) => '+R', + chr(115) => '+S', + chr(116) => '+T', + chr(117) => '+U', + chr(118) => '+V', + chr(119) => '+W', + chr(120) => '+X', + chr(121) => '+Y', + chr(122) => '+Z', + chr(123) => '%P', + chr(124) => '%Q', + chr(125) => '%R', + chr(126) => '%S', + chr(127) => '%T' + ); + $code_ext = ''; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + if (ord($code{$i}) > 127) { + throw new InvalidCharacterException('Only supports till char 127'); + } + $code_ext .= $encode[$code{$i}]; + } + + return $code_ext; + } + + /** + * Calculate CODE 39 checksum (modulo 43). + * + * @param string $code code to represent. + * @return string char checksum. + * @protected + */ + protected function checksum_code39($code) + { + $chars = array( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '-', + '.', + ' ', + '$', + '/', + '+', + '%' + ); + $sum = 0; + $codelength = strlen($code); + for ($i = 0; $i < $codelength; ++$i) { + $k = array_keys($chars, $code{$i}); + $sum += $k[0]; + } + $j = ($sum % 43); + + return $chars[$j]; + } + + /** + * CODE 93 - USS-93 + * Compact code similar to Code 39 + * + * @param $code (string) code to represent. + * @return array barcode representation. + * @protected + */ + protected function barcode_code93($code) + { + $chr = []; + $chr[48] = '131112'; // 0 + $chr[49] = '111213'; // 1 + $chr[50] = '111312'; // 2 + $chr[51] = '111411'; // 3 + $chr[52] = '121113'; // 4 + $chr[53] = '121212'; // 5 + $chr[54] = '121311'; // 6 + $chr[55] = '111114'; // 7 + $chr[56] = '131211'; // 8 + $chr[57] = '141111'; // 9 + $chr[65] = '211113'; // A + $chr[66] = '211212'; // B + $chr[67] = '211311'; // C + $chr[68] = '221112'; // D + $chr[69] = '221211'; // E + $chr[70] = '231111'; // F + $chr[71] = '112113'; // G + $chr[72] = '112212'; // H + $chr[73] = '112311'; // I + $chr[74] = '122112'; // J + $chr[75] = '132111'; // K + $chr[76] = '111123'; // L + $chr[77] = '111222'; // M + $chr[78] = '111321'; // N + $chr[79] = '121122'; // O + $chr[80] = '131121'; // P + $chr[81] = '212112'; // Q + $chr[82] = '212211'; // R + $chr[83] = '211122'; // S + $chr[84] = '211221'; // T + $chr[85] = '221121'; // U + $chr[86] = '222111'; // V + $chr[87] = '112122'; // W + $chr[88] = '112221'; // X + $chr[89] = '122121'; // Y + $chr[90] = '123111'; // Z + $chr[45] = '121131'; // - + $chr[46] = '311112'; // . + $chr[32] = '311211'; // + $chr[36] = '321111'; // $ + $chr[47] = '112131'; // / + $chr[43] = '113121'; // + + $chr[37] = '211131'; // % + $chr[128] = '121221'; // ($) + $chr[129] = '311121'; // (/) + $chr[130] = '122211'; // (+) + $chr[131] = '312111'; // (%) + $chr[42] = '111141'; // start-stop + $code = strtoupper($code); + $encode = array( + chr(0) => chr(131) . 'U', + chr(1) => chr(128) . 'A', + chr(2) => chr(128) . 'B', + chr(3) => chr(128) . 'C', + chr(4) => chr(128) . 'D', + chr(5) => chr(128) . 'E', + chr(6) => chr(128) . 'F', + chr(7) => chr(128) . 'G', + chr(8) => chr(128) . 'H', + chr(9) => chr(128) . 'I', + chr(10) => chr(128) . 'J', + chr(11) => '£K', + chr(12) => chr(128) . 'L', + chr(13) => chr(128) . 'M', + chr(14) => chr(128) . 'N', + chr(15) => chr(128) . 'O', + chr(16) => chr(128) . 'P', + chr(17) => chr(128) . 'Q', + chr(18) => chr(128) . 'R', + chr(19) => chr(128) . 'S', + chr(20) => chr(128) . 'T', + chr(21) => chr(128) . 'U', + chr(22) => chr(128) . 'V', + chr(23) => chr(128) . 'W', + chr(24) => chr(128) . 'X', + chr(25) => chr(128) . 'Y', + chr(26) => chr(128) . 'Z', + chr(27) => chr(131) . 'A', + chr(28) => chr(131) . 'B', + chr(29) => chr(131) . 'C', + chr(30) => chr(131) . 'D', + chr(31) => chr(131) . 'E', + chr(32) => ' ', + chr(33) => chr(129) . 'A', + chr(34) => chr(129) . 'B', + chr(35) => chr(129) . 'C', + chr(36) => chr(129) . 'D', + chr(37) => chr(129) . 'E', + chr(38) => chr(129) . 'F', + chr(39) => chr(129) . 'G', + chr(40) => chr(129) . 'H', + chr(41) => chr(129) . 'I', + chr(42) => chr(129) . 'J', + chr(43) => chr(129) . 'K', + chr(44) => chr(129) . 'L', + chr(45) => '-', + chr(46) => '.', + chr(47) => chr(129) . 'O', + chr(48) => '0', + chr(49) => '1', + chr(50) => '2', + chr(51) => '3', + chr(52) => '4', + chr(53) => '5', + chr(54) => '6', + chr(55) => '7', + chr(56) => '8', + chr(57) => '9', + chr(58) => chr(129) . 'Z', + chr(59) => chr(131) . 'F', + chr(60) => chr(131) . 'G', + chr(61) => chr(131) . 'H', + chr(62) => chr(131) . 'I', + chr(63) => chr(131) . 'J', + chr(64) => chr(131) . 'V', + chr(65) => 'A', + chr(66) => 'B', + chr(67) => 'C', + chr(68) => 'D', + chr(69) => 'E', + chr(70) => 'F', + chr(71) => 'G', + chr(72) => 'H', + chr(73) => 'I', + chr(74) => 'J', + chr(75) => 'K', + chr(76) => 'L', + chr(77) => 'M', + chr(78) => 'N', + chr(79) => 'O', + chr(80) => 'P', + chr(81) => 'Q', + chr(82) => 'R', + chr(83) => 'S', + chr(84) => 'T', + chr(85) => 'U', + chr(86) => 'V', + chr(87) => 'W', + chr(88) => 'X', + chr(89) => 'Y', + chr(90) => 'Z', + chr(91) => chr(131) . 'K', + chr(92) => chr(131) . 'L', + chr(93) => chr(131) . 'M', + chr(94) => chr(131) . 'N', + chr(95) => chr(131) . 'O', + chr(96) => chr(131) . 'W', + chr(97) => chr(130) . 'A', + chr(98) => chr(130) . 'B', + chr(99) => chr(130) . 'C', + chr(100) => chr(130) . 'D', + chr(101) => chr(130) . 'E', + chr(102) => chr(130) . 'F', + chr(103) => chr(130) . 'G', + chr(104) => chr(130) . 'H', + chr(105) => chr(130) . 'I', + chr(106) => chr(130) . 'J', + chr(107) => chr(130) . 'K', + chr(108) => chr(130) . 'L', + chr(109) => chr(130) . 'M', + chr(110) => chr(130) . 'N', + chr(111) => chr(130) . 'O', + chr(112) => chr(130) . 'P', + chr(113) => chr(130) . 'Q', + chr(114) => chr(130) . 'R', + chr(115) => chr(130) . 'S', + chr(116) => chr(130) . 'T', + chr(117) => chr(130) . 'U', + chr(118) => chr(130) . 'V', + chr(119) => chr(130) . 'W', + chr(120) => chr(130) . 'X', + chr(121) => chr(130) . 'Y', + chr(122) => chr(130) . 'Z', + chr(123) => chr(131) . 'P', + chr(124) => chr(131) . 'Q', + chr(125) => chr(131) . 'R', + chr(126) => chr(131) . 'S', + chr(127) => chr(131) . 'T' + ); + $code_ext = ''; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + if (ord($code{$i}) > 127) { + throw new InvalidCharacterException('Only supports till char 127'); + } + $code_ext .= $encode[$code{$i}]; + } + // checksum + $code_ext .= $this->checksum_code93($code_ext); + // add start and stop codes + $code = '*' . $code_ext . '*'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = ord($code{$i}); + if ( ! isset($chr[$char])) { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char]{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + + return $bararray; + } + + /** + * Calculate CODE 93 checksum (modulo 47). + * + * @param $code (string) code to represent. + * @return string checksum code. + * @protected + */ + protected function checksum_code93($code) + { + $chars = array( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '-', + '.', + ' ', + '$', + '/', + '+', + '%', + '<', + '=', + '>', + '?' + ); + // translate special characters + $code = strtr($code, chr(128) . chr(131) . chr(129) . chr(130), '<=>?'); + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $k = array_keys($chars, $code{$i}); + $check += ($k[0] * $p); + ++$p; + if ($p > 20) { + $p = 1; + } + } + $check %= 47; + $c = $chars[$check]; + $code .= $c; + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $k = array_keys($chars, $code{$i}); + $check += ($k[0] * $p); + ++$p; + if ($p > 15) { + $p = 1; + } + } + $check %= 47; + $k = $chars[$check]; + $checksum = $c . $k; + // resto respecial characters + $checksum = strtr($checksum, '<=>?', chr(128) . chr(131) . chr(129) . chr(130)); + + return $checksum; + } + + /** + * Checksum for standard 2 of 5 barcodes. + * + * @param $code (string) code to process. + * @return int checksum. + * @protected + */ + protected function checksum_s25($code) + { + $len = strlen($code); + $sum = 0; + for ($i = 0; $i < $len; $i += 2) { + $sum += $code{$i}; + } + $sum *= 3; + for ($i = 1; $i < $len; $i += 2) { + $sum += ($code{$i}); + } + $r = $sum % 10; + if ($r > 0) { + $r = (10 - $r); + } + + return $r; + } + + /** + * MSI. + * Variation of Plessey code, with similar applications + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * + * @param $code (string) code to represent. + * @param $checksum (boolean) if true add a checksum to the code (modulo 11) + * @return array barcode representation. + * @protected + */ + protected function barcode_msi($code, $checksum = false) + { + $chr['0'] = '100100100100'; + $chr['1'] = '100100100110'; + $chr['2'] = '100100110100'; + $chr['3'] = '100100110110'; + $chr['4'] = '100110100100'; + $chr['5'] = '100110100110'; + $chr['6'] = '100110110100'; + $chr['7'] = '100110110110'; + $chr['8'] = '110100100100'; + $chr['9'] = '110100100110'; + $chr['A'] = '110100110100'; + $chr['B'] = '110100110110'; + $chr['C'] = '110110100100'; + $chr['D'] = '110110100110'; + $chr['E'] = '110110110100'; + $chr['F'] = '110110110110'; + if ($checksum) { + // add checksum + $clen = strlen($code); + $p = 2; + $check = 0; + for ($i = ($clen - 1); $i >= 0; --$i) { + $check += (hexdec($code{$i}) * $p); + ++$p; + if ($p > 7) { + $p = 2; + } + } + $check %= 11; + if ($check > 0) { + $check = 11 - $check; + } + $code .= $check; + } + $seq = '110'; // left guard + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code{$i}; + if ( ! isset($chr[$digit])) { + throw new InvalidCharacterException('Char ' . $digit . ' is unsupported'); + } + $seq .= $chr[$digit]; + } + $seq .= '1001'; // right guard + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Standard 2 of 5 barcodes. + * Used in airline ticket marking, photofinishing + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * + * @param $code (string) code to represent. + * @param $checksum (boolean) if true add a checksum to the code + * @return array barcode representation. + * @protected + */ + protected function barcode_s25($code, $checksum = false) + { + $chr['0'] = '10101110111010'; + $chr['1'] = '11101010101110'; + $chr['2'] = '10111010101110'; + $chr['3'] = '11101110101010'; + $chr['4'] = '10101110101110'; + $chr['5'] = '11101011101010'; + $chr['6'] = '10111011101010'; + $chr['7'] = '10101011101110'; + $chr['8'] = '10101110111010'; + $chr['9'] = '10111010111010'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if ((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0' . $code; + } + $seq = '11011010'; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code{$i}; + if ( ! isset($chr[$digit])) { + throw new InvalidCharacterException('Char ' . $digit . ' is unsupported'); + } + $seq .= $chr[$digit]; + } + $seq .= '1101011'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Convert binary barcode sequence to TCPDF barcode array. + * + * @param $seq (string) barcode as binary sequence. + * @param $bararray (array) barcode array. + * òparam array $bararray TCPDF barcode array to fill up + * @return array barcode representation. + * @protected + */ + protected function binseq_to_array($seq, $bararray) + { + $len = strlen($seq); + $w = 0; + $k = 0; + for ($i = 0; $i < $len; ++$i) { + $w += 1; + if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i + 1)}))) { + if ($seq{$i} == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + + return $bararray; + } + + /** + * Interleaved 2 of 5 barcodes. + * Compact numeric code, widely used in industry, air cargo + * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. + * + * @param $code (string) code to represent. + * @param $checksum (boolean) if true add a checksum to the code + * @return array barcode representation. + * @protected + */ + protected function barcode_i25($code, $checksum = false) + { + $chr['0'] = '11221'; + $chr['1'] = '21112'; + $chr['2'] = '12112'; + $chr['3'] = '22111'; + $chr['4'] = '11212'; + $chr['5'] = '21211'; + $chr['6'] = '12211'; + $chr['7'] = '11122'; + $chr['8'] = '21121'; + $chr['9'] = '12121'; + $chr['A'] = '11'; + $chr['Z'] = '21'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if ((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0' . $code; + } + // add start and stop codes + $code = 'AA' . strtolower($code) . 'ZA'; + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; $i = ($i + 2)) { + $char_bar = $code{$i}; + $char_space = $code{$i + 1}; + if ( ! isset($chr[$char_bar]) || ! isset($chr[$char_space])) { + throw new InvalidCharacterException(); + } + // create a bar-space sequence + $seq = ''; + $chrlen = strlen($chr[$char_bar]); + for ($s = 0; $s < $chrlen; $s++) { + $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s}; + } + $seqlen = strlen($seq); + for ($j = 0; $j < $seqlen; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * C128 barcodes. + * Very capable code, excellent density, high reliability; in very wide use world-wide + * + * @param $code (string) code to represent. + * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode) + * @return array barcode representation. + * @protected + */ + protected function barcode_c128($code, $type = '') + { + $chr = array( + '212222', /* 00 */ + '222122', /* 01 */ + '222221', /* 02 */ + '121223', /* 03 */ + '121322', /* 04 */ + '131222', /* 05 */ + '122213', /* 06 */ + '122312', /* 07 */ + '132212', /* 08 */ + '221213', /* 09 */ + '221312', /* 10 */ + '231212', /* 11 */ + '112232', /* 12 */ + '122132', /* 13 */ + '122231', /* 14 */ + '113222', /* 15 */ + '123122', /* 16 */ + '123221', /* 17 */ + '223211', /* 18 */ + '221132', /* 19 */ + '221231', /* 20 */ + '213212', /* 21 */ + '223112', /* 22 */ + '312131', /* 23 */ + '311222', /* 24 */ + '321122', /* 25 */ + '321221', /* 26 */ + '312212', /* 27 */ + '322112', /* 28 */ + '322211', /* 29 */ + '212123', /* 30 */ + '212321', /* 31 */ + '232121', /* 32 */ + '111323', /* 33 */ + '131123', /* 34 */ + '131321', /* 35 */ + '112313', /* 36 */ + '132113', /* 37 */ + '132311', /* 38 */ + '211313', /* 39 */ + '231113', /* 40 */ + '231311', /* 41 */ + '112133', /* 42 */ + '112331', /* 43 */ + '132131', /* 44 */ + '113123', /* 45 */ + '113321', /* 46 */ + '133121', /* 47 */ + '313121', /* 48 */ + '211331', /* 49 */ + '231131', /* 50 */ + '213113', /* 51 */ + '213311', /* 52 */ + '213131', /* 53 */ + '311123', /* 54 */ + '311321', /* 55 */ + '331121', /* 56 */ + '312113', /* 57 */ + '312311', /* 58 */ + '332111', /* 59 */ + '314111', /* 60 */ + '221411', /* 61 */ + '431111', /* 62 */ + '111224', /* 63 */ + '111422', /* 64 */ + '121124', /* 65 */ + '121421', /* 66 */ + '141122', /* 67 */ + '141221', /* 68 */ + '112214', /* 69 */ + '112412', /* 70 */ + '122114', /* 71 */ + '122411', /* 72 */ + '142112', /* 73 */ + '142211', /* 74 */ + '241211', /* 75 */ + '221114', /* 76 */ + '413111', /* 77 */ + '241112', /* 78 */ + '134111', /* 79 */ + '111242', /* 80 */ + '121142', /* 81 */ + '121241', /* 82 */ + '114212', /* 83 */ + '124112', /* 84 */ + '124211', /* 85 */ + '411212', /* 86 */ + '421112', /* 87 */ + '421211', /* 88 */ + '212141', /* 89 */ + '214121', /* 90 */ + '412121', /* 91 */ + '111143', /* 92 */ + '111341', /* 93 */ + '131141', /* 94 */ + '114113', /* 95 */ + '114311', /* 96 */ + '411113', /* 97 */ + '411311', /* 98 */ + '113141', /* 99 */ + '114131', /* 100 */ + '311141', /* 101 */ + '411131', /* 102 */ + '211412', /* 103 START A */ + '211214', /* 104 START B */ + '211232', /* 105 START C */ + '233111', /* STOP */ + '200000' /* END */ + ); + // ASCII characters for code A (ASCII 00 - 95) + $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; + $keys_a .= chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8) . chr(9); + $keys_a .= chr(10) . chr(11) . chr(12) . chr(13) . chr(14) . chr(15) . chr(16) . chr(17) . chr(18) . chr(19); + $keys_a .= chr(20) . chr(21) . chr(22) . chr(23) . chr(24) . chr(25) . chr(26) . chr(27) . chr(28) . chr(29); + $keys_a .= chr(30) . chr(31); + // ASCII characters for code B (ASCII 32 - 127) + $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . chr(127); + // special codes + $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101); + $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100); + // array of symbols + $code_data = array(); + // length of the code + $len = strlen($code); + switch (strtoupper($type)) { + case 'A': { // MODE A + $startid = 103; + for ($i = 0; $i < $len; ++$i) { + $char = $code{$i}; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_a[$char_id]; + } elseif (($char_id >= 0) AND ($char_id <= 95)) { + $code_data[] = strpos($keys_a, $char); + } else { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + } + break; + } + case 'B': { // MODE B + $startid = 104; + for ($i = 0; $i < $len; ++$i) { + $char = $code{$i}; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_b[$char_id]; + } elseif (($char_id >= 32) AND ($char_id <= 127)) { + $code_data[] = strpos($keys_b, $char); + } else { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + } + break; + } + case 'C': { // MODE C + $startid = 105; + if (ord($code[0]) == 241) { + $code_data[] = 102; + $code = substr($code, 1); + --$len; + } + if (($len % 2) != 0) { + throw new InvalidLengthException('Length must be even'); + } + for ($i = 0; $i < $len; $i += 2) { + $chrnum = $code{$i} . $code{$i + 1}; + if (preg_match('/([0-9]{2})/', $chrnum) > 0) { + $code_data[] = intval($chrnum); + } else { + throw new InvalidCharacterException(); + } + } + break; + } + default: { // MODE AUTO + // split code into sequences + $sequence = array(); + // get numeric sequences (if any) + $numseq = array(); + preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) AND ! empty($numseq[1])) { + $end_offset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + + // numeric sequence + $slen = strlen($val[0]); + if (($slen % 2) != 0) { + // the length must be even + ++$offset; + $val[0] = substr($val[0],1); + } + + if ($offset > $end_offset) { + // non numeric sequence + $sequence = array_merge($sequence, + $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset)))); + } + // numeric sequence fallback + $slen = strlen($val[0]); + if (($slen % 2) != 0) { + // the length must be even + --$slen; + } + $sequence[] = array('C', substr($code, $offset, $slen), $slen); + $end_offset = $offset + $slen; + } + if ($end_offset < $len) { + $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset))); + } + } else { + // text code (non C mode) + $sequence = array_merge($sequence, $this->get128ABsequence($code)); + } + // process the sequence + foreach ($sequence as $key => $seq) { + switch ($seq[0]) { + case 'A': { + if ($key == 0) { + $startid = 103; + } elseif ($sequence[($key - 1)][0] != 'A') { + if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND ( ! isset($sequence[($key - 1)][3]))) { + // single character shift + $code_data[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif ( ! isset($sequence[($key - 1)][3])) { + $code_data[] = 101; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1]{$i}; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_a[$char_id]; + } else { + $code_data[] = strpos($keys_a, $char); + } + } + break; + } + case 'B': { + if ($key == 0) { + $tmpchr = ord($seq[1][0]); + if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) { + switch ($sequence[($key + 1)][0]) { + case 'A': { + $startid = 103; + $sequence[$key][0] = 'A'; + $code_data[] = $fnc_a[$tmpchr]; + break; + } + case 'C': { + $startid = 105; + $sequence[$key][0] = 'C'; + $code_data[] = $fnc_a[$tmpchr]; + break; + } + } + break; + } else { + $startid = 104; + } + } elseif ($sequence[($key - 1)][0] != 'B') { + if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND ( ! isset($sequence[($key - 1)][3]))) { + // single character shift + $code_data[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif ( ! isset($sequence[($key - 1)][3])) { + $code_data[] = 100; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1]{$i}; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_b[$char_id]; + } else { + $code_data[] = strpos($keys_b, $char); + } + } + break; + } + case 'C': { + if ($key == 0) { + $startid = 105; + } elseif ($sequence[($key - 1)][0] != 'C') { + $code_data[] = 99; + } + for ($i = 0; $i < $seq[2]; $i += 2) { + $chrnum = $seq[1]{$i} . $seq[1]{$i + 1}; + $code_data[] = intval($chrnum); + } + break; + } + } + } + } + } + // calculate check character + $sum = $startid; + foreach ($code_data as $key => $val) { + $sum += ($val * ($key + 1)); + } + // add check character + $code_data[] = ($sum % 103); + // add stop sequence + $code_data[] = 106; + $code_data[] = 107; + // add start code at the beginning + array_unshift($code_data, $startid); + // build barcode array + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + foreach ($code_data as $val) { + $seq = $chr[$val]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + } + } + + return $bararray; + } + + /** + * Split text code in A/B sequence for 128 code + * + * @param $code (string) code to split. + * @return array sequence + * @protected + */ + protected function get128ABsequence($code) + { + $len = strlen($code); + $sequence = array(); + // get A sequences (if any) + $numseq = array(); + preg_match_all('/([\x00-\x1f])/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) AND ! empty($numseq[1])) { + $end_offset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + if ($offset > $end_offset) { + // B sequence + $sequence[] = array( + 'B', + substr($code, $end_offset, ($offset - $end_offset)), + ($offset - $end_offset) + ); + } + // A sequence + $slen = strlen($val[0]); + $sequence[] = array('A', substr($code, $offset, $slen), $slen); + $end_offset = $offset + $slen; + } + if ($end_offset < $len) { + $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset)); + } + } else { + // only B sequence + $sequence[] = array('B', $code, $len); + } + + return $sequence; + } + + /** + * EAN13 and UPC-A barcodes. + * EAN13: European Article Numbering international retail product code + * UPC-A: Universal product code seen on almost all retail products in the USA and Canada + * UPC-E: Short version of UPC symbol + * + * @param $code (string) code to represent. + * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A + * @return array barcode representation. + * @protected + */ + protected function barcode_eanupc($code, $len = 13) + { + $upce = false; + if ($len == 6) { + $len = 12; // UPC-A + $upce = true; // UPC-E mode + } + $data_len = $len - 1; + //Padding + $code = str_pad($code, $data_len, '0', STR_PAD_LEFT); + $code_len = strlen($code); + // calculate check digit + $sum_a = 0; + for ($i = 1; $i < $data_len; $i += 2) { + $sum_a += $code{$i}; + } + if ($len > 12) { + $sum_a *= 3; + } + $sum_b = 0; + for ($i = 0; $i < $data_len; $i += 2) { + $sum_b += ($code{$i}); + } + if ($len < 13) { + $sum_b *= 3; + } + $r = ($sum_a + $sum_b) % 10; + if ($r > 0) { + $r = (10 - $r); + } + if ($code_len == $data_len) { + // add check digit + $code .= $r; + } elseif ($r !== intval($code{$data_len})) { + throw new InvalidCheckDigitException(); + } + if ($len == 12) { + // UPC-A + $code = '0' . $code; + ++$len; + } + if ($upce) { + // convert UPC-A to UPC-E + $tmp = substr($code, 4, 3); + if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) { + // manufacturer code ends in 000, 100, or 200 + $upce_code = substr($code, 2, 2) . substr($code, 9, 3) . substr($code, 4, 1); + } else { + $tmp = substr($code, 5, 2); + if ($tmp == '00') { + // manufacturer code ends in 00 + $upce_code = substr($code, 2, 3) . substr($code, 10, 2) . '3'; + } else { + $tmp = substr($code, 6, 1); + if ($tmp == '0') { + // manufacturer code ends in 0 + $upce_code = substr($code, 2, 4) . substr($code, 11, 1) . '4'; + } else { + // manufacturer code does not end in zero + $upce_code = substr($code, 2, 5) . substr($code, 11, 1); + } + } + } + } + //Convert digits to bars + $codes = array( + 'A' => array( // left odd parity + '0' => '0001101', + '1' => '0011001', + '2' => '0010011', + '3' => '0111101', + '4' => '0100011', + '5' => '0110001', + '6' => '0101111', + '7' => '0111011', + '8' => '0110111', + '9' => '0001011' + ), + 'B' => array( // left even parity + '0' => '0100111', + '1' => '0110011', + '2' => '0011011', + '3' => '0100001', + '4' => '0011101', + '5' => '0111001', + '6' => '0000101', + '7' => '0010001', + '8' => '0001001', + '9' => '0010111' + ), + 'C' => array( // right + '0' => '1110010', + '1' => '1100110', + '2' => '1101100', + '3' => '1000010', + '4' => '1011100', + '5' => '1001110', + '6' => '1010000', + '7' => '1000100', + '8' => '1001000', + '9' => '1110100' + ) + ); + $parities = array( + '0' => array('A', 'A', 'A', 'A', 'A', 'A'), + '1' => array('A', 'A', 'B', 'A', 'B', 'B'), + '2' => array('A', 'A', 'B', 'B', 'A', 'B'), + '3' => array('A', 'A', 'B', 'B', 'B', 'A'), + '4' => array('A', 'B', 'A', 'A', 'B', 'B'), + '5' => array('A', 'B', 'B', 'A', 'A', 'B'), + '6' => array('A', 'B', 'B', 'B', 'A', 'A'), + '7' => array('A', 'B', 'A', 'B', 'A', 'B'), + '8' => array('A', 'B', 'A', 'B', 'B', 'A'), + '9' => array('A', 'B', 'B', 'A', 'B', 'A') + ); + $upce_parities = array(); + $upce_parities[0] = array( + '0' => array('B', 'B', 'B', 'A', 'A', 'A'), + '1' => array('B', 'B', 'A', 'B', 'A', 'A'), + '2' => array('B', 'B', 'A', 'A', 'B', 'A'), + '3' => array('B', 'B', 'A', 'A', 'A', 'B'), + '4' => array('B', 'A', 'B', 'B', 'A', 'A'), + '5' => array('B', 'A', 'A', 'B', 'B', 'A'), + '6' => array('B', 'A', 'A', 'A', 'B', 'B'), + '7' => array('B', 'A', 'B', 'A', 'B', 'A'), + '8' => array('B', 'A', 'B', 'A', 'A', 'B'), + '9' => array('B', 'A', 'A', 'B', 'A', 'B') + ); + $upce_parities[1] = array( + '0' => array('A', 'A', 'A', 'B', 'B', 'B'), + '1' => array('A', 'A', 'B', 'A', 'B', 'B'), + '2' => array('A', 'A', 'B', 'B', 'A', 'B'), + '3' => array('A', 'A', 'B', 'B', 'B', 'A'), + '4' => array('A', 'B', 'A', 'A', 'B', 'B'), + '5' => array('A', 'B', 'B', 'A', 'A', 'B'), + '6' => array('A', 'B', 'B', 'B', 'A', 'A'), + '7' => array('A', 'B', 'A', 'B', 'A', 'B'), + '8' => array('A', 'B', 'A', 'B', 'B', 'A'), + '9' => array('A', 'B', 'B', 'A', 'B', 'A') + ); + $k = 0; + $seq = '101'; // left guard bar + if ($upce) { + $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $p = $upce_parities[$code[1]][$r]; + for ($i = 0; $i < 6; ++$i) { + $seq .= $codes[$p[$i]][$upce_code{$i}]; + } + $seq .= '010101'; // right guard bar + } else { + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $half_len = intval(ceil($len / 2)); + if ($len == 8) { + for ($i = 0; $i < $half_len; ++$i) { + $seq .= $codes['A'][$code{$i}]; + } + } else { + $p = $parities[$code[0]]; + for ($i = 1; $i < $half_len; ++$i) { + $seq .= $codes[$p[$i - 1]][$code{$i}]; + } + } + $seq .= '01010'; // center guard bar + for ($i = $half_len; $i < $len; ++$i) { + if ( ! isset($codes['C'][$code{$i}])) { + throw new InvalidCharacterException('Char ' . $code{$i} . ' not allowed'); + } + $seq .= $codes['C'][$code{$i}]; + } + $seq .= '101'; // right guard bar + } + $clen = strlen($seq); + $w = 0; + for ($i = 0; $i < $clen; ++$i) { + $w += 1; + if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i + 1)}))) { + if ($seq{$i} == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + + return $bararray; + } + + /** + * UPC-Based Extensions + * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers + * 5-Digit Ext.: Used to mark suggested retail price of books + * + * @param $code (string) code to represent. + * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit + * @return array barcode representation. + * @protected + */ + protected function barcode_eanext($code, $len = 5) + { + //Padding + $code = str_pad($code, $len, '0', STR_PAD_LEFT); + // calculate check digit + if ($len == 2) { + $r = $code % 4; + } elseif ($len == 5) { + $r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3])); + $r %= 10; + } else { + throw new InvalidCheckDigitException(); + } + //Convert digits to bars + $codes = array( + 'A' => array( // left odd parity + '0' => '0001101', + '1' => '0011001', + '2' => '0010011', + '3' => '0111101', + '4' => '0100011', + '5' => '0110001', + '6' => '0101111', + '7' => '0111011', + '8' => '0110111', + '9' => '0001011' + ), + 'B' => array( // left even parity + '0' => '0100111', + '1' => '0110011', + '2' => '0011011', + '3' => '0100001', + '4' => '0011101', + '5' => '0111001', + '6' => '0000101', + '7' => '0010001', + '8' => '0001001', + '9' => '0010111' + ) + ); + $parities = array(); + $parities[2] = array( + '0' => array('A', 'A'), + '1' => array('A', 'B'), + '2' => array('B', 'A'), + '3' => array('B', 'B') + ); + $parities[5] = array( + '0' => array('B', 'B', 'A', 'A', 'A'), + '1' => array('B', 'A', 'B', 'A', 'A'), + '2' => array('B', 'A', 'A', 'B', 'A'), + '3' => array('B', 'A', 'A', 'A', 'B'), + '4' => array('A', 'B', 'B', 'A', 'A'), + '5' => array('A', 'A', 'B', 'B', 'A'), + '6' => array('A', 'A', 'A', 'B', 'B'), + '7' => array('A', 'B', 'A', 'B', 'A'), + '8' => array('A', 'B', 'A', 'A', 'B'), + '9' => array('A', 'A', 'B', 'A', 'B') + ); + $p = $parities[$len][$r]; + $seq = '1011'; // left guard bar + $seq .= $codes[$p[0]][$code[0]]; + for ($i = 1; $i < $len; ++$i) { + $seq .= '01'; // separator + $seq .= $codes[$p[$i]][$code{$i}]; + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * POSTNET and PLANET barcodes. + * Used by U.S. Postal Service for automated mail sorting + * + * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or + * DDDDD-DDDD. + * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET + * @return array barcode representation. + * @protected + */ + protected function barcode_postnet($code, $planet = false) + { + // bar length + if ($planet) { + $barlen = Array( + 0 => Array(1, 1, 2, 2, 2), + 1 => Array(2, 2, 2, 1, 1), + 2 => Array(2, 2, 1, 2, 1), + 3 => Array(2, 2, 1, 1, 2), + 4 => Array(2, 1, 2, 2, 1), + 5 => Array(2, 1, 2, 1, 2), + 6 => Array(2, 1, 1, 2, 2), + 7 => Array(1, 2, 2, 2, 1), + 8 => Array(1, 2, 2, 1, 2), + 9 => Array(1, 2, 1, 2, 2) + ); + } else { + $barlen = Array( + 0 => Array(2, 2, 1, 1, 1), + 1 => Array(1, 1, 1, 2, 2), + 2 => Array(1, 1, 2, 1, 2), + 3 => Array(1, 1, 2, 2, 1), + 4 => Array(1, 2, 1, 1, 2), + 5 => Array(1, 2, 1, 2, 1), + 6 => Array(1, 2, 2, 1, 1), + 7 => Array(2, 1, 1, 1, 2), + 8 => Array(2, 1, 1, 2, 1), + 9 => Array(2, 1, 2, 1, 1) + ); + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $k = 0; + $code = str_replace('-', '', $code); + $code = str_replace(' ', '', $code); + $len = strlen($code); + // calculate checksum + $sum = 0; + for ($i = 0; $i < $len; ++$i) { + $sum += intval($code{$i}); + } + $chkd = ($sum % 10); + if ($chkd > 0) { + $chkd = (10 - $chkd); + } + $code .= $chkd; + $len = strlen($code); + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 5; ++$j) { + $h = $barlen[$code{$i}][$j]; + $p = floor(1 / $h); + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + // end bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 1; + + return $bararray; + } + + /** + * RMS4CC - CBC - KIX + * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) + * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. + * + * @param $code (string) code to print + * @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) + * - in this case the house number must be sufficed with an X and placed at the end of the code. + * @return array barcode representation. + * @protected + */ + protected function barcode_rms4cc($code, $kix = false) + { + $notkix = ! $kix; + // bar mode + // 1 = pos 1, length 2 + // 2 = pos 1, length 3 + // 3 = pos 2, length 1 + // 4 = pos 2, length 2 + $barmode = array( + '0' => array(3, 3, 2, 2), + '1' => array(3, 4, 1, 2), + '2' => array(3, 4, 2, 1), + '3' => array(4, 3, 1, 2), + '4' => array(4, 3, 2, 1), + '5' => array(4, 4, 1, 1), + '6' => array(3, 1, 4, 2), + '7' => array(3, 2, 3, 2), + '8' => array(3, 2, 4, 1), + '9' => array(4, 1, 3, 2), + 'A' => array(4, 1, 4, 1), + 'B' => array(4, 2, 3, 1), + 'C' => array(3, 1, 2, 4), + 'D' => array(3, 2, 1, 4), + 'E' => array(3, 2, 2, 3), + 'F' => array(4, 1, 1, 4), + 'G' => array(4, 1, 2, 3), + 'H' => array(4, 2, 1, 3), + 'I' => array(1, 3, 4, 2), + 'J' => array(1, 4, 3, 2), + 'K' => array(1, 4, 4, 1), + 'L' => array(2, 3, 3, 2), + 'M' => array(2, 3, 4, 1), + 'N' => array(2, 4, 3, 1), + 'O' => array(1, 3, 2, 4), + 'P' => array(1, 4, 1, 4), + 'Q' => array(1, 4, 2, 3), + 'R' => array(2, 3, 1, 4), + 'S' => array(2, 3, 2, 3), + 'T' => array(2, 4, 1, 3), + 'U' => array(1, 1, 4, 4), + 'V' => array(1, 2, 3, 4), + 'W' => array(1, 2, 4, 3), + 'X' => array(2, 1, 3, 4), + 'Y' => array(2, 1, 4, 3), + 'Z' => array(2, 2, 3, 3) + ); + $code = strtoupper($code); + $len = strlen($code); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + if ($notkix) { + // table for checksum calculation (row,col) + $checktable = array( + '0' => array(1, 1), + '1' => array(1, 2), + '2' => array(1, 3), + '3' => array(1, 4), + '4' => array(1, 5), + '5' => array(1, 0), + '6' => array(2, 1), + '7' => array(2, 2), + '8' => array(2, 3), + '9' => array(2, 4), + 'A' => array(2, 5), + 'B' => array(2, 0), + 'C' => array(3, 1), + 'D' => array(3, 2), + 'E' => array(3, 3), + 'F' => array(3, 4), + 'G' => array(3, 5), + 'H' => array(3, 0), + 'I' => array(4, 1), + 'J' => array(4, 2), + 'K' => array(4, 3), + 'L' => array(4, 4), + 'M' => array(4, 5), + 'N' => array(4, 0), + 'O' => array(5, 1), + 'P' => array(5, 2), + 'Q' => array(5, 3), + 'R' => array(5, 4), + 'S' => array(5, 5), + 'T' => array(5, 0), + 'U' => array(0, 1), + 'V' => array(0, 2), + 'W' => array(0, 3), + 'X' => array(0, 4), + 'Y' => array(0, 5), + 'Z' => array(0, 0) + ); + $row = 0; + $col = 0; + for ($i = 0; $i < $len; ++$i) { + $row += $checktable[$code{$i}][0]; + $col += $checktable[$code{$i}][1]; + } + $row %= 6; + $col %= 6; + $chk = array_keys($checktable, array($row, $col)); + $code .= $chk[0]; + ++$len; + } + $k = 0; + if ($notkix) { + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 4; ++$j) { + switch ($barmode[$code{$i}][$j]) { + case 1: { + $p = 0; + $h = 2; + break; + } + case 2: { + $p = 0; + $h = 3; + break; + } + case 3: { + $p = 1; + $h = 1; + break; + } + case 4: { + $p = 1; + $h = 2; + break; + } + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + if ($notkix) { + // stop bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0); + $bararray['maxw'] += 1; + } + + return $bararray; + } + + /** + * CODABAR barcodes. + * Older code often used in library systems, sometimes in blood banks + * + * @param $code (string) code to represent. + * @return array barcode representation. + * @protected + */ + protected function barcode_codabar($code) + { + $chr = array( + '0' => '11111221', + '1' => '11112211', + '2' => '11121121', + '3' => '22111111', + '4' => '11211211', + '5' => '21111211', + '6' => '12111121', + '7' => '12112111', + '8' => '12211111', + '9' => '21121111', + '-' => '11122111', + '$' => '11221111', + ':' => '21112121', + '/' => '21211121', + '.' => '21212111', + '+' => '11222221', + 'A' => '11221211', + 'B' => '12121121', + 'C' => '11121221', + 'D' => '11122211' + ); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $w = 0; + $seq = ''; + $code = 'A' . strtoupper($code) . 'A'; + $len = strlen($code); + for ($i = 0; $i < $len; ++$i) { + if ( ! isset($chr[$code{$i}])) { + throw new InvalidCharacterException('Char ' . $code{$i} . ' is unsupported'); + } + $seq = $chr[$code{$i}]; + for ($j = 0; $j < 8; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * CODE11 barcodes. + * Used primarily for labeling telecommunications equipment + * + * @param $code (string) code to represent. + * @return array barcode representation. + * @protected + */ + protected function barcode_code11($code) + { + $chr = array( + '0' => '111121', + '1' => '211121', + '2' => '121121', + '3' => '221111', + '4' => '112121', + '5' => '212111', + '6' => '122111', + '7' => '111221', + '8' => '211211', + '9' => '211111', + '-' => '112111', + 'S' => '112211' + ); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $w = 0; + $seq = ''; + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $digit = $code{$i}; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 10) { + $p = 1; + } + } + $check %= 11; + if ($check == 10) { + $check = '-'; + } + $code .= $check; + if ($len > 10) { + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $digit = $code{$i}; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 9) { + $p = 1; + } + } + $check %= 11; + $code .= $check; + ++$len; + } + $code = 'S' . $code . 'S'; + $len += 3; + for ($i = 0; $i < $len; ++$i) { + if ( ! isset($chr[$code{$i}])) { + throw new InvalidCharacterException('Char ' . $code{$i} . ' is unsupported'); + } + $seq = $chr[$code{$i}]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * Pharmacode + * Contains digits (0 to 9) + * + * @param $code (string) code to represent. + * @return array barcode representation. + * @protected + */ + protected function barcode_pharmacode($code) + { + $seq = ''; + $code = intval($code); + while ($code > 0) { + if (($code % 2) == 0) { + $seq .= '11100'; + $code -= 2; + } else { + $seq .= '100'; + $code -= 1; + } + $code /= 2; + } + $seq = substr($seq, 0, -2); + $seq = strrev($seq); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Pharmacode two-track + * Contains digits (0 to 9) + * + * @param $code (string) code to represent. + * @return array barcode representation. + * @protected + */ + protected function barcode_pharmacode2t($code) + { + $seq = ''; + $code = intval($code); + do { + switch ($code % 3) { + case 0: { + $seq .= '3'; + $code = ($code - 3) / 3; + break; + } + case 1: { + $seq .= '1'; + $code = ($code - 1) / 3; + break; + } + case 2: { + $seq .= '2'; + $code = ($code - 2) / 3; + break; + } + } + } while ($code != 0); + $seq = strrev($seq); + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $len = strlen($seq); + for ($i = 0; $i < $len; ++$i) { + switch ($seq{$i}) { + case '1': { + $p = 1; + $h = 1; + break; + } + case '2': { + $p = 0; + $h = 1; + break; + } + case '3': { + $p = 0; + $h = 2; + break; + } + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + + return $bararray; + } + + /** + * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + * (requires PHP bcmath extension) + * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. + * The fields are described as follows:
  • The Barcode Identifier shall be assigned by USPS to encode the + * presort identification that is currently printed in human readable form on the optional endorsement line (OEL) + * as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The + * allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and + * 90–94.
  • The Service Type Identifier shall be assigned by USPS for any combination of services requested + * on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. + * Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each + * service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier + * values.
  • The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number + * that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- + * 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.
  • The + * Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The + * allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when + * used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the + * mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be + * 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, + * and 00000000000–99999999999.
+ * + * @param $code (string) code to print, separate the ZIP (routing code) from the rest using a minus char '-' + * (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode) + * @return array barcode representation. + * @protected + */ + protected function barcode_imb($code) + { + $asc_chr = array( + 4, + 0, + 2, + 6, + 3, + 5, + 1, + 9, + 8, + 7, + 1, + 2, + 0, + 6, + 4, + 8, + 2, + 9, + 5, + 3, + 0, + 1, + 3, + 7, + 4, + 6, + 8, + 9, + 2, + 0, + 5, + 1, + 9, + 4, + 3, + 8, + 6, + 7, + 1, + 2, + 4, + 3, + 9, + 5, + 7, + 8, + 3, + 0, + 2, + 1, + 4, + 0, + 9, + 1, + 7, + 0, + 2, + 4, + 6, + 3, + 7, + 1, + 9, + 5, + 8 + ); + $dsc_chr = array( + 7, + 1, + 9, + 5, + 8, + 0, + 2, + 4, + 6, + 3, + 5, + 8, + 9, + 7, + 3, + 0, + 6, + 1, + 7, + 4, + 6, + 8, + 9, + 2, + 5, + 1, + 7, + 5, + 4, + 3, + 8, + 7, + 6, + 0, + 2, + 5, + 4, + 9, + 3, + 0, + 1, + 6, + 8, + 2, + 0, + 4, + 5, + 9, + 6, + 7, + 5, + 2, + 6, + 3, + 8, + 5, + 1, + 9, + 8, + 7, + 4, + 0, + 2, + 6, + 3 + ); + $asc_pos = array( + 3, + 0, + 8, + 11, + 1, + 12, + 8, + 11, + 10, + 6, + 4, + 12, + 2, + 7, + 9, + 6, + 7, + 9, + 2, + 8, + 4, + 0, + 12, + 7, + 10, + 9, + 0, + 7, + 10, + 5, + 7, + 9, + 6, + 8, + 2, + 12, + 1, + 4, + 2, + 0, + 1, + 5, + 4, + 6, + 12, + 1, + 0, + 9, + 4, + 7, + 5, + 10, + 2, + 6, + 9, + 11, + 2, + 12, + 6, + 7, + 5, + 11, + 0, + 3, + 2 + ); + $dsc_pos = array( + 2, + 10, + 12, + 5, + 9, + 1, + 5, + 4, + 3, + 9, + 11, + 5, + 10, + 1, + 6, + 3, + 4, + 1, + 10, + 0, + 2, + 11, + 8, + 6, + 1, + 12, + 3, + 8, + 6, + 4, + 4, + 11, + 0, + 6, + 1, + 9, + 11, + 5, + 3, + 7, + 3, + 10, + 7, + 11, + 8, + 2, + 10, + 3, + 5, + 8, + 0, + 3, + 12, + 11, + 8, + 4, + 5, + 1, + 3, + 0, + 7, + 12, + 9, + 8, + 10 + ); + $code_arr = explode('-', $code); + $tracking_number = $code_arr[0]; + if (isset($code_arr[1])) { + $routing_code = $code_arr[1]; + } else { + $routing_code = ''; + } + // Conversion of Routing Code + switch (strlen($routing_code)) { + case 0: { + $binary_code = 0; + break; + } + case 5: { + $binary_code = bcadd($routing_code, '1'); + break; + } + case 9: { + $binary_code = bcadd($routing_code, '100001'); + break; + } + case 11: { + $binary_code = bcadd($routing_code, '1000100001'); + break; + } + default: { + throw new BarcodeException('Routing code unknown'); + break; + } + } + $binary_code = bcmul($binary_code, 10); + $binary_code = bcadd($binary_code, $tracking_number[0]); + $binary_code = bcmul($binary_code, 5); + $binary_code = bcadd($binary_code, $tracking_number[1]); + $binary_code .= substr($tracking_number, 2, 18); + // convert to hexadecimal + $binary_code = $this->dec_to_hex($binary_code); + // pad to get 13 bytes + $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT); + // convert string to array of bytes + $binary_code_arr = chunk_split($binary_code, 2, "\r"); + $binary_code_arr = substr($binary_code_arr, 0, -1); + $binary_code_arr = explode("\r", $binary_code_arr); + // calculate frame check sequence + $fcs = $this->imb_crc11fcs($binary_code_arr); + // exclude first 2 bits from first byte + $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2)); + $binary_code_102bit = $first_byte . substr($binary_code, 2); + // convert binary data to codewords + $codewords = array(); + $data = $this->hex_to_dec($binary_code_102bit); + $codewords[0] = bcmod($data, 636) * 2; + $data = bcdiv($data, 636); + for ($i = 1; $i < 9; ++$i) { + $codewords[$i] = bcmod($data, 1365); + $data = bcdiv($data, 1365); + } + $codewords[9] = $data; + if (($fcs >> 10) == 1) { + $codewords[9] += 659; + } + // generate lookup tables + $table2of13 = $this->imb_tables(2, 78); + $table5of13 = $this->imb_tables(5, 1287); + // convert codewords to characters + $characters = array(); + $bitmask = 512; + foreach ($codewords as $k => $val) { + if ($val <= 1286) { + $chrcode = $table5of13[$val]; + } else { + $chrcode = $table2of13[($val - 1287)]; + } + if (($fcs & $bitmask) > 0) { + // bitwise invert + $chrcode = ((~$chrcode) & 8191); + } + $characters[] = $chrcode; + $bitmask /= 2; + } + $characters = array_reverse($characters); + // build bars + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + for ($i = 0; $i < 65; ++$i) { + $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0); + $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0); + if ($asc AND $dsc) { + // full bar (F) + $p = 0; + $h = 3; + } elseif ($asc) { + // ascender (A) + $p = 0; + $h = 2; + } elseif ($dsc) { + // descender (D) + $p = 1; + $h = 2; + } else { + // tracker (T) + $p = 1; + $h = 1; + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + + return $bararray; + } + + /** + * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + * + * @param $code (string) pre-formatted IMB barcode (65 chars "FADT") + * @return array barcode representation. + * @protected + */ + protected function barcode_imb_pre($code) + { + if ( ! preg_match('/^[fadtFADT]{65}$/', $code) == 1) { + throw new InvalidFormatException(); + } + $characters = str_split(strtolower($code), 1); + // build bars + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + for ($i = 0; $i < 65; ++$i) { + switch ($characters[$i]) { + case 'f': { + // full bar + $p = 0; + $h = 3; + break; + } + case 'a': { + // ascender + $p = 0; + $h = 2; + break; + } + case 'd': { + // descender + $p = 1; + $h = 2; + break; + } + case 't': { + // tracker (short) + $p = 1; + $h = 1; + break; + } + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + + return $bararray; + } + + /** + * Convert large integer number to hexadecimal representation. + * (requires PHP bcmath extension) + * + * @param $number (string) number to convert specified as a string + * @return string hexadecimal representation + */ + protected function dec_to_hex($number) + { + if ($number == 0) { + return '00'; + } + + $hex = []; + + while ($number > 0) { + array_push($hex, strtoupper(dechex(bcmod($number, '16')))); + $number = bcdiv($number, '16', 0); + } + $hex = array_reverse($hex); + + return implode($hex); + } + + /** + * Convert large hexadecimal number to decimal representation (string). + * (requires PHP bcmath extension) + * + * @param $hex (string) hexadecimal number to convert specified as a string + * @return string hexadecimal representation + */ + protected function hex_to_dec($hex) + { + $dec = 0; + $bitval = 1; + $len = strlen($hex); + for ($pos = ($len - 1); $pos >= 0; --$pos) { + $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval)); + $bitval = bcmul($bitval, 16); + } + + return $dec; + } + + /** + * Intelligent Mail Barcode calculation of Frame Check Sequence + * + * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified). + * @return int 11 bit Frame Check Sequence as integer (decimal base) + * @protected + */ + protected function imb_crc11fcs($code_arr) + { + $genpoly = 0x0F35; // generator polynomial + $fcs = 0x07FF; // Frame Check Sequence + // do most significant byte skipping the 2 most significant bits + $data = hexdec($code_arr[0]) << 5; + for ($bit = 2; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + // do rest of bytes + for ($byte = 1; $byte < 13; ++$byte) { + $data = hexdec($code_arr[$byte]) << 3; + for ($bit = 0; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + } + + return $fcs; + } + + /** + * Reverse unsigned short value + * + * @param $num (int) value to reversr + * @return int reversed value + * @protected + */ + protected function imb_reverse_us($num) + { + $rev = 0; + for ($i = 0; $i < 16; ++$i) { + $rev <<= 1; + $rev |= ($num & 1); + $num >>= 1; + } + + return $rev; + } + + /** + * generate Nof13 tables used for Intelligent Mail Barcode + * + * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table + * @param $size (int) size of table (78 for n=2 and 1287 for n=5) + * @return array requested table + * @protected + */ + protected function imb_tables($n, $size) + { + $table = array(); + $lli = 0; // LUT lower index + $lui = $size - 1; // LUT upper index + for ($count = 0; $count < 8192; ++$count) { + $bit_count = 0; + for ($bit_index = 0; $bit_index < 13; ++$bit_index) { + $bit_count += intval(($count & (1 << $bit_index)) != 0); + } + // if we don't have the right number of bits on, go on to the next value + if ($bit_count == $n) { + $reverse = ($this->imb_reverse_us($count) >> 3); + // if the reverse is less than count, we have already visited this pair before + if ($reverse >= $count) { + // If count is symmetric, place it at the first free slot from the end of the list. + // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list + if ($reverse == $count) { + $table[$lui] = $count; + --$lui; + } else { + $table[$lli] = $count; + ++$lli; + $table[$lli] = $reverse; + ++$lli; + } + } + } + } + + return $table; + } + + protected function convertBarcodeArrayToNewStyle($oldBarcodeArray) + { + $newBarcodeArray = []; + $newBarcodeArray['code'] = $oldBarcodeArray['code']; + $newBarcodeArray['maxWidth'] = $oldBarcodeArray['maxw']; + $newBarcodeArray['maxHeight'] = $oldBarcodeArray['maxh']; + $newBarcodeArray['bars'] = []; + foreach ($oldBarcodeArray['bcode'] as $oldbar) { + $newBar = []; + $newBar['width'] = $oldbar['w']; + $newBar['height'] = $oldbar['h']; + $newBar['positionVertical'] = $oldbar['p']; + $newBar['drawBar'] = $oldbar['t']; + $newBar['drawSpacing'] = ! $oldbar['t']; + + $newBarcodeArray['bars'][] = $newBar; + } + + return $newBarcodeArray; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php new file mode 100755 index 00000000..eeb95078 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php @@ -0,0 +1,43 @@ +getBarcodeData($code, $type); + + $html = '
' . "\n"; + + $positionHorizontal = 0; + foreach ($barcodeData['bars'] as $bar) { + $barWidth = round(($bar['width'] * $widthFactor), 3); + $barHeight = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); + + if ($bar['drawBar']) { + $positionVertical = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); + // draw a vertical bar + $html .= '
 
' . "\n"; + } + + $positionHorizontal += $barWidth; + } + + $html .= '
' . "\n"; + + return $html; + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php new file mode 100755 index 00000000..9772226e --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php @@ -0,0 +1,77 @@ +getBarcodeData($code, $type); + + // calculate image size + $width = ($barcodeData['maxWidth'] * $widthFactor); + $height = $totalHeight; + + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + $jpg = imagecreate($width, $height); + $colorBackground = imagecolorallocate($jpg, 255, 255, 255); + imagecolortransparent($jpg, $colorBackground); + $colorForeground = imagecolorallocate($jpg, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $colorForeground = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); + $jpg = new \Imagick(); + $jpg->newImage($width, $height, 'white', 'jpg'); + $imageMagickObject = new \imagickdraw(); + $imageMagickObject->setFillColor($colorForeground); + } else { + throw new BarcodeException('Neither gd-lib or imagick are installed!'); + } + + // print bars + $positionHorizontal = 0; + foreach ($barcodeData['bars'] as $bar) { + $bw = round(($bar['width'] * $widthFactor), 3); + $bh = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); + if ($bar['drawBar']) { + $y = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); + // draw a vertical bar + if ($imagick && isset($imageMagickObject)) { + $imageMagickObject->rectangle($positionHorizontal, $y, ($positionHorizontal + $bw), ($y + $bh)); + } else { + imagefilledrectangle($jpg, $positionHorizontal, $y, ($positionHorizontal + $bw) - 1, ($y + $bh), + $colorForeground); + } + } + $positionHorizontal += $bw; + } + ob_start(); + if ($imagick && isset($imageMagickObject)) { + $jpg->drawImage($imageMagickObject); + echo $jpg; + } else { + imagejpeg($jpg); + imagedestroy($jpg); + } + $image = ob_get_clean(); + + return $image; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php new file mode 100755 index 00000000..f7883922 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php @@ -0,0 +1,76 @@ +getBarcodeData($code, $type); + + // calculate image size + $width = ($barcodeData['maxWidth'] * $widthFactor); + $height = $totalHeight; + + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + $png = imagecreate($width, $height); + $colorBackground = imagecolorallocate($png, 255, 255, 255); + imagecolortransparent($png, $colorBackground); + $colorForeground = imagecolorallocate($png, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $colorForeground = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); + $png = new \Imagick(); + $png->newImage($width, $height, 'none', 'png'); + $imageMagickObject = new \imagickdraw(); + $imageMagickObject->setFillColor($colorForeground); + } else { + throw new BarcodeException('Neither gd-lib or imagick are installed!'); + } + + // print bars + $positionHorizontal = 0; + foreach ($barcodeData['bars'] as $bar) { + $bw = round(($bar['width'] * $widthFactor), 3); + $bh = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); + if ($bar['drawBar']) { + $y = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); + // draw a vertical bar + if ($imagick && isset($imageMagickObject)) { + $imageMagickObject->rectangle($positionHorizontal, $y, ($positionHorizontal + $bw), ($y + $bh)); + } else { + imagefilledrectangle($png, $positionHorizontal, $y, ($positionHorizontal + $bw) - 1, ($y + $bh), + $colorForeground); + } + } + $positionHorizontal += $bw; + } + ob_start(); + if ($imagick && isset($imageMagickObject)) { + $png->drawImage($imageMagickObject); + echo $png; + } else { + imagepng($png); + imagedestroy($png); + } + $image = ob_get_clean(); + + return $image; + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php new file mode 100755 index 00000000..01af454d --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php @@ -0,0 +1,50 @@ +getBarcodeData($code, $type); + + // replace table for special characters + $repstr = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); + + $width = round(($barcodeData['maxWidth'] * $widthFactor), 3); + + $svg = '' . "\n"; + $svg .= '' . "\n"; + $svg .= '' . "\n"; + $svg .= "\t" . '' . strtr($barcodeData['code'], $repstr) . '' . "\n"; + $svg .= "\t" . '' . "\n"; + // print bars + $positionHorizontal = 0; + foreach ($barcodeData['bars'] as $bar) { + $barWidth = round(($bar['width'] * $widthFactor), 3); + $barHeight = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); + if ($bar['drawBar']) { + $positionVertical = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); + // draw a vertical bar + $svg .= "\t\t" . '' . "\n"; + } + $positionHorizontal += $barWidth; + } + $svg .= "\t" . '' . "\n"; + $svg .= '' . "\n"; + + return $svg; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php b/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php new file mode 100755 index 00000000..9ee1ad4a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php @@ -0,0 +1,5 @@ +getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertEquals('PNG', substr($generated, 1, 3)); + } + + /** + * @test + */ + public function svg_barcode_generator_can_generate_ean_13_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('081231723897', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13.svg', $generated); + } + + /** + * @test + */ + public function html_barcode_generator_can_generate_code_128_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorHTML(); + $generated = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-code128.html', $generated); + } + + /** + * @test + */ + public function jpg_barcode_generator_can_generate_code_128_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + } + + /** + * @test + * @expectedException \Picqer\Barcode\Exceptions\InvalidCharacterException + */ + public function ean13_generator_throws_exception_if_invalid_chars_are_used() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('A123', $generator::TYPE_EAN_13); + } + + /** + * @test + */ + public function ean13_generator_accepting_13_chars() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('0049000004632', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + /** + * @test + */ + public function ean13_generator_accepting_12_chars_and_generates_13th_check_digit() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('004900000463', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + /** + * @test + */ + public function ean13_generator_accepting_11_chars_and_generates_13th_check_digit_and_adds_leading_zero() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('04900000463', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + /** + * @test + * @expectedException \Picqer\Barcode\Exceptions\InvalidCheckDigitException + */ + public function ean13_generator_throws_exception_when_wrong_check_digit_is_given() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('0049000004633', $generator::TYPE_EAN_13); + } + + /** + * @test + * @expectedException \Picqer\Barcode\Exceptions\UnknownTypeException + */ + public function generator_throws_unknown_type_exceptions() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('0049000004633', 'vladimir'); + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg new file mode 100755 index 00000000..427ff401 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg @@ -0,0 +1,37 @@ + + + + 0049000004632 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html new file mode 100755 index 00000000..4a332e57 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html @@ -0,0 +1,32 @@ +
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
 
+
diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg new file mode 100755 index 00000000..96e16193 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg @@ -0,0 +1,37 @@ + + + + 0812317238973 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/ripcord/ripcord.php b/vendor/ripcord/ripcord.php new file mode 100644 index 00000000..739dbb89 --- /dev/null +++ b/vendor/ripcord/ripcord.php @@ -0,0 +1,356 @@ + + * @copyright Copyright (C) 2010, Muze + * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License + * @version Ripcord 0.9 - PHP 5 + */ + +/** + * The ripcord class contains a number of useful static methods. This makes it a bit easier to create a server or client, convert types + * and check for errors. + * @package Ripcord + */ +class ripcord +{ + /** + * This method checks whether the given argument is an XML-RPC fault. + * @param mixed $fault + * @return bool + */ + public static function isFault($fault) + { + if ( isset($fault) && is_array($fault) ) { + return xmlrpc_is_fault($fault); + } else { + return false; + } + } + + /** + * This method generates an XML-RPC fault with the given code and message. + * @param int $code + * @param string $message + * @return array + */ + public static function fault($code, $message) + { + return array('faultCode' => $code, 'faultString' => $message); + } + + /** + * This method returns a new Ripcord server, which by default implements XML-RPC, Simple RPC and SOAP 1.1. + * The server will publish any methods passed through the $services argument. It can be configured through + * the $options argument. + * @param mixed $services Optional. Either an object or an array of objects. If the array has non-numeric keys, the key will be used as a namespace for the methods in the object. + * @param array $options Optional. An array of options to set for the Ripcord server. + * @see Ripcord_Server + */ + public static function server($services = null, $options = null, $documentor = null) + { + self::load('Ripcord_Server'); + if ( !isset($documentor) ) + { + $doc = array('name', 'css', 'wsdl', 'wsdl2'); + $docOptions = array(); + foreach ( $doc as $key ) + { + if ( isset($options[$key]) ) + { + $docOptions[$key] = $options[$key]; + unset( $options[$key] ); + } + } + $docOptions['version'] = $options['version']; + $documentor = self::documentor( $docOptions ); + } + return new Ripcord_Server($services, $options, $documentor); + } + + /** + * This method returns a new Ripcord client. By default this will be an XML-RPC client, but you can change this + * through the $options argument. + * @param string $url The url of the RPC server to connect with + * @param array $options Optional. An array of options to set for the Ripcord client. + * @see Ripcord_Client + */ + public static function client($url, $options = null, $transport = null ) + { + self::load('Ripcord_Client'); + if ( !isset($transport) ) + { + $transport = new Ripcord_Transport_Stream(); + } + return new Ripcord_Client($url, $options, $transport); + } + + /** + * This method returns a new Ripcord documentor object. + * @param array $options Optional. An array of options to set for the Ripcord documentor. + * @param object docCommentParser Optional. An object that parses a docComment block. Must + * implement the Ripcord_Documentor_CommentParser interface. + * @see Ripcord_Client + */ + public static function documentor( $options = null, $docCommentParser = null ) + { + self::load('Ripcord_Documentor'); + if (!$docCommentParser) { + $docCommentParser = new Ripcord_Documentor_Parser_phpdoc(); + } + return new Ripcord_Documentor( $options, $docCommentParser ); + } + + /** + * This method returns an XML-RPC datetime object from a given unix timestamp. + * @param int $timestamp + * @return object + */ + public static function datetime($timestamp) + { + $datetime = date("Ymd\TH:i:s", $timestamp); + xmlrpc_set_type($datetime, 'datetime'); + return $datetime; + } + + /** + * This method returns a unix timestamp from a given XML-RPC datetime object. + * It will throw a 'Variable is not of type datetime' Ripcord_Exception (code -6) + * if the given argument is not of the correct type. + * @param object $datetime + * @return int + */ + public static function timestamp($datetime) + { + if (xmlrpc_get_type($datetime)=='datetime') + { + return $datetime->timestamp; + } else { + throw Ripcord_Exception('Variable is not of type datetime', -6); + } + } + + /** + * This method returns an XML-RPC base64 object from a given binary string. + * @param string $binary + * @return object + */ + public static function base64($binary) + { + xmlrpc_set_type($binary, 'base64'); + return $binary; + } + + /** + * This method returns a (binary) string from a given XML-RPC base64 object. + * It will throw a 'Variable is not of type base64' Ripcord_Exception (code -7) + * if the given argument is not of the correct type. + * @param object $base64 + * @return string + */ + public static function binary($base64) + { + if (xmlrpc_get_type($base64)=='base64') + { + return $base64->scalar; + } else { + throw Ripcord_Exception('Variable is not of type base64', -7); + } + } + + /** + * This method returns the type of the given parameter. This can be any of the XML-RPC data types, e.g. + * 'struct', 'int', 'string', 'base64', 'boolean', 'double', 'array' or 'datetime'. + * @param mixed $param + * @return string + */ + public static function getType($param) + { + return xmlrpc_get_type($param); + } + + /** + * This method returns a new Ripcord client, configured to access a SOAP 1.1 server. + * @param string $url + * @param array $options Optional. + * @see Ripcord_Client + */ + public static function soapClient($url, $options = null, $transport = null) + { + $options['version'] = 'soap 1.1'; + return self::client($url, $options, $transport); + } + + /** + * This method returns a new Ripcord client, configured to access an XML-RPC server. + * @param string $url + * @param array $options Optional. + * @return object + * @see Ripcord_Client + */ + public static function xmlrpcClient($url, $options = null, $transport = null) + { + $options['version'] = 'xmlrpc'; + return self::client($url, $options, $transport); + } + + /** + * This method returns a new Ripcord client, configured to access a Simple RPC server. + * @param string $url + * @param array $options Optional. + * @return object + * @see Ripcord_Client + */ + public static function simpleClient($url, $options = null, $transport = null) + { + $options['version'] = 'simple'; + return self::client($url, $options, $transport); + } + + /** + * This method includes a ripcord class, using require_once. Used for autoloading ripcord classes. + * @param string $class The name of the class to load. + * @return boolean + */ + public static function load($class) + { + if (substr($class, 0, 8)=='Ripcord_') + { + $root = dirname(__FILE__).'/ripcord_'; + $class = substr($class, 8); + $file = str_replace('.', '', $class); + $file = str_replace('_', '/', $file); + $file = strtolower($file); + while ($file && $file!='.') + { + if ( file_exists($root.$file.'.php') ) + { + require_once($root.$file.'.php'); + return true; + } else { + $file = dirname($file); + } + } + } + return false; + } + + /** + * This method creates a new Ripcord_Client_Call object, which encodes the information needed for + * a method call to an rpc server. This is mostly used for the system.multiCall method. + * @param string $method The name of the method call to encode + * @param mixed $args,... The remainder of the arguments are encoded as parameters to the call + * @return object + */ + public static function encodeCall() + { + self::load('Ripcord_Client'); + $params = func_get_args(); + $method = array_shift($params); + return new Ripcord_Client_Call( $method, $params ); + } + + /* + * This method binds the first parameter to the output of a Ripcord client call. If + * the second argument is a Ripcord_Client_Call object, it binds the parameter to it, + * if not it simply assigns the second parameter to the first parameter. + * This means that doing: + * > ripcord::bind( $result, $client->someMethod() ) + * will always result in $result eventually containing the return value of $client->someMethod(). + * Whether multiCall mode has been enabled or not. + */ + public function bind(&$bound, $call) + { + if ( is_a( $call, 'Ripcord_Client_Call' ) ) + { + $call->bound =& $bound; + } else { + $bound = $call; + } + return null; + } + + /** + * Method {method} not found. - Thrown by the ripcord server when a requested method isn't found. + */ + const methodNotFound = -1; + /** + * Argument {index} is not a valid Ripcord call - Thrown by the client when passing incorrect arguments to system.multiCall. + */ + const notRipcordCall = -2; + /** + * Cannot recurse system.multiCall - Thrown by the ripcord server when system.multicall is called within itself. + */ + const cannotRecurse = -3; + /** + * Could not access {url} - Thrown by the transport object when unable to access the given url. + */ + const cannotAccessURL = -4; + /** + * PHP XMLRPC library is not installed - Thrown by the ripcord server and client when the xmlrpc library is not installed. + */ + const xmlrpcNotInstalled = -5; + /** + * Variable is not of type datetime - Thrown by the ripcord timestamp method. + */ + const notDatetime = -6; + /** + * Variable is not of type base64 - Thrown by the ripcord binary method. + */ + const notBase64 = -7; + /** + * Variable is not a classname or an object - Thrown by the ripcord server. + */ + const unknownServiceType = -8; +} + +/** + * This interface is implemented by all exceptions thrown by Ripcord. + * @package Ripcord + */ +interface Ripcord_Exception {} + +/** + * This class is used whenever an when a method passed to the server is invalid. + * - ripcord::methodNotFound (-1) Method {method} not found. - Thrown by the ripcord server when a requested method isn't found. + * @package Ripcord + */ +class Ripcord_BadMethodCallException extends BadMethodCallException implements Ripcord_Exception { } + +/** + * This class is used whenever prerequisite requirements are not met. + * - ripcord::xmlrpcNotInstalled (-5) PHP XMLRPC library is not installed - Thrown by the ripcord server and client when the xmlrpc library is not installed. + * @package Ripcord + */ +class Ripcord_ConfigurationException extends Exception implements Ripcord_Exception { } + +/** + * This class is used whenever an argument passed to a Ripcord method is invalid for any reason. Possible exceptions thrown are: + * - ripcord::notRipcordCall (-2) Argument {index} is not a valid Ripcord call - Thrown by the client when passing incorrect arguments to system.multiCall. + * - ripcord::cannotRecurse (-3) Cannot recurse system.multiCall - Thrown by the ripcord server when system.multicall is called within itself. + * - ripcord::notDateTime (-6) Variable is not of type datetime - Thrown by the ripcord timestamp method. + * - ripcord::notBase64 (-7) Variable is not of type base64 - Thrown by the ripcord binary method. + * - ripcord::unknownServiceType (-8) Variable is not a classname or an object - Thrown by the ripcord server. + * @package Ripcord + */ +class Ripcord_InvalidArgumentException extends InvalidArgumentException implements Ripcord_Exception { } + +/** + * This class is used whenever something goes wrong in sending / receiving data. Possible exceptions thrown are: + * - ripcord::cannotAccessURL (-4) Could not access {url} - Thrown by the transport object when unable to access the given url. + * @package Ripcord + */ +class Ripcord_TransportException extends RuntimeException implements Ripcord_Exception { } + +/** + * This class is used for exceptions generated from xmlrpc faults returned by the server. The code and message correspond + * to the code and message from the xmlrpc fault. + * @package Ripcord + */ +class Ripcord_RemoteException extends Exception implements Ripcord_Exception { } + +if (function_exists('spl_autoload_register')) { + spl_autoload_register('ripcord::load'); +} +?> \ No newline at end of file diff --git a/vendor/ripcord/ripcord_client.php b/vendor/ripcord/ripcord_client.php new file mode 100644 index 00000000..2410973a --- /dev/null +++ b/vendor/ripcord/ripcord_client.php @@ -0,0 +1,579 @@ + + * @copyright Copyright (C) 2010, Muze + * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License + * @version Ripcord 0.9 - PHP 5 + */ + +/** + * Includes the static ripcord factory class and exceptions + */ +require_once(dirname(__FILE__).'/ripcord.php'); + +/** + * This class implements a simple RPC client, for XML-RPC, (simplified) SOAP 1.1 or Simple RPC. The client abstracts + * the entire RPC process behind native PHP methods. Any method defined by the rpc server can be called as if it was + * a native method of the rpc client. + * + * E.g. + * + * film->getScore( 'e3dee9d19a8c3af7c92f9067d2945b59', 500 ); + * ?> + * + * + * The client has a simple interface for the system.multiCall method: + * + * system->multiCall()->start(); + * ripcord::bind( $methods, $client->system->listMethods() ); + * ripcord::bind( $foo, $client->getFoo() ); + * $client->system->multiCall()->execute(); + * ?> + * + * + * The soap client can only handle the basic php types and doesn't understand xml namespaces. Use PHP's SoapClient + * for complex soap calls. This client cannot parse wsdl. + * If you want to skip the ripcord::client factory method, you _must_ provide a transport object explicitly. + * + * @link http://wiki.moviemeter.nl/index.php/API Moviemeter API documentation + * @package Ripcord + */ +class Ripcord_Client +{ + /** + * The url of the rpc server + */ + private $_url = ''; + + /** + * The transport object, used to post requests. + */ + private $_transport = null; + + /** + * A list of output options, used with the xmlrpc_encode_request method. + * @see Ripcord_Server::setOutputOption() + */ + private $_outputOptions = array( + "output_type" => "xml", + "verbosity" => "pretty", + "escaping" => array("markup"), + "version" => "xmlrpc", + "encoding" => "utf-8" + ); + + /** + * The namespace to use when calling a method. + */ + private $_namespace = null; + + /** + * A reference to the root client object. This is so when you use namespaced sub clients, you can always + * find the _response and _request data in the root client. + */ + private $_rootClient = null; + + /** + * A flag to indicate whether or not to preemptively clone objects passed as arguments to methods, see + * php bug #50282. Only correctly set in the rootClient. + */ + private $_cloneObjects = false; + + /** + * A flag to indicate if we are in a multiCall block. Start this with $client->system->multiCall()->start() + */ + protected $_multiCall = false; + + /** + * A list of deferred encoded calls. + */ + protected $_multiCallArgs = array(); + + /** + * The exact response from the rpc server. For debugging purposes. + */ + public $_response = ''; + + /** + * The exact request from the client. For debugging purposes. + */ + public $_request = ''; + + /** + * Whether or not to throw exceptions when an xml-rpc fault is returned by the server. Default is false. + */ + public $_throwExceptions = false; + + /** + * Whether or not to decode the XML-RPC datetime and base64 types to unix timestamp and binary string + * respectively. + */ + public $_autoDecode = true; + + /** + * The constructor for the RPC client. + * @param string $url The url of the rpc server + * @param array $options Optional. A list of outputOptions. See {@link Ripcord_Server::setOutputOption()} + * @param object $rootClient Optional. Used internally when using namespaces. + * @throws Ripcord_ConfigurationException (ripcord::xmlrpcNotInstalled) when the xmlrpc extension is not available. + */ + public function __construct( $url, array $options = null, $transport = null, $rootClient = null ) + { + if ( !isset($rootClient) ) { + $rootClient = $this; + if ( !function_exists( 'xmlrpc_encode_request' ) ) + { + throw new Ripcord_ConfigurationException('PHP XMLRPC library is not installed', + ripcord::xmlrpcNotInstalled); + } + $version = explode('.', phpversion() ); + if ( (0 + $version[0]) == 5) { + if ( ( 0 + $version[1]) < 2 ) { + $this->_cloneObjects = true; // workaround for bug #50282 + } + } + } + $this->_rootClient = $rootClient; + $this->_url = $url; + if ( isset($options) ) + { + if ( isset($options['namespace']) ) + { + $this->_namespace = $options['namespace']; + unset( $options['namespace'] ); + } + $this->_outputOptions = $options; + } + if ( isset($transport) ) { + $this->_transport = $transport; + } + } + + /** + * This method catches any native method called on the client and calls it on the rpc server instead. It automatically + * parses the resulting xml and returns native php type results. + * @throws Ripcord_InvalidArgumentException (ripcord::notRipcordCall) when handling a multiCall and the + * arguments passed do not have the correct method call information + * @throws Ripcord_RemoteException when _throwExceptions is true and the server returns an XML-RPC Fault. + */ + public function __call($name, $args) + { + if ( isset($this->_namespace) ) + { + $name = $this->_namespace . '.' . $name; + } + + if ( $name === 'system.multiCall' || $name == 'system.multicall' ) + { + if ( !$args || ( is_array($args) && count($args)==0 ) ) + { + // multiCall is called without arguments, so return the fetch interface object + return new Ripcord_Client_MultiCall( $this->_rootClient, $name ); + } else if ( is_array( $args ) && (count( $args ) == 1) && + is_array( $args[0] ) && !isset( $args[0]['methodName'] ) ) + { + // multicall is called with a simple array of calls. + $args = $args[0]; + } + $this->_rootClient->_multiCall = false; + $params = array(); + $bound = array(); + foreach ( $args as $key => $arg ) + { + if ( !is_a( $arg, 'Ripcord_Client_Call' ) && + (!is_array($arg) || !isset($arg['methodName']) ) ) + { + throw new Ripcord_InvalidArgumentException( + 'Argument '.$key.' is not a valid Ripcord call', + ripcord::notRipcordCall); + } + if ( is_a( $arg, 'Ripcord_Client_Call' ) ) + { + $arg->index = count( $params ); + $params[] = $arg->encode(); + } + else + { + $arg['index'] = count( $params ); + $params[] = array( + 'methodName' => $arg['methodName'], + 'params' => isset($arg['params']) ? + (array) $arg['params'] : array() + ); + } + $bound[$key] = $arg; + } + $args = array( $params ); + $this->_rootClient->_multiCallArgs = array(); + } + if ( $this->_rootClient->_multiCall ) { + $call = new Ripcord_Client_Call( $name, $args ); + $this->_rootClient->_multiCallArgs[] = $call; + return $call; + } + if ($this->_rootClient->_cloneObjects) { //workaround for php bug 50282 + foreach( $args as $key => $arg) { + if (is_object($arg)) { + $args[$key] = clone $arg; + } + } + } + $request = xmlrpc_encode_request( $name, $args, $this->_outputOptions ); + $response = $this->_transport->post( $this->_url, $request ); + $result = xmlrpc_decode( $response, $this->_outputOptions['encoding'] ); + $this->_rootClient->_request = $request; + $this->_rootClient->_response = $response; + if ( ripcord::isFault( $result ) && $this->_throwExceptions ) + { + throw new Ripcord_RemoteException($result['faultString'], $result['faultCode']); + } + if ( isset($bound) && is_array( $bound ) ) + { + foreach ( $bound as $key => $callObject ) + { + if ( is_a( $callObject, 'Ripcord_Client_Call' ) ) + { + $returnValue = $result[$callObject->index]; + } + else + { + $returnValue = $result[$callObject['index']]; + } + if ( is_array( $returnValue ) && count( $returnValue ) == 1 ) + { + // XML-RPC specification says that non-fault results must be in a single item array + $returnValue = current($returnValue); + } + if ($this->_autoDecode) + { + $type = xmlrpc_get_type($returnValue); + switch ($type) + { + case 'base64' : + $returnValue = ripcord::binary($returnValue); + break; + case 'datetime' : + $returnValue = ripcord::timestamp($returnValue); + break; + } + } + if ( is_a( $callObject, 'Ripcord_Client_Call' ) ) { + $callObject->bound = $returnValue; + } + $bound[$key] = $returnValue; + } + $result = $bound; + } + return $result; + } + + /** + * This method catches any reference to properties of the client and uses them as a namespace. The + * property is automatically created as a new instance of the rpc client, with the name of the property + * as a namespace. + * @param string $name The name of the namespace + * @return object A Ripcord Client with the given namespace set. + */ + public function __get($name) + { + $result = null; + if ( !isset($this->{$name}) ) + { + $result = new Ripcord_Client( + $this->_url, + array_merge($this->_outputOptions, array( + 'namespace' => $this->_namespace ? + $this->_namespace . '.' . $name : $name + ) ), + $this->_transport, + $this->_rootClient + ); + $this->{$name} = $result; + } + return $result; + } +} + +/** + * This class provides the fetch interface for system.multiCall. It is returned + * when calling $client->system->multiCall() with no arguments. Upon construction + * it puts the originating client into multiCall deferred mode. The client will + * gather the requested method calls instead of executing them immediately. It + * will them execute all of them, in order, when calling + * $client->system->multiCall()->fetch(). + * This class extends Ripcord_Client only so it has access to its protected _multiCall + * property. + */ +class Ripcord_Client_MultiCall extends Ripcord_Client +{ + + /* + * The reference to the originating client to put into multiCall mode. + */ + private $client = null; + + /* + * This method creates a new multiCall fetch api object. + */ + public function __construct( $client, $methodName = 'system.multiCall' ) + { + $this->client = $client; + $this->methodName = $methodName; + } + + /* + * This method puts the client into multiCall mode. While in this mode all + * method calls are collected as deferred calls (Ripcord_Client_Call). + */ + public function start() + { + $this->client->_multiCall = true; + } + + /* + * This method finally calls the clients multiCall method with all deferred + * method calls since multiCall mode was enabled. + */ + public function execute() + { + if ($this->methodName=='system.multiCall') { + return $this->client->system->multiCall( $this->client->_multiCallArgs ); + } else { // system.multicall + return $this->client->system->multicall( $this->client->_multiCallArgs ); + } + } + +} + +/** + * This class is used with the Ripcord_Client when calling system.multiCall. Instead of immediately calling the method on the rpc server, + * a Ripcord_Client_Call object is created with all the information needed to call the method using the multicall parameters. The call object is + * returned immediately and is used as input parameter for the multiCall call. The result of the call can be bound to a php variable. This + * variable will be filled with the result of the call when it is available. + * @package Ripcord + */ +class Ripcord_Client_Call +{ + /** + * The method to call on the rpc server + */ + public $method = null; + + /** + * The arguments to pass on to the method. + */ + public $params = array(); + + /** + * The index in the multicall request array, if any. + */ + public $index = null; + + /** + * A reference to the php variable to fill with the result of the call, if any. + */ + public $bound = null; + + /** + * The constructor for the Ripcord_Client_Call class. + * @param string $method The name of the rpc method to call + * @param array $params The parameters for the rpc method. + */ + public function __construct($method, $params) + { + $this->method = $method; + $this->params = $params; + } + + /** + * This method allows you to bind a php variable to the result of this method call. + * When the method call's result is available, the php variable will be filled with + * this result. + * @param mixed $bound The variable to bind the result from this call to. + * @return object Returns this object for chaining. + */ + public function bind(&$bound) + { + $this->bound =& $bound; + return $this; + } + + /** + * This method returns the correct format for a multiCall argument. + * @return array An array with the methodName and params + */ + public function encode() { + return array( + 'methodName' => $this->method, + 'params' => (array) $this->params + ); + } + +} + +/** + * This interface describes the minimum interface needed for the transport object used by the + * Ripcord_Client + * @package Ripcord + */ +interface Ripcord_Transport +{ + /** + * This method must post the request to the given url and return the results. + * @param string $url The url to post to. + * @param string $request The request to post. + * @return string The server response + */ + public function post( $url, $request ); +} + +/** + * This class implements the Ripcord_Transport interface using PHP streams. + * @package Ripcord + */ +class Ripcord_Transport_Stream implements Ripcord_Transport +{ + /** + * A list of stream context options. + */ + private $options = array(); + + /** + * Contains the headers sent by the server. + */ + public $responseHeaders = null; + + /** + * This is the constructor for the Ripcord_Transport_Stream class. + * @param array $contextOptions Optional. An array with stream context options. + */ + public function __construct( $contextOptions = null ) + { + if ( isset($contextOptions) ) + { + $this->options = $contextOptions; + } + } + + /** + * This method posts the request to the given url. + * @param string $url The url to post to. + * @param string $request The request to post. + * @return string The server response + * @throws Ripcord_TransportException (ripcord::cannotAccessURL) when the given URL cannot be accessed for any reason. + */ + public function post( $url, $request ) + { + $options = array_merge( + $this->options, + array( + 'http' => array( + 'method' => "POST", + 'header' => "Content-Type: text/xml", + 'content' => $request + ) + ) + ); + $context = stream_context_create( $options ); + $result = @file_get_contents( $url, false, $context ); + $this->responseHeaders = $http_response_header; + if ( !$result ) + { + throw new Ripcord_TransportException( 'Could not access ' . $url, + ripcord::cannotAccessURL ); + } + return $result; + } +} + +/** + * This class implements the Ripcord_Transport interface using CURL. + * @package Ripcord + */ +class Ripcord_Transport_CURL implements Ripcord_Transport +{ + /** + * A list of CURL options. + */ + private $options = array(); + + /** + * A flag that indicates whether or not we can safely pass the previous exception to a new exception. + */ + private $skipPreviousException = false; + + /** + * Contains the headers sent by the server. + */ + public $responseHeaders = null; + + /** + * This is the constructor for the Ripcord_Transport_CURL class. + * @param array $curlOptions A list of CURL options. + */ + public function __construct( $curlOptions = null ) + { + if ( isset($curlOptions) ) + { + $this->options = $curlOptions; + } + $version = explode('.', phpversion() ); + if ( ( (0 + $version[0]) == 5) && ( 0 + $version[1]) < 3 ) { // previousException supported in php >= 5.3 + $this->_skipPreviousException = true; + } + } + + /** + * This method posts the request to the given url + * @param string $url The url to post to. + * @param string $request The request to post. + * @throws Ripcord_TransportException (ripcord::cannotAccessURL) when the given URL cannot be accessed for any reason. + * @return string The server response + */ + public function post( $url, $request) + { + $curl = curl_init(); + $options = (array) $this->options + array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $request, + CURLOPT_HEADER => true + ); + curl_setopt_array( $curl, $options ); + $contents = curl_exec( $curl ); + $headerSize = curl_getinfo( $curl, CURLINFO_HEADER_SIZE ); + $this->responseHeaders = substr( $contents, 0, $headerSize ); + $contents = substr( $contents, $headerSize ); + + if ( curl_errno( $curl ) ) + { + $errorNumber = curl_errno( $curl ); + $errorMessage = curl_error( $curl ); + curl_close( $curl ); + $version = explode('.', phpversion() ); + if (!$this->_skipPreviousException) { // previousException supported in php >= 5.3 + $exception = new Ripcord_TransportException( 'Could not access ' . $url + , ripcord::cannotAccessURL + , new Exception( $errorMessage, $errorNumber ) + ); + } else { + $exception = new Ripcord_TransportException( 'Could not access ' . $url + . ' ( original CURL error: ' . $errorMessage . ' ) ', + ripcord::cannotAccessURL + ); + } + throw $exception; + } + curl_close($curl); + return $contents; + } +} + +?> \ No newline at end of file diff --git a/vendor/ripcord/ripcord_server.php b/vendor/ripcord/ripcord_server.php new file mode 100644 index 00000000..535a1c3c --- /dev/null +++ b/vendor/ripcord/ripcord_server.php @@ -0,0 +1,417 @@ + + * @copyright Copyright (C) 2010, Muze + * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License + * @version Ripcord 0.9 - PHP 5 + */ + +/** + * Includes the static ripcord factory class and exceptions + */ +require_once(dirname(__FILE__).'/ripcord.php'); + +/** + * This class implements the Ripcord server. It is an OO wrapper around PHP's XML-RPC methods, with some added features. + * You can create an XML-RPC (or Simple RPC or a simple SOAP 1.1) server by defining a class with public methods and passing + * an object (or array of objects) of this class to the constructor of Ripcord_Server. Then simply call the run() method. + * + * A basic example: + * + * run(); + * ?> + * + * + * An example with namespaces in the method names and a static class as rpc service. + * + * $myObject, + * 'namespace2' => 'myOtherClass' + * ) + * ); + * $server->run(); + * ?> + * + * + * You don't need to instantiate a class to use it with Ripcord, in the above example 'myOtherClass' is the + * name of a PHP class to use. In addition you may also specify functions or methods directly, in any format + * that matches PHP's is_callable() criteria. + * @package Ripcord +*/ + +/* + TODO: + - create seperate interface for encoding / decoding requests + - create xmlrpc-epi class using xmlrpc_encode/decode for xml-rpc, simple-rpc and for now soap + - add json-rpc class (http://json-rpc.org/wiki/specification) + - pass list of protocol parsers/generators in the constructor of the server + - protocol must know how to handle the system.* methods +*/ +class Ripcord_Server +{ + /** + * Contains a reference to the Ripcord documentor object. + * @see Ripcord_Documentor + */ + private $documentor = null; + + /** + * Contains a reference to the XML-RPC server created with xmlrpc_server_create. + */ + private $xmlrpc = null; + + /** + * Contains a list of methods set for this server. Excludes the system.* methods automatically + * created by PHP's xmlrpc_server_create. + */ + private $methods = array(); + + /** + * Contains an array with outputOptions, used when calling methods on the xmlrpc server created with + * xmlrpc_server_create. These options can be overridden through the $options parameter of the + * Ripcord_Server constructor. + * @see Ripcord_Server::setOutputOption() + */ + private $outputOptions = array( + "output_type" => "xml", + "verbosity" => "pretty", + "escaping" => array("markup"), + "version" => "auto", + "encoding" => "utf-8" + ); + + /** + * Creates a new instance of the Ripcord server. + * @param mixed $services. Optional. An object or array of objects. The public methods in these objects will be exposed + * through the RPC server. If the services array has non-numeric keys, the key for each object will define its namespace. + * @param array $options. Optional. Allows you to override the default server settings. Accepted key names are: + * - 'documentor': allows you to specify an alternative HTML documentor class, or if set to false, no HTML documentor. + * - 'name' : The name of the server, used by the default HTML documentor. + * - 'css' : An url of a css file to link to in the HTML documentation. + * - 'wsdl' : The wsdl 1.0 description of this service (only usefull if you run the 'soap 1.1' version, or the 'auto' version + * - 'wsdl2' : The wsdl 2.0 description of this service + * In addition you can set any of the outputOptions for the xmlrpc server. + * @see Ripcord_Server::setOutputOption() + * @throws Ripcord_InvalidArgumentException (ripcord::unknownServiceType) when passed an incorrect service + * @throws Ripcord_ConfigurationException (ripcord::xmlrpcNotInstalled) when the xmlrpc extension in not available. + */ + function __construct($services = null, $options = null, $documentor = null) + { + if ( !function_exists( 'xmlrpc_server_create' ) ) + { + throw new Ripcord_ConfigurationException('PHP XMLRPC library is not installed', + ripcord::xmlrpcNotInstalled ); + } + libxml_disable_entity_loader(); // prevents XXE attacks + $this->xmlrpc = xmlrpc_server_create(); + if (isset($services)) + { + if (is_array($services)) + { + foreach ($services as $serviceName => $service) + { + $this->addService($service, $serviceName); + } + } else { + $this->addService($services); + } + } + if ( isset($documentor) && is_object($documentor) ) { + $this->documentor = $documentor; + xmlrpc_server_register_introspection_callback( $this->xmlrpc, + array( $this->documentor, 'getIntrospectionXML') ); + } + if ( isset($options) ) + { + $this->outputOptions = array_merge($this->outputOptions, $options); + } + } + + /** + * Allows you to add a service to the server after construction. + * @param object $service The object or class whose public methods must be added to the rpc server. May also be a function or method. + * @param string $serviceName Optional. The namespace for the methods. + * @throws Ripcord_InvalidArgumentException (ripcord::unknownServiceType) when passed an incorrect service + */ + public function addService($service, $serviceName = 0) + { + if ( is_object( $service ) ) + { + $reflection = new ReflectionObject( $service ); + } + else if ( is_string( $service ) && class_exists( $service ) ) + { + $reflection = new ReflectionClass( $service ); + } + else if ( is_callable( $service ) ) // method passed directly + { + $this->addMethod( $serviceName, $service ); + return; + } + else + { + throw new Ripcord_InvalidArgumentException( 'Unknown service type ' . $serviceName, + ripcord::unknownServiceType ); + } + if ( $serviceName && !is_numeric( $serviceName ) ) + { + $serviceName .= '.'; + } + else + { + $serviceName = ''; + } + $methods = $reflection->getMethods(); + if ( is_array( $methods ) ) + { + foreach( $methods as $method ) + { + if ( substr( $method->name, 0, 1 ) != '_' + && !$method->isPrivate() && !$method->isProtected()) + { + $rpcMethodName = $serviceName . $method->name; + $this->addMethod( + $rpcMethodName, + array( $service, $method->name ) + ); + } + } + } + } + + /** + * Allows you to add a single method to the server after construction. + * @param string $name The name of the method as exposed through the rpc server + * @param callback $method The name of the method to call, or an array with classname or object and method name. + */ + public function addMethod($name, $method) + { + $this->methods[$name] = array( + 'name' => $name, + 'call' => $method + ); + xmlrpc_server_register_method( $this->xmlrpc, $name, array( $this, 'call' ) ); + } + + /** + * Runs the rpc server. Automatically handles an incoming request. + */ + public function run() + { + if ($this->documentor) { + $this->documentor->setMethodData( $this->methods ); + } + $request_xml = file_get_contents( 'php://input' ); + if ( !$request_xml ) + { + if ( ( $query = $_SERVER['QUERY_STRING'] ) + && isset($this->wsdl[$query]) && $this->wsdl[$query] ) + { + header('Content-type: text/xml'); + header('Access-Control-Allow-Origin: *'); + $wsdl = $this->wsdl[$query]; + header('Content-Length: '.strlen($wsdl) ); + echo $wsdl; + } + else if ( $this->documentor ) + { + header('Content-type: text/html; charset=' . $this->outputOptions['encoding']); + $this->documentor->handle( $this, $this->methods ); + } + else + { + // FIXME: add check for json-rpc protocol, if set and none of the xml protocols are set, use that + header('Content-type: text/xml'); + header('Access-Control-Allow-Origin: *'); + $result = xmlrpc_encode_request( + null, + ripcord::fault( -1, 'No request xml found.' ), + $this->outputOptions + ); + header('Content-Length: '.strlen( $result ) ); + echo $result; + } + } + else + { + // FIXME: add check for the protocol of the request, could be json-rpc, then check if it is supported. + header('Content-type: text/xml'); + header('Access-Control-Allow-Origin: *'); + $result = $this->handle( $request_xml ); + header('Content-Length: '.strlen($result) ); + echo $result; + } + } + + /** + * This method wraps around xmlrpc_decode_request, since it is borken in many ways. This wraps + * around all the ugliness needed to make it not dump core and not print expat warnings. + */ + private function parseRequest( $request_xml ) { + $xml = @simplexml_load_string($request_xml); + if (!$xml && !$xml->getNamespaces()) { + // FIXME: check for protocol json-rpc + //simplexml in combination with namespaces (soap) lets $xml evaluate to false + return xmlrpc_encode_request( + null, + ripcord::fault( -3, 'Invalid Method Call - Ripcord Server accepts only XML-RPC, SimpleRPC or SOAP 1.1 calls'), + $this->outputOptions + ); + } else { + // prevent segmentation fault on incorrect xmlrpc request (without methodName) + $methodCall = $xml->xpath('//methodCall'); + if ($methodCall) { //xml-rpc + $methodName = $xml->xpath('//methodName'); + if (!$methodName) { + return xmlrpc_encode_request( + null, + ripcord::fault( -3, 'Invalid Method Call - No methodName given'), + $this->outputOptions + ); + } + } + } + $method = null; + ob_start(); // xmlrpc_decode echo expat errors if the xml is not valid, can't stop it. + $params = xmlrpc_decode_request($request_xml, $method); + ob_end_clean(); // clean up any xml errors + return array( 'methodName' => $method, 'params' => $params ); + } + + /** + * This method implements the system.multiCall method without dumping core. The built-in method from the + * xmlrpc library dumps core when you have registered any php methods, fixed in php 5.3.2 + */ + private function multiCall( $params = null ) { + if ( $params && is_array( $params ) ) + { + $result = array(); + $params = $params[0]; + foreach ( $params as $param ) { + $method = $param['methodName']; + $args = $param['params']; + try { + // XML-RPC specification says that non-fault results must be in a single item array + $result[] = array( $this->call($method, $args) ); + } catch( Exception $e) { + $result[] = ripcord::fault( $e->getCode(), $e->getMessage() ); + } + } + $result = xmlrpc_encode_request( null, $result, $this->outputOptions ); + } else { + $result = xmlrpc_encode_request( + null, + ripcord::fault( -2, 'Illegal or no params set for system.multiCall'), + $this->outputOptions + ); + } + return $result; + } + + /** + * Handles the given request xml + * @param string $request_xml The incoming request. + * @return string + */ + public function handle($request_xml) + { + $result = $this->parseRequest( $request_xml ); + if (!$result || ripcord::isFault( $result ) ) + { + return $result; + } + else + { + $method = $result['methodName']; + $params = $result['params']; + } + if ( $method == 'system.multiCall' || $method == 'system.multicall' ) { + // php's xml-rpc server (xmlrpc-epi) crashes on multicall, so handle it ourselves... fixed in php 5.3.2 + $result = $this->multiCall( $params ); + } else { + try { + $result = xmlrpc_server_call_method( + $this->xmlrpc, $request_xml, null, $this->outputOptions + ); + } catch( Exception $e) { + $result = xmlrpc_encode_request( + null, + ripcord::fault( $e->getCode(), $e->getMessage() ), + $this->outputOptions + ); + } + } + return $result; + } + + /** + * Calls a method by its rpc name. + * @param string $method The rpc name of the method + * @param array $args The arguments to this method + * @return mixed + * @throws Ripcord_InvalidArgumentException (ripcord::cannotRecurse) when passed a recursive multiCall + * @throws Ripcord_BadMethodCallException (ripcord::methodNotFound) when the requested method isn't available. + */ + public function call( $method, $args = null ) + { + if ( isset( $this->methods[$method] ) ) + { + $call = $this->methods[$method]['call']; + return call_user_func_array( $call, $args); + } else { + if ( substr( $method, 0, 7 ) == 'system.' ) + { + if ( $method == 'system.multiCall' ) { + throw new Ripcord_InvalidArgumentException( + 'Cannot recurse system.multiCall', ripcord::cannotRecurse ); + } + // system methods are handled internally by the xmlrpc server, so we've got to create a makebelieve request, + // there is no other way because of a badly designed API + $req = xmlrpc_encode_request( $method, $args, $this->outputOptions ); + $result = xmlrpc_server_call_method( $this->xmlrpc, $req, null, + $this->outputOptions); + return xmlrpc_decode( $result ); + } else { + throw new Ripcord_BadMethodCallException( 'Method '.$method.' not found.', + ripcord::methodNotFound ); + } + } + } + + /** + * Allows you to set specific output options of the server after construction. + * @param string $option The name of the option + * @param mixed $value The value of the option + * The options are: + * - output_type: Return data as either php native data or xml encoded. Can be either 'php' or 'xml'. 'xml' is the default. + * - verbosity: Determines the compactness of generated xml. Can be either 'no_white_space', 'newlines_only' or 'pretty'. + * 'pretty' is the default. + * - escaping: Determines how/whether to escape certain characters. 1 or more values are allowed. If multiple, they need + * to be specified as a sub-array. Options are: 'cdata', 'non-ascii', 'non-print' and 'markup'. Default is 'non-ascii', + * 'non-print' and 'markup'. + * - version: Version of the xml vocabulary to use. Currently, three are supported: 'xmlrpc', 'soap 1.1' and 'simple'. The + * keyword 'auto' is also recognized and tells the server to respond in whichever version the request cam in. 'auto' is + * the default. + * - encoding: The character encoding that the data is in. Can be any supported character encoding. Default is 'utf-8'. + */ + public function setOutputOption($option, $value) + { + if ( isset($this->outputOptions[$option]) ) + { + $this->outputOptions[$option] = $value; + return true; + } else { + return false; + } + } +} + +?> \ No newline at end of file diff --git a/vendor/symfony/options-resolver/.gitignore b/vendor/symfony/options-resolver/.gitignore new file mode 100755 index 00000000..c49a5d8d --- /dev/null +++ b/vendor/symfony/options-resolver/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/vendor/symfony/options-resolver/CHANGELOG.md b/vendor/symfony/options-resolver/CHANGELOG.md new file mode 100755 index 00000000..c5bd1062 --- /dev/null +++ b/vendor/symfony/options-resolver/CHANGELOG.md @@ -0,0 +1,46 @@ +CHANGELOG +========= + +2.6.0 +----- + + * deprecated OptionsResolverInterface + * [BC BREAK] removed "array" type hint from OptionsResolverInterface methods + setRequired(), setAllowedValues(), addAllowedValues(), setAllowedTypes() and + addAllowedTypes() + * added OptionsResolver::setDefault() + * added OptionsResolver::hasDefault() + * added OptionsResolver::setNormalizer() + * added OptionsResolver::isRequired() + * added OptionsResolver::getRequiredOptions() + * added OptionsResolver::isMissing() + * added OptionsResolver::getMissingOptions() + * added OptionsResolver::setDefined() + * added OptionsResolver::isDefined() + * added OptionsResolver::getDefinedOptions() + * added OptionsResolver::remove() + * added OptionsResolver::clear() + * deprecated OptionsResolver::replaceDefaults() + * deprecated OptionsResolver::setOptional() in favor of setDefined() + * deprecated OptionsResolver::isKnown() in favor of isDefined() + * [BC BREAK] OptionsResolver::isRequired() returns true now if a required + option has a default value set + * [BC BREAK] merged Options into OptionsResolver and turned Options into an + interface + * deprecated Options::overload() (now in OptionsResolver) + * deprecated Options::set() (now in OptionsResolver) + * deprecated Options::get() (now in OptionsResolver) + * deprecated Options::has() (now in OptionsResolver) + * deprecated Options::replace() (now in OptionsResolver) + * [BC BREAK] Options::get() (now in OptionsResolver) can only be used within + lazy option/normalizer closures now + * [BC BREAK] removed Traversable interface from Options since using within + lazy option/normalizer closures resulted in exceptions + * [BC BREAK] removed Options::all() since using within lazy option/normalizer + closures resulted in exceptions + * [BC BREAK] OptionDefinitionException now extends LogicException instead of + RuntimeException + * [BC BREAK] normalizers are not executed anymore for unset options + * normalizers are executed after validating the options now + * [BC BREAK] an UndefinedOptionsException is now thrown instead of an + InvalidOptionsException when non-existing options are passed diff --git a/vendor/symfony/options-resolver/Exception/AccessException.php b/vendor/symfony/options-resolver/Exception/AccessException.php new file mode 100755 index 00000000..c12b6806 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/AccessException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Thrown when trying to read an option outside of or write it inside of + * {@link \Symfony\Component\OptionsResolver\Options::resolve()}. + * + * @author Bernhard Schussek + */ +class AccessException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/options-resolver/Exception/ExceptionInterface.php b/vendor/symfony/options-resolver/Exception/ExceptionInterface.php new file mode 100755 index 00000000..b62bb51d --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Marker interface for all exceptions thrown by the OptionsResolver component. + * + * @author Bernhard Schussek + */ +interface ExceptionInterface +{ +} diff --git a/vendor/symfony/options-resolver/Exception/InvalidArgumentException.php b/vendor/symfony/options-resolver/Exception/InvalidArgumentException.php new file mode 100755 index 00000000..6d421d68 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Thrown when an argument is invalid. + * + * @author Bernhard Schussek + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/options-resolver/Exception/InvalidOptionsException.php b/vendor/symfony/options-resolver/Exception/InvalidOptionsException.php new file mode 100755 index 00000000..6fd4f125 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/InvalidOptionsException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Thrown when the value of an option does not match its validation rules. + * + * You should make sure a valid value is passed to the option. + * + * @author Bernhard Schussek + */ +class InvalidOptionsException extends InvalidArgumentException +{ +} diff --git a/vendor/symfony/options-resolver/Exception/MissingOptionsException.php b/vendor/symfony/options-resolver/Exception/MissingOptionsException.php new file mode 100755 index 00000000..faa487f1 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/MissingOptionsException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Exception thrown when a required option is missing. + * + * Add the option to the passed options array. + * + * @author Bernhard Schussek + */ +class MissingOptionsException extends InvalidArgumentException +{ +} diff --git a/vendor/symfony/options-resolver/Exception/NoSuchOptionException.php b/vendor/symfony/options-resolver/Exception/NoSuchOptionException.php new file mode 100755 index 00000000..4c3280f4 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/NoSuchOptionException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Thrown when trying to read an option that has no value set. + * + * When accessing optional options from within a lazy option or normalizer you should first + * check whether the optional option is set. You can do this with `isset($options['optional'])`. + * In contrast to the {@link UndefinedOptionsException}, this is a runtime exception that can + * occur when evaluating lazy options. + * + * @author Tobias Schultze + */ +class NoSuchOptionException extends \OutOfBoundsException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/options-resolver/Exception/OptionDefinitionException.php b/vendor/symfony/options-resolver/Exception/OptionDefinitionException.php new file mode 100755 index 00000000..e8e339d4 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/OptionDefinitionException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Thrown when two lazy options have a cyclic dependency. + * + * @author Bernhard Schussek + */ +class OptionDefinitionException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/options-resolver/Exception/UndefinedOptionsException.php b/vendor/symfony/options-resolver/Exception/UndefinedOptionsException.php new file mode 100755 index 00000000..6ca3fce4 --- /dev/null +++ b/vendor/symfony/options-resolver/Exception/UndefinedOptionsException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Exception thrown when an undefined option is passed. + * + * You should remove the options in question from your code or define them + * beforehand. + * + * @author Bernhard Schussek + */ +class UndefinedOptionsException extends InvalidArgumentException +{ +} diff --git a/vendor/symfony/options-resolver/LICENSE b/vendor/symfony/options-resolver/LICENSE new file mode 100755 index 00000000..21d7fb9e --- /dev/null +++ b/vendor/symfony/options-resolver/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2018 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/options-resolver/Options.php b/vendor/symfony/options-resolver/Options.php new file mode 100755 index 00000000..d444ec42 --- /dev/null +++ b/vendor/symfony/options-resolver/Options.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver; + +/** + * Contains resolved option values. + * + * @author Bernhard Schussek + * @author Tobias Schultze + */ +interface Options extends \ArrayAccess, \Countable +{ +} diff --git a/vendor/symfony/options-resolver/OptionsResolver.php b/vendor/symfony/options-resolver/OptionsResolver.php new file mode 100755 index 00000000..20d0770e --- /dev/null +++ b/vendor/symfony/options-resolver/OptionsResolver.php @@ -0,0 +1,1157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver; + +use Symfony\Component\OptionsResolver\Exception\AccessException; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; +use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException; +use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException; +use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException; + +/** + * Validates options and merges them with default values. + * + * @author Bernhard Schussek + * @author Tobias Schultze + */ +class OptionsResolver implements Options, OptionsResolverInterface +{ + /** + * The fully qualified name of the {@link Options} interface. + * + * @internal + */ + const OPTIONS_INTERFACE = 'Symfony\\Component\\OptionsResolver\\Options'; + + /** + * The names of all defined options. + */ + private $defined = array(); + + /** + * The default option values. + */ + private $defaults = array(); + + /** + * The names of required options. + */ + private $required = array(); + + /** + * The resolved option values. + */ + private $resolved = array(); + + /** + * A list of normalizer closures. + * + * @var \Closure[] + */ + private $normalizers = array(); + + /** + * A list of accepted values for each option. + */ + private $allowedValues = array(); + + /** + * A list of accepted types for each option. + */ + private $allowedTypes = array(); + + /** + * A list of closures for evaluating lazy options. + */ + private $lazy = array(); + + /** + * A list of lazy options whose closure is currently being called. + * + * This list helps detecting circular dependencies between lazy options. + */ + private $calling = array(); + + /** + * Whether the instance is locked for reading. + * + * Once locked, the options cannot be changed anymore. This is + * necessary in order to avoid inconsistencies during the resolving + * process. If any option is changed after being read, all evaluated + * lazy options that depend on this option would become invalid. + */ + private $locked = false; + + private static $typeAliases = array( + 'boolean' => 'bool', + 'integer' => 'int', + 'double' => 'float', + ); + + /** + * Sets the default value of a given option. + * + * If the default value should be set based on other options, you can pass + * a closure with the following signature: + * + * function (Options $options) { + * // ... + * } + * + * The closure will be evaluated when {@link resolve()} is called. The + * closure has access to the resolved values of other options through the + * passed {@link Options} instance: + * + * function (Options $options) { + * if (isset($options['port'])) { + * // ... + * } + * } + * + * If you want to access the previously set default value, add a second + * argument to the closure's signature: + * + * $options->setDefault('name', 'Default Name'); + * + * $options->setDefault('name', function (Options $options, $previousValue) { + * // 'Default Name' === $previousValue + * }); + * + * This is mostly useful if the configuration of the {@link Options} object + * is spread across different locations of your code, such as base and + * sub-classes. + * + * @param string $option The name of the option + * @param mixed $value The default value of the option + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function setDefault($option, $value) + { + // Setting is not possible once resolving starts, because then lazy + // options could manipulate the state of the object, leading to + // inconsistent results. + if ($this->locked) { + throw new AccessException('Default values cannot be set from a lazy option or normalizer.'); + } + + // If an option is a closure that should be evaluated lazily, store it + // in the "lazy" property. + if ($value instanceof \Closure) { + $reflClosure = new \ReflectionFunction($value); + $params = $reflClosure->getParameters(); + + if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && self::OPTIONS_INTERFACE === $class->name) { + // Initialize the option if no previous value exists + if (!isset($this->defaults[$option])) { + $this->defaults[$option] = null; + } + + // Ignore previous lazy options if the closure has no second parameter + if (!isset($this->lazy[$option]) || !isset($params[1])) { + $this->lazy[$option] = array(); + } + + // Store closure for later evaluation + $this->lazy[$option][] = $value; + $this->defined[$option] = true; + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + } + + // This option is not lazy anymore + unset($this->lazy[$option]); + + // Yet undefined options can be marked as resolved, because we only need + // to resolve options with lazy closures, normalizers or validation + // rules, none of which can exist for undefined options + // If the option was resolved before, update the resolved value + if (!isset($this->defined[$option]) || array_key_exists($option, $this->resolved)) { + $this->resolved[$option] = $value; + } + + $this->defaults[$option] = $value; + $this->defined[$option] = true; + + return $this; + } + + /** + * Sets a list of default values. + * + * @param array $defaults The default values to set + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function setDefaults(array $defaults) + { + foreach ($defaults as $option => $value) { + $this->setDefault($option, $value); + } + + return $this; + } + + /** + * Returns whether a default value is set for an option. + * + * Returns true if {@link setDefault()} was called for this option. + * An option is also considered set if it was set to null. + * + * @param string $option The option name + * + * @return bool Whether a default value is set + */ + public function hasDefault($option) + { + return array_key_exists($option, $this->defaults); + } + + /** + * Marks one or more options as required. + * + * @param string|string[] $optionNames One or more option names + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function setRequired($optionNames) + { + if ($this->locked) { + throw new AccessException('Options cannot be made required from a lazy option or normalizer.'); + } + + foreach ((array) $optionNames as $option) { + $this->defined[$option] = true; + $this->required[$option] = true; + } + + return $this; + } + + /** + * Returns whether an option is required. + * + * An option is required if it was passed to {@link setRequired()}. + * + * @param string $option The name of the option + * + * @return bool Whether the option is required + */ + public function isRequired($option) + { + return isset($this->required[$option]); + } + + /** + * Returns the names of all required options. + * + * @return string[] The names of the required options + * + * @see isRequired() + */ + public function getRequiredOptions() + { + return array_keys($this->required); + } + + /** + * Returns whether an option is missing a default value. + * + * An option is missing if it was passed to {@link setRequired()}, but not + * to {@link setDefault()}. This option must be passed explicitly to + * {@link resolve()}, otherwise an exception will be thrown. + * + * @param string $option The name of the option + * + * @return bool Whether the option is missing + */ + public function isMissing($option) + { + return isset($this->required[$option]) && !array_key_exists($option, $this->defaults); + } + + /** + * Returns the names of all options missing a default value. + * + * @return string[] The names of the missing options + * + * @see isMissing() + */ + public function getMissingOptions() + { + return array_keys(array_diff_key($this->required, $this->defaults)); + } + + /** + * Defines a valid option name. + * + * Defines an option name without setting a default value. The option will + * be accepted when passed to {@link resolve()}. When not passed, the + * option will not be included in the resolved options. + * + * @param string|string[] $optionNames One or more option names + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function setDefined($optionNames) + { + if ($this->locked) { + throw new AccessException('Options cannot be defined from a lazy option or normalizer.'); + } + + foreach ((array) $optionNames as $option) { + $this->defined[$option] = true; + } + + return $this; + } + + /** + * Returns whether an option is defined. + * + * Returns true for any option passed to {@link setDefault()}, + * {@link setRequired()} or {@link setDefined()}. + * + * @param string $option The option name + * + * @return bool Whether the option is defined + */ + public function isDefined($option) + { + return isset($this->defined[$option]); + } + + /** + * Returns the names of all defined options. + * + * @return string[] The names of the defined options + * + * @see isDefined() + */ + public function getDefinedOptions() + { + return array_keys($this->defined); + } + + /** + * Sets the normalizer for an option. + * + * The normalizer should be a closure with the following signature: + * + * function (Options $options, $value) { + * // ... + * } + * + * The closure is invoked when {@link resolve()} is called. The closure + * has access to the resolved values of other options through the passed + * {@link Options} instance. + * + * The second parameter passed to the closure is the value of + * the option. + * + * The resolved option value is set to the return value of the closure. + * + * @param string $option The option name + * @param \Closure $normalizer The normalizer + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function setNormalizer($option, \Closure $normalizer) + { + if ($this->locked) { + throw new AccessException('Normalizers cannot be set from a lazy option or normalizer.'); + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + $this->normalizers[$option] = $normalizer; + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Sets the normalizers for an array of options. + * + * @param array $normalizers An array of closures + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + * + * @see setNormalizer() + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function setNormalizers(array $normalizers) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use setNormalizer() instead.', E_USER_DEPRECATED); + + foreach ($normalizers as $option => $normalizer) { + $this->setNormalizer($option, $normalizer); + } + + return $this; + } + + /** + * Sets allowed values for an option. + * + * Instead of passing values, you may also pass a closures with the + * following signature: + * + * function ($value) { + * // return true or false + * } + * + * The closure receives the value as argument and should return true to + * accept the value and false to reject the value. + * + * @param string $option The option name + * @param mixed $allowedValues One or more acceptable values/closures + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function setAllowedValues($option, $allowedValues = null) + { + if ($this->locked) { + throw new AccessException('Allowed values cannot be set from a lazy option or normalizer.'); + } + + // BC + if (\is_array($option) && null === $allowedValues) { + @trigger_error('Calling the '.__METHOD__.' method with an array of options is deprecated since Symfony 2.6 and will be removed in 3.0. Use the new signature with a single option instead.', E_USER_DEPRECATED); + + foreach ($option as $optionName => $optionValues) { + $this->setAllowedValues($optionName, $optionValues); + } + + return $this; + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + $this->allowedValues[$option] = \is_array($allowedValues) ? $allowedValues : array($allowedValues); + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Adds allowed values for an option. + * + * The values are merged with the allowed values defined previously. + * + * Instead of passing values, you may also pass a closures with the + * following signature: + * + * function ($value) { + * // return true or false + * } + * + * The closure receives the value as argument and should return true to + * accept the value and false to reject the value. + * + * @param string $option The option name + * @param mixed $allowedValues One or more acceptable values/closures + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function addAllowedValues($option, $allowedValues = null) + { + if ($this->locked) { + throw new AccessException('Allowed values cannot be added from a lazy option or normalizer.'); + } + + // BC + if (\is_array($option) && null === $allowedValues) { + @trigger_error('Calling the '.__METHOD__.' method with an array of options is deprecated since Symfony 2.6 and will be removed in 3.0. Use the new signature with a single option instead.', E_USER_DEPRECATED); + + foreach ($option as $optionName => $optionValues) { + $this->addAllowedValues($optionName, $optionValues); + } + + return $this; + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + if (!\is_array($allowedValues)) { + $allowedValues = array($allowedValues); + } + + if (!isset($this->allowedValues[$option])) { + $this->allowedValues[$option] = $allowedValues; + } else { + $this->allowedValues[$option] = array_merge($this->allowedValues[$option], $allowedValues); + } + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Sets allowed types for an option. + * + * Any type for which a corresponding is_() function exists is + * acceptable. Additionally, fully-qualified class or interface names may + * be passed. + * + * @param string $option The option name + * @param string|string[] $allowedTypes One or more accepted types + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function setAllowedTypes($option, $allowedTypes = null) + { + if ($this->locked) { + throw new AccessException('Allowed types cannot be set from a lazy option or normalizer.'); + } + + // BC + if (\is_array($option) && null === $allowedTypes) { + @trigger_error('Calling the '.__METHOD__.' method with an array of options is deprecated since Symfony 2.6 and will be removed in 3.0. Use the new signature with a single option instead.', E_USER_DEPRECATED); + + foreach ($option as $optionName => $optionTypes) { + $this->setAllowedTypes($optionName, $optionTypes); + } + + return $this; + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + $this->allowedTypes[$option] = (array) $allowedTypes; + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Adds allowed types for an option. + * + * The types are merged with the allowed types defined previously. + * + * Any type for which a corresponding is_() function exists is + * acceptable. Additionally, fully-qualified class or interface names may + * be passed. + * + * @param string $option The option name + * @param string|string[] $allowedTypes One or more accepted types + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function addAllowedTypes($option, $allowedTypes = null) + { + if ($this->locked) { + throw new AccessException('Allowed types cannot be added from a lazy option or normalizer.'); + } + + // BC + if (\is_array($option) && null === $allowedTypes) { + @trigger_error('Calling the '.__METHOD__.' method with an array of options is deprecated since Symfony 2.6 and will be removed in 3.0. Use the new signature with a single option instead.', E_USER_DEPRECATED); + + foreach ($option as $optionName => $optionTypes) { + $this->addAllowedTypes($optionName, $optionTypes); + } + + return $this; + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + if (!isset($this->allowedTypes[$option])) { + $this->allowedTypes[$option] = (array) $allowedTypes; + } else { + $this->allowedTypes[$option] = array_merge($this->allowedTypes[$option], (array) $allowedTypes); + } + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Removes the option with the given name. + * + * Undefined options are ignored. + * + * @param string|string[] $optionNames One or more option names + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function remove($optionNames) + { + if ($this->locked) { + throw new AccessException('Options cannot be removed from a lazy option or normalizer.'); + } + + foreach ((array) $optionNames as $option) { + unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]); + unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option]); + } + + return $this; + } + + /** + * Removes all options. + * + * @return $this + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function clear() + { + if ($this->locked) { + throw new AccessException('Options cannot be cleared from a lazy option or normalizer.'); + } + + $this->defined = array(); + $this->defaults = array(); + $this->required = array(); + $this->resolved = array(); + $this->lazy = array(); + $this->normalizers = array(); + $this->allowedTypes = array(); + $this->allowedValues = array(); + + return $this; + } + + /** + * Merges options with the default values stored in the container and + * validates them. + * + * Exceptions are thrown if: + * + * - Undefined options are passed; + * - Required options are missing; + * - Options have invalid types; + * - Options have invalid values. + * + * @param array $options A map of option names to values + * + * @return array The merged and validated options + * + * @throws UndefinedOptionsException If an option name is undefined + * @throws InvalidOptionsException If an option doesn't fulfill the + * specified validation rules + * @throws MissingOptionsException If a required option is missing + * @throws OptionDefinitionException If there is a cyclic dependency between + * lazy options and/or normalizers + * @throws NoSuchOptionException If a lazy option reads an unavailable option + * @throws AccessException If called from a lazy option or normalizer + */ + public function resolve(array $options = array()) + { + if ($this->locked) { + throw new AccessException('Options cannot be resolved from a lazy option or normalizer.'); + } + + // Allow this method to be called multiple times + $clone = clone $this; + + // Make sure that no unknown options are passed + $diff = array_diff_key($options, $clone->defined); + + if (\count($diff) > 0) { + ksort($clone->defined); + ksort($diff); + + throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', implode('", "', array_keys($diff)), implode('", "', array_keys($clone->defined)))); + } + + // Override options set by the user + foreach ($options as $option => $value) { + $clone->defaults[$option] = $value; + unset($clone->resolved[$option], $clone->lazy[$option]); + } + + // Check whether any required option is missing + $diff = array_diff_key($clone->required, $clone->defaults); + + if (\count($diff) > 0) { + ksort($diff); + + throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', implode('", "', array_keys($diff)))); + } + + // Lock the container + $clone->locked = true; + + // Now process the individual options. Use offsetGet(), which resolves + // the option itself and any options that the option depends on + foreach ($clone->defaults as $option => $_) { + $clone->offsetGet($option); + } + + return $clone->resolved; + } + + /** + * Returns the resolved value of an option. + * + * @param string $option The option name + * + * @return mixed The option value + * + * @throws AccessException If accessing this method outside of + * {@link resolve()} + * @throws NoSuchOptionException If the option is not set + * @throws InvalidOptionsException If the option doesn't fulfill the + * specified validation rules + * @throws OptionDefinitionException If there is a cyclic dependency between + * lazy options and/or normalizers + */ + public function offsetGet($option) + { + if (!$this->locked) { + throw new AccessException('Array access is only supported within closures of lazy options and normalizers.'); + } + + // Shortcut for resolved options + if (array_key_exists($option, $this->resolved)) { + return $this->resolved[$option]; + } + + // Check whether the option is set at all + if (!array_key_exists($option, $this->defaults)) { + if (!isset($this->defined[$option])) { + throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + throw new NoSuchOptionException(sprintf('The optional option "%s" has no value set. You should make sure it is set with "isset" before reading it.', $option)); + } + + $value = $this->defaults[$option]; + + // Resolve the option if the default value is lazily evaluated + if (isset($this->lazy[$option])) { + // If the closure is already being called, we have a cyclic + // dependency + if (isset($this->calling[$option])) { + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + } + + // The following section must be protected from cyclic + // calls. Set $calling for the current $option to detect a cyclic + // dependency + // BEGIN + $this->calling[$option] = true; + try { + foreach ($this->lazy[$option] as $closure) { + $value = $closure($this, $value); + } + } catch (\Exception $e) { + unset($this->calling[$option]); + throw $e; + } catch (\Throwable $e) { + unset($this->calling[$option]); + throw $e; + } + unset($this->calling[$option]); + // END + } + + // Validate the type of the resolved option + if (isset($this->allowedTypes[$option])) { + $valid = false; + + foreach ($this->allowedTypes[$option] as $type) { + $type = isset(self::$typeAliases[$type]) ? self::$typeAliases[$type] : $type; + + if (\function_exists($isFunction = 'is_'.$type)) { + if ($isFunction($value)) { + $valid = true; + break; + } + + continue; + } + + if ($value instanceof $type) { + $valid = true; + break; + } + } + + if (!$valid) { + throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $this->formatTypeOf($value))); + } + } + + // Validate the value of the resolved option + if (isset($this->allowedValues[$option])) { + $success = false; + $printableAllowedValues = array(); + + foreach ($this->allowedValues[$option] as $allowedValue) { + if ($allowedValue instanceof \Closure) { + if ($allowedValue($value)) { + $success = true; + break; + } + + // Don't include closures in the exception message + continue; + } elseif ($value === $allowedValue) { + $success = true; + break; + } + + $printableAllowedValues[] = $allowedValue; + } + + if (!$success) { + $message = sprintf( + 'The option "%s" with value %s is invalid.', + $option, + $this->formatValue($value) + ); + + if (\count($printableAllowedValues) > 0) { + $message .= sprintf( + ' Accepted values are: %s.', + $this->formatValues($printableAllowedValues) + ); + } + + throw new InvalidOptionsException($message); + } + } + + // Normalize the validated option + if (isset($this->normalizers[$option])) { + // If the closure is already being called, we have a cyclic + // dependency + if (isset($this->calling[$option])) { + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + } + + $normalizer = $this->normalizers[$option]; + + // The following section must be protected from cyclic + // calls. Set $calling for the current $option to detect a cyclic + // dependency + // BEGIN + $this->calling[$option] = true; + try { + $value = $normalizer($this, $value); + } catch (\Exception $e) { + unset($this->calling[$option]); + throw $e; + } catch (\Throwable $e) { + unset($this->calling[$option]); + throw $e; + } + unset($this->calling[$option]); + // END + } + + // Mark as resolved + $this->resolved[$option] = $value; + + return $value; + } + + /** + * Returns whether a resolved option with the given name exists. + * + * @param string $option The option name + * + * @return bool Whether the option is set + * + * @throws AccessException If accessing this method outside of {@link resolve()} + * + * @see \ArrayAccess::offsetExists() + */ + public function offsetExists($option) + { + if (!$this->locked) { + throw new AccessException('Array access is only supported within closures of lazy options and normalizers.'); + } + + return array_key_exists($option, $this->defaults); + } + + /** + * Not supported. + * + * @throws AccessException + */ + public function offsetSet($option, $value) + { + throw new AccessException('Setting options via array access is not supported. Use setDefault() instead.'); + } + + /** + * Not supported. + * + * @throws AccessException + */ + public function offsetUnset($option) + { + throw new AccessException('Removing options via array access is not supported. Use remove() instead.'); + } + + /** + * Returns the number of set options. + * + * This may be only a subset of the defined options. + * + * @return int Number of options + * + * @throws AccessException If accessing this method outside of {@link resolve()} + * + * @see \Countable::count() + */ + public function count() + { + if (!$this->locked) { + throw new AccessException('Counting is only supported within closures of lazy options and normalizers.'); + } + + return \count($this->defaults); + } + + /** + * Alias of {@link setDefault()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function set($option, $value) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the setDefaults() method instead.', E_USER_DEPRECATED); + + return $this->setDefault($option, $value); + } + + /** + * Shortcut for {@link clear()} and {@link setDefaults()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function replace(array $defaults) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the clear() and setDefaults() methods instead.', E_USER_DEPRECATED); + + $this->clear(); + + return $this->setDefaults($defaults); + } + + /** + * Alias of {@link setDefault()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function overload($option, $value) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the setDefault() method instead.', E_USER_DEPRECATED); + + return $this->setDefault($option, $value); + } + + /** + * Alias of {@link offsetGet()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function get($option) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the ArrayAccess syntax instead to get an option value.', E_USER_DEPRECATED); + + return $this->offsetGet($option); + } + + /** + * Alias of {@link offsetExists()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function has($option) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the ArrayAccess syntax instead to get an option value.', E_USER_DEPRECATED); + + return $this->offsetExists($option); + } + + /** + * Shortcut for {@link clear()} and {@link setDefaults()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function replaceDefaults(array $defaultValues) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the clear() and setDefaults() methods instead.', E_USER_DEPRECATED); + + $this->clear(); + + return $this->setDefaults($defaultValues); + } + + /** + * Alias of {@link setDefined()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function setOptional(array $optionNames) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the setDefined() method instead.', E_USER_DEPRECATED); + + return $this->setDefined($optionNames); + } + + /** + * Alias of {@link isDefined()}. + * + * @deprecated since version 2.6, to be removed in 3.0. + */ + public function isKnown($option) + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0. Use the isDefined() method instead.', E_USER_DEPRECATED); + + return $this->isDefined($option); + } + + /** + * Returns a string representation of the type of the value. + * + * This method should be used if you pass the type of a value as + * message parameter to a constraint violation. Note that such + * parameters should usually not be included in messages aimed at + * non-technical people. + * + * @param mixed $value The value to return the type of + * + * @return string The type of the value + */ + private function formatTypeOf($value) + { + return \is_object($value) ? \get_class($value) : \gettype($value); + } + + /** + * Returns a string representation of the value. + * + * This method returns the equivalent PHP tokens for most scalar types + * (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped + * in double quotes ("). + * + * @param mixed $value The value to format as string + * + * @return string The string representation of the passed value + */ + private function formatValue($value) + { + if (\is_object($value)) { + return \get_class($value); + } + + if (\is_array($value)) { + return 'array'; + } + + if (\is_string($value)) { + return '"'.$value.'"'; + } + + if (\is_resource($value)) { + return 'resource'; + } + + if (null === $value) { + return 'null'; + } + + if (false === $value) { + return 'false'; + } + + if (true === $value) { + return 'true'; + } + + return (string) $value; + } + + /** + * Returns a string representation of a list of values. + * + * Each of the values is converted to a string using + * {@link formatValue()}. The values are then concatenated with commas. + * + * @param array $values A list of values + * + * @return string The string representation of the value list + * + * @see formatValue() + */ + private function formatValues(array $values) + { + foreach ($values as $key => $value) { + $values[$key] = $this->formatValue($value); + } + + return implode(', ', $values); + } +} diff --git a/vendor/symfony/options-resolver/OptionsResolverInterface.php b/vendor/symfony/options-resolver/OptionsResolverInterface.php new file mode 100755 index 00000000..156cc751 --- /dev/null +++ b/vendor/symfony/options-resolver/OptionsResolverInterface.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver; + +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; +use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException; + +/** + * @author Bernhard Schussek + * + * @deprecated since version 2.6, to be removed in 3.0. Use {@link OptionsResolver} instead. + */ +interface OptionsResolverInterface +{ + /** + * Sets default option values. + * + * The options can either be values of any types or closures that + * evaluate the option value lazily. These closures must have one + * of the following signatures: + * + * function (Options $options) + * function (Options $options, $value) + * + * The second parameter passed to the closure is the previously + * set default value, in case you are overwriting an existing + * default value. + * + * The closures should return the lazily created option value. + * + * @param array $defaultValues A list of option names as keys and default + * values or closures as values + * + * @return $this + */ + public function setDefaults(array $defaultValues); + + /** + * Replaces default option values. + * + * Old defaults are erased, which means that closures passed here cannot + * access the previous default value. This may be useful to improve + * performance if the previous default value is calculated by an expensive + * closure. + * + * @param array $defaultValues A list of option names as keys and default + * values or closures as values + * + * @return $this + */ + public function replaceDefaults(array $defaultValues); + + /** + * Sets optional options. + * + * This method declares valid option names without setting default values for them. + * If these options are not passed to {@link resolve()} and no default has been set + * for them, they will be missing in the final options array. This can be helpful + * if you want to determine whether an option has been set or not because otherwise + * {@link resolve()} would trigger an exception for unknown options. + * + * @param array $optionNames A list of option names + * + * @return $this + */ + public function setOptional(array $optionNames); + + /** + * Sets required options. + * + * If these options are not passed to {@link resolve()} and no default has been set for + * them, an exception will be thrown. + * + * @param array $optionNames A list of option names + * + * @return $this + */ + public function setRequired($optionNames); + + /** + * Sets allowed values for a list of options. + * + * @param array $allowedValues A list of option names as keys and arrays + * with values acceptable for that option as + * values + * + * @return $this + * + * @throws InvalidOptionsException if an option has not been defined + * (see {@link isKnown()}) for which + * an allowed value is set + */ + public function setAllowedValues($allowedValues); + + /** + * Adds allowed values for a list of options. + * + * The values are merged with the allowed values defined previously. + * + * @param array $allowedValues A list of option names as keys and arrays + * with values acceptable for that option as + * values + * + * @return $this + * + * @throws InvalidOptionsException if an option has not been defined + * (see {@link isKnown()}) for which + * an allowed value is set + */ + public function addAllowedValues($allowedValues); + + /** + * Sets allowed types for a list of options. + * + * @param array $allowedTypes A list of option names as keys and type + * names passed as string or array as values + * + * @return $this + * + * @throws InvalidOptionsException if an option has not been defined for + * which an allowed type is set + */ + public function setAllowedTypes($allowedTypes); + + /** + * Adds allowed types for a list of options. + * + * The types are merged with the allowed types defined previously. + * + * @param array $allowedTypes A list of option names as keys and type + * names passed as string or array as values + * + * @return $this + * + * @throws InvalidOptionsException if an option has not been defined for + * which an allowed type is set + */ + public function addAllowedTypes($allowedTypes); + + /** + * Sets normalizers that are applied on resolved options. + * + * The normalizers should be closures with the following signature: + * + * function (Options $options, $value) + * + * The second parameter passed to the closure is the value of + * the option. + * + * The closure should return the normalized value. + * + * @param array $normalizers An array of closures + * + * @return $this + */ + public function setNormalizers(array $normalizers); + + /** + * Returns whether an option is known. + * + * An option is known if it has been passed to either {@link setDefaults()}, + * {@link setRequired()} or {@link setOptional()} before. + * + * @param string $option The name of the option + * + * @return bool Whether the option is known + */ + public function isKnown($option); + + /** + * Returns whether an option is required. + * + * An option is required if it has been passed to {@link setRequired()}, + * but not to {@link setDefaults()}. That is, the option has been declared + * as required and no default value has been set. + * + * @param string $option The name of the option + * + * @return bool Whether the option is required + */ + public function isRequired($option); + + /** + * Returns the combination of the default and the passed options. + * + * @param array $options The custom option values + * + * @return array A list of options and their values + * + * @throws InvalidOptionsException if any of the passed options has not + * been defined or does not contain an + * allowed value + * @throws MissingOptionsException if a required option is missing + * @throws OptionDefinitionException if a cyclic dependency is detected + * between two lazy options + */ + public function resolve(array $options = array()); +} diff --git a/vendor/symfony/options-resolver/README.md b/vendor/symfony/options-resolver/README.md new file mode 100755 index 00000000..245e69b5 --- /dev/null +++ b/vendor/symfony/options-resolver/README.md @@ -0,0 +1,15 @@ +OptionsResolver Component +========================= + +The OptionsResolver component is `array_replace` on steroids. It allows you to +create an options system with required options, defaults, validation (type, +value), normalization and more. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/options_resolver.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/options-resolver/Tests/LegacyOptionsResolverTest.php b/vendor/symfony/options-resolver/Tests/LegacyOptionsResolverTest.php new file mode 100755 index 00000000..c2e53109 --- /dev/null +++ b/vendor/symfony/options-resolver/Tests/LegacyOptionsResolverTest.php @@ -0,0 +1,734 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @group legacy + */ +class LegacyOptionsResolverTest extends TestCase +{ + /** + * @var OptionsResolver + */ + private $resolver; + + protected function setUp() + { + $this->resolver = new OptionsResolver(); + } + + public function testResolve() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => '2', + )); + + $options = array( + 'two' => '20', + ); + + $this->assertEquals(array( + 'one' => '1', + 'two' => '20', + ), $this->resolver->resolve($options)); + } + + public function testResolveNumericOptions() + { + $this->resolver->setDefaults(array( + '1' => '1', + '2' => '2', + )); + + $options = array( + '2' => '20', + ); + + $this->assertEquals(array( + '1' => '1', + '2' => '20', + ), $this->resolver->resolve($options)); + } + + public function testResolveLazy() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => function (Options $options) { + return '20'; + }, + )); + + $this->assertEquals(array( + 'one' => '1', + 'two' => '20', + ), $this->resolver->resolve(array())); + } + + public function testTypeAliasesForAllowedTypes() + { + $this->resolver->setDefaults(array( + 'force' => false, + )); + + $this->resolver->setAllowedTypes(array( + 'force' => 'boolean', + )); + + $this->assertSame(array('force' => true), $this->resolver->resolve(array( + 'force' => true, + ))); + } + + public function testResolveLazyDependencyOnOptional() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => function (Options $options) { + return $options['one'].'2'; + }, + )); + + $options = array( + 'one' => '10', + ); + + $this->assertEquals(array( + 'one' => '10', + 'two' => '102', + ), $this->resolver->resolve($options)); + } + + public function testResolveLazyDependencyOnMissingOptionalWithoutDefault() + { + $test = $this; + + $this->resolver->setOptional(array( + 'one', + )); + + $this->resolver->setDefaults(array( + 'two' => function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertArrayNotHasKey('one', $options); + + return '2'; + }, + )); + + $options = array(); + + $this->assertEquals(array( + 'two' => '2', + ), $this->resolver->resolve($options)); + } + + public function testResolveLazyDependencyOnOptionalWithoutDefault() + { + $test = $this; + + $this->resolver->setOptional(array( + 'one', + )); + + $this->resolver->setDefaults(array( + 'two' => function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertArrayHasKey('one', $options); + + return $options['one'].'2'; + }, + )); + + $options = array( + 'one' => '10', + ); + + $this->assertEquals(array( + 'one' => '10', + 'two' => '102', + ), $this->resolver->resolve($options)); + } + + public function testResolveLazyDependencyOnRequired() + { + $this->resolver->setRequired(array( + 'one', + )); + $this->resolver->setDefaults(array( + 'two' => function (Options $options) { + return $options['one'].'2'; + }, + )); + + $options = array( + 'one' => '10', + ); + + $this->assertEquals(array( + 'one' => '10', + 'two' => '102', + ), $this->resolver->resolve($options)); + } + + public function testResolveLazyReplaceDefaults() + { + $test = $this; + + $this->resolver->setDefaults(array( + 'one' => function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->fail('Previous closure should not be executed'); + }, + )); + + $this->resolver->replaceDefaults(array( + 'one' => function (Options $options, $previousValue) { + return '1'; + }, + )); + + $this->assertEquals(array( + 'one' => '1', + ), $this->resolver->resolve(array())); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @expectedExceptionMessage The option "foo" does not exist. Defined options are: "one", "three", "two". + */ + public function testResolveFailsIfNonExistingOption() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setRequired(array( + 'two', + )); + + $this->resolver->setOptional(array( + 'three', + )); + + $this->resolver->resolve(array( + 'foo' => 'bar', + )); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + */ + public function testResolveFailsIfMissingRequiredOption() + { + $this->resolver->setRequired(array( + 'one', + )); + + $this->resolver->setDefaults(array( + 'two' => '2', + )); + + $this->resolver->resolve(array( + 'two' => '20', + )); + } + + public function testResolveSucceedsIfOptionValueAllowed() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedValues(array( + 'one' => array('1', 'one'), + )); + + $options = array( + 'one' => 'one', + ); + + $this->assertEquals(array( + 'one' => 'one', + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionValueAllowed2() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => '2', + )); + + $this->resolver->setAllowedValues(array( + 'one' => '1', + 'two' => '2', + )); + $this->resolver->addAllowedValues(array( + 'one' => 'one', + 'two' => 'two', + )); + + $options = array( + 'one' => '1', + 'two' => 'two', + ); + + $this->assertEquals(array( + 'one' => '1', + 'two' => 'two', + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionalWithAllowedValuesNotSet() + { + $this->resolver->setRequired(array( + 'one', + )); + + $this->resolver->setOptional(array( + 'two', + )); + + $this->resolver->setAllowedValues(array( + 'one' => array('1', 'one'), + 'two' => array('2', 'two'), + )); + + $options = array( + 'one' => '1', + ); + + $this->assertEquals(array( + 'one' => '1', + ), $this->resolver->resolve($options)); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfOptionValueNotAllowed() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedValues(array( + 'one' => array('1', 'one'), + )); + + $this->resolver->resolve(array( + 'one' => '2', + )); + } + + public function testResolveSucceedsIfOptionTypeAllowed() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'string', + )); + + $options = array( + 'one' => 'one', + ); + + $this->assertEquals(array( + 'one' => 'one', + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionTypeAllowedPassArray() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => array('string', 'bool'), + )); + + $options = array( + 'one' => true, + ); + + $this->assertEquals(array( + 'one' => true, + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionTypeAllowedPassObject() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'object', + )); + + $object = new \stdClass(); + $options = array( + 'one' => $object, + ); + + $this->assertEquals(array( + 'one' => $object, + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionTypeAllowedPassClass() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => '\stdClass', + )); + + $object = new \stdClass(); + $options = array( + 'one' => $object, + ); + + $this->assertEquals(array( + 'one' => $object, + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionTypeAllowedAddTypes() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => '2', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'string', + 'two' => 'bool', + )); + $this->resolver->addAllowedTypes(array( + 'one' => 'float', + 'two' => 'integer', + )); + + $options = array( + 'one' => 1.23, + 'two' => false, + ); + + $this->assertEquals(array( + 'one' => 1.23, + 'two' => false, + ), $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfOptionalWithTypeAndWithoutValue() + { + $this->resolver->setOptional(array( + 'one', + 'two', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'string', + 'two' => 'int', + )); + + $options = array( + 'two' => 1, + ); + + $this->assertEquals(array( + 'two' => 1, + ), $this->resolver->resolve($options)); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfOptionTypeNotAllowed() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => array('string', 'bool'), + )); + + $this->resolver->resolve(array( + 'one' => 1.23, + )); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfOptionTypeNotAllowedMultipleOptions() + { + $this->resolver->setDefaults(array( + 'one' => '1', + 'two' => '2', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'string', + 'two' => 'bool', + )); + + $this->resolver->resolve(array( + 'one' => 'foo', + 'two' => 1.23, + )); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfOptionTypeNotAllowedAddTypes() + { + $this->resolver->setDefaults(array( + 'one' => '1', + )); + + $this->resolver->setAllowedTypes(array( + 'one' => 'string', + )); + $this->resolver->addAllowedTypes(array( + 'one' => 'bool', + )); + + $this->resolver->resolve(array( + 'one' => 1.23, + )); + } + + public function testFluidInterface() + { + $this->resolver->setDefaults(array('one' => '1')) + ->replaceDefaults(array('one' => '2')) + ->setAllowedValues(array('one' => array('1', '2'))) + ->addAllowedValues(array('one' => array('3'))) + ->setRequired(array('two')) + ->setOptional(array('three')); + + $options = array( + 'two' => '2', + ); + + $this->assertEquals(array( + 'one' => '2', + 'two' => '2', + ), $this->resolver->resolve($options)); + } + + public function testKnownIfDefaultWasSet() + { + $this->assertFalse($this->resolver->isKnown('foo')); + + $this->resolver->setDefaults(array( + 'foo' => 'bar', + )); + + $this->assertTrue($this->resolver->isKnown('foo')); + } + + public function testKnownIfRequired() + { + $this->assertFalse($this->resolver->isKnown('foo')); + + $this->resolver->setRequired(array( + 'foo', + )); + + $this->assertTrue($this->resolver->isKnown('foo')); + } + + public function testKnownIfOptional() + { + $this->assertFalse($this->resolver->isKnown('foo')); + + $this->resolver->setOptional(array( + 'foo', + )); + + $this->assertTrue($this->resolver->isKnown('foo')); + } + + public function testRequiredIfRequired() + { + $this->assertFalse($this->resolver->isRequired('foo')); + + $this->resolver->setRequired(array( + 'foo', + )); + + $this->assertTrue($this->resolver->isRequired('foo')); + } + + public function testNormalizersTransformFinalOptions() + { + $this->resolver->setDefaults(array( + 'foo' => 'bar', + 'bam' => 'baz', + )); + $this->resolver->setNormalizers(array( + 'foo' => function (Options $options, $value) { + return $options['bam'].'['.$value.']'; + }, + )); + + $expected = array( + 'foo' => 'baz[bar]', + 'bam' => 'baz', + ); + + $this->assertEquals($expected, $this->resolver->resolve(array())); + + $expected = array( + 'foo' => 'boo[custom]', + 'bam' => 'boo', + ); + + $this->assertEquals($expected, $this->resolver->resolve(array( + 'foo' => 'custom', + 'bam' => 'boo', + ))); + } + + public function testResolveWithoutOptionSucceedsIfRequiredAndDefaultValue() + { + $this->resolver->setRequired(array( + 'foo', + )); + $this->resolver->setDefaults(array( + 'foo' => 'bar', + )); + + $this->assertEquals(array( + 'foo' => 'bar', + ), $this->resolver->resolve(array())); + } + + public function testResolveWithoutOptionSucceedsIfDefaultValueAndRequired() + { + $this->resolver->setDefaults(array( + 'foo' => 'bar', + )); + $this->resolver->setRequired(array( + 'foo', + )); + + $this->assertEquals(array( + 'foo' => 'bar', + ), $this->resolver->resolve(array())); + } + + public function testResolveSucceedsIfOptionRequiredAndValueAllowed() + { + $this->resolver->setRequired(array( + 'one', 'two', + )); + $this->resolver->setAllowedValues(array( + 'two' => array('2'), + )); + + $options = array( + 'one' => '1', + 'two' => '2', + ); + + $this->assertEquals($options, $this->resolver->resolve($options)); + } + + public function testResolveSucceedsIfValueAllowedCallbackReturnsTrue() + { + $this->resolver->setRequired(array( + 'test', + )); + $this->resolver->setAllowedValues(array( + 'test' => function ($value) { + return true; + }, + )); + + $options = array( + 'test' => true, + ); + + $this->assertEquals($options, $this->resolver->resolve($options)); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfValueAllowedCallbackReturnsFalse() + { + $this->resolver->setRequired(array( + 'test', + )); + $this->resolver->setAllowedValues(array( + 'test' => function ($value) { + return false; + }, + )); + + $options = array( + 'test' => true, + ); + + $this->assertEquals($options, $this->resolver->resolve($options)); + } + + public function testClone() + { + $this->resolver->setDefaults(array('one' => '1')); + + $clone = clone $this->resolver; + + // Changes after cloning don't affect each other + $this->resolver->setDefaults(array('two' => '2')); + $clone->setDefaults(array('three' => '3')); + + $this->assertEquals(array( + 'one' => '1', + 'two' => '2', + ), $this->resolver->resolve()); + + $this->assertEquals(array( + 'one' => '1', + 'three' => '3', + ), $clone->resolve()); + } + + public function testOverloadReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->overload('foo', 'bar')); + } + + public function testOverloadCallsSet() + { + $this->resolver->overload('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } +} diff --git a/vendor/symfony/options-resolver/Tests/LegacyOptionsTest.php b/vendor/symfony/options-resolver/Tests/LegacyOptionsTest.php new file mode 100755 index 00000000..fe97b0fb --- /dev/null +++ b/vendor/symfony/options-resolver/Tests/LegacyOptionsTest.php @@ -0,0 +1,336 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @group legacy + */ +class LegacyOptionsTest extends TestCase +{ + /** + * @var OptionsResolver + */ + private $options; + + protected function setUp() + { + $this->options = new OptionsResolver(); + } + + public function testSetLazyOption() + { + $this->options->set('foo', function (Options $options) { + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'dynamic'), $this->options->resolve()); + } + + public function testOverloadKeepsPreviousValue() + { + $test = $this; + + // defined by superclass + $this->options->set('foo', 'bar'); + + // defined by subclass + $this->options->overload('foo', function (Options $options, $previousValue) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $previousValue); + + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'dynamic'), $this->options->resolve()); + } + + public function testPreviousValueIsEvaluatedIfLazy() + { + $test = $this; + + // defined by superclass + $this->options->set('foo', function (Options $options) { + return 'bar'; + }); + + // defined by subclass + $this->options->overload('foo', function (Options $options, $previousValue) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $previousValue); + + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'dynamic'), $this->options->resolve()); + } + + public function testPreviousValueIsNotEvaluatedIfNoSecondArgument() + { + $test = $this; + + // defined by superclass + $this->options->set('foo', function (Options $options) use ($test) { + $test->fail('Should not be called'); + }); + + // defined by subclass, no $previousValue argument defined! + $this->options->overload('foo', function (Options $options) { + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'dynamic'), $this->options->resolve()); + } + + public function testLazyOptionCanAccessOtherOptions() + { + $test = $this; + + $this->options->set('foo', 'bar'); + + $this->options->set('bam', function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $options->get('foo')); + + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'bar', 'bam' => 'dynamic'), $this->options->resolve()); + } + + public function testLazyOptionCanAccessOtherLazyOptions() + { + $test = $this; + + $this->options->set('foo', function (Options $options) { + return 'bar'; + }); + + $this->options->set('bam', function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $options->get('foo')); + + return 'dynamic'; + }); + + $this->assertEquals(array('foo' => 'bar', 'bam' => 'dynamic'), $this->options->resolve()); + } + + public function testNormalizer() + { + $this->options->set('foo', 'bar'); + + $this->options->setNormalizer('foo', function () { + return 'normalized'; + }); + + $this->assertEquals(array('foo' => 'normalized'), $this->options->resolve()); + } + + public function testNormalizerReceivesUnnormalizedValue() + { + $this->options->set('foo', 'bar'); + + $this->options->setNormalizer('foo', function (Options $options, $value) { + return 'normalized['.$value.']'; + }); + + $this->assertEquals(array('foo' => 'normalized[bar]'), $this->options->resolve()); + } + + public function testNormalizerCanAccessOtherOptions() + { + $test = $this; + + $this->options->set('foo', 'bar'); + $this->options->set('bam', 'baz'); + + $this->options->setNormalizer('bam', function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $options->get('foo')); + + return 'normalized'; + }); + + $this->assertEquals(array('foo' => 'bar', 'bam' => 'normalized'), $this->options->resolve()); + } + + public function testNormalizerCanAccessOtherLazyOptions() + { + $test = $this; + + $this->options->set('foo', function (Options $options) { + return 'bar'; + }); + $this->options->set('bam', 'baz'); + + $this->options->setNormalizer('bam', function (Options $options) use ($test) { + /* @var TestCase $test */ + $test->assertEquals('bar', $options->get('foo')); + + return 'normalized'; + }); + + $this->assertEquals(array('foo' => 'bar', 'bam' => 'normalized'), $this->options->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailForCyclicDependencies() + { + $this->options->set('foo', function (Options $options) { + $options->get('bam'); + }); + + $this->options->set('bam', function (Options $options) { + $options->get('foo'); + }); + + $this->options->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailForCyclicDependenciesBetweenNormalizers() + { + $this->options->set('foo', 'bar'); + $this->options->set('bam', 'baz'); + + $this->options->setNormalizer('foo', function (Options $options) { + $options->get('bam'); + }); + + $this->options->setNormalizer('bam', function (Options $options) { + $options->get('foo'); + }); + + $this->options->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailForCyclicDependenciesBetweenNormalizerAndLazyOption() + { + $this->options->set('foo', function (Options $options) { + $options->get('bam'); + }); + $this->options->set('bam', 'baz'); + + $this->options->setNormalizer('bam', function (Options $options) { + $options->get('foo'); + }); + + $this->options->resolve(); + } + + public function testReplaceClearsAndSets() + { + $this->options->set('one', '1'); + + $this->options->replace(array( + 'two' => '2', + 'three' => function (Options $options) { + return '2' === $options['two'] ? '3' : 'foo'; + }, + )); + + $this->assertEquals(array( + 'two' => '2', + 'three' => '3', + ), $this->options->resolve()); + } + + public function testClearRemovesAllOptions() + { + $this->options->set('one', 1); + $this->options->set('two', 2); + + $this->options->clear(); + + $this->assertEmpty($this->options->resolve()); + } + + public function testOverloadCannotBeEvaluatedLazilyWithoutExpectedClosureParams() + { + $this->options->set('foo', 'bar'); + + $this->options->overload('foo', function () { + return 'test'; + }); + + $resolved = $this->options->resolve(); + $this->assertInternalType('callable', $resolved['foo']); + } + + public function testOverloadCannotBeEvaluatedLazilyWithoutFirstParamTypeHint() + { + $this->options->set('foo', 'bar'); + + $this->options->overload('foo', function ($object) { + return 'test'; + }); + + $resolved = $this->options->resolve(); + $this->assertInternalType('callable', $resolved['foo']); + } + + public function testRemoveOptionAndNormalizer() + { + $this->options->set('foo1', 'bar'); + $this->options->setNormalizer('foo1', function (Options $options) { + return ''; + }); + $this->options->set('foo2', 'bar'); + $this->options->setNormalizer('foo2', function (Options $options) { + return ''; + }); + + $this->options->remove('foo2'); + $this->assertEquals(array('foo1' => ''), $this->options->resolve()); + } + + public function testReplaceOptionAndNormalizer() + { + $this->options->set('foo1', 'bar'); + $this->options->setNormalizer('foo1', function (Options $options) { + return ''; + }); + $this->options->set('foo2', 'bar'); + $this->options->setNormalizer('foo2', function (Options $options) { + return ''; + }); + + $this->options->replace(array('foo1' => 'new')); + $this->assertEquals(array('foo1' => 'new'), $this->options->resolve()); + } + + public function testClearOptionAndNormalizer() + { + $this->options->set('foo1', 'bar'); + $this->options->setNormalizer('foo1', function (Options $options) { + return ''; + }); + $this->options->set('foo2', 'bar'); + $this->options->setNormalizer('foo2', function (Options $options) { + return ''; + }); + + $this->options->clear(); + $this->assertEmpty($this->options->resolve()); + } +} diff --git a/vendor/symfony/options-resolver/Tests/OptionsResolver2Dot6Test.php b/vendor/symfony/options-resolver/Tests/OptionsResolver2Dot6Test.php new file mode 100755 index 00000000..09cf81c3 --- /dev/null +++ b/vendor/symfony/options-resolver/Tests/OptionsResolver2Dot6Test.php @@ -0,0 +1,1495 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Tests; + +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\TestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class OptionsResolver2Dot6Test extends TestCase +{ + /** + * @var OptionsResolver + */ + private $resolver; + + protected function setUp() + { + $this->resolver = new OptionsResolver(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @expectedExceptionMessage The option "foo" does not exist. Defined options are: "a", "z". + */ + public function testResolveFailsIfNonExistingOption() + { + $this->resolver->setDefault('z', '1'); + $this->resolver->setDefault('a', '2'); + + $this->resolver->resolve(array('foo' => 'bar')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @expectedExceptionMessage The options "baz", "foo", "ping" do not exist. Defined options are: "a", "z". + */ + public function testResolveFailsIfMultipleNonExistingOptions() + { + $this->resolver->setDefault('z', '1'); + $this->resolver->setDefault('a', '2'); + + $this->resolver->resolve(array('ping' => 'pong', 'foo' => 'bar', 'baz' => 'bam')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testResolveFailsFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->resolve(array()); + }); + + $this->resolver->resolve(); + } + + public function testSetDefaultReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->setDefault('foo', 'bar')); + } + + public function testSetDefault() + { + $this->resolver->setDefault('one', '1'); + $this->resolver->setDefault('two', '20'); + + $this->assertEquals(array( + 'one' => '1', + 'two' => '20', + ), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetDefaultFromLazyOption() + { + $this->resolver->setDefault('lazy', function (Options $options) { + $options->setDefault('default', 42); + }); + + $this->resolver->resolve(); + } + + public function testHasDefault() + { + $this->assertFalse($this->resolver->hasDefault('foo')); + $this->resolver->setDefault('foo', 42); + $this->assertTrue($this->resolver->hasDefault('foo')); + } + + public function testHasDefaultWithNullValue() + { + $this->assertFalse($this->resolver->hasDefault('foo')); + $this->resolver->setDefault('foo', null); + $this->assertTrue($this->resolver->hasDefault('foo')); + } + + public function testSetLazyReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->setDefault('foo', function (Options $options) {})); + } + + public function testSetLazyClosure() + { + $this->resolver->setDefault('foo', function (Options $options) { + return 'lazy'; + }); + + $this->assertEquals(array('foo' => 'lazy'), $this->resolver->resolve()); + } + + public function testClosureWithoutTypeHintNotInvoked() + { + $closure = function ($options) { + Assert::fail('Should not be called'); + }; + + $this->resolver->setDefault('foo', $closure); + + $this->assertSame(array('foo' => $closure), $this->resolver->resolve()); + } + + public function testClosureWithoutParametersNotInvoked() + { + $closure = function () { + Assert::fail('Should not be called'); + }; + + $this->resolver->setDefault('foo', $closure); + + $this->assertSame(array('foo' => $closure), $this->resolver->resolve()); + } + + public function testAccessPreviousDefaultValue() + { + // defined by superclass + $this->resolver->setDefault('foo', 'bar'); + + // defined by subclass + $this->resolver->setDefault('foo', function (Options $options, $previousValue) { + Assert::assertEquals('bar', $previousValue); + + return 'lazy'; + }); + + $this->assertEquals(array('foo' => 'lazy'), $this->resolver->resolve()); + } + + public function testAccessPreviousLazyDefaultValue() + { + // defined by superclass + $this->resolver->setDefault('foo', function (Options $options) { + return 'bar'; + }); + + // defined by subclass + $this->resolver->setDefault('foo', function (Options $options, $previousValue) { + Assert::assertEquals('bar', $previousValue); + + return 'lazy'; + }); + + $this->assertEquals(array('foo' => 'lazy'), $this->resolver->resolve()); + } + + public function testPreviousValueIsNotEvaluatedIfNoSecondArgument() + { + // defined by superclass + $this->resolver->setDefault('foo', function () { + Assert::fail('Should not be called'); + }); + + // defined by subclass, no $previousValue argument defined! + $this->resolver->setDefault('foo', function (Options $options) { + return 'lazy'; + }); + + $this->assertEquals(array('foo' => 'lazy'), $this->resolver->resolve()); + } + + public function testOverwrittenLazyOptionNotEvaluated() + { + $this->resolver->setDefault('foo', function (Options $options) { + Assert::fail('Should not be called'); + }); + + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testInvokeEachLazyOptionOnlyOnce() + { + $calls = 0; + + $this->resolver->setDefault('lazy1', function (Options $options) use (&$calls) { + Assert::assertSame(1, ++$calls); + + $options['lazy2']; + }); + + $this->resolver->setDefault('lazy2', function (Options $options) use (&$calls) { + Assert::assertSame(2, ++$calls); + }); + + $this->resolver->resolve(); + + $this->assertSame(2, $calls); + } + + public function testSetRequiredReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->setRequired('foo')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetRequiredFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setRequired('bar'); + }); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException + */ + public function testResolveFailsIfRequiredOptionMissing() + { + $this->resolver->setRequired('foo'); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfRequiredOptionSet() + { + $this->resolver->setRequired('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + public function testResolveSucceedsIfRequiredOptionPassed() + { + $this->resolver->setRequired('foo'); + + $this->assertNotEmpty($this->resolver->resolve(array('foo' => 'bar'))); + } + + public function testIsRequired() + { + $this->assertFalse($this->resolver->isRequired('foo')); + $this->resolver->setRequired('foo'); + $this->assertTrue($this->resolver->isRequired('foo')); + } + + public function testRequiredIfSetBefore() + { + $this->assertFalse($this->resolver->isRequired('foo')); + + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setRequired('foo'); + + $this->assertTrue($this->resolver->isRequired('foo')); + } + + public function testStillRequiredAfterSet() + { + $this->assertFalse($this->resolver->isRequired('foo')); + + $this->resolver->setRequired('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertTrue($this->resolver->isRequired('foo')); + } + + public function testIsNotRequiredAfterRemove() + { + $this->assertFalse($this->resolver->isRequired('foo')); + $this->resolver->setRequired('foo'); + $this->resolver->remove('foo'); + $this->assertFalse($this->resolver->isRequired('foo')); + } + + public function testIsNotRequiredAfterClear() + { + $this->assertFalse($this->resolver->isRequired('foo')); + $this->resolver->setRequired('foo'); + $this->resolver->clear(); + $this->assertFalse($this->resolver->isRequired('foo')); + } + + public function testGetRequiredOptions() + { + $this->resolver->setRequired(array('foo', 'bar')); + $this->resolver->setDefault('bam', 'baz'); + $this->resolver->setDefault('foo', 'boo'); + + $this->assertSame(array('foo', 'bar'), $this->resolver->getRequiredOptions()); + } + + public function testIsMissingIfNotSet() + { + $this->assertFalse($this->resolver->isMissing('foo')); + $this->resolver->setRequired('foo'); + $this->assertTrue($this->resolver->isMissing('foo')); + } + + public function testIsNotMissingIfSet() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->assertFalse($this->resolver->isMissing('foo')); + $this->resolver->setRequired('foo'); + $this->assertFalse($this->resolver->isMissing('foo')); + } + + public function testIsNotMissingAfterRemove() + { + $this->resolver->setRequired('foo'); + $this->resolver->remove('foo'); + $this->assertFalse($this->resolver->isMissing('foo')); + } + + public function testIsNotMissingAfterClear() + { + $this->resolver->setRequired('foo'); + $this->resolver->clear(); + $this->assertFalse($this->resolver->isRequired('foo')); + } + + public function testGetMissingOptions() + { + $this->resolver->setRequired(array('foo', 'bar')); + $this->resolver->setDefault('bam', 'baz'); + $this->resolver->setDefault('foo', 'boo'); + + $this->assertSame(array('bar'), $this->resolver->getMissingOptions()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetDefinedFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setDefined('bar'); + }); + + $this->resolver->resolve(); + } + + public function testDefinedOptionsNotIncludedInResolvedOptions() + { + $this->resolver->setDefined('foo'); + + $this->assertSame(array(), $this->resolver->resolve()); + } + + public function testDefinedOptionsIncludedIfDefaultSetBefore() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setDefined('foo'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testDefinedOptionsIncludedIfDefaultSetAfter() + { + $this->resolver->setDefined('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testDefinedOptionsIncludedIfPassedToResolve() + { + $this->resolver->setDefined('foo'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve(array('foo' => 'bar'))); + } + + public function testIsDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setDefined('foo'); + $this->assertTrue($this->resolver->isDefined('foo')); + } + + public function testLazyOptionsAreDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setDefault('foo', function (Options $options) {}); + $this->assertTrue($this->resolver->isDefined('foo')); + } + + public function testRequiredOptionsAreDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setRequired('foo'); + $this->assertTrue($this->resolver->isDefined('foo')); + } + + public function testSetOptionsAreDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setDefault('foo', 'bar'); + $this->assertTrue($this->resolver->isDefined('foo')); + } + + public function testGetDefinedOptions() + { + $this->resolver->setDefined(array('foo', 'bar')); + $this->resolver->setDefault('baz', 'bam'); + $this->resolver->setRequired('boo'); + + $this->assertSame(array('foo', 'bar', 'baz', 'boo'), $this->resolver->getDefinedOptions()); + } + + public function testRemovedOptionsAreNotDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setDefined('foo'); + $this->assertTrue($this->resolver->isDefined('foo')); + $this->resolver->remove('foo'); + $this->assertFalse($this->resolver->isDefined('foo')); + } + + public function testClearedOptionsAreNotDefined() + { + $this->assertFalse($this->resolver->isDefined('foo')); + $this->resolver->setDefined('foo'); + $this->assertTrue($this->resolver->isDefined('foo')); + $this->resolver->clear(); + $this->assertFalse($this->resolver->isDefined('foo')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testSetAllowedTypesFailsIfUnknownOption() + { + $this->resolver->setAllowedTypes('foo', 'string'); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetAllowedTypesFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setAllowedTypes('bar', 'string'); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + /** + * @dataProvider provideInvalidTypes + */ + public function testResolveFailsIfInvalidType($actualType, $allowedType, $exceptionMessage) + { + $this->resolver->setDefined('option'); + $this->resolver->setAllowedTypes('option', $allowedType); + + if (method_exists($this, 'expectException')) { + $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); + $this->expectExceptionMessage($exceptionMessage); + } else { + $this->setExpectedException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException', $exceptionMessage); + } + + $this->resolver->resolve(array('option' => $actualType)); + } + + public function provideInvalidTypes() + { + return array( + array(true, 'string', 'The option "option" with value true is expected to be of type "string", but is of type "boolean".'), + array(false, 'string', 'The option "option" with value false is expected to be of type "string", but is of type "boolean".'), + array(fopen(__FILE__, 'r'), 'string', 'The option "option" with value resource is expected to be of type "string", but is of type "resource".'), + array(array(), 'string', 'The option "option" with value array is expected to be of type "string", but is of type "array".'), + array(new OptionsResolver(), 'string', 'The option "option" with value Symfony\Component\OptionsResolver\OptionsResolver is expected to be of type "string", but is of type "Symfony\Component\OptionsResolver\OptionsResolver".'), + array(42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'), + array(null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'), + array('bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'), + ); + } + + public function testResolveSucceedsIfValidType() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedTypes('foo', 'string'); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The option "foo" with value 42 is expected to be of type "string" or "bool", but is of type "integer". + */ + public function testResolveFailsIfInvalidTypeMultiple() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedTypes('foo', array('string', 'bool')); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidTypeMultiple() + { + $this->resolver->setDefault('foo', true); + $this->resolver->setAllowedTypes('foo', array('string', 'bool')); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + public function testResolveSucceedsIfInstanceOfClass() + { + $this->resolver->setDefault('foo', new \stdClass()); + $this->resolver->setAllowedTypes('foo', '\stdClass'); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testAddAllowedTypesFailsIfUnknownOption() + { + $this->resolver->addAllowedTypes('foo', 'string'); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfAddAllowedTypesFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->addAllowedTypes('bar', 'string'); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfInvalidAddedType() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->addAllowedTypes('foo', 'string'); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidAddedType() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->addAllowedTypes('foo', 'string'); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfInvalidAddedTypeMultiple() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->addAllowedTypes('foo', array('string', 'bool')); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidAddedTypeMultiple() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->addAllowedTypes('foo', array('string', 'bool')); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + public function testAddAllowedTypesDoesNotOverwrite() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedTypes('foo', 'string'); + $this->resolver->addAllowedTypes('foo', 'bool'); + + $this->resolver->setDefault('foo', 'bar'); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + public function testAddAllowedTypesDoesNotOverwrite2() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedTypes('foo', 'string'); + $this->resolver->addAllowedTypes('foo', 'bool'); + + $this->resolver->setDefault('foo', false); + + $this->assertNotEmpty($this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testSetAllowedValuesFailsIfUnknownOption() + { + $this->resolver->setAllowedValues('foo', 'bar'); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetAllowedValuesFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setAllowedValues('bar', 'baz'); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The option "foo" with value 42 is invalid. Accepted values are: "bar". + */ + public function testResolveFailsIfInvalidValue() + { + $this->resolver->setDefined('foo'); + $this->resolver->setAllowedValues('foo', 'bar'); + + $this->resolver->resolve(array('foo' => 42)); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The option "foo" with value null is invalid. Accepted values are: "bar". + */ + public function testResolveFailsIfInvalidValueIsNull() + { + $this->resolver->setDefault('foo', null); + $this->resolver->setAllowedValues('foo', 'bar'); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfInvalidValueStrict() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedValues('foo', '42'); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidValue() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', 'bar'); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testResolveSucceedsIfValidValueIsNull() + { + $this->resolver->setDefault('foo', null); + $this->resolver->setAllowedValues('foo', null); + + $this->assertEquals(array('foo' => null), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The option "foo" with value 42 is invalid. Accepted values are: "bar", false, null. + */ + public function testResolveFailsIfInvalidValueMultiple() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedValues('foo', array('bar', false, null)); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidValueMultiple() + { + $this->resolver->setDefault('foo', 'baz'); + $this->resolver->setAllowedValues('foo', array('bar', 'baz')); + + $this->assertEquals(array('foo' => 'baz'), $this->resolver->resolve()); + } + + public function testResolveFailsIfClosureReturnsFalse() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedValues('foo', function ($value) use (&$passedValue) { + $passedValue = $value; + + return false; + }); + + try { + $this->resolver->resolve(); + $this->fail('Should fail'); + } catch (InvalidOptionsException $e) { + } + + $this->assertSame(42, $passedValue); + } + + public function testResolveSucceedsIfClosureReturnsTrue() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', function ($value) use (&$passedValue) { + $passedValue = $value; + + return true; + }); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + $this->assertSame('bar', $passedValue); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfAllClosuresReturnFalse() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedValues('foo', array( + function () { return false; }, + function () { return false; }, + function () { return false; }, + )); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfAnyClosureReturnsTrue() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', array( + function () { return false; }, + function () { return true; }, + function () { return false; }, + )); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testAddAllowedValuesFailsIfUnknownOption() + { + $this->resolver->addAllowedValues('foo', 'bar'); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfAddAllowedValuesFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->addAllowedValues('bar', 'baz'); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfInvalidAddedValue() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->addAllowedValues('foo', 'bar'); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidAddedValue() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->addAllowedValues('foo', 'bar'); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testResolveSucceedsIfValidAddedValueIsNull() + { + $this->resolver->setDefault('foo', null); + $this->resolver->addAllowedValues('foo', null); + + $this->assertEquals(array('foo' => null), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfInvalidAddedValueMultiple() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->addAllowedValues('foo', array('bar', 'baz')); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfValidAddedValueMultiple() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->addAllowedValues('foo', array('bar', 'baz')); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testAddAllowedValuesDoesNotOverwrite() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', 'bar'); + $this->resolver->addAllowedValues('foo', 'baz'); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testAddAllowedValuesDoesNotOverwrite2() + { + $this->resolver->setDefault('foo', 'baz'); + $this->resolver->setAllowedValues('foo', 'bar'); + $this->resolver->addAllowedValues('foo', 'baz'); + + $this->assertEquals(array('foo' => 'baz'), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testResolveFailsIfAllAddedClosuresReturnFalse() + { + $this->resolver->setDefault('foo', 42); + $this->resolver->setAllowedValues('foo', function () { return false; }); + $this->resolver->addAllowedValues('foo', function () { return false; }); + + $this->resolver->resolve(); + } + + public function testResolveSucceedsIfAnyAddedClosureReturnsTrue() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', function () { return false; }); + $this->resolver->addAllowedValues('foo', function () { return true; }); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testResolveSucceedsIfAnyAddedClosureReturnsTrue2() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', function () { return true; }); + $this->resolver->addAllowedValues('foo', function () { return false; }); + + $this->assertEquals(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testSetNormalizerReturnsThis() + { + $this->resolver->setDefault('foo', 'bar'); + $this->assertSame($this->resolver, $this->resolver->setNormalizer('foo', function () {})); + } + + public function testSetNormalizerClosure() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setNormalizer('foo', function () { + return 'normalized'; + }); + + $this->assertEquals(array('foo' => 'normalized'), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testSetNormalizerFailsIfUnknownOption() + { + $this->resolver->setNormalizer('foo', function () {}); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetNormalizerFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setNormalizer('foo', function () {}); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + public function testNormalizerReceivesSetOption() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return 'normalized['.$value.']'; + }); + + $this->assertEquals(array('foo' => 'normalized[bar]'), $this->resolver->resolve()); + } + + public function testNormalizerReceivesPassedOption() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return 'normalized['.$value.']'; + }); + + $resolved = $this->resolver->resolve(array('foo' => 'baz')); + + $this->assertEquals(array('foo' => 'normalized[baz]'), $resolved); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testValidateTypeBeforeNormalization() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->resolver->setAllowedTypes('foo', 'int'); + + $this->resolver->setNormalizer('foo', function () { + Assert::fail('Should not be called.'); + }); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + */ + public function testValidateValueBeforeNormalization() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->resolver->setAllowedValues('foo', 'baz'); + + $this->resolver->setNormalizer('foo', function () { + Assert::fail('Should not be called.'); + }); + + $this->resolver->resolve(); + } + + public function testNormalizerCanAccessOtherOptions() + { + $this->resolver->setDefault('default', 'bar'); + $this->resolver->setDefault('norm', 'baz'); + + $this->resolver->setNormalizer('norm', function (Options $options) { + /* @var TestCase $test */ + Assert::assertSame('bar', $options['default']); + + return 'normalized'; + }); + + $this->assertEquals(array( + 'default' => 'bar', + 'norm' => 'normalized', + ), $this->resolver->resolve()); + } + + public function testNormalizerCanAccessLazyOptions() + { + $this->resolver->setDefault('lazy', function (Options $options) { + return 'bar'; + }); + $this->resolver->setDefault('norm', 'baz'); + + $this->resolver->setNormalizer('norm', function (Options $options) { + /* @var TestCase $test */ + Assert::assertEquals('bar', $options['lazy']); + + return 'normalized'; + }); + + $this->assertEquals(array( + 'lazy' => 'bar', + 'norm' => 'normalized', + ), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailIfCyclicDependencyBetweenNormalizers() + { + $this->resolver->setDefault('norm1', 'bar'); + $this->resolver->setDefault('norm2', 'baz'); + + $this->resolver->setNormalizer('norm1', function (Options $options) { + $options['norm2']; + }); + + $this->resolver->setNormalizer('norm2', function (Options $options) { + $options['norm1']; + }); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailIfCyclicDependencyBetweenNormalizerAndLazyOption() + { + $this->resolver->setDefault('lazy', function (Options $options) { + $options['norm']; + }); + + $this->resolver->setDefault('norm', 'baz'); + + $this->resolver->setNormalizer('norm', function (Options $options) { + $options['lazy']; + }); + + $this->resolver->resolve(); + } + + public function testCaughtExceptionFromNormalizerDoesNotCrashOptionResolver() + { + $throw = true; + + $this->resolver->setDefaults(array('catcher' => null, 'thrower' => null)); + + $this->resolver->setNormalizer('catcher', function (Options $options) { + try { + return $options['thrower']; + } catch (\Exception $e) { + return false; + } + }); + + $this->resolver->setNormalizer('thrower', function () use (&$throw) { + if ($throw) { + $throw = false; + throw new \UnexpectedValueException('throwing'); + } + + return true; + }); + + $this->assertSame(array('catcher' => false, 'thrower' => true), $this->resolver->resolve()); + } + + public function testCaughtExceptionFromLazyDoesNotCrashOptionResolver() + { + $throw = true; + + $this->resolver->setDefault('catcher', function (Options $options) { + try { + return $options['thrower']; + } catch (\Exception $e) { + return false; + } + }); + + $this->resolver->setDefault('thrower', function (Options $options) use (&$throw) { + if ($throw) { + $throw = false; + throw new \UnexpectedValueException('throwing'); + } + + return true; + }); + + $this->assertSame(array('catcher' => false, 'thrower' => true), $this->resolver->resolve()); + } + + public function testInvokeEachNormalizerOnlyOnce() + { + $calls = 0; + + $this->resolver->setDefault('norm1', 'bar'); + $this->resolver->setDefault('norm2', 'baz'); + + $this->resolver->setNormalizer('norm1', function ($options) use (&$calls) { + Assert::assertSame(1, ++$calls); + + $options['norm2']; + }); + $this->resolver->setNormalizer('norm2', function () use (&$calls) { + Assert::assertSame(2, ++$calls); + }); + + $this->resolver->resolve(); + + $this->assertSame(2, $calls); + } + + public function testNormalizerNotCalledForUnsetOptions() + { + $this->resolver->setDefined('norm'); + + $this->resolver->setNormalizer('norm', function () { + Assert::fail('Should not be called.'); + }); + + $this->assertEmpty($this->resolver->resolve()); + } + + public function testSetDefaultsReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->setDefaults(array('foo', 'bar'))); + } + + public function testSetDefaults() + { + $this->resolver->setDefault('one', '1'); + $this->resolver->setDefault('two', 'bar'); + + $this->resolver->setDefaults(array( + 'two' => '2', + 'three' => '3', + )); + + $this->assertEquals(array( + 'one' => '1', + 'two' => '2', + 'three' => '3', + ), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfSetDefaultsFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->setDefaults(array('two' => '2')); + }); + + $this->resolver->resolve(); + } + + public function testRemoveReturnsThis() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame($this->resolver, $this->resolver->remove('foo')); + } + + public function testRemoveSingleOption() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setDefault('baz', 'boo'); + $this->resolver->remove('foo'); + + $this->assertSame(array('baz' => 'boo'), $this->resolver->resolve()); + } + + public function testRemoveMultipleOptions() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setDefault('baz', 'boo'); + $this->resolver->setDefault('doo', 'dam'); + + $this->resolver->remove(array('foo', 'doo')); + + $this->assertSame(array('baz' => 'boo'), $this->resolver->resolve()); + } + + public function testRemoveLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + return 'lazy'; + }); + $this->resolver->remove('foo'); + + $this->assertSame(array(), $this->resolver->resolve()); + } + + public function testRemoveNormalizer() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return 'normalized'; + }); + $this->resolver->remove('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testRemoveAllowedTypes() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedTypes('foo', 'int'); + $this->resolver->remove('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testRemoveAllowedValues() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', array('baz', 'boo')); + $this->resolver->remove('foo'); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfRemoveFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->remove('bar'); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + public function testRemoveUnknownOptionIgnored() + { + $this->assertNotNull($this->resolver->remove('foo')); + } + + public function testClearReturnsThis() + { + $this->assertSame($this->resolver, $this->resolver->clear()); + } + + public function testClearRemovesAllOptions() + { + $this->resolver->setDefault('one', 1); + $this->resolver->setDefault('two', 2); + + $this->resolver->clear(); + + $this->assertEmpty($this->resolver->resolve()); + } + + public function testClearLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + return 'lazy'; + }); + $this->resolver->clear(); + + $this->assertSame(array(), $this->resolver->resolve()); + } + + public function testClearNormalizer() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return 'normalized'; + }); + $this->resolver->clear(); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testClearAllowedTypes() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedTypes('foo', 'int'); + $this->resolver->clear(); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + public function testClearAllowedValues() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setAllowedValues('foo', 'baz'); + $this->resolver->clear(); + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame(array('foo' => 'bar'), $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfClearFromLazyption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->clear(); + }); + + $this->resolver->setDefault('bar', 'baz'); + + $this->resolver->resolve(); + } + + public function testClearOptionAndNormalizer() + { + $this->resolver->setDefault('foo1', 'bar'); + $this->resolver->setNormalizer('foo1', function (Options $options) { + return ''; + }); + $this->resolver->setDefault('foo2', 'bar'); + $this->resolver->setNormalizer('foo2', function (Options $options) { + return ''; + }); + + $this->resolver->clear(); + $this->assertEmpty($this->resolver->resolve()); + } + + public function testArrayAccess() + { + $this->resolver->setDefault('default1', 0); + $this->resolver->setDefault('default2', 1); + $this->resolver->setRequired('required'); + $this->resolver->setDefined('defined'); + $this->resolver->setDefault('lazy1', function (Options $options) { + return 'lazy'; + }); + + $this->resolver->setDefault('lazy2', function (Options $options) { + Assert::assertArrayHasKey('default1', $options); + Assert::assertArrayHasKey('default2', $options); + Assert::assertArrayHasKey('required', $options); + Assert::assertArrayHasKey('lazy1', $options); + Assert::assertArrayHasKey('lazy2', $options); + Assert::assertArrayNotHasKey('defined', $options); + + Assert::assertSame(0, $options['default1']); + Assert::assertSame(42, $options['default2']); + Assert::assertSame('value', $options['required']); + Assert::assertSame('lazy', $options['lazy1']); + + // Obviously $options['lazy'] and $options['defined'] cannot be + // accessed + }); + + $this->resolver->resolve(array('default2' => 42, 'required' => 'value')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testArrayAccessGetFailsOutsideResolve() + { + $this->resolver->setDefault('default', 0); + + $this->resolver['default']; + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testArrayAccessExistsFailsOutsideResolve() + { + $this->resolver->setDefault('default', 0); + + isset($this->resolver['default']); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testArrayAccessSetNotSupported() + { + $this->resolver['default'] = 0; + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testArrayAccessUnsetNotSupported() + { + $this->resolver->setDefault('default', 0); + + unset($this->resolver['default']); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @expectedExceptionMessage The option "undefined" does not exist. Defined options are: "foo", "lazy". + */ + public function testFailIfGetNonExisting() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->resolver->setDefault('lazy', function (Options $options) { + $options['undefined']; + }); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException + * @expectedExceptionMessage The optional option "defined" has no value set. You should make sure it is set with "isset" before reading it. + */ + public function testFailIfGetDefinedButUnset() + { + $this->resolver->setDefined('defined'); + + $this->resolver->setDefault('lazy', function (Options $options) { + $options['defined']; + }); + + $this->resolver->resolve(); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException + */ + public function testFailIfCyclicDependency() + { + $this->resolver->setDefault('lazy1', function (Options $options) { + $options['lazy2']; + }); + + $this->resolver->setDefault('lazy2', function (Options $options) { + $options['lazy1']; + }); + + $this->resolver->resolve(); + } + + public function testCount() + { + $this->resolver->setDefault('default', 0); + $this->resolver->setRequired('required'); + $this->resolver->setDefined('defined'); + $this->resolver->setDefault('lazy1', function () {}); + + $this->resolver->setDefault('lazy2', function (Options $options) { + Assert::assertCount(4, $options); + }); + + $this->assertCount(4, $this->resolver->resolve(array('required' => 'value'))); + } + + /** + * In resolve() we count the options that are actually set (which may be + * only a subset of the defined options). Outside of resolve(), it's not + * clear what is counted. + * + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testCountFailsOutsideResolve() + { + $this->resolver->setDefault('foo', 0); + $this->resolver->setRequired('bar'); + $this->resolver->setDefined('bar'); + $this->resolver->setDefault('lazy1', function () {}); + + \count($this->resolver); + } +} diff --git a/vendor/symfony/options-resolver/composer.json b/vendor/symfony/options-resolver/composer.json new file mode 100755 index 00000000..226dab6a --- /dev/null +++ b/vendor/symfony/options-resolver/composer.json @@ -0,0 +1,33 @@ +{ + "name": "symfony/options-resolver", + "type": "library", + "description": "Symfony OptionsResolver Component", + "keywords": ["options", "config", "configuration"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + } +} diff --git a/vendor/symfony/options-resolver/phpunit.xml.dist b/vendor/symfony/options-resolver/phpunit.xml.dist new file mode 100755 index 00000000..9a2ec111 --- /dev/null +++ b/vendor/symfony/options-resolver/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/vendor/symfony/polyfill-ctype/Ctype.php b/vendor/symfony/polyfill-ctype/Ctype.php new file mode 100755 index 00000000..58414dc7 --- /dev/null +++ b/vendor/symfony/polyfill-ctype/Ctype.php @@ -0,0 +1,227 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Ctype; + +/** + * Ctype implementation through regex. + * + * @internal + * + * @author Gert de Pagter + */ +final class Ctype +{ + /** + * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. + * + * @see https://php.net/ctype-alnum + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_alnum($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is a letter, FALSE otherwise. + * + * @see https://php.net/ctype-alpha + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_alpha($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); + } + + /** + * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. + * + * @see https://php.net/ctype-cntrl + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_cntrl($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); + } + + /** + * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. + * + * @see https://php.net/ctype-digit + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_digit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. + * + * @see https://php.net/ctype-graph + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_graph($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); + } + + /** + * Returns TRUE if every character in text is a lowercase letter. + * + * @see https://php.net/ctype-lower + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_lower($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); + } + + /** + * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. + * + * @see https://php.net/ctype-print + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_print($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); + } + + /** + * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. + * + * @see https://php.net/ctype-punct + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_punct($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); + } + + /** + * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. + * + * @see https://php.net/ctype-space + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_space($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); + } + + /** + * Returns TRUE if every character in text is an uppercase letter. + * + * @see https://php.net/ctype-upper + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_upper($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); + } + + /** + * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. + * + * @see https://php.net/ctype-xdigit + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_xdigit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); + } + + /** + * Converts integers to their char versions according to normal ctype behaviour, if needed. + * + * If an integer between -128 and 255 inclusive is provided, + * it is interpreted as the ASCII value of a single character + * (negative values have 256 added in order to allow characters in the Extended ASCII range). + * Any other integer is interpreted as a string containing the decimal digits of the integer. + * + * @param string|int $int + * + * @return mixed + */ + private static function convert_int_to_char_for_ctype($int) + { + if (!\is_int($int)) { + return $int; + } + + if ($int < -128 || $int > 255) { + return (string) $int; + } + + if ($int < 0) { + $int += 256; + } + + return \chr($int); + } +} diff --git a/vendor/symfony/polyfill-ctype/LICENSE b/vendor/symfony/polyfill-ctype/LICENSE new file mode 100755 index 00000000..3f853aaf --- /dev/null +++ b/vendor/symfony/polyfill-ctype/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-ctype/README.md b/vendor/symfony/polyfill-ctype/README.md new file mode 100755 index 00000000..8add1ab0 --- /dev/null +++ b/vendor/symfony/polyfill-ctype/README.md @@ -0,0 +1,12 @@ +Symfony Polyfill / Ctype +======================== + +This component provides `ctype_*` functions to users who run php versions without the ctype extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-ctype/bootstrap.php b/vendor/symfony/polyfill-ctype/bootstrap.php new file mode 100755 index 00000000..14d1d0fa --- /dev/null +++ b/vendor/symfony/polyfill-ctype/bootstrap.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Ctype as p; + +if (!function_exists('ctype_alnum')) { + function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } + function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } + function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } + function ctype_digit($text) { return p\Ctype::ctype_digit($text); } + function ctype_graph($text) { return p\Ctype::ctype_graph($text); } + function ctype_lower($text) { return p\Ctype::ctype_lower($text); } + function ctype_print($text) { return p\Ctype::ctype_print($text); } + function ctype_punct($text) { return p\Ctype::ctype_punct($text); } + function ctype_space($text) { return p\Ctype::ctype_space($text); } + function ctype_upper($text) { return p\Ctype::ctype_upper($text); } + function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } +} diff --git a/vendor/symfony/polyfill-ctype/composer.json b/vendor/symfony/polyfill-ctype/composer.json new file mode 100755 index 00000000..c24e20ca --- /dev/null +++ b/vendor/symfony/polyfill-ctype/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/polyfill-ctype", + "type": "library", + "description": "Symfony polyfill for ctype functions", + "keywords": ["polyfill", "compatibility", "portable", "ctype"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + } +} diff --git a/vendor/symfony/property-access/.gitignore b/vendor/symfony/property-access/.gitignore new file mode 100755 index 00000000..c49a5d8d --- /dev/null +++ b/vendor/symfony/property-access/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/vendor/symfony/property-access/CHANGELOG.md b/vendor/symfony/property-access/CHANGELOG.md new file mode 100755 index 00000000..574106e5 --- /dev/null +++ b/vendor/symfony/property-access/CHANGELOG.md @@ -0,0 +1,29 @@ +CHANGELOG +========= + +2.7.0 +------ + + * `UnexpectedTypeException` now expects three constructor arguments: The invalid property value, + the `PropertyPathInterface` object and the current index of the property path. + +2.5.0 +------ + + * allowed non alpha numeric characters in second level and deeper object properties names + * [BC BREAK] when accessing an index on an object that does not implement + ArrayAccess, a NoSuchIndexException is now thrown instead of the + semantically wrong NoSuchPropertyException + * [BC BREAK] added isReadable() and isWritable() to PropertyAccessorInterface + +2.3.0 +------ + + * added PropertyAccessorBuilder, to enable or disable the support of "__call" + * added support for "__call" in the PropertyAccessor (disabled by default) + * [BC BREAK] changed PropertyAccessor to continue its search for a property or + method even if a non-public match was found. Before, a PropertyAccessDeniedException + was thrown in this case. Class PropertyAccessDeniedException was removed + now. + * deprecated PropertyAccess::getPropertyAccessor + * added PropertyAccess::createPropertyAccessor and PropertyAccess::createPropertyAccessorBuilder diff --git a/vendor/symfony/property-access/Exception/AccessException.php b/vendor/symfony/property-access/Exception/AccessException.php new file mode 100755 index 00000000..b3a85464 --- /dev/null +++ b/vendor/symfony/property-access/Exception/AccessException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when a property path is not available. + * + * @author Stéphane Escandell + */ +class AccessException extends RuntimeException +{ +} diff --git a/vendor/symfony/property-access/Exception/ExceptionInterface.php b/vendor/symfony/property-access/Exception/ExceptionInterface.php new file mode 100755 index 00000000..d1fcdac9 --- /dev/null +++ b/vendor/symfony/property-access/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Marker interface for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +interface ExceptionInterface +{ +} diff --git a/vendor/symfony/property-access/Exception/InvalidArgumentException.php b/vendor/symfony/property-access/Exception/InvalidArgumentException.php new file mode 100755 index 00000000..47bc7e15 --- /dev/null +++ b/vendor/symfony/property-access/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Base InvalidArgumentException for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/property-access/Exception/InvalidPropertyPathException.php b/vendor/symfony/property-access/Exception/InvalidPropertyPathException.php new file mode 100755 index 00000000..69de31ce --- /dev/null +++ b/vendor/symfony/property-access/Exception/InvalidPropertyPathException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when a property path is malformed. + * + * @author Bernhard Schussek + */ +class InvalidPropertyPathException extends RuntimeException +{ +} diff --git a/vendor/symfony/property-access/Exception/NoSuchIndexException.php b/vendor/symfony/property-access/Exception/NoSuchIndexException.php new file mode 100755 index 00000000..597b9904 --- /dev/null +++ b/vendor/symfony/property-access/Exception/NoSuchIndexException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when an index cannot be found. + * + * @author Stéphane Escandell + */ +class NoSuchIndexException extends AccessException +{ +} diff --git a/vendor/symfony/property-access/Exception/NoSuchPropertyException.php b/vendor/symfony/property-access/Exception/NoSuchPropertyException.php new file mode 100755 index 00000000..1c7eda5f --- /dev/null +++ b/vendor/symfony/property-access/Exception/NoSuchPropertyException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when a property cannot be found. + * + * @author Bernhard Schussek + */ +class NoSuchPropertyException extends AccessException +{ +} diff --git a/vendor/symfony/property-access/Exception/OutOfBoundsException.php b/vendor/symfony/property-access/Exception/OutOfBoundsException.php new file mode 100755 index 00000000..a3c45597 --- /dev/null +++ b/vendor/symfony/property-access/Exception/OutOfBoundsException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Base OutOfBoundsException for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/property-access/Exception/RuntimeException.php b/vendor/symfony/property-access/Exception/RuntimeException.php new file mode 100755 index 00000000..9fe843e3 --- /dev/null +++ b/vendor/symfony/property-access/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Base RuntimeException for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/property-access/Exception/UnexpectedTypeException.php b/vendor/symfony/property-access/Exception/UnexpectedTypeException.php new file mode 100755 index 00000000..16898198 --- /dev/null +++ b/vendor/symfony/property-access/Exception/UnexpectedTypeException.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +use Symfony\Component\PropertyAccess\PropertyPathInterface; + +/** + * Thrown when a value does not match an expected type. + * + * @author Bernhard Schussek + */ +class UnexpectedTypeException extends RuntimeException +{ + /** + * @param mixed $value The unexpected value found while traversing property path + * @param PropertyPathInterface $path The property path + * @param int $pathIndex The property path index when the unexpected value was found + */ + public function __construct($value, $path, $pathIndex = null) + { + if (3 === \func_num_args() && $path instanceof PropertyPathInterface) { + $message = sprintf( + 'PropertyAccessor requires a graph of objects or arrays to operate on, '. + 'but it found type "%s" while trying to traverse path "%s" at property "%s".', + \gettype($value), + (string) $path, + $path->getElement($pathIndex) + ); + } else { + @trigger_error('The '.__CLASS__.' constructor now expects 3 arguments: the invalid property value, the '.__NAMESPACE__.'\PropertyPathInterface object and the current index of the property path.', E_USER_DEPRECATED); + + $message = sprintf( + 'Expected argument of type "%s", "%s" given', + $path, + \is_object($value) ? \get_class($value) : \gettype($value) + ); + } + + parent::__construct($message); + } +} diff --git a/vendor/symfony/property-access/LICENSE b/vendor/symfony/property-access/LICENSE new file mode 100755 index 00000000..21d7fb9e --- /dev/null +++ b/vendor/symfony/property-access/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2018 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/property-access/PropertyAccess.php b/vendor/symfony/property-access/PropertyAccess.php new file mode 100755 index 00000000..eeb37529 --- /dev/null +++ b/vendor/symfony/property-access/PropertyAccess.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Entry point of the PropertyAccess component. + * + * @author Bernhard Schussek + */ +final class PropertyAccess +{ + /** + * Creates a property accessor with the default configuration. + * + * @return PropertyAccessor + */ + public static function createPropertyAccessor() + { + return self::createPropertyAccessorBuilder()->getPropertyAccessor(); + } + + /** + * Creates a property accessor builder. + * + * @return PropertyAccessorBuilder + */ + public static function createPropertyAccessorBuilder() + { + return new PropertyAccessorBuilder(); + } + + /** + * Alias of {@link createPropertyAccessor}. + * + * @return PropertyAccessor + * + * @deprecated since version 2.3, to be removed in 3.0. + * Use {@link createPropertyAccessor()} instead. + */ + public static function getPropertyAccessor() + { + @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.3 and will be removed in 3.0. Use the createPropertyAccessor() method instead.', E_USER_DEPRECATED); + + return self::createPropertyAccessor(); + } + + /** + * This class cannot be instantiated. + */ + private function __construct() + { + } +} diff --git a/vendor/symfony/property-access/PropertyAccessor.php b/vendor/symfony/property-access/PropertyAccessor.php new file mode 100755 index 00000000..0c05fa88 --- /dev/null +++ b/vendor/symfony/property-access/PropertyAccessor.php @@ -0,0 +1,812 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\AccessException; +use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException; +use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; + +/** + * Default implementation of {@link PropertyAccessorInterface}. + * + * @author Bernhard Schussek + * @author Kévin Dunglas + * @author Nicolas Grekas + */ +class PropertyAccessor implements PropertyAccessorInterface +{ + /** + * @internal + */ + const VALUE = 0; + + /** + * @internal + */ + const REF = 1; + + /** + * @internal + */ + const IS_REF_CHAINED = 2; + + /** + * @internal + */ + const ACCESS_HAS_PROPERTY = 0; + + /** + * @internal + */ + const ACCESS_TYPE = 1; + + /** + * @internal + */ + const ACCESS_NAME = 2; + + /** + * @internal + */ + const ACCESS_REF = 3; + + /** + * @internal + */ + const ACCESS_ADDER = 4; + + /** + * @internal + */ + const ACCESS_REMOVER = 5; + + /** + * @internal + */ + const ACCESS_TYPE_METHOD = 0; + + /** + * @internal + */ + const ACCESS_TYPE_PROPERTY = 1; + + /** + * @internal + */ + const ACCESS_TYPE_MAGIC = 2; + + /** + * @internal + */ + const ACCESS_TYPE_ADDER_AND_REMOVER = 3; + + /** + * @internal + */ + const ACCESS_TYPE_NOT_FOUND = 4; + + private $magicCall; + private $ignoreInvalidIndices; + private $readPropertyCache = array(); + private $writePropertyCache = array(); + + private static $previousErrorHandler = false; + private static $errorHandler = array(__CLASS__, 'handleError'); + private static $resultProto = array(self::VALUE => null); + + /** + * Should not be used by application code. Use + * {@link PropertyAccess::createPropertyAccessor()} instead. + * + * @param bool $magicCall + * @param bool $throwExceptionOnInvalidIndex + */ + public function __construct($magicCall = false, $throwExceptionOnInvalidIndex = false) + { + $this->magicCall = $magicCall; + $this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex; + } + + /** + * {@inheritdoc} + */ + public function getValue($objectOrArray, $propertyPath) + { + if (!$propertyPath instanceof PropertyPathInterface) { + $propertyPath = new PropertyPath($propertyPath); + } + + $zval = array( + self::VALUE => $objectOrArray, + ); + $propertyValues = $this->readPropertiesUntil($zval, $propertyPath, $propertyPath->getLength(), $this->ignoreInvalidIndices); + + return $propertyValues[\count($propertyValues) - 1][self::VALUE]; + } + + /** + * {@inheritdoc} + */ + public function setValue(&$objectOrArray, $propertyPath, $value) + { + if (!$propertyPath instanceof PropertyPathInterface) { + $propertyPath = new PropertyPath($propertyPath); + } + + $zval = array( + self::VALUE => $objectOrArray, + self::REF => &$objectOrArray, + ); + $propertyValues = $this->readPropertiesUntil($zval, $propertyPath, $propertyPath->getLength() - 1); + $overwrite = true; + + try { + if (\PHP_VERSION_ID < 70000 && false === self::$previousErrorHandler) { + self::$previousErrorHandler = set_error_handler(self::$errorHandler); + } + + for ($i = \count($propertyValues) - 1; 0 <= $i; --$i) { + $zval = $propertyValues[$i]; + unset($propertyValues[$i]); + + // You only need set value for current element if: + // 1. it's the parent of the last index element + // OR + // 2. its child is not passed by reference + // + // This may avoid uncessary value setting process for array elements. + // For example: + // '[a][b][c]' => 'old-value' + // If you want to change its value to 'new-value', + // you only need set value for '[a][b][c]' and it's safe to ignore '[a][b]' and '[a]' + if ($overwrite) { + $property = $propertyPath->getElement($i); + + if ($propertyPath->isIndex($i)) { + if ($overwrite = !isset($zval[self::REF])) { + $ref = &$zval[self::REF]; + $ref = $zval[self::VALUE]; + } + $this->writeIndex($zval, $property, $value); + if ($overwrite) { + $zval[self::VALUE] = $zval[self::REF]; + } + } else { + $this->writeProperty($zval, $property, $value); + } + + // if current element is an object + // OR + // if current element's reference chain is not broken - current element + // as well as all its ancients in the property path are all passed by reference, + // then there is no need to continue the value setting process + if (\is_object($zval[self::VALUE]) || isset($zval[self::IS_REF_CHAINED])) { + break; + } + } + + $value = $zval[self::VALUE]; + } + } catch (\TypeError $e) { + try { + self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0); + } catch (InvalidArgumentException $e) { + } + } catch (\Exception $e) { + } catch (\Throwable $e) { + } + + if (\PHP_VERSION_ID < 70000 && false !== self::$previousErrorHandler) { + restore_error_handler(); + self::$previousErrorHandler = false; + } + if (isset($e)) { + throw $e; + } + } + + /** + * @internal + */ + public static function handleError($type, $message, $file, $line, $context) + { + if (E_RECOVERABLE_ERROR === $type) { + self::throwInvalidArgumentException($message, debug_backtrace(false), 1); + } + + return null !== self::$previousErrorHandler && false !== \call_user_func(self::$previousErrorHandler, $type, $message, $file, $line, $context); + } + + private static function throwInvalidArgumentException($message, $trace, $i) + { + // the type mismatch is not caused by invalid arguments (but e.g. by an incompatible return type hint of the writer method) + if (0 !== strpos($message, 'Argument ')) { + return; + } + + if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && array_key_exists(0, $trace[$i]['args'])) { + $pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface ')); + $pos += \strlen($delim); + $type = $trace[$i]['args'][0]; + $type = \is_object($type) ? \get_class($type) : \gettype($type); + + throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', substr($message, $pos, strpos($message, ',', $pos) - $pos), $type)); + } + } + + /** + * {@inheritdoc} + */ + public function isReadable($objectOrArray, $propertyPath) + { + if (!$propertyPath instanceof PropertyPathInterface) { + $propertyPath = new PropertyPath($propertyPath); + } + + try { + $zval = array( + self::VALUE => $objectOrArray, + ); + $this->readPropertiesUntil($zval, $propertyPath, $propertyPath->getLength(), $this->ignoreInvalidIndices); + + return true; + } catch (AccessException $e) { + return false; + } catch (UnexpectedTypeException $e) { + return false; + } + } + + /** + * {@inheritdoc} + */ + public function isWritable($objectOrArray, $propertyPath) + { + if (!$propertyPath instanceof PropertyPathInterface) { + $propertyPath = new PropertyPath($propertyPath); + } + + try { + $zval = array( + self::VALUE => $objectOrArray, + ); + $propertyValues = $this->readPropertiesUntil($zval, $propertyPath, $propertyPath->getLength() - 1); + + for ($i = \count($propertyValues) - 1; 0 <= $i; --$i) { + $zval = $propertyValues[$i]; + unset($propertyValues[$i]); + + if ($propertyPath->isIndex($i)) { + if (!$zval[self::VALUE] instanceof \ArrayAccess && !\is_array($zval[self::VALUE])) { + return false; + } + } else { + if (!$this->isPropertyWritable($zval[self::VALUE], $propertyPath->getElement($i))) { + return false; + } + } + + if (\is_object($zval[self::VALUE])) { + return true; + } + } + + return true; + } catch (AccessException $e) { + return false; + } catch (UnexpectedTypeException $e) { + return false; + } + } + + /** + * Reads the path from an object up to a given path index. + * + * @param array $zval The array containing the object or array to read from + * @param PropertyPathInterface $propertyPath The property path to read + * @param int $lastIndex The index up to which should be read + * @param bool $ignoreInvalidIndices Whether to ignore invalid indices or throw an exception + * + * @return array The values read in the path + * + * @throws UnexpectedTypeException if a value within the path is neither object nor array + * @throws NoSuchIndexException If a non-existing index is accessed + */ + private function readPropertiesUntil($zval, PropertyPathInterface $propertyPath, $lastIndex, $ignoreInvalidIndices = true) + { + if (!\is_object($zval[self::VALUE]) && !\is_array($zval[self::VALUE])) { + throw new UnexpectedTypeException($zval[self::VALUE], $propertyPath, 0); + } + + // Add the root object to the list + $propertyValues = array($zval); + + for ($i = 0; $i < $lastIndex; ++$i) { + $property = $propertyPath->getElement($i); + $isIndex = $propertyPath->isIndex($i); + + if ($isIndex) { + // Create missing nested arrays on demand + if (($zval[self::VALUE] instanceof \ArrayAccess && !$zval[self::VALUE]->offsetExists($property)) || + (\is_array($zval[self::VALUE]) && !isset($zval[self::VALUE][$property]) && !array_key_exists($property, $zval[self::VALUE])) + ) { + if (!$ignoreInvalidIndices) { + if (!\is_array($zval[self::VALUE])) { + if (!$zval[self::VALUE] instanceof \Traversable) { + throw new NoSuchIndexException(sprintf('Cannot read index "%s" while trying to traverse path "%s".', $property, (string) $propertyPath)); + } + + $zval[self::VALUE] = iterator_to_array($zval[self::VALUE]); + } + + throw new NoSuchIndexException(sprintf('Cannot read index "%s" while trying to traverse path "%s". Available indices are "%s".', $property, (string) $propertyPath, print_r(array_keys($zval[self::VALUE]), true))); + } + + if ($i + 1 < $propertyPath->getLength()) { + if (isset($zval[self::REF])) { + $zval[self::VALUE][$property] = array(); + $zval[self::REF] = $zval[self::VALUE]; + } else { + $zval[self::VALUE] = array($property => array()); + } + } + } + + $zval = $this->readIndex($zval, $property); + } else { + $zval = $this->readProperty($zval, $property); + } + + // the final value of the path must not be validated + if ($i + 1 < $propertyPath->getLength() && !\is_object($zval[self::VALUE]) && !\is_array($zval[self::VALUE])) { + throw new UnexpectedTypeException($zval[self::VALUE], $propertyPath, $i + 1); + } + + if (isset($zval[self::REF]) && (0 === $i || isset($propertyValues[$i - 1][self::IS_REF_CHAINED]))) { + // Set the IS_REF_CHAINED flag to true if: + // current property is passed by reference and + // it is the first element in the property path or + // the IS_REF_CHAINED flag of its parent element is true + // Basically, this flag is true only when the reference chain from the top element to current element is not broken + $zval[self::IS_REF_CHAINED] = true; + } + + $propertyValues[] = $zval; + } + + return $propertyValues; + } + + /** + * Reads a key from an array-like structure. + * + * @param array $zval The array containing the array or \ArrayAccess object to read from + * @param string|int $index The key to read + * + * @return array The array containing the value of the key + * + * @throws NoSuchIndexException If the array does not implement \ArrayAccess or it is not an array + */ + private function readIndex($zval, $index) + { + if (!$zval[self::VALUE] instanceof \ArrayAccess && !\is_array($zval[self::VALUE])) { + throw new NoSuchIndexException(sprintf('Cannot read index "%s" from object of type "%s" because it doesn\'t implement \ArrayAccess.', $index, \get_class($zval[self::VALUE]))); + } + + $result = self::$resultProto; + + if (isset($zval[self::VALUE][$index])) { + $result[self::VALUE] = $zval[self::VALUE][$index]; + + if (!isset($zval[self::REF])) { + // Save creating references when doing read-only lookups + } elseif (\is_array($zval[self::VALUE])) { + $result[self::REF] = &$zval[self::REF][$index]; + } elseif (\is_object($result[self::VALUE])) { + $result[self::REF] = $result[self::VALUE]; + } + } + + return $result; + } + + /** + * Reads the a property from an object. + * + * @param array $zval The array containing the object to read from + * @param string $property The property to read + * + * @return array The array containing the value of the property + * + * @throws NoSuchPropertyException if the property does not exist or is not public + */ + private function readProperty($zval, $property) + { + if (!\is_object($zval[self::VALUE])) { + throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you intended to write the property path as "[%1$s]" instead.', $property)); + } + + $result = self::$resultProto; + $object = $zval[self::VALUE]; + $access = $this->getReadAccessInfo(\get_class($object), $property); + + if (self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE]) { + $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}(); + } elseif (self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]) { + $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}; + + if ($access[self::ACCESS_REF] && isset($zval[self::REF])) { + $result[self::REF] = &$object->{$access[self::ACCESS_NAME]}; + } + } elseif (!$access[self::ACCESS_HAS_PROPERTY] && property_exists($object, $property)) { + // Needed to support \stdClass instances. We need to explicitly + // exclude $access[self::ACCESS_HAS_PROPERTY], otherwise if + // a *protected* property was found on the class, property_exists() + // returns true, consequently the following line will result in a + // fatal error. + + $result[self::VALUE] = $object->$property; + if (isset($zval[self::REF])) { + $result[self::REF] = &$object->$property; + } + } elseif (self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]) { + // we call the getter and hope the __call do the job + $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}(); + } else { + throw new NoSuchPropertyException($access[self::ACCESS_NAME]); + } + + // Objects are always passed around by reference + if (isset($zval[self::REF]) && \is_object($result[self::VALUE])) { + $result[self::REF] = $result[self::VALUE]; + } + + return $result; + } + + /** + * Guesses how to read the property value. + * + * @param string $class + * @param string $property + * + * @return array + */ + private function getReadAccessInfo($class, $property) + { + $key = $class.'::'.$property; + + if (isset($this->readPropertyCache[$key])) { + $access = $this->readPropertyCache[$key]; + } else { + $access = array(); + + $reflClass = new \ReflectionClass($class); + $access[self::ACCESS_HAS_PROPERTY] = $reflClass->hasProperty($property); + $camelProp = $this->camelize($property); + $getter = 'get'.$camelProp; + $getsetter = lcfirst($camelProp); // jQuery style, e.g. read: last(), write: last($item) + $isser = 'is'.$camelProp; + $hasser = 'has'.$camelProp; + + if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $getter; + } elseif ($reflClass->hasMethod($getsetter) && $reflClass->getMethod($getsetter)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $getsetter; + } elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $isser; + } elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $hasser; + } elseif ($reflClass->hasMethod('__get') && $reflClass->getMethod('__get')->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_PROPERTY; + $access[self::ACCESS_NAME] = $property; + $access[self::ACCESS_REF] = false; + } elseif ($access[self::ACCESS_HAS_PROPERTY] && $reflClass->getProperty($property)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_PROPERTY; + $access[self::ACCESS_NAME] = $property; + $access[self::ACCESS_REF] = true; + } elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) { + // we call the getter and hope the __call do the job + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC; + $access[self::ACCESS_NAME] = $getter; + } else { + $methods = array($getter, $getsetter, $isser, $hasser, '__get'); + if ($this->magicCall) { + $methods[] = '__call'; + } + + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; + $access[self::ACCESS_NAME] = sprintf( + 'Neither the property "%s" nor one of the methods "%s()" '. + 'exist and have public access in class "%s".', + $property, + implode('()", "', $methods), + $reflClass->name + ); + } + + $this->readPropertyCache[$key] = $access; + } + + return $access; + } + + /** + * Sets the value of an index in a given array-accessible value. + * + * @param array $zval The array containing the array or \ArrayAccess object to write to + * @param string|int $index The index to write at + * @param mixed $value The value to write + * + * @throws NoSuchIndexException If the array does not implement \ArrayAccess or it is not an array + */ + private function writeIndex($zval, $index, $value) + { + if (!$zval[self::VALUE] instanceof \ArrayAccess && !\is_array($zval[self::VALUE])) { + throw new NoSuchIndexException(sprintf('Cannot modify index "%s" in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, \get_class($zval[self::VALUE]))); + } + + $zval[self::REF][$index] = $value; + } + + /** + * Sets the value of a property in the given object. + * + * @param array $zval The array containing the object to write to + * @param string $property The property to write + * @param mixed $value The value to write + * + * @throws NoSuchPropertyException if the property does not exist or is not public + */ + private function writeProperty($zval, $property, $value) + { + if (!\is_object($zval[self::VALUE])) { + throw new NoSuchPropertyException(sprintf('Cannot write property "%s" to an array. Maybe you should write the property path as "[%1$s]" instead?', $property)); + } + + $object = $zval[self::VALUE]; + $access = $this->getWriteAccessInfo(\get_class($object), $property, $value); + + if (self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE]) { + $object->{$access[self::ACCESS_NAME]}($value); + } elseif (self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]) { + $object->{$access[self::ACCESS_NAME]} = $value; + } elseif (self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE]) { + $this->writeCollection($zval, $property, $value, $access[self::ACCESS_ADDER], $access[self::ACCESS_REMOVER]); + } elseif (!$access[self::ACCESS_HAS_PROPERTY] && property_exists($object, $property)) { + // Needed to support \stdClass instances. We need to explicitly + // exclude $access[self::ACCESS_HAS_PROPERTY], otherwise if + // a *protected* property was found on the class, property_exists() + // returns true, consequently the following line will result in a + // fatal error. + + $object->$property = $value; + } elseif (self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]) { + $object->{$access[self::ACCESS_NAME]}($value); + } else { + throw new NoSuchPropertyException($access[self::ACCESS_NAME]); + } + } + + /** + * Adjusts a collection-valued property by calling add*() and remove*() methods. + * + * @param array $zval The array containing the object to write to + * @param string $property The property to write + * @param iterable $collection The collection to write + * @param string $addMethod The add*() method + * @param string $removeMethod The remove*() method + */ + private function writeCollection($zval, $property, $collection, $addMethod, $removeMethod) + { + // At this point the add and remove methods have been found + $previousValue = $this->readProperty($zval, $property); + $previousValue = $previousValue[self::VALUE]; + + if ($previousValue instanceof \Traversable) { + $previousValue = iterator_to_array($previousValue); + } + if ($previousValue && \is_array($previousValue)) { + if (\is_object($collection)) { + $collection = iterator_to_array($collection); + } + foreach ($previousValue as $key => $item) { + if (!\in_array($item, $collection, true)) { + unset($previousValue[$key]); + $zval[self::VALUE]->{$removeMethod}($item); + } + } + } else { + $previousValue = false; + } + + foreach ($collection as $item) { + if (!$previousValue || !\in_array($item, $previousValue, true)) { + $zval[self::VALUE]->{$addMethod}($item); + } + } + } + + /** + * Guesses how to write the property value. + * + * @param string $class + * @param string $property + * @param mixed $value + * + * @return array + */ + private function getWriteAccessInfo($class, $property, $value) + { + $key = $class.'::'.$property; + + if (isset($this->writePropertyCache[$key])) { + $access = $this->writePropertyCache[$key]; + } else { + $access = array(); + + $reflClass = new \ReflectionClass($class); + $access[self::ACCESS_HAS_PROPERTY] = $reflClass->hasProperty($property); + $camelized = $this->camelize($property); + $singulars = (array) StringUtil::singularify($camelized); + + if (\is_array($value) || $value instanceof \Traversable) { + $methods = $this->findAdderAndRemover($reflClass, $singulars); + + if (null !== $methods) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER; + $access[self::ACCESS_ADDER] = $methods[0]; + $access[self::ACCESS_REMOVER] = $methods[1]; + } + } + + if (!isset($access[self::ACCESS_TYPE])) { + $setter = 'set'.$camelized; + $getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item) + + if ($this->isMethodAccessible($reflClass, $setter, 1)) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $setter; + } elseif ($this->isMethodAccessible($reflClass, $getsetter, 1)) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $getsetter; + } elseif ($this->isMethodAccessible($reflClass, '__set', 2)) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_PROPERTY; + $access[self::ACCESS_NAME] = $property; + } elseif ($access[self::ACCESS_HAS_PROPERTY] && $reflClass->getProperty($property)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_PROPERTY; + $access[self::ACCESS_NAME] = $property; + } elseif ($this->magicCall && $this->isMethodAccessible($reflClass, '__call', 2)) { + // we call the getter and hope the __call do the job + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC; + $access[self::ACCESS_NAME] = $setter; + } elseif (null !== $methods = $this->findAdderAndRemover($reflClass, $singulars)) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; + $access[self::ACCESS_NAME] = sprintf( + 'The property "%s" in class "%s" can be defined with the methods "%s()" but '. + 'the new value must be an array or an instance of \Traversable, '. + '"%s" given.', + $property, + $reflClass->name, + implode('()", "', $methods), + \is_object($value) ? \get_class($value) : \gettype($value) + ); + } else { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; + $access[self::ACCESS_NAME] = sprintf( + 'Neither the property "%s" nor one of the methods %s"%s()", "%s()", '. + '"__set()" or "__call()" exist and have public access in class "%s".', + $property, + implode('', array_map(function ($singular) { + return '"add'.$singular.'()"/"remove'.$singular.'()", '; + }, $singulars)), + $setter, + $getsetter, + $reflClass->name + ); + } + } + + $this->writePropertyCache[$key] = $access; + } + + return $access; + } + + /** + * Returns whether a property is writable in the given object. + * + * @param object $object The object to write to + * @param string $property The property to write + * + * @return bool Whether the property is writable + */ + private function isPropertyWritable($object, $property) + { + if (!\is_object($object)) { + return false; + } + + $access = $this->getWriteAccessInfo(\get_class($object), $property, array()); + + return self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE] + || self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE] + || self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE] + || (!$access[self::ACCESS_HAS_PROPERTY] && property_exists($object, $property)) + || self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]; + } + + /** + * Camelizes a given string. + * + * @param string $string Some string + * + * @return string The camelized version of the string + */ + private function camelize($string) + { + return str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); + } + + /** + * Searches for add and remove methods. + * + * @param \ReflectionClass $reflClass The reflection class for the given object + * @param array $singulars The singular form of the property name or null + * + * @return array|null An array containing the adder and remover when found, null otherwise + */ + private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars) + { + foreach ($singulars as $singular) { + $addMethod = 'add'.$singular; + $removeMethod = 'remove'.$singular; + + $addMethodFound = $this->isMethodAccessible($reflClass, $addMethod, 1); + $removeMethodFound = $this->isMethodAccessible($reflClass, $removeMethod, 1); + + if ($addMethodFound && $removeMethodFound) { + return array($addMethod, $removeMethod); + } + } + } + + /** + * Returns whether a method is public and has the number of required parameters. + * + * @param \ReflectionClass $class The class of the method + * @param string $methodName The method name + * @param int $parameters The number of parameters + * + * @return bool Whether the method is public and has $parameters required parameters + */ + private function isMethodAccessible(\ReflectionClass $class, $methodName, $parameters) + { + if ($class->hasMethod($methodName)) { + $method = $class->getMethod($methodName); + + if ($method->isPublic() + && $method->getNumberOfRequiredParameters() <= $parameters + && $method->getNumberOfParameters() >= $parameters) { + return true; + } + } + + return false; + } +} diff --git a/vendor/symfony/property-access/PropertyAccessorBuilder.php b/vendor/symfony/property-access/PropertyAccessorBuilder.php new file mode 100755 index 00000000..4b3ad693 --- /dev/null +++ b/vendor/symfony/property-access/PropertyAccessorBuilder.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * A configurable builder to create a PropertyAccessor. + * + * @author Jérémie Augustin + */ +class PropertyAccessorBuilder +{ + private $magicCall = false; + private $throwExceptionOnInvalidIndex = false; + + /** + * Enables the use of "__call" by the PropertyAccessor. + * + * @return $this + */ + public function enableMagicCall() + { + $this->magicCall = true; + + return $this; + } + + /** + * Disables the use of "__call" by the PropertyAccessor. + * + * @return $this + */ + public function disableMagicCall() + { + $this->magicCall = false; + + return $this; + } + + /** + * @return bool whether the use of "__call" by the PropertyAccessor is enabled + */ + public function isMagicCallEnabled() + { + return $this->magicCall; + } + + /** + * Enables exceptions when reading a non-existing index. + * + * This has no influence on writing non-existing indices with PropertyAccessorInterface::setValue() + * which are always created on-the-fly. + * + * @return $this + */ + public function enableExceptionOnInvalidIndex() + { + $this->throwExceptionOnInvalidIndex = true; + + return $this; + } + + /** + * Disables exceptions when reading a non-existing index. + * + * Instead, null is returned when calling PropertyAccessorInterface::getValue() on a non-existing index. + * + * @return $this + */ + public function disableExceptionOnInvalidIndex() + { + $this->throwExceptionOnInvalidIndex = false; + + return $this; + } + + /** + * @return bool whether an exception is thrown or null is returned when reading a non-existing index + */ + public function isExceptionOnInvalidIndexEnabled() + { + return $this->throwExceptionOnInvalidIndex; + } + + /** + * Builds and returns a new PropertyAccessor object. + * + * @return PropertyAccessorInterface The built PropertyAccessor + */ + public function getPropertyAccessor() + { + return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex); + } +} diff --git a/vendor/symfony/property-access/PropertyAccessorInterface.php b/vendor/symfony/property-access/PropertyAccessorInterface.php new file mode 100755 index 00000000..51fa0cc7 --- /dev/null +++ b/vendor/symfony/property-access/PropertyAccessorInterface.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Writes and reads values to/from an object/array graph. + * + * @author Bernhard Schussek + */ +interface PropertyAccessorInterface +{ + /** + * Sets the value at the end of the property path of the object graph. + * + * Example: + * + * use Symfony\Component\PropertyAccess\PropertyAccess; + * + * $propertyAccessor = PropertyAccess::createPropertyAccessor(); + * + * echo $propertyAccessor->setValue($object, 'child.name', 'Fabien'); + * // equals echo $object->getChild()->setName('Fabien'); + * + * This method first tries to find a public setter for each property in the + * path. The name of the setter must be the camel-cased property name + * prefixed with "set". + * + * If the setter does not exist, this method tries to find a public + * property. The value of the property is then changed. + * + * If neither is found, an exception is thrown. + * + * @param object|array $objectOrArray The object or array to modify + * @param string|PropertyPathInterface $propertyPath The property path to modify + * @param mixed $value The value to set at the end of the property path + * + * @throws Exception\InvalidArgumentException If the property path is invalid + * @throws Exception\AccessException If a property/index does not exist or is not public + * @throws Exception\UnexpectedTypeException If a value within the path is neither object nor array + */ + public function setValue(&$objectOrArray, $propertyPath, $value); + + /** + * Returns the value at the end of the property path of the object graph. + * + * Example: + * + * use Symfony\Component\PropertyAccess\PropertyAccess; + * + * $propertyAccessor = PropertyAccess::createPropertyAccessor(); + * + * echo $propertyAccessor->getValue($object, 'child.name); + * // equals echo $object->getChild()->getName(); + * + * This method first tries to find a public getter for each property in the + * path. The name of the getter must be the camel-cased property name + * prefixed with "get", "is", or "has". + * + * If the getter does not exist, this method tries to find a public + * property. The value of the property is then returned. + * + * If none of them are found, an exception is thrown. + * + * @param object|array $objectOrArray The object or array to traverse + * @param string|PropertyPathInterface $propertyPath The property path to read + * + * @return mixed The value at the end of the property path + * + * @throws Exception\InvalidArgumentException If the property path is invalid + * @throws Exception\AccessException If a property/index does not exist or is not public + * @throws Exception\UnexpectedTypeException If a value within the path is neither object + * nor array + */ + public function getValue($objectOrArray, $propertyPath); + + /** + * Returns whether a value can be written at a given property path. + * + * Whenever this method returns true, {@link setValue()} is guaranteed not + * to throw an exception when called with the same arguments. + * + * @param object|array $objectOrArray The object or array to check + * @param string|PropertyPathInterface $propertyPath The property path to check + * + * @return bool Whether the value can be set + * + * @throws Exception\InvalidArgumentException If the property path is invalid + */ + public function isWritable($objectOrArray, $propertyPath); + + /** + * Returns whether a property path can be read from an object graph. + * + * Whenever this method returns true, {@link getValue()} is guaranteed not + * to throw an exception when called with the same arguments. + * + * @param object|array $objectOrArray The object or array to check + * @param string|PropertyPathInterface $propertyPath The property path to check + * + * @return bool Whether the property path can be read + * + * @throws Exception\InvalidArgumentException If the property path is invalid + */ + public function isReadable($objectOrArray, $propertyPath); +} diff --git a/vendor/symfony/property-access/PropertyPath.php b/vendor/symfony/property-access/PropertyPath.php new file mode 100755 index 00000000..2897a4ad --- /dev/null +++ b/vendor/symfony/property-access/PropertyPath.php @@ -0,0 +1,205 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException; +use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException; +use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException; + +/** + * Default implementation of {@link PropertyPathInterface}. + * + * @author Bernhard Schussek + */ +class PropertyPath implements \IteratorAggregate, PropertyPathInterface +{ + /** + * Character used for separating between plural and singular of an element. + */ + const SINGULAR_SEPARATOR = '|'; + + /** + * The elements of the property path. + * + * @var array + */ + private $elements = array(); + + /** + * The number of elements in the property path. + * + * @var int + */ + private $length; + + /** + * Contains a Boolean for each property in $elements denoting whether this + * element is an index. It is a property otherwise. + * + * @var array + */ + private $isIndex = array(); + + /** + * String representation of the path. + * + * @var string + */ + private $pathAsString; + + /** + * Constructs a property path from a string. + * + * @param PropertyPath|string $propertyPath The property path as string or instance + * + * @throws InvalidArgumentException If the given path is not a string + * @throws InvalidPropertyPathException If the syntax of the property path is not valid + */ + public function __construct($propertyPath) + { + // Can be used as copy constructor + if ($propertyPath instanceof self) { + /* @var PropertyPath $propertyPath */ + $this->elements = $propertyPath->elements; + $this->length = $propertyPath->length; + $this->isIndex = $propertyPath->isIndex; + $this->pathAsString = $propertyPath->pathAsString; + + return; + } + if (!\is_string($propertyPath)) { + throw new InvalidArgumentException(sprintf('The property path constructor needs a string or an instance of "Symfony\Component\PropertyAccess\PropertyPath". Got: "%s"', \is_object($propertyPath) ? \get_class($propertyPath) : \gettype($propertyPath))); + } + + if ('' === $propertyPath) { + throw new InvalidPropertyPathException('The property path should not be empty.'); + } + + $this->pathAsString = $propertyPath; + $position = 0; + $remaining = $propertyPath; + + // first element is evaluated differently - no leading dot for properties + $pattern = '/^(([^\.\[]++)|\[([^\]]++)\])(.*)/'; + + while (preg_match($pattern, $remaining, $matches)) { + if ('' !== $matches[2]) { + $element = $matches[2]; + $this->isIndex[] = false; + } else { + $element = $matches[3]; + $this->isIndex[] = true; + } + + $this->elements[] = $element; + + $position += \strlen($matches[1]); + $remaining = $matches[4]; + $pattern = '/^(\.([^\.|\[]++)|\[([^\]]++)\])(.*)/'; + } + + if ('' !== $remaining) { + throw new InvalidPropertyPathException(sprintf('Could not parse property path "%s". Unexpected token "%s" at position %d', $propertyPath, $remaining[0], $position)); + } + + $this->length = \count($this->elements); + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return $this->pathAsString; + } + + /** + * {@inheritdoc} + */ + public function getLength() + { + return $this->length; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + if ($this->length <= 1) { + return; + } + + $parent = clone $this; + + --$parent->length; + $parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '['))); + array_pop($parent->elements); + array_pop($parent->isIndex); + + return $parent; + } + + /** + * Returns a new iterator for this path. + * + * @return PropertyPathIteratorInterface + */ + public function getIterator() + { + return new PropertyPathIterator($this); + } + + /** + * {@inheritdoc} + */ + public function getElements() + { + return $this->elements; + } + + /** + * {@inheritdoc} + */ + public function getElement($index) + { + if (!isset($this->elements[$index])) { + throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index)); + } + + return $this->elements[$index]; + } + + /** + * {@inheritdoc} + */ + public function isProperty($index) + { + if (!isset($this->isIndex[$index])) { + throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index)); + } + + return !$this->isIndex[$index]; + } + + /** + * {@inheritdoc} + */ + public function isIndex($index) + { + if (!isset($this->isIndex[$index])) { + throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index)); + } + + return $this->isIndex[$index]; + } +} diff --git a/vendor/symfony/property-access/PropertyPathBuilder.php b/vendor/symfony/property-access/PropertyPathBuilder.php new file mode 100755 index 00000000..e17c53c0 --- /dev/null +++ b/vendor/symfony/property-access/PropertyPathBuilder.php @@ -0,0 +1,299 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException; + +/** + * @author Bernhard Schussek + */ +class PropertyPathBuilder +{ + private $elements = array(); + private $isIndex = array(); + + /** + * Creates a new property path builder. + * + * @param PropertyPathInterface|string|null $path The path to initially store + * in the builder. Optional. + */ + public function __construct($path = null) + { + if (null !== $path) { + $this->append($path); + } + } + + /** + * Appends a (sub-) path to the current path. + * + * @param PropertyPathInterface|string $path The path to append + * @param int $offset The offset where the appended + * piece starts in $path + * @param int $length The length of the appended piece + * If 0, the full path is appended + */ + public function append($path, $offset = 0, $length = 0) + { + if (\is_string($path)) { + $path = new PropertyPath($path); + } + + if (0 === $length) { + $end = $path->getLength(); + } else { + $end = $offset + $length; + } + + for (; $offset < $end; ++$offset) { + $this->elements[] = $path->getElement($offset); + $this->isIndex[] = $path->isIndex($offset); + } + } + + /** + * Appends an index element to the current path. + * + * @param string $name The name of the appended index + */ + public function appendIndex($name) + { + $this->elements[] = $name; + $this->isIndex[] = true; + } + + /** + * Appends a property element to the current path. + * + * @param string $name The name of the appended property + */ + public function appendProperty($name) + { + $this->elements[] = $name; + $this->isIndex[] = false; + } + + /** + * Removes elements from the current path. + * + * @param int $offset The offset at which to remove + * @param int $length The length of the removed piece + * + * @throws OutOfBoundsException if offset is invalid + */ + public function remove($offset, $length = 1) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset)); + } + + $this->resize($offset, $length, 0); + } + + /** + * Replaces a sub-path by a different (sub-) path. + * + * @param int $offset The offset at which to replace + * @param int $length The length of the piece to replace + * @param PropertyPathInterface|string $path The path to insert + * @param int $pathOffset The offset where the inserted piece + * starts in $path + * @param int $pathLength The length of the inserted piece + * If 0, the full path is inserted + * + * @throws OutOfBoundsException If the offset is invalid + */ + public function replace($offset, $length, $path, $pathOffset = 0, $pathLength = 0) + { + if (\is_string($path)) { + $path = new PropertyPath($path); + } + + if ($offset < 0 && abs($offset) <= $this->getLength()) { + $offset = $this->getLength() + $offset; + } elseif (!isset($this->elements[$offset])) { + throw new OutOfBoundsException('The offset '.$offset.' is not within the property path'); + } + + if (0 === $pathLength) { + $pathLength = $path->getLength() - $pathOffset; + } + + $this->resize($offset, $length, $pathLength); + + for ($i = 0; $i < $pathLength; ++$i) { + $this->elements[$offset + $i] = $path->getElement($pathOffset + $i); + $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i); + } + ksort($this->elements); + } + + /** + * Replaces a property element by an index element. + * + * @param int $offset The offset at which to replace + * @param string $name The new name of the element. Optional + * + * @throws OutOfBoundsException If the offset is invalid + */ + public function replaceByIndex($offset, $name = null) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset)); + } + + if (null !== $name) { + $this->elements[$offset] = $name; + } + + $this->isIndex[$offset] = true; + } + + /** + * Replaces an index element by a property element. + * + * @param int $offset The offset at which to replace + * @param string $name The new name of the element. Optional + * + * @throws OutOfBoundsException If the offset is invalid + */ + public function replaceByProperty($offset, $name = null) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset)); + } + + if (null !== $name) { + $this->elements[$offset] = $name; + } + + $this->isIndex[$offset] = false; + } + + /** + * Returns the length of the current path. + * + * @return int The path length + */ + public function getLength() + { + return \count($this->elements); + } + + /** + * Returns the current property path. + * + * @return PropertyPathInterface The constructed property path + */ + public function getPropertyPath() + { + $pathAsString = $this->__toString(); + + return '' !== $pathAsString ? new PropertyPath($pathAsString) : null; + } + + /** + * Returns the current property path as string. + * + * @return string The property path as string + */ + public function __toString() + { + $string = ''; + + foreach ($this->elements as $offset => $element) { + if ($this->isIndex[$offset]) { + $element = '['.$element.']'; + } elseif ('' !== $string) { + $string .= '.'; + } + + $string .= $element; + } + + return $string; + } + + /** + * Resizes the path so that a chunk of length $cutLength is + * removed at $offset and another chunk of length $insertionLength + * can be inserted. + * + * @param int $offset The offset where the removed chunk starts + * @param int $cutLength The length of the removed chunk + * @param int $insertionLength The length of the inserted chunk + */ + private function resize($offset, $cutLength, $insertionLength) + { + // Nothing else to do in this case + if ($insertionLength === $cutLength) { + return; + } + + $length = \count($this->elements); + + if ($cutLength > $insertionLength) { + // More elements should be removed than inserted + $diff = $cutLength - $insertionLength; + $newLength = $length - $diff; + + // Shift elements to the left (left-to-right until the new end) + // Max allowed offset to be shifted is such that + // $offset + $diff < $length (otherwise invalid index access) + // i.e. $offset < $length - $diff = $newLength + for ($i = $offset; $i < $newLength; ++$i) { + $this->elements[$i] = $this->elements[$i + $diff]; + $this->isIndex[$i] = $this->isIndex[$i + $diff]; + } + + // All remaining elements should be removed + for (; $i < $length; ++$i) { + unset($this->elements[$i], $this->isIndex[$i]); + } + } else { + $diff = $insertionLength - $cutLength; + + $newLength = $length + $diff; + $indexAfterInsertion = $offset + $insertionLength; + + // $diff <= $insertionLength + // $indexAfterInsertion >= $insertionLength + // => $diff <= $indexAfterInsertion + + // In each of the following loops, $i >= $diff must hold, + // otherwise ($i - $diff) becomes negative. + + // Shift old elements to the right to make up space for the + // inserted elements. This needs to be done left-to-right in + // order to preserve an ascending array index order + // Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff, + // $i >= $diff is guaranteed. + for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) { + $this->elements[$i] = $this->elements[$i - $diff]; + $this->isIndex[$i] = $this->isIndex[$i - $diff]; + } + + // Shift remaining elements to the right. Do this right-to-left + // so we don't overwrite elements before copying them + // The last written index is the immediate index after the inserted + // string, because the indices before that will be overwritten + // anyway. + // Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff, + // $i >= $diff is guaranteed. + for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) { + $this->elements[$i] = $this->elements[$i - $diff]; + $this->isIndex[$i] = $this->isIndex[$i - $diff]; + } + } + } +} diff --git a/vendor/symfony/property-access/PropertyPathInterface.php b/vendor/symfony/property-access/PropertyPathInterface.php new file mode 100755 index 00000000..b627ebc4 --- /dev/null +++ b/vendor/symfony/property-access/PropertyPathInterface.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * A sequence of property names or array indices. + * + * @author Bernhard Schussek + */ +interface PropertyPathInterface extends \Traversable +{ + /** + * Returns the string representation of the property path. + * + * @return string The path as string + */ + public function __toString(); + + /** + * Returns the length of the property path, i.e. the number of elements. + * + * @return int The path length + */ + public function getLength(); + + /** + * Returns the parent property path. + * + * The parent property path is the one that contains the same items as + * this one except for the last one. + * + * If this property path only contains one item, null is returned. + * + * @return PropertyPath The parent path or null + */ + public function getParent(); + + /** + * Returns the elements of the property path as array. + * + * @return array An array of property/index names + */ + public function getElements(); + + /** + * Returns the element at the given index in the property path. + * + * @param int $index The index key + * + * @return string A property or index name + * + * @throws Exception\OutOfBoundsException If the offset is invalid + */ + public function getElement($index); + + /** + * Returns whether the element at the given index is a property. + * + * @param int $index The index in the property path + * + * @return bool Whether the element at this index is a property + * + * @throws Exception\OutOfBoundsException If the offset is invalid + */ + public function isProperty($index); + + /** + * Returns whether the element at the given index is an array index. + * + * @param int $index The index in the property path + * + * @return bool Whether the element at this index is an array index + * + * @throws Exception\OutOfBoundsException If the offset is invalid + */ + public function isIndex($index); +} diff --git a/vendor/symfony/property-access/PropertyPathIterator.php b/vendor/symfony/property-access/PropertyPathIterator.php new file mode 100755 index 00000000..02fa26e1 --- /dev/null +++ b/vendor/symfony/property-access/PropertyPathIterator.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Traverses a property path and provides additional methods to find out + * information about the current element. + * + * @author Bernhard Schussek + */ +class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface +{ + protected $path; + + /** + * @param PropertyPathInterface $path The property path to traverse + */ + public function __construct(PropertyPathInterface $path) + { + parent::__construct($path->getElements()); + + $this->path = $path; + } + + /** + * {@inheritdoc} + */ + public function isIndex() + { + return $this->path->isIndex($this->key()); + } + + /** + * {@inheritdoc} + */ + public function isProperty() + { + return $this->path->isProperty($this->key()); + } +} diff --git a/vendor/symfony/property-access/PropertyPathIteratorInterface.php b/vendor/symfony/property-access/PropertyPathIteratorInterface.php new file mode 100755 index 00000000..79b1bbfe --- /dev/null +++ b/vendor/symfony/property-access/PropertyPathIteratorInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * @author Bernhard Schussek + */ +interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator +{ + /** + * Returns whether the current element in the property path is an array + * index. + * + * @return bool + */ + public function isIndex(); + + /** + * Returns whether the current element in the property path is a property + * name. + * + * @return bool + */ + public function isProperty(); +} diff --git a/vendor/symfony/property-access/README.md b/vendor/symfony/property-access/README.md new file mode 100755 index 00000000..1959fd9e --- /dev/null +++ b/vendor/symfony/property-access/README.md @@ -0,0 +1,14 @@ +PropertyAccess Component +======================== + +The PropertyAccess component provides function to read and write from/to an +object or array using a simple string notation. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/property_access/index.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/property-access/StringUtil.php b/vendor/symfony/property-access/StringUtil.php new file mode 100755 index 00000000..500a7673 --- /dev/null +++ b/vendor/symfony/property-access/StringUtil.php @@ -0,0 +1,226 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Creates singulars from plurals. + * + * @author Bernhard Schussek + */ +class StringUtil +{ + /** + * Map english plural to singular suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + private static $pluralMap = array( + // First entry: plural suffix, reversed + // Second entry: length of plural suffix + // Third entry: Whether the suffix may succeed a vocal + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: singular suffix, normal + + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + array('a', 1, true, true, array('on', 'um')), + + // nebulae (nebula) + array('ea', 2, true, true, 'a'), + + // services (service) + array('secivres', 8, true, true, 'service'), + + // mice (mouse), lice (louse) + array('eci', 3, false, true, 'ouse'), + + // geese (goose) + array('esee', 4, false, true, 'oose'), + + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + array('i', 1, true, true, 'us'), + + // men (man), women (woman) + array('nem', 3, true, true, 'man'), + + // children (child) + array('nerdlihc', 8, true, true, 'child'), + + // oxen (ox) + array('nexo', 4, false, false, 'ox'), + + // indices (index), appendices (appendix), prices (price) + array('seci', 4, false, true, array('ex', 'ix', 'ice')), + + // selfies (selfie) + array('seifles', 7, true, true, 'selfie'), + + // movies (movie) + array('seivom', 6, true, true, 'movie'), + + // feet (foot) + array('teef', 4, true, true, 'foot'), + + // geese (goose) + array('eseeg', 5, true, true, 'goose'), + + // teeth (tooth) + array('hteet', 5, true, true, 'tooth'), + + // news (news) + array('swen', 4, true, true, 'news'), + + // series (series) + array('seires', 6, true, true, 'series'), + + // babies (baby) + array('sei', 3, false, true, 'y'), + + // accesses (access), addresses (address), kisses (kiss) + array('sess', 4, true, false, 'ss'), + + // analyses (analysis), ellipses (ellipsis), funguses (fungus), + // neuroses (neurosis), theses (thesis), emphases (emphasis), + // oases (oasis), crises (crisis), houses (house), bases (base), + // atlases (atlas) + array('ses', 3, true, true, array('s', 'se', 'sis')), + + // objectives (objective), alternative (alternatives) + array('sevit', 5, true, true, 'tive'), + + // drives (drive) + array('sevird', 6, false, true, 'drive'), + + // lives (life), wives (wife) + array('sevi', 4, false, true, 'ife'), + + // moves (move) + array('sevom', 5, true, true, 'move'), + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) + array('sev', 3, true, true, array('f', 've', 'ff')), + + // axes (axis), axes (ax), axes (axe) + array('sexa', 4, false, false, array('ax', 'axe', 'axis')), + + // indexes (index), matrixes (matrix) + array('sex', 3, true, false, 'x'), + + // quizzes (quiz) + array('sezz', 4, true, false, 'z'), + + // bureaus (bureau) + array('suae', 4, false, true, 'eau'), + + // roses (rose), garages (garage), cassettes (cassette), + // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), + // shoes (shoe) + array('se', 2, true, true, array('', 'e')), + + // tags (tag) + array('s', 1, true, true, ''), + + // chateaux (chateau) + array('xuae', 4, false, true, 'eau'), + + // people (person) + array('elpoep', 6, true, true, 'person'), + ); + + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + + /** + * Returns the singular form of a word. + * + * If the method can't determine the form with certainty, an array of the + * possible singulars is returned. + * + * @param string $plural A word in plural form + * + * @return string|array The singular form or an array of possible singular + * forms + */ + public static function singularify($plural) + { + $pluralRev = strrev($plural); + $lowerPluralRev = strtolower($pluralRev); + $pluralLength = \strlen($lowerPluralRev); + + // The outer loop iterates over the entries of the plural table + // The inner loop $j iterates over the characters of the plural suffix + // in the plural table to compare them with the characters of the actual + // given plural suffix + foreach (self::$pluralMap as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + + // Compare characters in the plural table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerPluralRev[$j]) { + // Let $j point to the next character + ++$j; + + // Successfully compared the last character + // Add an entry with the singular suffix to the singular array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $pluralLength) { + $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]); + + if (!$map[2] && $nextIsVocal) { + // suffix may not succeed a vocal but next char is one + break; + } + + if (!$map[3] && !$nextIsVocal) { + // suffix may not succeed a consonant but next char is one + break; + } + } + + $newBase = substr($plural, 0, $pluralLength - $suffixLength); + $newSuffix = $map[4]; + + // Check whether the first character in the plural suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = ctype_upper($pluralRev[$j - 1]); + + if (\is_array($newSuffix)) { + $singulars = array(); + + foreach ($newSuffix as $newSuffixEntry) { + $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); + } + + return $singulars; + } + + return $newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix); + } + + // Suffix is longer than word + if ($j === $pluralLength) { + break; + } + } + } + + // Assume that plural and singular is identical + return $plural; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/NonTraversableArrayObject.php b/vendor/symfony/property-access/Tests/Fixtures/NonTraversableArrayObject.php new file mode 100755 index 00000000..d2ff9358 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/NonTraversableArrayObject.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +/** + * This class is a hand written simplified version of PHP native `ArrayObject` + * class, to show that it behaves differently than the PHP native implementation. + */ +class NonTraversableArrayObject implements \ArrayAccess, \Countable, \Serializable +{ + private $array; + + public function __construct(array $array = null) + { + $this->array = $array ?: array(); + } + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->array); + } + + public function offsetGet($offset) + { + return $this->array[$offset]; + } + + public function offsetSet($offset, $value) + { + if (null === $offset) { + $this->array[] = $value; + } else { + $this->array[$offset] = $value; + } + } + + public function offsetUnset($offset) + { + unset($this->array[$offset]); + } + + public function count() + { + return \count($this->array); + } + + public function serialize() + { + return serialize($this->array); + } + + public function unserialize($serialized) + { + $this->array = (array) unserialize((string) $serialized); + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/ReturnTyped.php b/vendor/symfony/property-access/Tests/Fixtures/ReturnTyped.php new file mode 100755 index 00000000..71c4a574 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/ReturnTyped.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class ReturnTyped +{ + public function getFoos(): array + { + return 'It doesn\'t respect the return type on purpose'; + } + + public function addFoo(\DateTime $dateTime) + { + } + + public function removeFoo(\DateTime $dateTime) + { + } + + public function setName($name): self + { + return 'This does not respect the return type on purpose.'; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TestClass.php b/vendor/symfony/property-access/Tests/Fixtures/TestClass.php new file mode 100755 index 00000000..7b1b9275 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TestClass.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClass +{ + public $publicProperty; + protected $protectedProperty; + private $privateProperty; + + private $publicAccessor; + private $publicMethodAccessor; + private $publicGetSetter; + private $publicAccessorWithDefaultValue; + private $publicAccessorWithRequiredAndDefaultValue; + private $publicAccessorWithMoreRequiredParameters; + private $publicIsAccessor; + private $publicHasAccessor; + private $publicGetter; + + public function __construct($value) + { + $this->publicProperty = $value; + $this->publicAccessor = $value; + $this->publicMethodAccessor = $value; + $this->publicGetSetter = $value; + $this->publicAccessorWithDefaultValue = $value; + $this->publicAccessorWithRequiredAndDefaultValue = $value; + $this->publicAccessorWithMoreRequiredParameters = $value; + $this->publicIsAccessor = $value; + $this->publicHasAccessor = $value; + $this->publicGetter = $value; + } + + public function setPublicAccessor($value) + { + $this->publicAccessor = $value; + } + + public function setPublicAccessorWithDefaultValue($value = null) + { + $this->publicAccessorWithDefaultValue = $value; + } + + public function setPublicAccessorWithRequiredAndDefaultValue($value, $optional = null) + { + $this->publicAccessorWithRequiredAndDefaultValue = $value; + } + + public function setPublicAccessorWithMoreRequiredParameters($value, $needed) + { + $this->publicAccessorWithMoreRequiredParameters = $value; + } + + public function getPublicAccessor() + { + return $this->publicAccessor; + } + + public function getPublicAccessorWithDefaultValue() + { + return $this->publicAccessorWithDefaultValue; + } + + public function getPublicAccessorWithRequiredAndDefaultValue() + { + return $this->publicAccessorWithRequiredAndDefaultValue; + } + + public function getPublicAccessorWithMoreRequiredParameters() + { + return $this->publicAccessorWithMoreRequiredParameters; + } + + public function setPublicIsAccessor($value) + { + $this->publicIsAccessor = $value; + } + + public function isPublicIsAccessor() + { + return $this->publicIsAccessor; + } + + public function setPublicHasAccessor($value) + { + $this->publicHasAccessor = $value; + } + + public function hasPublicHasAccessor() + { + return $this->publicHasAccessor; + } + + public function publicGetSetter($value = null) + { + if (null !== $value) { + $this->publicGetSetter = $value; + } + + return $this->publicGetSetter; + } + + public function getPublicMethodMutator() + { + return $this->publicGetSetter; + } + + protected function setProtectedAccessor($value) + { + } + + protected function getProtectedAccessor() + { + return 'foobar'; + } + + protected function setProtectedIsAccessor($value) + { + } + + protected function isProtectedIsAccessor() + { + return 'foobar'; + } + + protected function setProtectedHasAccessor($value) + { + } + + protected function hasProtectedHasAccessor() + { + return 'foobar'; + } + + private function setPrivateAccessor($value) + { + } + + private function getPrivateAccessor() + { + return 'foobar'; + } + + private function setPrivateIsAccessor($value) + { + } + + private function isPrivateIsAccessor() + { + return 'foobar'; + } + + private function setPrivateHasAccessor($value) + { + } + + private function hasPrivateHasAccessor() + { + return 'foobar'; + } + + public function getPublicGetter() + { + return $this->publicGetter; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TestClassIsWritable.php b/vendor/symfony/property-access/Tests/Fixtures/TestClassIsWritable.php new file mode 100755 index 00000000..4e966cda --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TestClassIsWritable.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassIsWritable +{ + protected $value; + + public function getValue() + { + return $this->value; + } + + public function __construct($value) + { + $this->value = $value; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicCall.php b/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicCall.php new file mode 100755 index 00000000..0d6c1f0b --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicCall.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassMagicCall +{ + private $magicCallProperty; + + public function __construct($value) + { + $this->magicCallProperty = $value; + } + + public function __call($method, array $args) + { + if ('getMagicCallProperty' === $method) { + return $this->magicCallProperty; + } + + if ('getConstantMagicCallProperty' === $method) { + return 'constant value'; + } + + if ('setMagicCallProperty' === $method) { + $this->magicCallProperty = reset($args); + } + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicGet.php b/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicGet.php new file mode 100755 index 00000000..e4653253 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TestClassMagicGet.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassMagicGet +{ + private $magicProperty; + + public $publicProperty; + + public function __construct($value) + { + $this->magicProperty = $value; + } + + public function __set($property, $value) + { + if ('magicProperty' === $property) { + $this->magicProperty = $value; + } + } + + public function __get($property) + { + if ('magicProperty' === $property) { + return $this->magicProperty; + } + + if ('constantMagicProperty' === $property) { + return 'constant value'; + } + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TestClassSetValue.php b/vendor/symfony/property-access/Tests/Fixtures/TestClassSetValue.php new file mode 100755 index 00000000..f0a7f1f4 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TestClassSetValue.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClassSetValue +{ + protected $value; + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } + + public function __construct($value) + { + $this->value = $value; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/Ticket5775Object.php b/vendor/symfony/property-access/Tests/Fixtures/Ticket5775Object.php new file mode 100755 index 00000000..5954dc37 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/Ticket5775Object.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class Ticket5775Object +{ + private $property; + + public function getProperty() + { + return $this->property; + } + + private function setProperty() + { + } + + public function __set($property, $value) + { + $this->$property = $value; + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TraversableArrayObject.php b/vendor/symfony/property-access/Tests/Fixtures/TraversableArrayObject.php new file mode 100755 index 00000000..6758f18f --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TraversableArrayObject.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +/** + * This class is a hand written simplified version of PHP native `ArrayObject` + * class, to show that it behaves differently than the PHP native implementation. + */ +class TraversableArrayObject implements \ArrayAccess, \IteratorAggregate, \Countable, \Serializable +{ + private $array; + + public function __construct(array $array = null) + { + $this->array = $array ?: array(); + } + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->array); + } + + public function offsetGet($offset) + { + return $this->array[$offset]; + } + + public function offsetSet($offset, $value) + { + if (null === $offset) { + $this->array[] = $value; + } else { + $this->array[$offset] = $value; + } + } + + public function offsetUnset($offset) + { + unset($this->array[$offset]); + } + + public function getIterator() + { + return new \ArrayIterator($this->array); + } + + public function count() + { + return \count($this->array); + } + + public function serialize() + { + return serialize($this->array); + } + + public function unserialize($serialized) + { + $this->array = (array) unserialize((string) $serialized); + } +} diff --git a/vendor/symfony/property-access/Tests/Fixtures/TypeHinted.php b/vendor/symfony/property-access/Tests/Fixtures/TypeHinted.php new file mode 100755 index 00000000..ce0f3d89 --- /dev/null +++ b/vendor/symfony/property-access/Tests/Fixtures/TypeHinted.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class TypeHinted +{ + private $date; + + /** + * @var \Countable + */ + private $countable; + + public function setDate(\DateTime $date) + { + $this->date = $date; + } + + public function getDate() + { + return $this->date; + } + + /** + * @return \Countable + */ + public function getCountable() + { + return $this->countable; + } + + /** + * @param \Countable $countable + */ + public function setCountable(\Countable $countable) + { + $this->countable = $countable; + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorArrayAccessTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorArrayAccessTest.php new file mode 100755 index 00000000..b0ed69c8 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorArrayAccessTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessor; + +abstract class PropertyAccessorArrayAccessTest extends TestCase +{ + /** + * @var PropertyAccessor + */ + protected $propertyAccessor; + + protected function setUp() + { + $this->propertyAccessor = new PropertyAccessor(); + } + + abstract protected function getContainer(array $array); + + public function getValidPropertyPaths() + { + return array( + array($this->getContainer(array('firstName' => 'Bernhard')), '[firstName]', 'Bernhard'), + array($this->getContainer(array('person' => $this->getContainer(array('firstName' => 'Bernhard')))), '[person][firstName]', 'Bernhard'), + ); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testGetValue($collection, $path, $value) + { + $this->assertSame($value, $this->propertyAccessor->getValue($collection, $path)); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchIndexException + */ + public function testGetValueFailsIfNoSuchIndex() + { + $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder() + ->enableExceptionOnInvalidIndex() + ->getPropertyAccessor(); + + $object = $this->getContainer(array('firstName' => 'Bernhard')); + + $this->propertyAccessor->getValue($object, '[lastName]'); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testSetValue($collection, $path) + { + $this->propertyAccessor->setValue($collection, $path, 'Updated'); + + $this->assertSame('Updated', $this->propertyAccessor->getValue($collection, $path)); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testIsReadable($collection, $path) + { + $this->assertTrue($this->propertyAccessor->isReadable($collection, $path)); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testIsWritable($collection, $path) + { + $this->assertTrue($this->propertyAccessor->isWritable($collection, $path)); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorArrayObjectTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorArrayObjectTest.php new file mode 100755 index 00000000..fb0b3837 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorArrayObjectTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +class PropertyAccessorArrayObjectTest extends PropertyAccessorCollectionTest +{ + protected function getContainer(array $array) + { + return new \ArrayObject($array); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorArrayTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorArrayTest.php new file mode 100755 index 00000000..c9828263 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorArrayTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +class PropertyAccessorArrayTest extends PropertyAccessorCollectionTest +{ + protected function getContainer(array $array) + { + return $array; + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorBuilderTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorBuilderTest.php new file mode 100755 index 00000000..f57433d8 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorBuilderTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\PropertyAccessorBuilder; + +class PropertyAccessorBuilderTest extends TestCase +{ + /** + * @var PropertyAccessorBuilder + */ + protected $builder; + + protected function setUp() + { + $this->builder = new PropertyAccessorBuilder(); + } + + protected function tearDown() + { + $this->builder = null; + } + + public function testEnableMagicCall() + { + $this->assertSame($this->builder, $this->builder->enableMagicCall()); + } + + public function testDisableMagicCall() + { + $this->assertSame($this->builder, $this->builder->disableMagicCall()); + } + + public function testIsMagicCallEnable() + { + $this->assertFalse($this->builder->isMagicCallEnabled()); + $this->assertTrue($this->builder->enableMagicCall()->isMagicCallEnabled()); + $this->assertFalse($this->builder->disableMagicCall()->isMagicCallEnabled()); + } + + public function testGetPropertyAccessor() + { + $this->assertInstanceOf('Symfony\Component\PropertyAccess\PropertyAccessor', $this->builder->getPropertyAccessor()); + $this->assertInstanceOf('Symfony\Component\PropertyAccess\PropertyAccessor', $this->builder->enableMagicCall()->getPropertyAccessor()); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorCollectionTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorCollectionTest.php new file mode 100755 index 00000000..a27718c6 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorCollectionTest.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +class PropertyAccessorCollectionTest_Car +{ + private $axes; + + public function __construct($axes = null) + { + $this->axes = $axes; + } + + // In the test, use a name that StringUtil can't uniquely singularify + public function addAxis($axis) + { + $this->axes[] = $axis; + } + + public function removeAxis($axis) + { + foreach ($this->axes as $key => $value) { + if ($value === $axis) { + unset($this->axes[$key]); + + return; + } + } + } + + public function getAxes() + { + return $this->axes; + } +} + +class PropertyAccessorCollectionTest_CarOnlyAdder +{ + public function addAxis($axis) + { + } + + public function getAxes() + { + } +} + +class PropertyAccessorCollectionTest_CarOnlyRemover +{ + public function removeAxis($axis) + { + } + + public function getAxes() + { + } +} + +class PropertyAccessorCollectionTest_CarNoAdderAndRemover +{ + public function getAxes() + { + } +} + +class PropertyAccessorCollectionTest_CompositeCar +{ + public function getStructure() + { + } + + public function setStructure($structure) + { + } +} + +class PropertyAccessorCollectionTest_CarStructure +{ + public function addAxis($axis) + { + } + + public function removeAxis($axis) + { + } + + public function getAxes() + { + } +} + +abstract class PropertyAccessorCollectionTest extends PropertyAccessorArrayAccessTest +{ + public function testSetValueCallsAdderAndRemoverForCollections() + { + $axesBefore = $this->getContainer(array(1 => 'second', 3 => 'fourth', 4 => 'fifth')); + $axesMerged = $this->getContainer(array(1 => 'first', 2 => 'second', 3 => 'third')); + $axesAfter = $this->getContainer(array(1 => 'second', 5 => 'first', 6 => 'third')); + $axesMergedCopy = \is_object($axesMerged) ? clone $axesMerged : $axesMerged; + + // Don't use a mock in order to test whether the collections are + // modified while iterating them + $car = new PropertyAccessorCollectionTest_Car($axesBefore); + + $this->propertyAccessor->setValue($car, 'axes', $axesMerged); + + $this->assertEquals($axesAfter, $car->getAxes()); + + // The passed collection was not modified + $this->assertEquals($axesMergedCopy, $axesMerged); + } + + public function testSetValueCallsAdderAndRemoverForNestedCollections() + { + $car = $this->getMockBuilder(__CLASS__.'_CompositeCar')->getMock(); + $structure = $this->getMockBuilder(__CLASS__.'_CarStructure')->getMock(); + $axesBefore = $this->getContainer(array(1 => 'second', 3 => 'fourth')); + $axesAfter = $this->getContainer(array(0 => 'first', 1 => 'second', 2 => 'third')); + + $car->expects($this->any()) + ->method('getStructure') + ->will($this->returnValue($structure)); + + $structure->expects($this->at(0)) + ->method('getAxes') + ->will($this->returnValue($axesBefore)); + $structure->expects($this->at(1)) + ->method('removeAxis') + ->with('fourth'); + $structure->expects($this->at(2)) + ->method('addAxis') + ->with('first'); + $structure->expects($this->at(3)) + ->method('addAxis') + ->with('third'); + + $this->propertyAccessor->setValue($car, 'structure.axes', $axesAfter); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + * @expectedExceptionMessage Neither the property "axes" nor one of the methods "addAx()"/"removeAx()", "addAxe()"/"removeAxe()", "addAxis()"/"removeAxis()", "setAxes()", "axes()", "__set()" or "__call()" exist and have public access in class "Mock_PropertyAccessorCollectionTest_CarNoAdderAndRemover + */ + public function testSetValueFailsIfNoAdderNorRemoverFound() + { + $car = $this->getMockBuilder(__CLASS__.'_CarNoAdderAndRemover')->getMock(); + $axesBefore = $this->getContainer(array(1 => 'second', 3 => 'fourth')); + $axesAfter = $this->getContainer(array(0 => 'first', 1 => 'second', 2 => 'third')); + + $car->expects($this->any()) + ->method('getAxes') + ->will($this->returnValue($axesBefore)); + + $this->propertyAccessor->setValue($car, 'axes', $axesAfter); + } + + public function testIsWritableReturnsTrueIfAdderAndRemoverExists() + { + $car = $this->getMockBuilder(__CLASS__.'_Car')->getMock(); + $this->assertTrue($this->propertyAccessor->isWritable($car, 'axes')); + } + + public function testIsWritableReturnsFalseIfOnlyAdderExists() + { + $car = $this->getMockBuilder(__CLASS__.'_CarOnlyAdder')->getMock(); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); + } + + public function testIsWritableReturnsFalseIfOnlyRemoverExists() + { + $car = $this->getMockBuilder(__CLASS__.'_CarOnlyRemover')->getMock(); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); + } + + public function testIsWritableReturnsFalseIfNoAdderNorRemoverExists() + { + $car = $this->getMockBuilder(__CLASS__.'_CarNoAdderAndRemover')->getMock(); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + * expectedExceptionMessageRegExp /The property "axes" in class "Mock_PropertyAccessorCollectionTest_Car[^"]*" can be defined with the methods "addAxis()", "removeAxis()" but the new value must be an array or an instance of \Traversable, "string" given./ + */ + public function testSetValueFailsIfAdderAndRemoverExistButValueIsNotTraversable() + { + $car = $this->getMockBuilder(__CLASS__.'_Car')->getMock(); + + $this->propertyAccessor->setValue($car, 'axes', 'Not an array or Traversable'); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorNonTraversableArrayObjectTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorNonTraversableArrayObjectTest.php new file mode 100755 index 00000000..6910d8be --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorNonTraversableArrayObjectTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use Symfony\Component\PropertyAccess\Tests\Fixtures\NonTraversableArrayObject; + +class PropertyAccessorNonTraversableArrayObjectTest extends PropertyAccessorArrayAccessTest +{ + protected function getContainer(array $array) + { + return new NonTraversableArrayObject($array); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorTest.php new file mode 100755 index 00000000..b0567291 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorTest.php @@ -0,0 +1,605 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\PropertyAccessor; +use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassSetValue; +use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TypeHinted; + +class PropertyAccessorTest extends TestCase +{ + /** + * @var PropertyAccessor + */ + private $propertyAccessor; + + protected function setUp() + { + $this->propertyAccessor = new PropertyAccessor(); + } + + public function getPathsWithUnexpectedType() + { + return array( + array('', 'foobar'), + array('foo', 'foobar'), + array(null, 'foobar'), + array(123, 'foobar'), + array((object) array('prop' => null), 'prop.foobar'), + array((object) array('prop' => (object) array('subProp' => null)), 'prop.subProp.foobar'), + array(array('index' => null), '[index][foobar]'), + array(array('index' => array('subIndex' => null)), '[index][subIndex][foobar]'), + ); + } + + public function getPathsWithMissingProperty() + { + return array( + array((object) array('firstName' => 'Bernhard'), 'lastName'), + array((object) array('property' => (object) array('firstName' => 'Bernhard')), 'property.lastName'), + array(array('index' => (object) array('firstName' => 'Bernhard')), '[index].lastName'), + array(new TestClass('Bernhard'), 'protectedProperty'), + array(new TestClass('Bernhard'), 'privateProperty'), + array(new TestClass('Bernhard'), 'protectedAccessor'), + array(new TestClass('Bernhard'), 'protectedIsAccessor'), + array(new TestClass('Bernhard'), 'protectedHasAccessor'), + array(new TestClass('Bernhard'), 'privateAccessor'), + array(new TestClass('Bernhard'), 'privateIsAccessor'), + array(new TestClass('Bernhard'), 'privateHasAccessor'), + + // Properties are not camelized + array(new TestClass('Bernhard'), 'public_property'), + ); + } + + public function getPathsWithMissingIndex() + { + return array( + array(array('firstName' => 'Bernhard'), '[lastName]'), + array(array(), '[index][lastName]'), + array(array('index' => array()), '[index][lastName]'), + array(array('index' => array('firstName' => 'Bernhard')), '[index][lastName]'), + array((object) array('property' => array('firstName' => 'Bernhard')), 'property[lastName]'), + ); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testGetValue($objectOrArray, $path, $value) + { + $this->assertSame($value, $this->propertyAccessor->getValue($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingProperty + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testGetValueThrowsExceptionIfPropertyNotFound($objectOrArray, $path) + { + $this->propertyAccessor->getValue($objectOrArray, $path); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testGetValueThrowsNoExceptionIfIndexNotFound($objectOrArray, $path) + { + $this->assertNull($this->propertyAccessor->getValue($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchIndexException + */ + public function testGetValueThrowsExceptionIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path) + { + $this->propertyAccessor = new PropertyAccessor(false, true); + $this->propertyAccessor->getValue($objectOrArray, $path); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchIndexException + */ + public function testGetValueThrowsExceptionIfNotArrayAccess() + { + $this->propertyAccessor->getValue(new \stdClass(), '[index]'); + } + + public function testGetValueReadsMagicGet() + { + $this->assertSame('Bernhard', $this->propertyAccessor->getValue(new TestClassMagicGet('Bernhard'), 'magicProperty')); + } + + public function testGetValueReadsArrayWithMissingIndexForCustomPropertyPath() + { + $object = new \ArrayObject(); + $array = array('child' => array('index' => $object)); + + $this->assertNull($this->propertyAccessor->getValue($array, '[child][index][foo][bar]')); + $this->assertSame(array(), $object->getArrayCopy()); + } + + // https://github.com/symfony/symfony/pull/4450 + public function testGetValueReadsMagicGetThatReturnsConstant() + { + $this->assertSame('constant value', $this->propertyAccessor->getValue(new TestClassMagicGet('Bernhard'), 'constantMagicProperty')); + } + + public function testGetValueNotModifyObject() + { + $object = new \stdClass(); + $object->firstName = array('Bernhard'); + + $this->assertNull($this->propertyAccessor->getValue($object, 'firstName[1]')); + $this->assertSame(array('Bernhard'), $object->firstName); + } + + public function testGetValueNotModifyObjectException() + { + $propertyAccessor = new PropertyAccessor(false, true); + $object = new \stdClass(); + $object->firstName = array('Bernhard'); + + try { + $propertyAccessor->getValue($object, 'firstName[1]'); + } catch (NoSuchIndexException $e) { + } + + $this->assertSame(array('Bernhard'), $object->firstName); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testGetValueDoesNotReadMagicCallByDefault() + { + $this->propertyAccessor->getValue(new TestClassMagicCall('Bernhard'), 'magicCallProperty'); + } + + public function testGetValueReadsMagicCallIfEnabled() + { + $this->propertyAccessor = new PropertyAccessor(true); + + $this->assertSame('Bernhard', $this->propertyAccessor->getValue(new TestClassMagicCall('Bernhard'), 'magicCallProperty')); + } + + // https://github.com/symfony/symfony/pull/4450 + public function testGetValueReadsMagicCallThatReturnsConstant() + { + $this->propertyAccessor = new PropertyAccessor(true); + + $this->assertSame('constant value', $this->propertyAccessor->getValue(new TestClassMagicCall('Bernhard'), 'constantMagicCallProperty')); + } + + /** + * @dataProvider getPathsWithUnexpectedType + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + * @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on + */ + public function testGetValueThrowsExceptionIfNotObjectOrArray($objectOrArray, $path) + { + $this->propertyAccessor->getValue($objectOrArray, $path); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testSetValue($objectOrArray, $path) + { + $this->propertyAccessor->setValue($objectOrArray, $path, 'Updated'); + + $this->assertSame('Updated', $this->propertyAccessor->getValue($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingProperty + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testSetValueThrowsExceptionIfPropertyNotFound($objectOrArray, $path) + { + $this->propertyAccessor->setValue($objectOrArray, $path, 'Updated'); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testSetValueThrowsNoExceptionIfIndexNotFound($objectOrArray, $path) + { + $this->propertyAccessor->setValue($objectOrArray, $path, 'Updated'); + + $this->assertSame('Updated', $this->propertyAccessor->getValue($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testSetValueThrowsNoExceptionIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path) + { + $this->propertyAccessor = new PropertyAccessor(false, true); + $this->propertyAccessor->setValue($objectOrArray, $path, 'Updated'); + + $this->assertSame('Updated', $this->propertyAccessor->getValue($objectOrArray, $path)); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchIndexException + */ + public function testSetValueThrowsExceptionIfNotArrayAccess() + { + $object = new \stdClass(); + + $this->propertyAccessor->setValue($object, '[index]', 'Updated'); + } + + public function testSetValueUpdatesMagicSet() + { + $author = new TestClassMagicGet('Bernhard'); + + $this->propertyAccessor->setValue($author, 'magicProperty', 'Updated'); + + $this->assertEquals('Updated', $author->__get('magicProperty')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testSetValueThrowsExceptionIfThereAreMissingParameters() + { + $object = new TestClass('Bernhard'); + + $this->propertyAccessor->setValue($object, 'publicAccessorWithMoreRequiredParameters', 'Updated'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testSetValueDoesNotUpdateMagicCallByDefault() + { + $author = new TestClassMagicCall('Bernhard'); + + $this->propertyAccessor->setValue($author, 'magicCallProperty', 'Updated'); + } + + public function testSetValueUpdatesMagicCallIfEnabled() + { + $this->propertyAccessor = new PropertyAccessor(true); + + $author = new TestClassMagicCall('Bernhard'); + + $this->propertyAccessor->setValue($author, 'magicCallProperty', 'Updated'); + + $this->assertEquals('Updated', $author->__call('getMagicCallProperty', array())); + } + + /** + * @dataProvider getPathsWithUnexpectedType + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + * @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on + */ + public function testSetValueThrowsExceptionIfNotObjectOrArray($objectOrArray, $path) + { + $this->propertyAccessor->setValue($objectOrArray, $path, 'value'); + } + + public function testGetValueWhenArrayValueIsNull() + { + $this->propertyAccessor = new PropertyAccessor(false, true); + $this->assertNull($this->propertyAccessor->getValue(array('index' => array('nullable' => null)), '[index][nullable]')); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testIsReadable($objectOrArray, $path) + { + $this->assertTrue($this->propertyAccessor->isReadable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingProperty + */ + public function testIsReadableReturnsFalseIfPropertyNotFound($objectOrArray, $path) + { + $this->assertFalse($this->propertyAccessor->isReadable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testIsReadableReturnsTrueIfIndexNotFound($objectOrArray, $path) + { + // Non-existing indices can be read. In this case, null is returned + $this->assertTrue($this->propertyAccessor->isReadable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testIsReadableReturnsFalseIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path) + { + $this->propertyAccessor = new PropertyAccessor(false, true); + + // When exceptions are enabled, non-existing indices cannot be read + $this->assertFalse($this->propertyAccessor->isReadable($objectOrArray, $path)); + } + + public function testIsReadableRecognizesMagicGet() + { + $this->assertTrue($this->propertyAccessor->isReadable(new TestClassMagicGet('Bernhard'), 'magicProperty')); + } + + public function testIsReadableDoesNotRecognizeMagicCallByDefault() + { + $this->assertFalse($this->propertyAccessor->isReadable(new TestClassMagicCall('Bernhard'), 'magicCallProperty')); + } + + public function testIsReadableRecognizesMagicCallIfEnabled() + { + $this->propertyAccessor = new PropertyAccessor(true); + + $this->assertTrue($this->propertyAccessor->isReadable(new TestClassMagicCall('Bernhard'), 'magicCallProperty')); + } + + /** + * @dataProvider getPathsWithUnexpectedType + */ + public function testIsReadableReturnsFalseIfNotObjectOrArray($objectOrArray, $path) + { + $this->assertFalse($this->propertyAccessor->isReadable($objectOrArray, $path)); + } + + /** + * @dataProvider getValidPropertyPaths + */ + public function testIsWritable($objectOrArray, $path) + { + $this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingProperty + */ + public function testIsWritableReturnsFalseIfPropertyNotFound($objectOrArray, $path) + { + $this->assertFalse($this->propertyAccessor->isWritable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testIsWritableReturnsTrueIfIndexNotFound($objectOrArray, $path) + { + // Non-existing indices can be written. Arrays are created on-demand. + $this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path)); + } + + /** + * @dataProvider getPathsWithMissingIndex + */ + public function testIsWritableReturnsTrueIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path) + { + $this->propertyAccessor = new PropertyAccessor(false, true); + + // Non-existing indices can be written even if exceptions are enabled + $this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path)); + } + + public function testIsWritableRecognizesMagicSet() + { + $this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicGet('Bernhard'), 'magicProperty')); + } + + public function testIsWritableDoesNotRecognizeMagicCallByDefault() + { + $this->assertFalse($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty')); + } + + public function testIsWritableRecognizesMagicCallIfEnabled() + { + $this->propertyAccessor = new PropertyAccessor(true); + + $this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty')); + } + + /** + * @dataProvider getPathsWithUnexpectedType + */ + public function testIsWritableReturnsFalseIfNotObjectOrArray($objectOrArray, $path) + { + $this->assertFalse($this->propertyAccessor->isWritable($objectOrArray, $path)); + } + + public function getValidPropertyPaths() + { + return array( + array(array('Bernhard', 'Schussek'), '[0]', 'Bernhard'), + array(array('Bernhard', 'Schussek'), '[1]', 'Schussek'), + array(array('firstName' => 'Bernhard'), '[firstName]', 'Bernhard'), + array(array('index' => array('firstName' => 'Bernhard')), '[index][firstName]', 'Bernhard'), + array((object) array('firstName' => 'Bernhard'), 'firstName', 'Bernhard'), + array((object) array('property' => array('firstName' => 'Bernhard')), 'property[firstName]', 'Bernhard'), + array(array('index' => (object) array('firstName' => 'Bernhard')), '[index].firstName', 'Bernhard'), + array((object) array('property' => (object) array('firstName' => 'Bernhard')), 'property.firstName', 'Bernhard'), + + // Accessor methods + array(new TestClass('Bernhard'), 'publicProperty', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicAccessor', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicAccessorWithDefaultValue', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicAccessorWithRequiredAndDefaultValue', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicIsAccessor', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicHasAccessor', 'Bernhard'), + array(new TestClass('Bernhard'), 'publicGetSetter', 'Bernhard'), + + // Methods are camelized + array(new TestClass('Bernhard'), 'public_accessor', 'Bernhard'), + array(new TestClass('Bernhard'), '_public_accessor', 'Bernhard'), + + // Missing indices + array(array('index' => array()), '[index][firstName]', null), + array(array('root' => array('index' => array())), '[root][index][firstName]', null), + + // Special chars + array(array('%!@$§.' => 'Bernhard'), '[%!@$§.]', 'Bernhard'), + array(array('index' => array('%!@$§.' => 'Bernhard')), '[index][%!@$§.]', 'Bernhard'), + array((object) array('%!@$§' => 'Bernhard'), '%!@$§', 'Bernhard'), + array((object) array('property' => (object) array('%!@$§' => 'Bernhard')), 'property.%!@$§', 'Bernhard'), + + // nested objects and arrays + array(array('foo' => new TestClass('bar')), '[foo].publicGetSetter', 'bar'), + array(new TestClass(array('foo' => 'bar')), 'publicGetSetter[foo]', 'bar'), + array(new TestClass(new TestClass('bar')), 'publicGetter.publicGetSetter', 'bar'), + array(new TestClass(array('foo' => new TestClass('bar'))), 'publicGetter[foo].publicGetSetter', 'bar'), + array(new TestClass(new TestClass(new TestClass('bar'))), 'publicGetter.publicGetter.publicGetSetter', 'bar'), + array(new TestClass(array('foo' => array('baz' => new TestClass('bar')))), 'publicGetter[foo][baz].publicGetSetter', 'bar'), + ); + } + + public function testTicket5755() + { + $object = new Ticket5775Object(); + + $this->propertyAccessor->setValue($object, 'property', 'foobar'); + + $this->assertEquals('foobar', $object->getProperty()); + } + + public function testSetValueDeepWithMagicGetter() + { + $obj = new TestClassMagicGet('foo'); + $obj->publicProperty = array('foo' => array('bar' => 'some_value')); + $this->propertyAccessor->setValue($obj, 'publicProperty[foo][bar]', 'Updated'); + $this->assertSame('Updated', $obj->publicProperty['foo']['bar']); + } + + public function getReferenceChainObjectsForSetValue() + { + return array( + array(array('a' => array('b' => array('c' => 'old-value'))), '[a][b][c]', 'new-value'), + array(new TestClassSetValue(new TestClassSetValue('old-value')), 'value.value', 'new-value'), + array(new TestClassSetValue(array('a' => array('b' => array('c' => new TestClassSetValue('old-value'))))), 'value[a][b][c].value', 'new-value'), + array(new TestClassSetValue(array('a' => array('b' => 'old-value'))), 'value[a][b]', 'new-value'), + array(new \ArrayIterator(array('a' => array('b' => array('c' => 'old-value')))), '[a][b][c]', 'new-value'), + ); + } + + /** + * @dataProvider getReferenceChainObjectsForSetValue + */ + public function testSetValueForReferenceChainIssue($object, $path, $value) + { + $this->propertyAccessor->setValue($object, $path, $value); + + $this->assertEquals($value, $this->propertyAccessor->getValue($object, $path)); + } + + public function getReferenceChainObjectsForIsWritable() + { + return array( + array(new TestClassIsWritable(array('a' => array('b' => 'old-value'))), 'value[a][b]', false), + array(new TestClassIsWritable(new \ArrayIterator(array('a' => array('b' => 'old-value')))), 'value[a][b]', true), + array(new TestClassIsWritable(array('a' => array('b' => array('c' => new TestClassSetValue('old-value'))))), 'value[a][b][c].value', true), + ); + } + + /** + * @dataProvider getReferenceChainObjectsForIsWritable + */ + public function testIsWritableForReferenceChainIssue($object, $path, $value) + { + $this->assertEquals($value, $this->propertyAccessor->isWritable($object, $path)); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected argument of type "DateTime", "string" given + */ + public function testThrowTypeError() + { + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'date', 'This is a string, \DateTime expected.'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected argument of type "DateTime", "NULL" given + */ + public function testThrowTypeErrorWithNullArgument() + { + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'date', null); + } + + public function testSetTypeHint() + { + $date = new \DateTime(); + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'date', $date); + $this->assertSame($date, $object->getDate()); + } + + public function testArrayNotBeeingOverwritten() + { + $value = array('value1' => 'foo', 'value2' => 'bar'); + $object = new TestClass($value); + + $this->propertyAccessor->setValue($object, 'publicAccessor[value2]', 'baz'); + $this->assertSame('baz', $this->propertyAccessor->getValue($object, 'publicAccessor[value2]')); + $this->assertSame(array('value1' => 'foo', 'value2' => 'baz'), $object->getPublicAccessor()); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected argument of type "Countable", "string" given + */ + public function testThrowTypeErrorWithInterface() + { + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'countable', 'This is a string, \Countable expected.'); + } + + /** + * @requires PHP 7 + * + * @expectedException \TypeError + */ + public function testDoNotDiscardReturnTypeError() + { + $object = new ReturnTyped(); + + $this->propertyAccessor->setValue($object, 'foos', array(new \DateTime())); + } + + /** + * @requires PHP 7 + * + * @expectedException \TypeError + */ + public function testDoNotDiscardReturnTypeErrorWhenWriterMethodIsMisconfigured() + { + $object = new ReturnTyped(); + + $this->propertyAccessor->setValue($object, 'name', 'foo'); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyAccessorTraversableArrayObjectTest.php b/vendor/symfony/property-access/Tests/PropertyAccessorTraversableArrayObjectTest.php new file mode 100755 index 00000000..4e450011 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyAccessorTraversableArrayObjectTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use Symfony\Component\PropertyAccess\Tests\Fixtures\TraversableArrayObject; + +class PropertyAccessorTraversableArrayObjectTest extends PropertyAccessorCollectionTest +{ + protected function getContainer(array $array) + { + return new TraversableArrayObject($array); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyPathBuilderTest.php b/vendor/symfony/property-access/Tests/PropertyPathBuilderTest.php new file mode 100755 index 00000000..44822699 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyPathBuilderTest.php @@ -0,0 +1,288 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPathBuilder; + +/** + * @author Bernhard Schussek + */ +class PropertyPathBuilderTest extends TestCase +{ + const PREFIX = 'old1[old2].old3[old4][old5].old6'; + + /** + * @var PropertyPathBuilder + */ + private $builder; + + protected function setUp() + { + $this->builder = new PropertyPathBuilder(new PropertyPath(self::PREFIX)); + } + + public function testCreateEmpty() + { + $builder = new PropertyPathBuilder(); + + $this->assertNull($builder->getPropertyPath()); + } + + public function testCreateCopyPath() + { + $this->assertEquals(new PropertyPath(self::PREFIX), $this->builder->getPropertyPath()); + } + + public function testAppendIndex() + { + $this->builder->appendIndex('new1'); + + $path = new PropertyPath(self::PREFIX.'[new1]'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testAppendProperty() + { + $this->builder->appendProperty('new1'); + + $path = new PropertyPath(self::PREFIX.'.new1'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testAppend() + { + $this->builder->append(new PropertyPath('new1[new2]')); + + $path = new PropertyPath(self::PREFIX.'.new1[new2]'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testAppendUsingString() + { + $this->builder->append('new1[new2]'); + + $path = new PropertyPath(self::PREFIX.'.new1[new2]'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testAppendWithOffset() + { + $this->builder->append(new PropertyPath('new1[new2].new3'), 1); + + $path = new PropertyPath(self::PREFIX.'[new2].new3'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testAppendWithOffsetAndLength() + { + $this->builder->append(new PropertyPath('new1[new2].new3'), 1, 1); + + $path = new PropertyPath(self::PREFIX.'[new2]'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceByIndex() + { + $this->builder->replaceByIndex(1, 'new1'); + + $path = new PropertyPath('old1[new1].old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceByIndexWithoutName() + { + $this->builder->replaceByIndex(0); + + $path = new PropertyPath('[old1][old2].old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testReplaceByIndexDoesNotAllowInvalidOffsets() + { + $this->builder->replaceByIndex(6, 'new1'); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testReplaceByIndexDoesNotAllowNegativeOffsets() + { + $this->builder->replaceByIndex(-1, 'new1'); + } + + public function testReplaceByProperty() + { + $this->builder->replaceByProperty(1, 'new1'); + + $path = new PropertyPath('old1.new1.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceByPropertyWithoutName() + { + $this->builder->replaceByProperty(1); + + $path = new PropertyPath('old1.old2.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testReplaceByPropertyDoesNotAllowInvalidOffsets() + { + $this->builder->replaceByProperty(6, 'new1'); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testReplaceByPropertyDoesNotAllowNegativeOffsets() + { + $this->builder->replaceByProperty(-1, 'new1'); + } + + public function testReplace() + { + $this->builder->replace(1, 1, new PropertyPath('new1[new2].new3')); + + $path = new PropertyPath('old1.new1[new2].new3.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceUsingString() + { + $this->builder->replace(1, 1, 'new1[new2].new3'); + + $path = new PropertyPath('old1.new1[new2].new3.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceNegative() + { + $this->builder->replace(-1, 1, new PropertyPath('new1[new2].new3')); + + $path = new PropertyPath('old1[old2].old3[old4][old5].new1[new2].new3'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + /** + * @dataProvider provideInvalidOffsets + * @expectedException \OutOfBoundsException + */ + public function testReplaceDoesNotAllowInvalidOffsets($offset) + { + $this->builder->replace($offset, 1, new PropertyPath('new1[new2].new3')); + } + + public function provideInvalidOffsets() + { + return array( + array(6), + array(-7), + ); + } + + public function testReplaceWithLengthGreaterOne() + { + $this->builder->replace(0, 2, new PropertyPath('new1[new2].new3')); + + $path = new PropertyPath('new1[new2].new3.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceSubstring() + { + $this->builder->replace(1, 1, new PropertyPath('new1[new2].new3.new4[new5]'), 1, 3); + + $path = new PropertyPath('old1[new2].new3.new4.old3[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + public function testReplaceSubstringWithLengthGreaterOne() + { + $this->builder->replace(1, 2, new PropertyPath('new1[new2].new3.new4[new5]'), 1, 3); + + $path = new PropertyPath('old1[new2].new3.new4[old4][old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + // https://github.com/symfony/symfony/issues/5605 + public function testReplaceWithLongerPath() + { + // error occurs when path contains at least two more elements + // than the builder + $path = new PropertyPath('new1.new2.new3'); + + $builder = new PropertyPathBuilder(new PropertyPath('old1')); + $builder->replace(0, 1, $path); + + $this->assertEquals($path, $builder->getPropertyPath()); + } + + public function testReplaceWithLongerPathKeepsOrder() + { + $path = new PropertyPath('new1.new2.new3'); + $expected = new PropertyPath('new1.new2.new3.old2'); + + $builder = new PropertyPathBuilder(new PropertyPath('old1.old2')); + $builder->replace(0, 1, $path); + + $this->assertEquals($expected, $builder->getPropertyPath()); + } + + public function testRemove() + { + $this->builder->remove(3); + + $path = new PropertyPath('old1[old2].old3[old5].old6'); + + $this->assertEquals($path, $this->builder->getPropertyPath()); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testRemoveDoesNotAllowInvalidOffsets() + { + $this->builder->remove(6); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testRemoveDoesNotAllowNegativeOffsets() + { + $this->builder->remove(-1); + } +} diff --git a/vendor/symfony/property-access/Tests/PropertyPathTest.php b/vendor/symfony/property-access/Tests/PropertyPathTest.php new file mode 100755 index 00000000..6c5c6b22 --- /dev/null +++ b/vendor/symfony/property-access/Tests/PropertyPathTest.php @@ -0,0 +1,206 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\PropertyPath; + +class PropertyPathTest extends TestCase +{ + public function testToString() + { + $path = new PropertyPath('reference.traversable[index].property'); + + $this->assertEquals('reference.traversable[index].property', $path->__toString()); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testDotIsRequiredBeforeProperty() + { + new PropertyPath('[index]property'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testDotCannotBePresentAtTheBeginning() + { + new PropertyPath('.property'); + } + + public function providePathsContainingUnexpectedCharacters() + { + return array( + array('property.'), + array('property.['), + array('property..'), + array('property['), + array('property[['), + array('property[.'), + array('property[]'), + ); + } + + /** + * @dataProvider providePathsContainingUnexpectedCharacters + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testUnexpectedCharacters($path) + { + new PropertyPath($path); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testPathCannotBeEmpty() + { + new PropertyPath(''); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + */ + public function testPathCannotBeNull() + { + new PropertyPath(null); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + */ + public function testPathCannotBeFalse() + { + new PropertyPath(false); + } + + public function testZeroIsValidPropertyPath() + { + $propertyPath = new PropertyPath('0'); + + $this->assertSame('0', (string) $propertyPath); + } + + public function testGetParentWithDot() + { + $propertyPath = new PropertyPath('grandpa.parent.child'); + + $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); + } + + public function testGetParentWithIndex() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); + } + + public function testGetParentWhenThereIsNoParent() + { + $propertyPath = new PropertyPath('path'); + + $this->assertNull($propertyPath->getParent()); + } + + public function testCopyConstructor() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + $copy = new PropertyPath($propertyPath); + + $this->assertEquals($propertyPath, $copy); + } + + public function testGetElement() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertEquals('child', $propertyPath->getElement(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testGetElementDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->getElement(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testGetElementDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->getElement(-1); + } + + public function testIsProperty() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertTrue($propertyPath->isProperty(1)); + $this->assertFalse($propertyPath->isProperty(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsPropertyDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isProperty(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsPropertyDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isProperty(-1); + } + + public function testIsIndex() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertFalse($propertyPath->isIndex(1)); + $this->assertTrue($propertyPath->isIndex(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsIndexDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isIndex(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsIndexDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isIndex(-1); + } +} diff --git a/vendor/symfony/property-access/Tests/StringUtilTest.php b/vendor/symfony/property-access/Tests/StringUtilTest.php new file mode 100755 index 00000000..b6da7778 --- /dev/null +++ b/vendor/symfony/property-access/Tests/StringUtilTest.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyAccess\StringUtil; + +class StringUtilTest extends TestCase +{ + public function singularifyProvider() + { + // see http://english-zone.com/spelling/plurals.html + // see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English + return array( + array('accesses', 'access'), + array('addresses', 'address'), + array('agendas', 'agenda'), + array('alumnae', 'alumna'), + array('alumni', 'alumnus'), + array('analyses', array('analys', 'analyse', 'analysis')), + array('antennae', 'antenna'), + array('antennas', 'antenna'), + array('appendices', array('appendex', 'appendix', 'appendice')), + array('arches', array('arch', 'arche')), + array('atlases', array('atlas', 'atlase', 'atlasis')), + array('axes', array('ax', 'axe', 'axis')), + array('babies', 'baby'), + array('bacteria', array('bacterion', 'bacterium')), + array('bases', array('bas', 'base', 'basis')), + array('batches', array('batch', 'batche')), + array('beaux', 'beau'), + array('bees', array('be', 'bee')), + array('boxes', 'box'), + array('boys', 'boy'), + array('bureaus', 'bureau'), + array('bureaux', 'bureau'), + array('buses', array('bus', 'buse', 'busis')), + array('bushes', array('bush', 'bushe')), + array('calves', array('calf', 'calve', 'calff')), + array('cars', 'car'), + array('cassettes', array('cassett', 'cassette')), + array('caves', array('caf', 'cave', 'caff')), + array('chateaux', 'chateau'), + array('cheeses', array('chees', 'cheese', 'cheesis')), + array('children', 'child'), + array('circuses', array('circus', 'circuse', 'circusis')), + array('cliffs', 'cliff'), + array('committee', 'committee'), + array('crises', array('cris', 'crise', 'crisis')), + array('criteria', array('criterion', 'criterium')), + array('cups', 'cup'), + array('data', array('daton', 'datum')), + array('days', 'day'), + array('discos', 'disco'), + array('devices', array('devex', 'devix', 'device')), + array('drives', 'drive'), + array('drivers', 'driver'), + array('dwarves', array('dwarf', 'dwarve', 'dwarff')), + array('echoes', array('echo', 'echoe')), + array('elves', array('elf', 'elve', 'elff')), + array('emphases', array('emphas', 'emphase', 'emphasis')), + array('faxes', 'fax'), + array('feet', 'foot'), + array('feedback', 'feedback'), + array('foci', 'focus'), + array('focuses', array('focus', 'focuse', 'focusis')), + array('formulae', 'formula'), + array('formulas', 'formula'), + array('fungi', 'fungus'), + array('funguses', array('fungus', 'funguse', 'fungusis')), + array('garages', array('garag', 'garage')), + array('geese', 'goose'), + array('halves', array('half', 'halve', 'halff')), + array('hats', 'hat'), + array('heroes', array('hero', 'heroe')), + array('hippopotamuses', array('hippopotamus', 'hippopotamuse', 'hippopotamusis')), //hippopotami + array('hoaxes', 'hoax'), + array('hooves', array('hoof', 'hoove', 'hooff')), + array('houses', array('hous', 'house', 'housis')), + array('indexes', 'index'), + array('indices', array('index', 'indix', 'indice')), + array('ions', 'ion'), + array('irises', array('iris', 'irise', 'irisis')), + array('kisses', 'kiss'), + array('knives', 'knife'), + array('lamps', 'lamp'), + array('leaves', array('leaf', 'leave', 'leaff')), + array('lice', 'louse'), + array('lives', 'life'), + array('matrices', array('matrex', 'matrix', 'matrice')), + array('matrixes', 'matrix'), + array('men', 'man'), + array('mice', 'mouse'), + array('moves', 'move'), + array('movies', 'movie'), + array('nebulae', 'nebula'), + array('neuroses', array('neuros', 'neurose', 'neurosis')), + array('news', 'news'), + array('oases', array('oas', 'oase', 'oasis')), + array('objectives', 'objective'), + array('oxen', 'ox'), + array('parties', 'party'), + array('people', 'person'), + array('persons', 'person'), + array('phenomena', array('phenomenon', 'phenomenum')), + array('photos', 'photo'), + array('pianos', 'piano'), + array('plateaux', 'plateau'), + array('poppies', 'poppy'), + array('prices', array('prex', 'prix', 'price')), + array('quizzes', 'quiz'), + array('radii', 'radius'), + array('roofs', 'roof'), + array('roses', array('ros', 'rose', 'rosis')), + array('sandwiches', array('sandwich', 'sandwiche')), + array('scarves', array('scarf', 'scarve', 'scarff')), + array('schemas', 'schema'), //schemata + array('selfies', 'selfie'), + array('series', 'series'), + array('services', 'service'), + array('sheriffs', 'sheriff'), + array('shoes', array('sho', 'shoe')), + array('spies', 'spy'), + array('staves', array('staf', 'stave', 'staff')), + array('stories', 'story'), + array('strata', array('straton', 'stratum')), + array('suitcases', array('suitcas', 'suitcase', 'suitcasis')), + array('syllabi', 'syllabus'), + array('tags', 'tag'), + array('teeth', 'tooth'), + array('theses', array('thes', 'these', 'thesis')), + array('thieves', array('thief', 'thieve', 'thieff')), + array('trees', array('tre', 'tree')), + array('waltzes', array('waltz', 'waltze')), + array('wives', 'wife'), + + // test casing: if the first letter was uppercase, it should remain so + array('Men', 'Man'), + array('GrandChildren', 'GrandChild'), + array('SubTrees', array('SubTre', 'SubTree')), + + // Known issues + //array('insignia', 'insigne'), + //array('insignias', 'insigne'), + //array('rattles', 'rattle'), + ); + } + + /** + * @dataProvider singularifyProvider + */ + public function testSingularify($plural, $singular) + { + $single = StringUtil::singularify($plural); + if (\is_string($singular) && \is_array($single)) { + $this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single)); + } elseif (\is_array($singular) && \is_string($single)) { + $this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single); + } + + $this->assertEquals($singular, $single); + } +} diff --git a/vendor/symfony/property-access/composer.json b/vendor/symfony/property-access/composer.json new file mode 100755 index 00000000..51acb591 --- /dev/null +++ b/vendor/symfony/property-access/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/property-access", + "type": "library", + "description": "Symfony PropertyAccess Component", + "keywords": ["property", "index", "access", "object", "array", "extraction", "injection", "reflection", "property path"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9", + "symfony/polyfill-ctype": "~1.8" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\PropertyAccess\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + } +} diff --git a/vendor/symfony/property-access/phpunit.xml.dist b/vendor/symfony/property-access/phpunit.xml.dist new file mode 100755 index 00000000..c50bbb75 --- /dev/null +++ b/vendor/symfony/property-access/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + +