mirror of
https://github.com/standardebooks/web.git
synced 2025-07-12 09:32:24 -04:00
Add Composer autoloading functions and PHPStan for testing
This commit is contained in:
parent
e198c4db65
commit
f5d7d4e02a
1518 changed files with 169063 additions and 30 deletions
127
vendor/symfony/console/Helper/DebugFormatterHelper.php
vendored
Normal file
127
vendor/symfony/console/Helper/DebugFormatterHelper.php
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/**
|
||||
* Helps outputting debug information when running an external program from a command.
|
||||
*
|
||||
* An external program can be a Process, an HTTP request, or anything else.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DebugFormatterHelper extends Helper
|
||||
{
|
||||
private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
|
||||
private $started = [];
|
||||
private $count = -1;
|
||||
|
||||
/**
|
||||
* Starts a debug formatting session.
|
||||
*
|
||||
* @param string $id The id of the formatting session
|
||||
* @param string $message The message to display
|
||||
* @param string $prefix The prefix to use
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function start($id, $message, $prefix = 'RUN')
|
||||
{
|
||||
$this->started[$id] = ['border' => ++$this->count % \count($this->colors)];
|
||||
|
||||
return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds progress to a formatting session.
|
||||
*
|
||||
* @param string $id The id of the formatting session
|
||||
* @param string $buffer The message to display
|
||||
* @param bool $error Whether to consider the buffer as error
|
||||
* @param string $prefix The prefix for output
|
||||
* @param string $errorPrefix The prefix for error output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
|
||||
{
|
||||
$message = '';
|
||||
|
||||
if ($error) {
|
||||
if (isset($this->started[$id]['out'])) {
|
||||
$message .= "\n";
|
||||
unset($this->started[$id]['out']);
|
||||
}
|
||||
if (!isset($this->started[$id]['err'])) {
|
||||
$message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
|
||||
$this->started[$id]['err'] = true;
|
||||
}
|
||||
|
||||
$message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
|
||||
} else {
|
||||
if (isset($this->started[$id]['err'])) {
|
||||
$message .= "\n";
|
||||
unset($this->started[$id]['err']);
|
||||
}
|
||||
if (!isset($this->started[$id]['out'])) {
|
||||
$message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
|
||||
$this->started[$id]['out'] = true;
|
||||
}
|
||||
|
||||
$message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a formatting session.
|
||||
*
|
||||
* @param string $id The id of the formatting session
|
||||
* @param string $message The message to display
|
||||
* @param bool $successful Whether to consider the result as success
|
||||
* @param string $prefix The prefix for the end output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function stop($id, $message, $successful, $prefix = 'RES')
|
||||
{
|
||||
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
|
||||
|
||||
if ($successful) {
|
||||
return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
|
||||
}
|
||||
|
||||
$message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
|
||||
|
||||
unset($this->started[$id]['out'], $this->started[$id]['err']);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id The id of the formatting session
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getBorder($id)
|
||||
{
|
||||
return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'debug_formatter';
|
||||
}
|
||||
}
|
94
vendor/symfony/console/Helper/DescriptorHelper.php
vendored
Normal file
94
vendor/symfony/console/Helper/DescriptorHelper.php
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Descriptor\DescriptorInterface;
|
||||
use Symfony\Component\Console\Descriptor\JsonDescriptor;
|
||||
use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
|
||||
use Symfony\Component\Console\Descriptor\TextDescriptor;
|
||||
use Symfony\Component\Console\Descriptor\XmlDescriptor;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* This class adds helper method to describe objects in various formats.
|
||||
*
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
class DescriptorHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* @var DescriptorInterface[]
|
||||
*/
|
||||
private $descriptors = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->register('txt', new TextDescriptor())
|
||||
->register('xml', new XmlDescriptor())
|
||||
->register('json', new JsonDescriptor())
|
||||
->register('md', new MarkdownDescriptor())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes an object if supported.
|
||||
*
|
||||
* Available options are:
|
||||
* * format: string, the output format name
|
||||
* * raw_text: boolean, sets output type as raw
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param object $object
|
||||
* @param array $options
|
||||
*
|
||||
* @throws InvalidArgumentException when the given format is not supported
|
||||
*/
|
||||
public function describe(OutputInterface $output, $object, array $options = [])
|
||||
{
|
||||
$options = array_merge([
|
||||
'raw_text' => false,
|
||||
'format' => 'txt',
|
||||
], $options);
|
||||
|
||||
if (!isset($this->descriptors[$options['format']])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
|
||||
}
|
||||
|
||||
$descriptor = $this->descriptors[$options['format']];
|
||||
$descriptor->describe($output, $object, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a descriptor.
|
||||
*
|
||||
* @param string $format
|
||||
* @param DescriptorInterface $descriptor
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function register($format, DescriptorInterface $descriptor)
|
||||
{
|
||||
$this->descriptors[$format] = $descriptor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'descriptor';
|
||||
}
|
||||
}
|
106
vendor/symfony/console/Helper/FormatterHelper.php
vendored
Normal file
106
vendor/symfony/console/Helper/FormatterHelper.php
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* The Formatter class provides helpers to format messages.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FormatterHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* Formats a message within a section.
|
||||
*
|
||||
* @param string $section The section name
|
||||
* @param string $message The message
|
||||
* @param string $style The style to apply to the section
|
||||
*
|
||||
* @return string The format section
|
||||
*/
|
||||
public function formatSection($section, $message, $style = 'info')
|
||||
{
|
||||
return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message as a block of text.
|
||||
*
|
||||
* @param string|array $messages The message to write in the block
|
||||
* @param string $style The style to apply to the whole block
|
||||
* @param bool $large Whether to return a large block
|
||||
*
|
||||
* @return string The formatter message
|
||||
*/
|
||||
public function formatBlock($messages, $style, $large = false)
|
||||
{
|
||||
if (!\is_array($messages)) {
|
||||
$messages = [$messages];
|
||||
}
|
||||
|
||||
$len = 0;
|
||||
$lines = [];
|
||||
foreach ($messages as $message) {
|
||||
$message = OutputFormatter::escape($message);
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
}
|
||||
|
||||
$messages = $large ? [str_repeat(' ', $len)] : [];
|
||||
for ($i = 0; isset($lines[$i]); ++$i) {
|
||||
$messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i]));
|
||||
}
|
||||
if ($large) {
|
||||
$messages[] = str_repeat(' ', $len);
|
||||
}
|
||||
|
||||
for ($i = 0; isset($messages[$i]); ++$i) {
|
||||
$messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a message to the given length.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $length
|
||||
* @param string $suffix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function truncate($message, $length, $suffix = '...')
|
||||
{
|
||||
$computedLength = $length - $this->strlen($suffix);
|
||||
|
||||
if ($computedLength > $this->strlen($message)) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($message, null, true)) {
|
||||
return substr($message, 0, $length).$suffix;
|
||||
}
|
||||
|
||||
return mb_substr($message, 0, $length, $encoding).$suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'formatter';
|
||||
}
|
||||
}
|
138
vendor/symfony/console/Helper/Helper.php
vendored
Normal file
138
vendor/symfony/console/Helper/Helper.php
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
|
||||
/**
|
||||
* Helper is the base class for all helper classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Helper implements HelperInterface
|
||||
{
|
||||
protected $helperSet = null;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
return $this->helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a string, using mb_strwidth if it is available.
|
||||
*
|
||||
* @param string $string The string to check its length
|
||||
*
|
||||
* @return int The length of the string
|
||||
*/
|
||||
public static function strlen($string)
|
||||
{
|
||||
if (false === $encoding = mb_detect_encoding($string, null, true)) {
|
||||
return \strlen($string);
|
||||
}
|
||||
|
||||
return mb_strwidth($string, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subset of a string, using mb_substr if it is available.
|
||||
*
|
||||
* @param string $string String to subset
|
||||
* @param int $from Start offset
|
||||
* @param int|null $length Length to read
|
||||
*
|
||||
* @return string The string subset
|
||||
*/
|
||||
public static function substr($string, $from, $length = null)
|
||||
{
|
||||
if (false === $encoding = mb_detect_encoding($string, null, true)) {
|
||||
return substr($string, $from, $length);
|
||||
}
|
||||
|
||||
return mb_substr($string, $from, $length, $encoding);
|
||||
}
|
||||
|
||||
public static function formatTime($secs)
|
||||
{
|
||||
static $timeFormats = [
|
||||
[0, '< 1 sec'],
|
||||
[1, '1 sec'],
|
||||
[2, 'secs', 1],
|
||||
[60, '1 min'],
|
||||
[120, 'mins', 60],
|
||||
[3600, '1 hr'],
|
||||
[7200, 'hrs', 3600],
|
||||
[86400, '1 day'],
|
||||
[172800, 'days', 86400],
|
||||
];
|
||||
|
||||
foreach ($timeFormats as $index => $format) {
|
||||
if ($secs >= $format[0]) {
|
||||
if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
|
||||
|| $index == \count($timeFormats) - 1
|
||||
) {
|
||||
if (2 == \count($format)) {
|
||||
return $format[1];
|
||||
}
|
||||
|
||||
return floor($secs / $format[2]).' '.$format[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function formatMemory($memory)
|
||||
{
|
||||
if ($memory >= 1024 * 1024 * 1024) {
|
||||
return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
|
||||
}
|
||||
|
||||
if ($memory >= 1024 * 1024) {
|
||||
return sprintf('%.1f MiB', $memory / 1024 / 1024);
|
||||
}
|
||||
|
||||
if ($memory >= 1024) {
|
||||
return sprintf('%d KiB', $memory / 1024);
|
||||
}
|
||||
|
||||
return sprintf('%d B', $memory);
|
||||
}
|
||||
|
||||
public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
|
||||
{
|
||||
return self::strlen(self::removeDecoration($formatter, $string));
|
||||
}
|
||||
|
||||
public static function removeDecoration(OutputFormatterInterface $formatter, $string)
|
||||
{
|
||||
$isDecorated = $formatter->isDecorated();
|
||||
$formatter->setDecorated(false);
|
||||
// remove <...> formatting
|
||||
$string = $formatter->format($string);
|
||||
// remove already formatted characters
|
||||
$string = preg_replace("/\033\[[^m]*m/", '', $string);
|
||||
$formatter->setDecorated($isDecorated);
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
39
vendor/symfony/console/Helper/HelperInterface.php
vendored
Normal file
39
vendor/symfony/console/Helper/HelperInterface.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/**
|
||||
* HelperInterface is the interface all helpers must implement.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface HelperInterface
|
||||
{
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null);
|
||||
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet();
|
||||
|
||||
/**
|
||||
* Returns the canonical name of this helper.
|
||||
*
|
||||
* @return string The canonical name
|
||||
*/
|
||||
public function getName();
|
||||
}
|
108
vendor/symfony/console/Helper/HelperSet.php
vendored
Normal file
108
vendor/symfony/console/Helper/HelperSet.php
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* HelperSet represents a set of helpers to be used with a command.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class HelperSet implements \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var Helper[]
|
||||
*/
|
||||
private $helpers = [];
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* @param Helper[] $helpers An array of helper
|
||||
*/
|
||||
public function __construct(array $helpers = [])
|
||||
{
|
||||
foreach ($helpers as $alias => $helper) {
|
||||
$this->set($helper, \is_int($alias) ? null : $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a helper.
|
||||
*
|
||||
* @param HelperInterface $helper The helper instance
|
||||
* @param string $alias An alias
|
||||
*/
|
||||
public function set(HelperInterface $helper, $alias = null)
|
||||
{
|
||||
$this->helpers[$helper->getName()] = $helper;
|
||||
if (null !== $alias) {
|
||||
$this->helpers[$alias] = $helper;
|
||||
}
|
||||
|
||||
$helper->setHelperSet($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the helper if defined.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return bool true if the helper is defined, false otherwise
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->helpers[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper value.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return HelperInterface The helper instance
|
||||
*
|
||||
* @throws InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
|
||||
}
|
||||
|
||||
return $this->helpers[$name];
|
||||
}
|
||||
|
||||
public function setCommand(Command $command = null)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command associated with this helper set.
|
||||
*
|
||||
* @return Command A Command instance
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Helper[]
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->helpers);
|
||||
}
|
||||
}
|
33
vendor/symfony/console/Helper/InputAwareHelper.php
vendored
Normal file
33
vendor/symfony/console/Helper/InputAwareHelper.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Input\InputAwareInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* An implementation of InputAwareInterface for Helpers.
|
||||
*
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
*/
|
||||
abstract class InputAwareHelper extends Helper implements InputAwareInterface
|
||||
{
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setInput(InputInterface $input)
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
}
|
156
vendor/symfony/console/Helper/ProcessHelper.php
vendored
Normal file
156
vendor/symfony/console/Helper/ProcessHelper.php
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* The ProcessHelper class provides helpers to run external processes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final since Symfony 4.2
|
||||
*/
|
||||
class ProcessHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* Runs an external process.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param array|Process $cmd An instance of Process or an array of the command and arguments
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
* @param int $verbosity The threshold for verbosity
|
||||
*
|
||||
* @return Process The process that ran
|
||||
*/
|
||||
public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
$formatter = $this->getHelperSet()->get('debug_formatter');
|
||||
|
||||
if ($cmd instanceof Process) {
|
||||
$cmd = [$cmd];
|
||||
}
|
||||
|
||||
if (!\is_array($cmd)) {
|
||||
@trigger_error(sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
$cmd = [\method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd)];
|
||||
}
|
||||
|
||||
if (\is_string($cmd[0] ?? null)) {
|
||||
$process = new Process($cmd);
|
||||
$cmd = [];
|
||||
} elseif (($cmd[0] ?? null) instanceof Process) {
|
||||
$process = $cmd[0];
|
||||
unset($cmd[0]);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
|
||||
}
|
||||
|
||||
if ($verbosity <= $output->getVerbosity()) {
|
||||
$output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
|
||||
}
|
||||
|
||||
if ($output->isDebug()) {
|
||||
$callback = $this->wrapCallback($output, $process, $callback);
|
||||
}
|
||||
|
||||
$process->run($callback, $cmd);
|
||||
|
||||
if ($verbosity <= $output->getVerbosity()) {
|
||||
$message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
|
||||
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
|
||||
}
|
||||
|
||||
if (!$process->isSuccessful() && null !== $error) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
|
||||
}
|
||||
|
||||
return $process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the process.
|
||||
*
|
||||
* This is identical to run() except that an exception is thrown if the process
|
||||
* exits with a non-zero exit code.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param string|Process $cmd An instance of Process or a command to run
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
*
|
||||
* @return Process The process that ran
|
||||
*
|
||||
* @throws ProcessFailedException
|
||||
*
|
||||
* @see run()
|
||||
*/
|
||||
public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null)
|
||||
{
|
||||
$process = $this->run($output, $cmd, $error, $callback);
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new ProcessFailedException($process);
|
||||
}
|
||||
|
||||
return $process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a Process callback to add debugging output.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface interface
|
||||
* @param Process $process The Process
|
||||
* @param callable|null $callback A PHP callable
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
$formatter = $this->getHelperSet()->get('debug_formatter');
|
||||
|
||||
return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
|
||||
$output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
|
||||
|
||||
if (null !== $callback) {
|
||||
$callback($type, $buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private function escapeString($str)
|
||||
{
|
||||
return str_replace('<', '\\<', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'process';
|
||||
}
|
||||
}
|
530
vendor/symfony/console/Helper/ProgressBar.php
vendored
Normal file
530
vendor/symfony/console/Helper/ProgressBar.php
vendored
Normal file
|
@ -0,0 +1,530 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Terminal;
|
||||
|
||||
/**
|
||||
* The ProgressBar provides helpers to display progress output.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Chris Jones <leeked@gmail.com>
|
||||
*/
|
||||
final class ProgressBar
|
||||
{
|
||||
private $barWidth = 28;
|
||||
private $barChar;
|
||||
private $emptyBarChar = '-';
|
||||
private $progressChar = '>';
|
||||
private $format;
|
||||
private $internalFormat;
|
||||
private $redrawFreq = 1;
|
||||
private $output;
|
||||
private $step = 0;
|
||||
private $max;
|
||||
private $startTime;
|
||||
private $stepWidth;
|
||||
private $percent = 0.0;
|
||||
private $formatLineCount;
|
||||
private $messages = [];
|
||||
private $overwrite = true;
|
||||
private $terminal;
|
||||
private $firstRun = true;
|
||||
|
||||
private static $formatters;
|
||||
private static $formats;
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param int $max Maximum steps (0 if unknown)
|
||||
*/
|
||||
public function __construct(OutputInterface $output, int $max = 0)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
$this->output = $output;
|
||||
$this->setMaxSteps($max);
|
||||
$this->terminal = new Terminal();
|
||||
|
||||
if (!$this->output->isDecorated()) {
|
||||
// disable overwrite when output does not support ANSI codes.
|
||||
$this->overwrite = false;
|
||||
|
||||
// set a reasonable redraw frequency so output isn't flooded
|
||||
$this->setRedrawFrequency($max / 10);
|
||||
}
|
||||
|
||||
$this->startTime = time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a placeholder formatter for a given name.
|
||||
*
|
||||
* This method also allow you to override an existing placeholder.
|
||||
*
|
||||
* @param string $name The placeholder name (including the delimiter char like %)
|
||||
* @param callable $callable A PHP callable
|
||||
*/
|
||||
public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void
|
||||
{
|
||||
if (!self::$formatters) {
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
self::$formatters[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the placeholder formatter for a given name.
|
||||
*
|
||||
* @param string $name The placeholder name (including the delimiter char like %)
|
||||
*
|
||||
* @return callable|null A PHP callable
|
||||
*/
|
||||
public static function getPlaceholderFormatterDefinition(string $name): ?callable
|
||||
{
|
||||
if (!self::$formatters) {
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a format for a given name.
|
||||
*
|
||||
* This method also allow you to override an existing format.
|
||||
*
|
||||
* @param string $name The format name
|
||||
* @param string $format A format string
|
||||
*/
|
||||
public static function setFormatDefinition(string $name, string $format): void
|
||||
{
|
||||
if (!self::$formats) {
|
||||
self::$formats = self::initFormats();
|
||||
}
|
||||
|
||||
self::$formats[$name] = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format for a given name.
|
||||
*
|
||||
* @param string $name The format name
|
||||
*
|
||||
* @return string|null A format string
|
||||
*/
|
||||
public static function getFormatDefinition(string $name): ?string
|
||||
{
|
||||
if (!self::$formats) {
|
||||
self::$formats = self::initFormats();
|
||||
}
|
||||
|
||||
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a text with a named placeholder.
|
||||
*
|
||||
* The text is displayed when the progress bar is rendered but only
|
||||
* when the corresponding placeholder is part of the custom format line
|
||||
* (by wrapping the name with %).
|
||||
*
|
||||
* @param string $message The text to associate with the placeholder
|
||||
* @param string $name The name of the placeholder
|
||||
*/
|
||||
public function setMessage(string $message, string $name = 'message')
|
||||
{
|
||||
$this->messages[$name] = $message;
|
||||
}
|
||||
|
||||
public function getMessage(string $name = 'message')
|
||||
{
|
||||
return $this->messages[$name];
|
||||
}
|
||||
|
||||
public function getStartTime(): int
|
||||
{
|
||||
return $this->startTime;
|
||||
}
|
||||
|
||||
public function getMaxSteps(): int
|
||||
{
|
||||
return $this->max;
|
||||
}
|
||||
|
||||
public function getProgress(): int
|
||||
{
|
||||
return $this->step;
|
||||
}
|
||||
|
||||
private function getStepWidth(): int
|
||||
{
|
||||
return $this->stepWidth;
|
||||
}
|
||||
|
||||
public function getProgressPercent(): float
|
||||
{
|
||||
return $this->percent;
|
||||
}
|
||||
|
||||
public function setBarWidth(int $size)
|
||||
{
|
||||
$this->barWidth = max(1, $size);
|
||||
}
|
||||
|
||||
public function getBarWidth(): int
|
||||
{
|
||||
return $this->barWidth;
|
||||
}
|
||||
|
||||
public function setBarCharacter(string $char)
|
||||
{
|
||||
$this->barChar = $char;
|
||||
}
|
||||
|
||||
public function getBarCharacter(): string
|
||||
{
|
||||
if (null === $this->barChar) {
|
||||
return $this->max ? '=' : $this->emptyBarChar;
|
||||
}
|
||||
|
||||
return $this->barChar;
|
||||
}
|
||||
|
||||
public function setEmptyBarCharacter(string $char)
|
||||
{
|
||||
$this->emptyBarChar = $char;
|
||||
}
|
||||
|
||||
public function getEmptyBarCharacter(): string
|
||||
{
|
||||
return $this->emptyBarChar;
|
||||
}
|
||||
|
||||
public function setProgressCharacter(string $char)
|
||||
{
|
||||
$this->progressChar = $char;
|
||||
}
|
||||
|
||||
public function getProgressCharacter(): string
|
||||
{
|
||||
return $this->progressChar;
|
||||
}
|
||||
|
||||
public function setFormat(string $format)
|
||||
{
|
||||
$this->format = null;
|
||||
$this->internalFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the redraw frequency.
|
||||
*
|
||||
* @param int|float $freq The frequency in steps
|
||||
*/
|
||||
public function setRedrawFrequency(int $freq)
|
||||
{
|
||||
$this->redrawFreq = max($freq, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the progress output.
|
||||
*
|
||||
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
|
||||
*/
|
||||
public function start(int $max = null)
|
||||
{
|
||||
$this->startTime = time();
|
||||
$this->step = 0;
|
||||
$this->percent = 0.0;
|
||||
|
||||
if (null !== $max) {
|
||||
$this->setMaxSteps($max);
|
||||
}
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the progress output X steps.
|
||||
*
|
||||
* @param int $step Number of steps to advance
|
||||
*/
|
||||
public function advance(int $step = 1)
|
||||
{
|
||||
$this->setProgress($this->step + $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to overwrite the progressbar, false for new line.
|
||||
*/
|
||||
public function setOverwrite(bool $overwrite)
|
||||
{
|
||||
$this->overwrite = $overwrite;
|
||||
}
|
||||
|
||||
public function setProgress(int $step)
|
||||
{
|
||||
if ($this->max && $step > $this->max) {
|
||||
$this->max = $step;
|
||||
} elseif ($step < 0) {
|
||||
$step = 0;
|
||||
}
|
||||
|
||||
$prevPeriod = (int) ($this->step / $this->redrawFreq);
|
||||
$currPeriod = (int) ($step / $this->redrawFreq);
|
||||
$this->step = $step;
|
||||
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
|
||||
if ($prevPeriod !== $currPeriod || $this->max === $step) {
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
public function setMaxSteps(int $max)
|
||||
{
|
||||
$this->format = null;
|
||||
$this->max = max(0, $max);
|
||||
$this->stepWidth = $this->max ? Helper::strlen((string) $this->max) : 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the progress output.
|
||||
*/
|
||||
public function finish(): void
|
||||
{
|
||||
if (!$this->max) {
|
||||
$this->max = $this->step;
|
||||
}
|
||||
|
||||
if ($this->step === $this->max && !$this->overwrite) {
|
||||
// prevent double 100% output
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setProgress($this->max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the current progress string.
|
||||
*/
|
||||
public function display(): void
|
||||
{
|
||||
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $this->format) {
|
||||
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
|
||||
}
|
||||
|
||||
$this->overwrite($this->buildLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the progress bar from the current line.
|
||||
*
|
||||
* This is useful if you wish to write some output
|
||||
* while a progress bar is running.
|
||||
* Call display() to show the progress bar again.
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
if (!$this->overwrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $this->format) {
|
||||
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
|
||||
}
|
||||
|
||||
$this->overwrite('');
|
||||
}
|
||||
|
||||
private function setRealFormat(string $format)
|
||||
{
|
||||
// try to use the _nomax variant if available
|
||||
if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
|
||||
$this->format = self::getFormatDefinition($format.'_nomax');
|
||||
} elseif (null !== self::getFormatDefinition($format)) {
|
||||
$this->format = self::getFormatDefinition($format);
|
||||
} else {
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
$this->formatLineCount = substr_count($this->format, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites a previous message to the output.
|
||||
*/
|
||||
private function overwrite(string $message): void
|
||||
{
|
||||
if ($this->overwrite) {
|
||||
if (!$this->firstRun) {
|
||||
if ($this->output instanceof ConsoleSectionOutput) {
|
||||
$lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1;
|
||||
$this->output->clear($lines);
|
||||
} else {
|
||||
// Move the cursor to the beginning of the line
|
||||
$this->output->write("\x0D");
|
||||
|
||||
// Erase the line
|
||||
$this->output->write("\x1B[2K");
|
||||
|
||||
// Erase previous lines
|
||||
if ($this->formatLineCount > 0) {
|
||||
$this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($this->step > 0) {
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
$this->firstRun = false;
|
||||
|
||||
$this->output->write($message);
|
||||
}
|
||||
|
||||
private function determineBestFormat(): string
|
||||
{
|
||||
switch ($this->output->getVerbosity()) {
|
||||
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
|
||||
case OutputInterface::VERBOSITY_VERBOSE:
|
||||
return $this->max ? 'verbose' : 'verbose_nomax';
|
||||
case OutputInterface::VERBOSITY_VERY_VERBOSE:
|
||||
return $this->max ? 'very_verbose' : 'very_verbose_nomax';
|
||||
case OutputInterface::VERBOSITY_DEBUG:
|
||||
return $this->max ? 'debug' : 'debug_nomax';
|
||||
default:
|
||||
return $this->max ? 'normal' : 'normal_nomax';
|
||||
}
|
||||
}
|
||||
|
||||
private static function initPlaceholderFormatters(): array
|
||||
{
|
||||
return [
|
||||
'bar' => function (self $bar, OutputInterface $output) {
|
||||
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
|
||||
$display = str_repeat($bar->getBarCharacter(), $completeBars);
|
||||
if ($completeBars < $bar->getBarWidth()) {
|
||||
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
|
||||
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
|
||||
}
|
||||
|
||||
return $display;
|
||||
},
|
||||
'elapsed' => function (self $bar) {
|
||||
return Helper::formatTime(time() - $bar->getStartTime());
|
||||
},
|
||||
'remaining' => function (self $bar) {
|
||||
if (!$bar->getMaxSteps()) {
|
||||
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
|
||||
}
|
||||
|
||||
if (!$bar->getProgress()) {
|
||||
$remaining = 0;
|
||||
} else {
|
||||
$remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
|
||||
}
|
||||
|
||||
return Helper::formatTime($remaining);
|
||||
},
|
||||
'estimated' => function (self $bar) {
|
||||
if (!$bar->getMaxSteps()) {
|
||||
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
|
||||
}
|
||||
|
||||
if (!$bar->getProgress()) {
|
||||
$estimated = 0;
|
||||
} else {
|
||||
$estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
|
||||
}
|
||||
|
||||
return Helper::formatTime($estimated);
|
||||
},
|
||||
'memory' => function (self $bar) {
|
||||
return Helper::formatMemory(memory_get_usage(true));
|
||||
},
|
||||
'current' => function (self $bar) {
|
||||
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
|
||||
},
|
||||
'max' => function (self $bar) {
|
||||
return $bar->getMaxSteps();
|
||||
},
|
||||
'percent' => function (self $bar) {
|
||||
return floor($bar->getProgressPercent() * 100);
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private static function initFormats(): array
|
||||
{
|
||||
return [
|
||||
'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
|
||||
'normal_nomax' => ' %current% [%bar%]',
|
||||
|
||||
'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
|
||||
'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
|
||||
|
||||
'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
|
||||
'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
|
||||
|
||||
'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
|
||||
'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
|
||||
];
|
||||
}
|
||||
|
||||
private function buildLine(): string
|
||||
{
|
||||
$regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
|
||||
$callback = function ($matches) {
|
||||
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
|
||||
$text = $formatter($this, $this->output);
|
||||
} elseif (isset($this->messages[$matches[1]])) {
|
||||
$text = $this->messages[$matches[1]];
|
||||
} else {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
if (isset($matches[2])) {
|
||||
$text = sprintf('%'.$matches[2], $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
};
|
||||
$line = preg_replace_callback($regex, $callback, $this->format);
|
||||
|
||||
// gets string length for each sub line with multiline format
|
||||
$linesLength = array_map(function ($subLine) {
|
||||
return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
|
||||
}, explode("\n", $line));
|
||||
|
||||
$linesWidth = max($linesLength);
|
||||
|
||||
$terminalWidth = $this->terminal->getWidth();
|
||||
if ($linesWidth <= $terminalWidth) {
|
||||
return $line;
|
||||
}
|
||||
|
||||
$this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
|
||||
|
||||
return preg_replace_callback($regex, $callback, $this->format);
|
||||
}
|
||||
}
|
269
vendor/symfony/console/Helper/ProgressIndicator.php
vendored
Normal file
269
vendor/symfony/console/Helper/ProgressIndicator.php
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
class ProgressIndicator
|
||||
{
|
||||
private $output;
|
||||
private $startTime;
|
||||
private $format;
|
||||
private $message;
|
||||
private $indicatorValues;
|
||||
private $indicatorCurrent;
|
||||
private $indicatorChangeInterval;
|
||||
private $indicatorUpdateTime;
|
||||
private $started = false;
|
||||
|
||||
private static $formatters;
|
||||
private static $formats;
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output
|
||||
* @param string|null $format Indicator format
|
||||
* @param int $indicatorChangeInterval Change interval in milliseconds
|
||||
* @param array|null $indicatorValues Animated indicator characters
|
||||
*/
|
||||
public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
if (null === $format) {
|
||||
$format = $this->determineBestFormat();
|
||||
}
|
||||
|
||||
if (null === $indicatorValues) {
|
||||
$indicatorValues = ['-', '\\', '|', '/'];
|
||||
}
|
||||
|
||||
$indicatorValues = array_values($indicatorValues);
|
||||
|
||||
if (2 > \count($indicatorValues)) {
|
||||
throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
|
||||
}
|
||||
|
||||
$this->format = self::getFormatDefinition($format);
|
||||
$this->indicatorChangeInterval = $indicatorChangeInterval;
|
||||
$this->indicatorValues = $indicatorValues;
|
||||
$this->startTime = time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current indicator message.
|
||||
*
|
||||
* @param string|null $message
|
||||
*/
|
||||
public function setMessage($message)
|
||||
{
|
||||
$this->message = $message;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the indicator output.
|
||||
*
|
||||
* @param $message
|
||||
*/
|
||||
public function start($message)
|
||||
{
|
||||
if ($this->started) {
|
||||
throw new LogicException('Progress indicator already started.');
|
||||
}
|
||||
|
||||
$this->message = $message;
|
||||
$this->started = true;
|
||||
$this->startTime = time();
|
||||
$this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
|
||||
$this->indicatorCurrent = 0;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the indicator.
|
||||
*/
|
||||
public function advance()
|
||||
{
|
||||
if (!$this->started) {
|
||||
throw new LogicException('Progress indicator has not yet been started.');
|
||||
}
|
||||
|
||||
if (!$this->output->isDecorated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$currentTime = $this->getCurrentTimeInMilliseconds();
|
||||
|
||||
if ($currentTime < $this->indicatorUpdateTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
|
||||
++$this->indicatorCurrent;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the indicator with message.
|
||||
*
|
||||
* @param $message
|
||||
*/
|
||||
public function finish($message)
|
||||
{
|
||||
if (!$this->started) {
|
||||
throw new LogicException('Progress indicator has not yet been started.');
|
||||
}
|
||||
|
||||
$this->message = $message;
|
||||
$this->display();
|
||||
$this->output->writeln('');
|
||||
$this->started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format for a given name.
|
||||
*
|
||||
* @param string $name The format name
|
||||
*
|
||||
* @return string|null A format string
|
||||
*/
|
||||
public static function getFormatDefinition($name)
|
||||
{
|
||||
if (!self::$formats) {
|
||||
self::$formats = self::initFormats();
|
||||
}
|
||||
|
||||
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a placeholder formatter for a given name.
|
||||
*
|
||||
* This method also allow you to override an existing placeholder.
|
||||
*
|
||||
* @param string $name The placeholder name (including the delimiter char like %)
|
||||
* @param callable $callable A PHP callable
|
||||
*/
|
||||
public static function setPlaceholderFormatterDefinition($name, $callable)
|
||||
{
|
||||
if (!self::$formatters) {
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
self::$formatters[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the placeholder formatter for a given name.
|
||||
*
|
||||
* @param string $name The placeholder name (including the delimiter char like %)
|
||||
*
|
||||
* @return callable|null A PHP callable
|
||||
*/
|
||||
public static function getPlaceholderFormatterDefinition($name)
|
||||
{
|
||||
if (!self::$formatters) {
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
|
||||
}
|
||||
|
||||
private function display()
|
||||
{
|
||||
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$self = $this;
|
||||
|
||||
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
|
||||
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
|
||||
return $formatter($self);
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}, $this->format));
|
||||
}
|
||||
|
||||
private function determineBestFormat()
|
||||
{
|
||||
switch ($this->output->getVerbosity()) {
|
||||
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
|
||||
case OutputInterface::VERBOSITY_VERBOSE:
|
||||
return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
|
||||
case OutputInterface::VERBOSITY_VERY_VERBOSE:
|
||||
case OutputInterface::VERBOSITY_DEBUG:
|
||||
return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
|
||||
default:
|
||||
return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites a previous message to the output.
|
||||
*/
|
||||
private function overwrite(string $message)
|
||||
{
|
||||
if ($this->output->isDecorated()) {
|
||||
$this->output->write("\x0D\x1B[2K");
|
||||
$this->output->write($message);
|
||||
} else {
|
||||
$this->output->writeln($message);
|
||||
}
|
||||
}
|
||||
|
||||
private function getCurrentTimeInMilliseconds()
|
||||
{
|
||||
return round(microtime(true) * 1000);
|
||||
}
|
||||
|
||||
private static function initPlaceholderFormatters()
|
||||
{
|
||||
return [
|
||||
'indicator' => function (self $indicator) {
|
||||
return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
|
||||
},
|
||||
'message' => function (self $indicator) {
|
||||
return $indicator->message;
|
||||
},
|
||||
'elapsed' => function (self $indicator) {
|
||||
return Helper::formatTime(time() - $indicator->startTime);
|
||||
},
|
||||
'memory' => function () {
|
||||
return Helper::formatMemory(memory_get_usage(true));
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private static function initFormats()
|
||||
{
|
||||
return [
|
||||
'normal' => ' %indicator% %message%',
|
||||
'normal_no_ansi' => ' %message%',
|
||||
|
||||
'verbose' => ' %indicator% %message% (%elapsed:6s%)',
|
||||
'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
|
||||
|
||||
'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
|
||||
'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
|
||||
];
|
||||
}
|
||||
}
|
434
vendor/symfony/console/Helper/QuestionHelper.php
vendored
Normal file
434
vendor/symfony/console/Helper/QuestionHelper.php
vendored
Normal file
|
@ -0,0 +1,434 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\StreamableInputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
|
||||
/**
|
||||
* The QuestionHelper class provides helpers to interact with the user.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class QuestionHelper extends Helper
|
||||
{
|
||||
private $inputStream;
|
||||
private static $shell;
|
||||
private static $stty;
|
||||
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
*
|
||||
* @return mixed The user answer
|
||||
*
|
||||
* @throws RuntimeException If there is no data to read in the input stream
|
||||
*/
|
||||
public function ask(InputInterface $input, OutputInterface $output, Question $question)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
if (!$input->isInteractive()) {
|
||||
$default = $question->getDefault();
|
||||
|
||||
if (null !== $default && $question instanceof ChoiceQuestion) {
|
||||
$choices = $question->getChoices();
|
||||
|
||||
if (!$question->isMultiselect()) {
|
||||
return isset($choices[$default]) ? $choices[$default] : $default;
|
||||
}
|
||||
|
||||
$default = explode(',', $default);
|
||||
foreach ($default as $k => $v) {
|
||||
$v = trim($v);
|
||||
$default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
|
||||
$this->inputStream = $stream;
|
||||
}
|
||||
|
||||
if (!$question->getValidator()) {
|
||||
return $this->doAsk($output, $question);
|
||||
}
|
||||
|
||||
$interviewer = function () use ($output, $question) {
|
||||
return $this->doAsk($output, $question);
|
||||
};
|
||||
|
||||
return $this->validateAttempts($interviewer, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'question';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents usage of stty.
|
||||
*/
|
||||
public static function disableStty()
|
||||
{
|
||||
self::$stty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the question to the user.
|
||||
*
|
||||
* @return bool|mixed|string|null
|
||||
*
|
||||
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
|
||||
*/
|
||||
private function doAsk(OutputInterface $output, Question $question)
|
||||
{
|
||||
$this->writePrompt($output, $question);
|
||||
|
||||
$inputStream = $this->inputStream ?: STDIN;
|
||||
$autocomplete = $question->getAutocompleterValues();
|
||||
|
||||
if (null === $autocomplete || !$this->hasSttyAvailable()) {
|
||||
$ret = false;
|
||||
if ($question->isHidden()) {
|
||||
try {
|
||||
$ret = trim($this->getHiddenResponse($output, $inputStream));
|
||||
} catch (RuntimeException $e) {
|
||||
if (!$question->isHiddenFallback()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $ret) {
|
||||
$ret = fgets($inputStream, 4096);
|
||||
if (false === $ret) {
|
||||
throw new RuntimeException('Aborted');
|
||||
}
|
||||
$ret = trim($ret);
|
||||
}
|
||||
} else {
|
||||
$ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false)));
|
||||
}
|
||||
|
||||
if ($output instanceof ConsoleSectionOutput) {
|
||||
$output->addContent($ret);
|
||||
}
|
||||
|
||||
$ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
|
||||
|
||||
if ($normalizer = $question->getNormalizer()) {
|
||||
return $normalizer($ret);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the question prompt.
|
||||
*/
|
||||
protected function writePrompt(OutputInterface $output, Question $question)
|
||||
{
|
||||
$message = $question->getQuestion();
|
||||
|
||||
if ($question instanceof ChoiceQuestion) {
|
||||
$maxWidth = max(array_map([$this, 'strlen'], array_keys($question->getChoices())));
|
||||
|
||||
$messages = (array) $question->getQuestion();
|
||||
foreach ($question->getChoices() as $key => $value) {
|
||||
$width = $maxWidth - $this->strlen($key);
|
||||
$messages[] = ' [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
|
||||
}
|
||||
|
||||
$output->writeln($messages);
|
||||
|
||||
$message = $question->getPrompt();
|
||||
}
|
||||
|
||||
$output->write($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs an error message.
|
||||
*/
|
||||
protected function writeError(OutputInterface $output, \Exception $error)
|
||||
{
|
||||
if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
|
||||
$message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
|
||||
} else {
|
||||
$message = '<error>'.$error->getMessage().'</error>';
|
||||
}
|
||||
|
||||
$output->writeln($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocompletes a question.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param Question $question
|
||||
* @param resource $inputStream
|
||||
*/
|
||||
private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete): string
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
$i = 0;
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$numMatches = \count($matches);
|
||||
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
|
||||
// Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
|
||||
shell_exec('stty -icanon -echo');
|
||||
|
||||
// Add highlighted text style
|
||||
$output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
|
||||
|
||||
// Read a keypress
|
||||
while (!feof($inputStream)) {
|
||||
$c = fread($inputStream, 1);
|
||||
|
||||
// Backspace Character
|
||||
if ("\177" === $c) {
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
--$i;
|
||||
// Move cursor backwards
|
||||
$output->write("\033[1D");
|
||||
}
|
||||
|
||||
if (0 === $i) {
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$numMatches = \count($matches);
|
||||
} else {
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
// Pop the last character off the end of our string
|
||||
$ret = substr($ret, 0, $i);
|
||||
} elseif ("\033" === $c) {
|
||||
// Did we read an escape sequence?
|
||||
$c .= fread($inputStream, 2);
|
||||
|
||||
// A = Up Arrow. B = Down Arrow
|
||||
if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
|
||||
if ('A' === $c[2] && -1 === $ofs) {
|
||||
$ofs = 0;
|
||||
}
|
||||
|
||||
if (0 === $numMatches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ofs += ('A' === $c[2]) ? -1 : 1;
|
||||
$ofs = ($numMatches + $ofs) % $numMatches;
|
||||
}
|
||||
} elseif (\ord($c) < 32) {
|
||||
if ("\t" === $c || "\n" === $c) {
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
$ret = $matches[$ofs];
|
||||
// Echo out remaining chars for current match
|
||||
$output->write(substr($ret, $i));
|
||||
$i = \strlen($ret);
|
||||
}
|
||||
|
||||
if ("\n" === $c) {
|
||||
$output->write($c);
|
||||
break;
|
||||
}
|
||||
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
$output->write($c);
|
||||
$ret .= $c;
|
||||
++$i;
|
||||
|
||||
$numMatches = 0;
|
||||
$ofs = 0;
|
||||
|
||||
foreach ($autocomplete as $value) {
|
||||
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
|
||||
if (0 === strpos($value, $ret)) {
|
||||
$matches[$numMatches++] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Erase characters from cursor to end of line
|
||||
$output->write("\033[K");
|
||||
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
// Save cursor position
|
||||
$output->write("\0337");
|
||||
// Write highlighted text
|
||||
$output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).'</hl>');
|
||||
// Restore cursor position
|
||||
$output->write("\0338");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset stty so it behaves normally again
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hidden response from user.
|
||||
*
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param resource $inputStream The handler resource
|
||||
*
|
||||
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
|
||||
*/
|
||||
private function getHiddenResponse(OutputInterface $output, $inputStream): string
|
||||
{
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
|
||||
|
||||
// handle code running from a phar
|
||||
if ('phar:' === substr(__FILE__, 0, 5)) {
|
||||
$tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
|
||||
copy($exe, $tmpExe);
|
||||
$exe = $tmpExe;
|
||||
}
|
||||
|
||||
$value = rtrim(shell_exec($exe));
|
||||
$output->writeln('');
|
||||
|
||||
if (isset($tmpExe)) {
|
||||
unlink($tmpExe);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($this->hasSttyAvailable()) {
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
|
||||
shell_exec('stty -echo');
|
||||
$value = fgets($inputStream, 4096);
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
if (false === $value) {
|
||||
throw new RuntimeException('Aborted');
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
$output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (false !== $shell = $this->getShell()) {
|
||||
$readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
|
||||
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
|
||||
$value = rtrim(shell_exec($command));
|
||||
$output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new RuntimeException('Unable to hide the response.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an attempt.
|
||||
*
|
||||
* @param callable $interviewer A callable that will ask for a question and return the result
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param Question $question A Question instance
|
||||
*
|
||||
* @return mixed The validated response
|
||||
*
|
||||
* @throws \Exception In case the max number of attempts has been reached and no valid response has been given
|
||||
*/
|
||||
private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
|
||||
{
|
||||
$error = null;
|
||||
$attempts = $question->getMaxAttempts();
|
||||
while (null === $attempts || $attempts--) {
|
||||
if (null !== $error) {
|
||||
$this->writeError($output, $error);
|
||||
}
|
||||
|
||||
try {
|
||||
return $question->getValidator()($interviewer());
|
||||
} catch (RuntimeException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
||||
throw $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a valid unix shell.
|
||||
*
|
||||
* @return string|bool The valid shell name, false in case no valid shell is found
|
||||
*/
|
||||
private function getShell()
|
||||
{
|
||||
if (null !== self::$shell) {
|
||||
return self::$shell;
|
||||
}
|
||||
|
||||
self::$shell = false;
|
||||
|
||||
if (file_exists('/usr/bin/env')) {
|
||||
// handle other OSs with bash/zsh/ksh/csh if available to hide the answer
|
||||
$test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
|
||||
foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) {
|
||||
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
|
||||
self::$shell = $sh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Stty is available or not.
|
||||
*/
|
||||
private function hasSttyAvailable(): bool
|
||||
{
|
||||
if (null !== self::$stty) {
|
||||
return self::$stty;
|
||||
}
|
||||
|
||||
exec('stty 2>&1', $output, $exitcode);
|
||||
|
||||
return self::$stty = 0 === $exitcode;
|
||||
}
|
||||
}
|
96
vendor/symfony/console/Helper/SymfonyQuestionHelper.php
vendored
Normal file
96
vendor/symfony/console/Helper/SymfonyQuestionHelper.php
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Symfony Style Guide compliant question helper.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
class SymfonyQuestionHelper extends QuestionHelper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function writePrompt(OutputInterface $output, Question $question)
|
||||
{
|
||||
$text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
|
||||
$default = $question->getDefault();
|
||||
|
||||
switch (true) {
|
||||
case null === $default:
|
||||
$text = sprintf(' <info>%s</info>:', $text);
|
||||
|
||||
break;
|
||||
|
||||
case $question instanceof ConfirmationQuestion:
|
||||
$text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
|
||||
|
||||
break;
|
||||
|
||||
case $question instanceof ChoiceQuestion && $question->isMultiselect():
|
||||
$choices = $question->getChoices();
|
||||
$default = explode(',', $default);
|
||||
|
||||
foreach ($default as $key => $value) {
|
||||
$default[$key] = $choices[trim($value)];
|
||||
}
|
||||
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));
|
||||
|
||||
break;
|
||||
|
||||
case $question instanceof ChoiceQuestion:
|
||||
$choices = $question->getChoices();
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
|
||||
}
|
||||
|
||||
$output->writeln($text);
|
||||
|
||||
if ($question instanceof ChoiceQuestion) {
|
||||
$width = max(array_map('strlen', array_keys($question->getChoices())));
|
||||
|
||||
foreach ($question->getChoices() as $key => $value) {
|
||||
$output->writeln(sprintf(" [<comment>%-${width}s</comment>] %s", $key, $value));
|
||||
}
|
||||
}
|
||||
|
||||
$output->write(' > ');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function writeError(OutputInterface $output, \Exception $error)
|
||||
{
|
||||
if ($output instanceof SymfonyStyle) {
|
||||
$output->newLine();
|
||||
$output->error($error->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
parent::writeError($output, $error);
|
||||
}
|
||||
}
|
808
vendor/symfony/console/Helper/Table.php
vendored
Normal file
808
vendor/symfony/console/Helper/Table.php
vendored
Normal file
|
@ -0,0 +1,808 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Provides helpers to display a table.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Саша Стаменковић <umpirsky@gmail.com>
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
* @author Max Grigorian <maxakawizard@gmail.com>
|
||||
* @author Dany Maillard <danymaillard93b@gmail.com>
|
||||
*/
|
||||
class Table
|
||||
{
|
||||
private const SEPARATOR_TOP = 0;
|
||||
private const SEPARATOR_TOP_BOTTOM = 1;
|
||||
private const SEPARATOR_MID = 2;
|
||||
private const SEPARATOR_BOTTOM = 3;
|
||||
private const BORDER_OUTSIDE = 0;
|
||||
private const BORDER_INSIDE = 1;
|
||||
|
||||
private $headerTitle;
|
||||
private $footerTitle;
|
||||
|
||||
/**
|
||||
* Table headers.
|
||||
*/
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* Table rows.
|
||||
*/
|
||||
private $rows = [];
|
||||
|
||||
/**
|
||||
* Column widths cache.
|
||||
*/
|
||||
private $effectiveColumnWidths = [];
|
||||
|
||||
/**
|
||||
* Number of columns cache.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $numberOfColumns;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* @var TableStyle
|
||||
*/
|
||||
private $style;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $columnStyles = [];
|
||||
|
||||
/**
|
||||
* User set column widths.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $columnWidths = [];
|
||||
private $columnMaxWidths = [];
|
||||
|
||||
private static $styles;
|
||||
|
||||
private $rendered = false;
|
||||
|
||||
public function __construct(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
if (!self::$styles) {
|
||||
self::$styles = self::initStyles();
|
||||
}
|
||||
|
||||
$this->setStyle('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a style definition.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param TableStyle $style A TableStyle instance
|
||||
*/
|
||||
public static function setStyleDefinition($name, TableStyle $style)
|
||||
{
|
||||
if (!self::$styles) {
|
||||
self::$styles = self::initStyles();
|
||||
}
|
||||
|
||||
self::$styles[$name] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a style definition by name.
|
||||
*
|
||||
* @param string $name The style name
|
||||
*
|
||||
* @return TableStyle
|
||||
*/
|
||||
public static function getStyleDefinition($name)
|
||||
{
|
||||
if (!self::$styles) {
|
||||
self::$styles = self::initStyles();
|
||||
}
|
||||
|
||||
if (isset(self::$styles[$name])) {
|
||||
return self::$styles[$name];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table style.
|
||||
*
|
||||
* @param TableStyle|string $name The style name or a TableStyle instance
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStyle($name)
|
||||
{
|
||||
$this->style = $this->resolveStyle($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current table style.
|
||||
*
|
||||
* @return TableStyle
|
||||
*/
|
||||
public function getStyle()
|
||||
{
|
||||
return $this->style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table column style.
|
||||
*
|
||||
* @param int $columnIndex Column index
|
||||
* @param TableStyle|string $name The style name or a TableStyle instance
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumnStyle($columnIndex, $name)
|
||||
{
|
||||
$columnIndex = (int) $columnIndex;
|
||||
|
||||
$this->columnStyles[$columnIndex] = $this->resolveStyle($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current style for a column.
|
||||
*
|
||||
* If style was not set, it returns the global table style.
|
||||
*
|
||||
* @param int $columnIndex Column index
|
||||
*
|
||||
* @return TableStyle
|
||||
*/
|
||||
public function getColumnStyle($columnIndex)
|
||||
{
|
||||
return $this->columnStyles[$columnIndex] ?? $this->getStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum width of a column.
|
||||
*
|
||||
* @param int $columnIndex Column index
|
||||
* @param int $width Minimum column width in characters
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumnWidth($columnIndex, $width)
|
||||
{
|
||||
$this->columnWidths[(int) $columnIndex] = (int) $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum width of all columns.
|
||||
*
|
||||
* @param array $widths
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumnWidths(array $widths)
|
||||
{
|
||||
$this->columnWidths = [];
|
||||
foreach ($widths as $index => $width) {
|
||||
$this->setColumnWidth($index, $width);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum width of a column.
|
||||
*
|
||||
* Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while
|
||||
* formatted strings are preserved.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumnMaxWidth(int $columnIndex, int $width): self
|
||||
{
|
||||
if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
|
||||
throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_class($this->output->getFormatter())));
|
||||
}
|
||||
|
||||
$this->columnMaxWidths[$columnIndex] = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeaders(array $headers)
|
||||
{
|
||||
$headers = array_values($headers);
|
||||
if (!empty($headers) && !\is_array($headers[0])) {
|
||||
$headers = [$headers];
|
||||
}
|
||||
|
||||
$this->headers = $headers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRows(array $rows)
|
||||
{
|
||||
$this->rows = [];
|
||||
|
||||
return $this->addRows($rows);
|
||||
}
|
||||
|
||||
public function addRows(array $rows)
|
||||
{
|
||||
foreach ($rows as $row) {
|
||||
$this->addRow($row);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addRow($row)
|
||||
{
|
||||
if ($row instanceof TableSeparator) {
|
||||
$this->rows[] = $row;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!\is_array($row)) {
|
||||
throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
|
||||
}
|
||||
|
||||
$this->rows[] = array_values($row);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a row to the table, and re-renders the table.
|
||||
*/
|
||||
public function appendRow($row): self
|
||||
{
|
||||
if (!$this->output instanceof ConsoleSectionOutput) {
|
||||
throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
|
||||
}
|
||||
|
||||
if ($this->rendered) {
|
||||
$this->output->clear($this->calculateRowCount());
|
||||
}
|
||||
|
||||
$this->addRow($row);
|
||||
$this->render();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRow($column, array $row)
|
||||
{
|
||||
$this->rows[$column] = $row;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeaderTitle(?string $title): self
|
||||
{
|
||||
$this->headerTitle = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFooterTitle(?string $title): self
|
||||
{
|
||||
$this->footerTitle = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders table to output.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* +---------------+-----------------------+------------------+
|
||||
* | ISBN | Title | Author |
|
||||
* +---------------+-----------------------+------------------+
|
||||
* | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
|
||||
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||
* | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
|
||||
* +---------------+-----------------------+------------------+
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$rows = array_merge($this->headers, [$divider = new TableSeparator()], $this->rows);
|
||||
$this->calculateNumberOfColumns($rows);
|
||||
|
||||
$rows = $this->buildTableRows($rows);
|
||||
$this->calculateColumnsWidth($rows);
|
||||
|
||||
$isHeader = true;
|
||||
$isFirstRow = false;
|
||||
foreach ($rows as $row) {
|
||||
if ($divider === $row) {
|
||||
$isHeader = false;
|
||||
$isFirstRow = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($row instanceof TableSeparator) {
|
||||
$this->renderRowSeparator();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!$row) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isHeader || $isFirstRow) {
|
||||
if ($isFirstRow) {
|
||||
$this->renderRowSeparator(self::SEPARATOR_TOP_BOTTOM);
|
||||
$isFirstRow = false;
|
||||
} else {
|
||||
$this->renderRowSeparator(self::SEPARATOR_TOP, $this->headerTitle, $this->style->getHeaderTitleFormat());
|
||||
}
|
||||
}
|
||||
|
||||
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
|
||||
}
|
||||
$this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
|
||||
|
||||
$this->cleanup();
|
||||
$this->rendered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders horizontal header separator.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* +-----+-----------+-------+
|
||||
*/
|
||||
private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null)
|
||||
{
|
||||
if (0 === $count = $this->numberOfColumns) {
|
||||
return;
|
||||
}
|
||||
|
||||
$borders = $this->style->getBorderChars();
|
||||
if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$crossings = $this->style->getCrossingChars();
|
||||
if (self::SEPARATOR_MID === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
|
||||
} elseif (self::SEPARATOR_TOP === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
|
||||
} elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
|
||||
} else {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
|
||||
}
|
||||
|
||||
$markup = $leftChar;
|
||||
for ($column = 0; $column < $count; ++$column) {
|
||||
$markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
|
||||
$markup .= $column === $count - 1 ? $rightChar : $midChar;
|
||||
}
|
||||
|
||||
if (null !== $title) {
|
||||
$titleLength = Helper::strlenWithoutDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title));
|
||||
$markupLength = Helper::strlen($markup);
|
||||
if ($titleLength > $limit = $markupLength - 4) {
|
||||
$titleLength = $limit;
|
||||
$formatLength = Helper::strlenWithoutDecoration($formatter, sprintf($titleFormat, ''));
|
||||
$formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
|
||||
}
|
||||
|
||||
$titleStart = ($markupLength - $titleLength) / 2;
|
||||
if (false === mb_detect_encoding($markup, null, true)) {
|
||||
$markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
|
||||
} else {
|
||||
$markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength);
|
||||
}
|
||||
}
|
||||
|
||||
$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders vertical column separator.
|
||||
*/
|
||||
private function renderColumnSeparator($type = self::BORDER_OUTSIDE)
|
||||
{
|
||||
$borders = $this->style->getBorderChars();
|
||||
|
||||
return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders table row.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||
*/
|
||||
private function renderRow(array $row, string $cellFormat)
|
||||
{
|
||||
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
|
||||
$columns = $this->getRowColumns($row);
|
||||
$last = \count($columns) - 1;
|
||||
foreach ($columns as $i => $column) {
|
||||
$rowContent .= $this->renderCell($row, $column, $cellFormat);
|
||||
$rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
|
||||
}
|
||||
$this->output->writeln($rowContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders table cell with padding.
|
||||
*/
|
||||
private function renderCell(array $row, int $column, string $cellFormat)
|
||||
{
|
||||
$cell = isset($row[$column]) ? $row[$column] : '';
|
||||
$width = $this->effectiveColumnWidths[$column];
|
||||
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||
// add the width of the following columns(numbers of colspan).
|
||||
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
|
||||
$width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
|
||||
}
|
||||
}
|
||||
|
||||
// str_pad won't work properly with multi-byte strings, we need to fix the padding
|
||||
if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
|
||||
$width += \strlen($cell) - mb_strwidth($cell, $encoding);
|
||||
}
|
||||
|
||||
$style = $this->getColumnStyle($column);
|
||||
|
||||
if ($cell instanceof TableSeparator) {
|
||||
return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));
|
||||
}
|
||||
|
||||
$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
||||
$content = sprintf($style->getCellRowContentFormat(), $cell);
|
||||
|
||||
return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of columns for this table.
|
||||
*/
|
||||
private function calculateNumberOfColumns($rows)
|
||||
{
|
||||
$columns = [0];
|
||||
foreach ($rows as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columns[] = $this->getNumberOfColumns($row);
|
||||
}
|
||||
|
||||
$this->numberOfColumns = max($columns);
|
||||
}
|
||||
|
||||
private function buildTableRows($rows)
|
||||
{
|
||||
/** @var WrappableOutputFormatterInterface $formatter */
|
||||
$formatter = $this->output->getFormatter();
|
||||
$unmergedRows = [];
|
||||
for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
|
||||
$rows = $this->fillNextRows($rows, $rowKey);
|
||||
|
||||
// Remove any new line breaks and replace it with a new line
|
||||
foreach ($rows[$rowKey] as $column => $cell) {
|
||||
if (isset($this->columnMaxWidths[$column]) && Helper::strlenWithoutDecoration($formatter, $cell) > $this->columnMaxWidths[$column]) {
|
||||
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column]);
|
||||
}
|
||||
if (!strstr($cell, "\n")) {
|
||||
continue;
|
||||
}
|
||||
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
|
||||
foreach ($lines as $lineKey => $line) {
|
||||
if ($cell instanceof TableCell) {
|
||||
$line = new TableCell($line, ['colspan' => $cell->getColspan()]);
|
||||
}
|
||||
if (0 === $lineKey) {
|
||||
$rows[$rowKey][$column] = $line;
|
||||
} else {
|
||||
$unmergedRows[$rowKey][$lineKey][$column] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TableRows(function () use ($rows, $unmergedRows) {
|
||||
foreach ($rows as $rowKey => $row) {
|
||||
yield $this->fillCells($row);
|
||||
|
||||
if (isset($unmergedRows[$rowKey])) {
|
||||
foreach ($unmergedRows[$rowKey] as $row) {
|
||||
yield $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function calculateRowCount(): int
|
||||
{
|
||||
$numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));
|
||||
|
||||
if ($this->headers) {
|
||||
++$numberOfRows; // Add row for header separator
|
||||
}
|
||||
|
||||
++$numberOfRows; // Add row for footer separator
|
||||
|
||||
return $numberOfRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill rows that contains rowspan > 1.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function fillNextRows(array $rows, int $line): array
|
||||
{
|
||||
$unmergedRows = [];
|
||||
foreach ($rows[$line] as $column => $cell) {
|
||||
if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
|
||||
throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing __toString, %s given.', \gettype($cell)));
|
||||
}
|
||||
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
|
||||
$nbLines = $cell->getRowspan() - 1;
|
||||
$lines = [$cell];
|
||||
if (strstr($cell, "\n")) {
|
||||
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
|
||||
$nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
|
||||
|
||||
$rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
|
||||
unset($lines[0]);
|
||||
}
|
||||
|
||||
// create a two dimensional array (rowspan x colspan)
|
||||
$unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
|
||||
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
|
||||
$value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
|
||||
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
|
||||
if ($nbLines === $unmergedRowKey - $line) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
|
||||
// we need to know if $unmergedRow will be merged or inserted into $rows
|
||||
if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
|
||||
foreach ($unmergedRow as $cellKey => $cell) {
|
||||
// insert cell into row at cellKey position
|
||||
array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
|
||||
}
|
||||
} else {
|
||||
$row = $this->copyRow($rows, $unmergedRowKey - 1);
|
||||
foreach ($unmergedRow as $column => $cell) {
|
||||
if (!empty($cell)) {
|
||||
$row[$column] = $unmergedRow[$column];
|
||||
}
|
||||
}
|
||||
array_splice($rows, $unmergedRowKey, 0, [$row]);
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill cells for a row that contains colspan > 1.
|
||||
*/
|
||||
private function fillCells($row)
|
||||
{
|
||||
$newRow = [];
|
||||
foreach ($row as $column => $cell) {
|
||||
$newRow[] = $cell;
|
||||
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
|
||||
// insert empty value at column position
|
||||
$newRow[] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $newRow ?: $row;
|
||||
}
|
||||
|
||||
private function copyRow(array $rows, int $line): array
|
||||
{
|
||||
$row = $rows[$line];
|
||||
foreach ($row as $cellKey => $cellValue) {
|
||||
$row[$cellKey] = '';
|
||||
if ($cellValue instanceof TableCell) {
|
||||
$row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
|
||||
}
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of columns by row.
|
||||
*/
|
||||
private function getNumberOfColumns(array $row): int
|
||||
{
|
||||
$columns = \count($row);
|
||||
foreach ($row as $column) {
|
||||
$columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of columns for the given row.
|
||||
*/
|
||||
private function getRowColumns(array $row): array
|
||||
{
|
||||
$columns = range(0, $this->numberOfColumns - 1);
|
||||
foreach ($row as $cellKey => $cell) {
|
||||
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||
// exclude grouped columns.
|
||||
$columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates columns widths.
|
||||
*/
|
||||
private function calculateColumnsWidth(iterable $rows)
|
||||
{
|
||||
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
|
||||
$lengths = [];
|
||||
foreach ($rows as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($row as $i => $cell) {
|
||||
if ($cell instanceof TableCell) {
|
||||
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
|
||||
$textLength = Helper::strlen($textContent);
|
||||
if ($textLength > 0) {
|
||||
$contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
|
||||
foreach ($contentColumns as $position => $content) {
|
||||
$row[$i + $position] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$lengths[] = $this->getCellWidth($row, $column);
|
||||
}
|
||||
|
||||
$this->effectiveColumnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
|
||||
}
|
||||
}
|
||||
|
||||
private function getColumnSeparatorWidth(): int
|
||||
{
|
||||
return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
|
||||
}
|
||||
|
||||
private function getCellWidth(array $row, int $column): int
|
||||
{
|
||||
$cellWidth = 0;
|
||||
|
||||
if (isset($row[$column])) {
|
||||
$cell = $row[$column];
|
||||
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
||||
}
|
||||
|
||||
$columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0;
|
||||
$cellWidth = max($cellWidth, $columnWidth);
|
||||
|
||||
return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after rendering to cleanup cache data.
|
||||
*/
|
||||
private function cleanup()
|
||||
{
|
||||
$this->effectiveColumnWidths = [];
|
||||
$this->numberOfColumns = null;
|
||||
}
|
||||
|
||||
private static function initStyles()
|
||||
{
|
||||
$borderless = new TableStyle();
|
||||
$borderless
|
||||
->setHorizontalBorderChars('=')
|
||||
->setVerticalBorderChars(' ')
|
||||
->setDefaultCrossingChar(' ')
|
||||
;
|
||||
|
||||
$compact = new TableStyle();
|
||||
$compact
|
||||
->setHorizontalBorderChars('')
|
||||
->setVerticalBorderChars(' ')
|
||||
->setDefaultCrossingChar('')
|
||||
->setCellRowContentFormat('%s')
|
||||
;
|
||||
|
||||
$styleGuide = new TableStyle();
|
||||
$styleGuide
|
||||
->setHorizontalBorderChars('-')
|
||||
->setVerticalBorderChars(' ')
|
||||
->setDefaultCrossingChar(' ')
|
||||
->setCellHeaderFormat('%s')
|
||||
;
|
||||
|
||||
$box = (new TableStyle())
|
||||
->setHorizontalBorderChars('─')
|
||||
->setVerticalBorderChars('│')
|
||||
->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├')
|
||||
;
|
||||
|
||||
$boxDouble = (new TableStyle())
|
||||
->setHorizontalBorderChars('═', '─')
|
||||
->setVerticalBorderChars('║', '│')
|
||||
->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣')
|
||||
;
|
||||
|
||||
return [
|
||||
'default' => new TableStyle(),
|
||||
'borderless' => $borderless,
|
||||
'compact' => $compact,
|
||||
'symfony-style-guide' => $styleGuide,
|
||||
'box' => $box,
|
||||
'box-double' => $boxDouble,
|
||||
];
|
||||
}
|
||||
|
||||
private function resolveStyle($name)
|
||||
{
|
||||
if ($name instanceof TableStyle) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if (isset(self::$styles[$name])) {
|
||||
return self::$styles[$name];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
|
||||
}
|
||||
}
|
68
vendor/symfony/console/Helper/TableCell.php
vendored
Normal file
68
vendor/symfony/console/Helper/TableCell.php
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class TableCell
|
||||
{
|
||||
private $value;
|
||||
private $options = [
|
||||
'rowspan' => 1,
|
||||
'colspan' => 1,
|
||||
];
|
||||
|
||||
public function __construct(string $value = '', array $options = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
// check option names
|
||||
if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
|
||||
throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
|
||||
}
|
||||
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cell value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of colspan.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getColspan()
|
||||
{
|
||||
return (int) $this->options['colspan'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of rowspan.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRowspan()
|
||||
{
|
||||
return (int) $this->options['rowspan'];
|
||||
}
|
||||
}
|
32
vendor/symfony/console/Helper/TableRows.php
vendored
Normal file
32
vendor/symfony/console/Helper/TableRows.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class TableRows implements \IteratorAggregate
|
||||
{
|
||||
private $generator;
|
||||
|
||||
public function __construct(callable $generator)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
$g = $this->generator;
|
||||
|
||||
return $g();
|
||||
}
|
||||
}
|
25
vendor/symfony/console/Helper/TableSeparator.php
vendored
Normal file
25
vendor/symfony/console/Helper/TableSeparator.php
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/**
|
||||
* Marks a row as being a separator.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class TableSeparator extends TableCell
|
||||
{
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
parent::__construct('', $options);
|
||||
}
|
||||
}
|
458
vendor/symfony/console/Helper/TableStyle.php
vendored
Normal file
458
vendor/symfony/console/Helper/TableStyle.php
vendored
Normal file
|
@ -0,0 +1,458 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* Defines the styles for a Table.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Саша Стаменковић <umpirsky@gmail.com>
|
||||
* @author Dany Maillard <danymaillard93b@gmail.com>
|
||||
*/
|
||||
class TableStyle
|
||||
{
|
||||
private $paddingChar = ' ';
|
||||
private $horizontalOutsideBorderChar = '-';
|
||||
private $horizontalInsideBorderChar = '-';
|
||||
private $verticalOutsideBorderChar = '|';
|
||||
private $verticalInsideBorderChar = '|';
|
||||
private $crossingChar = '+';
|
||||
private $crossingTopRightChar = '+';
|
||||
private $crossingTopMidChar = '+';
|
||||
private $crossingTopLeftChar = '+';
|
||||
private $crossingMidRightChar = '+';
|
||||
private $crossingBottomRightChar = '+';
|
||||
private $crossingBottomMidChar = '+';
|
||||
private $crossingBottomLeftChar = '+';
|
||||
private $crossingMidLeftChar = '+';
|
||||
private $crossingTopLeftBottomChar = '+';
|
||||
private $crossingTopMidBottomChar = '+';
|
||||
private $crossingTopRightBottomChar = '+';
|
||||
private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
|
||||
private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
|
||||
private $cellHeaderFormat = '<info>%s</info>';
|
||||
private $cellRowFormat = '%s';
|
||||
private $cellRowContentFormat = ' %s ';
|
||||
private $borderFormat = '%s';
|
||||
private $padType = STR_PAD_RIGHT;
|
||||
|
||||
/**
|
||||
* Sets padding character, used for cell padding.
|
||||
*
|
||||
* @param string $paddingChar
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPaddingChar($paddingChar)
|
||||
{
|
||||
if (!$paddingChar) {
|
||||
throw new LogicException('The padding char must not be empty');
|
||||
}
|
||||
|
||||
$this->paddingChar = $paddingChar;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets padding character, used for cell padding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaddingChar()
|
||||
{
|
||||
return $this->paddingChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets horizontal border characters.
|
||||
*
|
||||
* <code>
|
||||
* ╔═══════════════╤══════════════════════════╤══════════════════╗
|
||||
* 1 ISBN 2 Title │ Author ║
|
||||
* ╠═══════════════╪══════════════════════════╪══════════════════╣
|
||||
* ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
|
||||
* ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
|
||||
* ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
|
||||
* ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
|
||||
* ╚═══════════════╧══════════════════════════╧══════════════════╝
|
||||
* </code>
|
||||
*
|
||||
* @param string $outside Outside border char (see #1 of example)
|
||||
* @param string|null $inside Inside border char (see #2 of example), equals $outside if null
|
||||
*/
|
||||
public function setHorizontalBorderChars(string $outside, string $inside = null): self
|
||||
{
|
||||
$this->horizontalOutsideBorderChar = $outside;
|
||||
$this->horizontalInsideBorderChar = $inside ?? $outside;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets horizontal border character.
|
||||
*
|
||||
* @param string $horizontalBorderChar
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated since Symfony 4.1, use {@link setHorizontalBorderChars()} instead.
|
||||
*/
|
||||
public function setHorizontalBorderChar($horizontalBorderChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets horizontal border character.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
|
||||
*/
|
||||
public function getHorizontalBorderChar()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->horizontalOutsideBorderChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets vertical border characters.
|
||||
*
|
||||
* <code>
|
||||
* ╔═══════════════╤══════════════════════════╤══════════════════╗
|
||||
* ║ ISBN │ Title │ Author ║
|
||||
* ╠═══════1═══════╪══════════════════════════╪══════════════════╣
|
||||
* ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
|
||||
* ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
|
||||
* ╟───────2───────┼──────────────────────────┼──────────────────╢
|
||||
* ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
|
||||
* ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
|
||||
* ╚═══════════════╧══════════════════════════╧══════════════════╝
|
||||
* </code>
|
||||
*
|
||||
* @param string $outside Outside border char (see #1 of example)
|
||||
* @param string|null $inside Inside border char (see #2 of example), equals $outside if null
|
||||
*/
|
||||
public function setVerticalBorderChars(string $outside, string $inside = null): self
|
||||
{
|
||||
$this->verticalOutsideBorderChar = $outside;
|
||||
$this->verticalInsideBorderChar = $inside ?? $outside;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets vertical border character.
|
||||
*
|
||||
* @param string $verticalBorderChar
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated since Symfony 4.1, use {@link setVerticalBorderChars()} instead.
|
||||
*/
|
||||
public function setVerticalBorderChar($verticalBorderChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets vertical border character.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
|
||||
*/
|
||||
public function getVerticalBorderChar()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->verticalOutsideBorderChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets border characters.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getBorderChars()
|
||||
{
|
||||
return [
|
||||
$this->horizontalOutsideBorderChar,
|
||||
$this->verticalOutsideBorderChar,
|
||||
$this->horizontalInsideBorderChar,
|
||||
$this->verticalInsideBorderChar,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets crossing characters.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* 1═══════════════2══════════════════════════2══════════════════3
|
||||
* ║ ISBN │ Title │ Author ║
|
||||
* 8'══════════════0'═════════════════════════0'═════════════════4'
|
||||
* ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║
|
||||
* ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║
|
||||
* 8───────────────0──────────────────────────0──────────────────4
|
||||
* ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║
|
||||
* ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║
|
||||
* 7═══════════════6══════════════════════════6══════════════════5
|
||||
* </code>
|
||||
*
|
||||
* @param string $cross Crossing char (see #0 of example)
|
||||
* @param string $topLeft Top left char (see #1 of example)
|
||||
* @param string $topMid Top mid char (see #2 of example)
|
||||
* @param string $topRight Top right char (see #3 of example)
|
||||
* @param string $midRight Mid right char (see #4 of example)
|
||||
* @param string $bottomRight Bottom right char (see #5 of example)
|
||||
* @param string $bottomMid Bottom mid char (see #6 of example)
|
||||
* @param string $bottomLeft Bottom left char (see #7 of example)
|
||||
* @param string $midLeft Mid left char (see #8 of example)
|
||||
* @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null
|
||||
* @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null
|
||||
* @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null
|
||||
*/
|
||||
public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): self
|
||||
{
|
||||
$this->crossingChar = $cross;
|
||||
$this->crossingTopLeftChar = $topLeft;
|
||||
$this->crossingTopMidChar = $topMid;
|
||||
$this->crossingTopRightChar = $topRight;
|
||||
$this->crossingMidRightChar = $midRight;
|
||||
$this->crossingBottomRightChar = $bottomRight;
|
||||
$this->crossingBottomMidChar = $bottomMid;
|
||||
$this->crossingBottomLeftChar = $bottomLeft;
|
||||
$this->crossingMidLeftChar = $midLeft;
|
||||
$this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
|
||||
$this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
|
||||
$this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default crossing character used for each cross.
|
||||
*
|
||||
* @see {@link setCrossingChars()} for setting each crossing individually.
|
||||
*/
|
||||
public function setDefaultCrossingChar(string $char): self
|
||||
{
|
||||
return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets crossing character.
|
||||
*
|
||||
* @param string $crossingChar
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated since Symfony 4.1. Use {@link setDefaultCrossingChar()} instead.
|
||||
*/
|
||||
public function setCrossingChar($crossingChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->setDefaultCrossingChar($crossingChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets crossing character.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCrossingChar()
|
||||
{
|
||||
return $this->crossingChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets crossing characters.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getCrossingChars(): array
|
||||
{
|
||||
return [
|
||||
$this->crossingChar,
|
||||
$this->crossingTopLeftChar,
|
||||
$this->crossingTopMidChar,
|
||||
$this->crossingTopRightChar,
|
||||
$this->crossingMidRightChar,
|
||||
$this->crossingBottomRightChar,
|
||||
$this->crossingBottomMidChar,
|
||||
$this->crossingBottomLeftChar,
|
||||
$this->crossingMidLeftChar,
|
||||
$this->crossingTopLeftBottomChar,
|
||||
$this->crossingTopMidBottomChar,
|
||||
$this->crossingTopRightBottomChar,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets header cell format.
|
||||
*
|
||||
* @param string $cellHeaderFormat
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCellHeaderFormat($cellHeaderFormat)
|
||||
{
|
||||
$this->cellHeaderFormat = $cellHeaderFormat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets header cell format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCellHeaderFormat()
|
||||
{
|
||||
return $this->cellHeaderFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets row cell format.
|
||||
*
|
||||
* @param string $cellRowFormat
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCellRowFormat($cellRowFormat)
|
||||
{
|
||||
$this->cellRowFormat = $cellRowFormat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets row cell format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCellRowFormat()
|
||||
{
|
||||
return $this->cellRowFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets row cell content format.
|
||||
*
|
||||
* @param string $cellRowContentFormat
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCellRowContentFormat($cellRowContentFormat)
|
||||
{
|
||||
$this->cellRowContentFormat = $cellRowContentFormat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets row cell content format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCellRowContentFormat()
|
||||
{
|
||||
return $this->cellRowContentFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table border format.
|
||||
*
|
||||
* @param string $borderFormat
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBorderFormat($borderFormat)
|
||||
{
|
||||
$this->borderFormat = $borderFormat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets table border format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBorderFormat()
|
||||
{
|
||||
return $this->borderFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cell padding type.
|
||||
*
|
||||
* @param int $padType STR_PAD_*
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPadType($padType)
|
||||
{
|
||||
if (!\in_array($padType, [STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH], true)) {
|
||||
throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
|
||||
}
|
||||
|
||||
$this->padType = $padType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets cell padding type.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPadType()
|
||||
{
|
||||
return $this->padType;
|
||||
}
|
||||
|
||||
public function getHeaderTitleFormat(): string
|
||||
{
|
||||
return $this->headerTitleFormat;
|
||||
}
|
||||
|
||||
public function setHeaderTitleFormat(string $format): self
|
||||
{
|
||||
$this->headerTitleFormat = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFooterTitleFormat(): string
|
||||
{
|
||||
return $this->footerTitleFormat;
|
||||
}
|
||||
|
||||
public function setFooterTitleFormat(string $format): self
|
||||
{
|
||||
$this->footerTitleFormat = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue