From 5a75d6725d27e2feba90c02986ec2d4429d10e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 12:17:23 +0800 Subject: [PATCH 01/79] Optimized code. --- src/snowflake/publish/snowflake.php | 1 - src/snowflake/src/Config.php | 74 +++++++++++++ src/snowflake/src/ConfigInterface.php | 36 ++++++ src/snowflake/src/ConfigProvider.php | 5 +- src/snowflake/src/IdGenerator.php | 68 ++++++++++++ .../IdGenerator/MilliSecondIdGenerator.php | 36 ++++++ src/snowflake/src/IdGeneratorInterface.php | 4 - src/snowflake/src/Meta.php | 76 ++++--------- src/snowflake/src/MetaGenerator.php | 61 ++++++++++ .../RandomMilliSecondMetaGenerator.php | 43 ++++++++ src/snowflake/src/RandomMetaGenerator.php | 28 ----- src/snowflake/src/Snowflake.php | 104 ------------------ src/snowflake/src/SnowflakeFactory.php | 7 +- src/snowflake/tests/GeneratorTest.php | 34 +++--- 14 files changed, 365 insertions(+), 212 deletions(-) create mode 100644 src/snowflake/src/Config.php create mode 100644 src/snowflake/src/ConfigInterface.php create mode 100644 src/snowflake/src/IdGenerator.php create mode 100644 src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php create mode 100644 src/snowflake/src/MetaGenerator.php create mode 100644 src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php delete mode 100644 src/snowflake/src/RandomMetaGenerator.php delete mode 100644 src/snowflake/src/Snowflake.php diff --git a/src/snowflake/publish/snowflake.php b/src/snowflake/publish/snowflake.php index 1cbc63960..f3cf354d1 100644 --- a/src/snowflake/publish/snowflake.php +++ b/src/snowflake/publish/snowflake.php @@ -13,6 +13,5 @@ declare(strict_types=1); use Hyperf\Snowflake\IdGeneratorInterface; return [ - 'level' => IdGeneratorInterface::LEVEL_MILLISECOND, 'begin_second' => IdGeneratorInterface::DEFAULT_SECOND, ]; diff --git a/src/snowflake/src/Config.php b/src/snowflake/src/Config.php new file mode 100644 index 000000000..e155a84ae --- /dev/null +++ b/src/snowflake/src/Config.php @@ -0,0 +1,74 @@ + [ IdGeneratorInterface::class => SnowflakeFactory::class, - MetaGeneratorInterface::class => RandomMetaGenerator::class, + MetaGeneratorInterface::class => RandomMilliSecondMetaGenerator::class, + ConfigInterface::class => Config::class, ], 'commands' => [ ], diff --git a/src/snowflake/src/IdGenerator.php b/src/snowflake/src/IdGenerator.php new file mode 100644 index 000000000..5259e714f --- /dev/null +++ b/src/snowflake/src/IdGenerator.php @@ -0,0 +1,68 @@ +metaGenerator = $metaGenerator; + $this->config = $config; + } + + abstract public function getBeginTimeStamp(): int; + + public function generate(?Meta $meta = null): int + { + $meta = $this->meta($meta); + + $timestamp = ($meta->timestamp - $this->getBeginTimeStamp()) << $this->config->getTimeStampShift(); + $dataCenterId = $meta->dataCenterId << $this->config->getDataCenterShift(); + $workerId = $meta->workerId << $this->config->getWorkerIdShift(); + + return $timestamp | $dataCenterId | $workerId | $meta->sequence; + } + + public function degenerate(int $id): Meta + { + $timestamp = $id >> $this->config->getTimeStampShift(); + $dataCenterId = $id >> $this->config->getDataCenterShift(); + $workerId = $id >> $this->config->getWorkerIdShift(); + + return new Meta( + $timestamp << $this->config->getDataCenterBits() ^ $dataCenterId, + $dataCenterId << $this->config->getWorkerBits() ^ $workerId, + $workerId << $this->config->getSequenceBits() ^ $id, + $timestamp + $this->getBeginTimeStamp() + ); + } + + protected function meta(?Meta $meta = null): Meta + { + if (is_null($meta)) { + return $this->metaGenerator->generate(); + } + + return $meta; + } +} diff --git a/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php b/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php new file mode 100644 index 000000000..78ed2a280 --- /dev/null +++ b/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php @@ -0,0 +1,36 @@ +beginTimeStamp = $beginTimeStamp * 1000; + parent::__construct($metaGenerator, $config); + } + + public function getBeginTimeStamp(): int + { + return $this->beginTimeStamp; + } +} diff --git a/src/snowflake/src/IdGeneratorInterface.php b/src/snowflake/src/IdGeneratorInterface.php index 00fc61ccb..fd22e7fa9 100644 --- a/src/snowflake/src/IdGeneratorInterface.php +++ b/src/snowflake/src/IdGeneratorInterface.php @@ -14,10 +14,6 @@ namespace Hyperf\Snowflake; interface IdGeneratorInterface extends \Hyperf\Contract\IdGeneratorInterface { - const LEVEL_SECOND = 1; - - const LEVEL_MILLISECOND = 2; - const DEFAULT_SECOND = 1565712000; public function generate(?Meta $meta = null): int; diff --git a/src/snowflake/src/Meta.php b/src/snowflake/src/Meta.php index cc582fa6b..63da0e257 100644 --- a/src/snowflake/src/Meta.php +++ b/src/snowflake/src/Meta.php @@ -16,30 +16,23 @@ use Hyperf\Snowflake\Exception\SnowflakeException; class Meta { + const MILLISECOND_BITS = 41; + + const DATA_CENTER_ID_BITS = 5; + + const MACHINE_ID_BITS = 5; + const SEQUENCE_BITS = 12; - const MILLISECOND_BITS = 39; - - const BUSINESS_ID_BITS = 4; - - const DATA_CENTER_ID_BITS = 2; - - const MACHINE_ID_BITS = 7; - /** - * @var int [0, 15] - */ - public $businessId; - - /** - * @var int [0, 3] + * @var int [0, 31] */ public $dataCenterId; /** - * @var int [0, 127] + * @var int [0, 31] */ - public $machineId; + public $workerId; /** * @var int [0, 4095] @@ -51,50 +44,21 @@ class Meta */ public $timestamp = 0; - public function __construct(int $businessId, int $dataCenterId, int $machineId, int $sequence) + public function __construct(int $dataCenterId, int $workerId, int $sequence, int $timestamp) { - if ($businessId < 0 || $businessId > $this->maxBusinessId()) { - throw new SnowflakeException('Business Id can\'t be greater than 15 or less than 0'); - } - if ($dataCenterId < 0 || $dataCenterId > $this->maxDataCenterId()) { - throw new SnowflakeException('DataCenter Id can\'t be greater than 4 or less than 0'); - } - if ($machineId < 0 || $machineId > $this->maxMachineId()) { - throw new SnowflakeException('Machine Id can\'t be greater than 128 or less than 0'); - } - if ($sequence < 0 || $sequence > $this->maxSequence()) { - throw new SnowflakeException('Sequence can\'t be greater than 4096 or less than 0'); - } + // if ($dataCenterId < 0 || $dataCenterId > $this->maxDataCenterId()) { + // throw new SnowflakeException('DataCenter Id can\'t be greater than 4 or less than 0'); + // } + // if ($machineId < 0 || $machineId > $this->maxMachineId()) { + // throw new SnowflakeException('Machine Id can\'t be greater than 128 or less than 0'); + // } + // if ($sequence < 0 || $sequence > $this->maxSequence()) { + // throw new SnowflakeException('Sequence can\'t be greater than 4096 or less than 0'); + // } - $this->businessId = $businessId; $this->dataCenterId = $dataCenterId; - $this->machineId = $machineId; + $this->workerId = $workerId; $this->sequence = $sequence; - } - - public function setTimestamp(int $timestamp): self - { $this->timestamp = $timestamp; - return $this; - } - - protected function maxMachineId(): int - { - return -1 ^ (-1 << self::MACHINE_ID_BITS); - } - - protected function maxDataCenterId(): int - { - return -1 ^ (-1 << self::DATA_CENTER_ID_BITS); - } - - protected function maxBusinessId(): int - { - return -1 ^ (-1 << self::BUSINESS_ID_BITS); - } - - protected function maxSequence(): int - { - return -1 ^ (-1 << self::SEQUENCE_BITS); } } diff --git a/src/snowflake/src/MetaGenerator.php b/src/snowflake/src/MetaGenerator.php new file mode 100644 index 000000000..21e9334cd --- /dev/null +++ b/src/snowflake/src/MetaGenerator.php @@ -0,0 +1,61 @@ +config = $config; + $this->lastTimeStamp = $this->getTimeStamp(); + } + + public function generate(): Meta + { + $timestamp = $this->getTimeStamp(); + + if ($timestamp < $this->lastTimeStamp) { + throw new SnowflakeException(sprintf('Clock moved backwards. Refusing to generate id for %d milliseconds', $this->lastTimeStamp - $timestamp)); + } + + if ($timestamp == $this->lastTimeStamp) { + $this->sequence = ($this->sequence + 1) % $this->config->maxSequence(); + if ($this->sequence == 0) { + $timestamp = $this->getNextTimeStamp(); + } + } else { + $this->sequence = 0; + } + + return new Meta($this->getDataCenterId(), $this->getWorkerId(), $this->sequence, $timestamp); + } + + abstract public function getDataCenterId(): int; + + abstract public function getWorkerId(): int; + + abstract public function getTimeStamp(): int; + + abstract public function getNextTimeStamp(): int; +} diff --git a/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php new file mode 100644 index 000000000..733bb8191 --- /dev/null +++ b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php @@ -0,0 +1,43 @@ +getTimeStamp(); + while ($timestamp <= $this->lastTimeStamp) { + $timestamp = $this->getTimeStamp(); + } + + return $timestamp; + } +} diff --git a/src/snowflake/src/RandomMetaGenerator.php b/src/snowflake/src/RandomMetaGenerator.php deleted file mode 100644 index 2b409bffe..000000000 --- a/src/snowflake/src/RandomMetaGenerator.php +++ /dev/null @@ -1,28 +0,0 @@ -sequence++) % 4096; - - return new Meta($businessId, $dataCenterId, $machineId, $sequence); - } -} diff --git a/src/snowflake/src/Snowflake.php b/src/snowflake/src/Snowflake.php deleted file mode 100644 index b96121788..000000000 --- a/src/snowflake/src/Snowflake.php +++ /dev/null @@ -1,104 +0,0 @@ -metaGenerator = $metaGenerator; - $this->level = $level; - $this->beginSecond = $level == self::LEVEL_SECOND ? $beginSecond : $beginSecond * 1000; - } - - public function generate(?Meta $meta = null): int - { - $meta = $this->meta($meta); - - $timestamp = $this->getTimestamp(); - - $timestamp = ($timestamp - $this->beginSecond) << $this->getTimestampShift(); - $businessId = $meta->businessId << $this->getBusinessIdShift(); - $dataCenterId = $meta->dataCenterId << $this->getDataCenterShift(); - $machineId = $meta->machineId << $this->getMachineIdShift(); - - return $timestamp | $businessId | $dataCenterId | $machineId | $meta->sequence; - } - - public function degenerate(int $id): Meta - { - $timestamp = $id >> $this->getTimestampShift(); - $businessId = $id >> $this->getBusinessIdShift(); - $dataCenterId = $id >> $this->getDataCenterShift(); - $machineId = $id >> $this->getMachineIdShift(); - - return (new Meta( - $timestamp << Meta::BUSINESS_ID_BITS ^ $businessId, - $businessId << Meta::DATA_CENTER_ID_BITS ^ $dataCenterId, - $dataCenterId << Meta::MACHINE_ID_BITS ^ $machineId, - $machineId << Meta::SEQUENCE_BITS ^ $id - ))->setTimestamp($timestamp + $this->beginSecond); - } - - protected function getTimestampShift(): int - { - return Meta::SEQUENCE_BITS + Meta::MACHINE_ID_BITS + Meta::DATA_CENTER_ID_BITS + Meta::BUSINESS_ID_BITS; - } - - protected function getBusinessIdShift(): int - { - return Meta::SEQUENCE_BITS + Meta::MACHINE_ID_BITS + Meta::DATA_CENTER_ID_BITS; - } - - protected function getDataCenterShift(): int - { - return Meta::SEQUENCE_BITS + Meta::MACHINE_ID_BITS; - } - - protected function getMachineIdShift(): int - { - return Meta::SEQUENCE_BITS; - } - - protected function getTimestamp(): int - { - if ($this->level == self::LEVEL_SECOND) { - return time(); - } - return intval(microtime(true) * 1000); - } - - protected function meta(?Meta $meta = null): Meta - { - if (is_null($meta)) { - return $this->metaGenerator->generate(); - } - - return $meta; - } -} diff --git a/src/snowflake/src/SnowflakeFactory.php b/src/snowflake/src/SnowflakeFactory.php index 1ce8b0b55..45bbaf17f 100644 --- a/src/snowflake/src/SnowflakeFactory.php +++ b/src/snowflake/src/SnowflakeFactory.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Snowflake; use Hyperf\Contract\ConfigInterface; +use Hyperf\Snowflake\IdGenerator\MilliSecondIdGenerator; use Psr\Container\ContainerInterface; class SnowflakeFactory @@ -20,12 +21,10 @@ class SnowflakeFactory public function __invoke(ContainerInterface $container) { $config = $container->get(ConfigInterface::class); - $level = $config->get('snowflake.level', IdGeneratorInterface::LEVEL_MILLISECOND); $beginSecond = $config->get('snowflake.begin_second', IdGeneratorInterface::DEFAULT_SECOND); - return make(Snowflake::class, [ - 'level' => $level, - 'beginSecond' => $beginSecond, + return make(MilliSecondIdGenerator::class, [ + 'beginTimeStamp' => $beginSecond, ]); } } diff --git a/src/snowflake/tests/GeneratorTest.php b/src/snowflake/tests/GeneratorTest.php index 5a9c5de45..5b29e5469 100644 --- a/src/snowflake/tests/GeneratorTest.php +++ b/src/snowflake/tests/GeneratorTest.php @@ -12,7 +12,10 @@ declare(strict_types=1); namespace HyperfTest\Snowflake; +use Hyperf\Snowflake\Config; +use Hyperf\Snowflake\IdGenerator\MilliSecondIdGenerator; use Hyperf\Snowflake\Meta; +use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; use Hyperf\Snowflake\RandomMetaGenerator; use Hyperf\Snowflake\Snowflake; use PHPUnit\Framework\TestCase; @@ -25,13 +28,15 @@ class GeneratorTest extends TestCase { public function testGenerateReturnInt() { - $generator = new Snowflake(new RandomMetaGenerator()); + $config = new Config(); + $generator = new MilliSecondIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); $this->assertTrue(is_int($generator->generate())); } public function testDegenerateInstanceofMeta() { - $generator = new Snowflake(new RandomMetaGenerator()); + $config = new Config(); + $generator = new MilliSecondIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); $id = $generator->generate(); @@ -40,27 +45,28 @@ class GeneratorTest extends TestCase public function testGenerateAndDegenerate() { - $metaGenerator = new RandomMetaGenerator(); - $generator = new Snowflake($metaGenerator); + $config = new Config(); + $metaGenerator = new RandomMilliSecondMetaGenerator($config); + $generator = new MilliSecondIdGenerator($metaGenerator, $config); $meta = $metaGenerator->generate(); $id = $generator->generate($meta); - $this->assertEquals($meta, $generator->degenerate($id)->setTimestamp(0)); - - $id = $generator->generate(); - $this->assertEquals($meta->sequence + 1, $generator->degenerate($id)->sequence); + $this->assertEquals($meta, $generator->degenerate($id)); } public function testDegenerateMaxId() { - $generator = new Snowflake(new RandomMetaGenerator(), Snowflake::LEVEL_SECOND, 0); + $config = new Config(); + $metaGenerator = new RandomMilliSecondMetaGenerator($config); + $generator = new MilliSecondIdGenerator($metaGenerator, $config); + $meta = $generator->degenerate(PHP_INT_MAX); $days = intval(($meta->timestamp) / (3600 * 24 * 1000)); - $this->assertSame(3181, $days); + $this->assertSame(43573, $days); - $generator = new Snowflake(new RandomMetaGenerator(), Snowflake::LEVEL_SECOND, 0); - $meta = $generator->degenerate(PHP_INT_MAX); - $years = intval($meta->timestamp / (3600 * 24 * 365)); - $this->assertSame(8716, $years); + // $generator = new Snowflake(new RandomMetaGenerator(), Snowflake::LEVEL_SECOND, 0); + // $meta = $generator->degenerate(PHP_INT_MAX); + // $years = intval($meta->timestamp / (3600 * 24 * 365)); + // $this->assertSame(8716, $years); } } From 5c8f71b593098053ad5fbec19523627e99f67cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 13:45:43 +0800 Subject: [PATCH 02/79] Optimized code. --- src/snowflake/publish/snowflake.php | 4 +- src/snowflake/src/ConfigProvider.php | 6 +- src/snowflake/src/IdGenerator.php | 17 ++--- .../IdGenerator/MilliSecondIdGenerator.php | 36 --------- .../src/IdGenerator/SnowflakeIdGenerator.php | 19 +++++ src/snowflake/src/IdGeneratorInterface.php | 2 - src/snowflake/src/Meta.php | 75 ++++++++++++++----- src/snowflake/src/MetaGenerator.php | 18 ++++- ...keFactory.php => MetaGeneratorFactory.php} | 8 +- src/snowflake/src/MetaGeneratorInterface.php | 4 + src/snowflake/tests/GeneratorTest.php | 14 ++-- 11 files changed, 119 insertions(+), 84 deletions(-) delete mode 100644 src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php create mode 100644 src/snowflake/src/IdGenerator/SnowflakeIdGenerator.php rename src/snowflake/src/{SnowflakeFactory.php => MetaGeneratorFactory.php} (67%) diff --git a/src/snowflake/publish/snowflake.php b/src/snowflake/publish/snowflake.php index f3cf354d1..2ea0515aa 100644 --- a/src/snowflake/publish/snowflake.php +++ b/src/snowflake/publish/snowflake.php @@ -10,8 +10,8 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -use Hyperf\Snowflake\IdGeneratorInterface; +use Hyperf\Snowflake\MetaGeneratorInterface; return [ - 'begin_second' => IdGeneratorInterface::DEFAULT_SECOND, + 'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND, ]; diff --git a/src/snowflake/src/ConfigProvider.php b/src/snowflake/src/ConfigProvider.php index 202b34a06..58c038e73 100644 --- a/src/snowflake/src/ConfigProvider.php +++ b/src/snowflake/src/ConfigProvider.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Hyperf\Snowflake; -use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; +use Hyperf\Snowflake\IdGenerator\SnowflakeIdGenerator; class ConfigProvider { @@ -20,8 +20,8 @@ class ConfigProvider { return [ 'dependencies' => [ - IdGeneratorInterface::class => SnowflakeFactory::class, - MetaGeneratorInterface::class => RandomMilliSecondMetaGenerator::class, + IdGeneratorInterface::class => SnowflakeIdGenerator::class, + MetaGeneratorInterface::class => MetaGeneratorFactory::class, ConfigInterface::class => Config::class, ], 'commands' => [ diff --git a/src/snowflake/src/IdGenerator.php b/src/snowflake/src/IdGenerator.php index 5259e714f..a8197c255 100644 --- a/src/snowflake/src/IdGenerator.php +++ b/src/snowflake/src/IdGenerator.php @@ -30,30 +30,29 @@ abstract class IdGenerator implements IdGeneratorInterface $this->config = $config; } - abstract public function getBeginTimeStamp(): int; - public function generate(?Meta $meta = null): int { $meta = $this->meta($meta); - $timestamp = ($meta->timestamp - $this->getBeginTimeStamp()) << $this->config->getTimeStampShift(); - $dataCenterId = $meta->dataCenterId << $this->config->getDataCenterShift(); - $workerId = $meta->workerId << $this->config->getWorkerIdShift(); + $interval = $meta->getTimeInterval() << $this->config->getTimeStampShift(); + $dataCenterId = $meta->getDataCenterId() << $this->config->getDataCenterShift(); + $workerId = $meta->getWorkerId() << $this->config->getWorkerIdShift(); - return $timestamp | $dataCenterId | $workerId | $meta->sequence; + return $interval | $dataCenterId | $workerId | $meta->getSequence(); } public function degenerate(int $id): Meta { - $timestamp = $id >> $this->config->getTimeStampShift(); + $interval = $id >> $this->config->getTimeStampShift(); $dataCenterId = $id >> $this->config->getDataCenterShift(); $workerId = $id >> $this->config->getWorkerIdShift(); return new Meta( - $timestamp << $this->config->getDataCenterBits() ^ $dataCenterId, + $interval << $this->config->getDataCenterBits() ^ $dataCenterId, $dataCenterId << $this->config->getWorkerBits() ^ $workerId, $workerId << $this->config->getSequenceBits() ^ $id, - $timestamp + $this->getBeginTimeStamp() + $interval + $this->metaGenerator->getBeginTimeStamp(), + $this->metaGenerator->getBeginTimeStamp() ); } diff --git a/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php b/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php deleted file mode 100644 index 78ed2a280..000000000 --- a/src/snowflake/src/IdGenerator/MilliSecondIdGenerator.php +++ /dev/null @@ -1,36 +0,0 @@ -beginTimeStamp = $beginTimeStamp * 1000; - parent::__construct($metaGenerator, $config); - } - - public function getBeginTimeStamp(): int - { - return $this->beginTimeStamp; - } -} diff --git a/src/snowflake/src/IdGenerator/SnowflakeIdGenerator.php b/src/snowflake/src/IdGenerator/SnowflakeIdGenerator.php new file mode 100644 index 000000000..e95200e63 --- /dev/null +++ b/src/snowflake/src/IdGenerator/SnowflakeIdGenerator.php @@ -0,0 +1,19 @@ + $this->maxDataCenterId()) { - // throw new SnowflakeException('DataCenter Id can\'t be greater than 4 or less than 0'); - // } - // if ($machineId < 0 || $machineId > $this->maxMachineId()) { - // throw new SnowflakeException('Machine Id can\'t be greater than 128 or less than 0'); - // } - // if ($sequence < 0 || $sequence > $this->maxSequence()) { - // throw new SnowflakeException('Sequence can\'t be greater than 4096 or less than 0'); - // } - $this->dataCenterId = $dataCenterId; $this->workerId = $workerId; $this->sequence = $sequence; $this->timestamp = $timestamp; + $this->beginTimeStamp = $beginTimeStamp; + } + + public function getTimeInterval(): int + { + return $this->timestamp - $this->beginTimeStamp; + } + + /** + * @return int + */ + public function getDataCenterId(): int + { + return $this->dataCenterId; + } + + /** + * @return int + */ + public function getWorkerId(): int + { + return $this->workerId; + } + + /** + * @return int + */ + public function getSequence(): int + { + return $this->sequence; + } + + /** + * @return int + */ + public function getTimestamp(): int + { + return $this->timestamp; + } + + /** + * @return int + */ + public function getBeginTimeStamp(): int + { + return $this->beginTimeStamp; } } diff --git a/src/snowflake/src/MetaGenerator.php b/src/snowflake/src/MetaGenerator.php index 21e9334cd..7e8bdf735 100644 --- a/src/snowflake/src/MetaGenerator.php +++ b/src/snowflake/src/MetaGenerator.php @@ -25,10 +25,13 @@ abstract class MetaGenerator implements MetaGeneratorInterface protected $lastTimeStamp = 0; - public function __construct(ConfigInterface $config) + protected $beginTimeStamp = 0; + + public function __construct(ConfigInterface $config, int $beginTimeStamp = self::DEFAULT_BEGIN_SECOND) { $this->config = $config; $this->lastTimeStamp = $this->getTimeStamp(); + $this->beginTimeStamp = $beginTimeStamp * 1000; } public function generate(): Meta @@ -36,7 +39,7 @@ abstract class MetaGenerator implements MetaGeneratorInterface $timestamp = $this->getTimeStamp(); if ($timestamp < $this->lastTimeStamp) { - throw new SnowflakeException(sprintf('Clock moved backwards. Refusing to generate id for %d milliseconds', $this->lastTimeStamp - $timestamp)); + throw new SnowflakeException(sprintf('Clock moved backwards. Refusing to generate id for %d milliseconds.', $this->lastTimeStamp - $timestamp)); } if ($timestamp == $this->lastTimeStamp) { @@ -48,7 +51,16 @@ abstract class MetaGenerator implements MetaGeneratorInterface $this->sequence = 0; } - return new Meta($this->getDataCenterId(), $this->getWorkerId(), $this->sequence, $timestamp); + if ($timestamp < $this->beginTimeStamp) { + throw new SnowflakeException(sprintf('The beginTimeStamp %d is invalid, because it smaller than timestamp %d.', $this->beginTimeStamp, $timestamp)); + } + + return new Meta($this->getDataCenterId(), $this->getWorkerId(), $this->sequence, $timestamp, $this->beginTimeStamp); + } + + public function getBeginTimeStamp(): int + { + return $this->beginTimeStamp; } abstract public function getDataCenterId(): int; diff --git a/src/snowflake/src/SnowflakeFactory.php b/src/snowflake/src/MetaGeneratorFactory.php similarity index 67% rename from src/snowflake/src/SnowflakeFactory.php rename to src/snowflake/src/MetaGeneratorFactory.php index 45bbaf17f..aad59dea9 100644 --- a/src/snowflake/src/SnowflakeFactory.php +++ b/src/snowflake/src/MetaGeneratorFactory.php @@ -13,17 +13,17 @@ declare(strict_types=1); namespace Hyperf\Snowflake; use Hyperf\Contract\ConfigInterface; -use Hyperf\Snowflake\IdGenerator\MilliSecondIdGenerator; +use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; use Psr\Container\ContainerInterface; -class SnowflakeFactory +class MetaGeneratorFactory { public function __invoke(ContainerInterface $container) { $config = $container->get(ConfigInterface::class); - $beginSecond = $config->get('snowflake.begin_second', IdGeneratorInterface::DEFAULT_SECOND); + $beginSecond = $config->get('snowflake.begin_second', MetaGeneratorInterface::DEFAULT_BEGIN_SECOND); - return make(MilliSecondIdGenerator::class, [ + return make(RandomMilliSecondMetaGenerator::class, [ 'beginTimeStamp' => $beginSecond, ]); } diff --git a/src/snowflake/src/MetaGeneratorInterface.php b/src/snowflake/src/MetaGeneratorInterface.php index 6487381dd..198936a17 100644 --- a/src/snowflake/src/MetaGeneratorInterface.php +++ b/src/snowflake/src/MetaGeneratorInterface.php @@ -14,5 +14,9 @@ namespace Hyperf\Snowflake; interface MetaGeneratorInterface { + const DEFAULT_BEGIN_SECOND = 1560960000; + public function generate(): Meta; + + public function getBeginTimeStamp(): int; } diff --git a/src/snowflake/tests/GeneratorTest.php b/src/snowflake/tests/GeneratorTest.php index 5b29e5469..3b663c01a 100644 --- a/src/snowflake/tests/GeneratorTest.php +++ b/src/snowflake/tests/GeneratorTest.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace HyperfTest\Snowflake; use Hyperf\Snowflake\Config; -use Hyperf\Snowflake\IdGenerator\MilliSecondIdGenerator; +use Hyperf\Snowflake\IdGenerator\SnowflakeIdGenerator; use Hyperf\Snowflake\Meta; use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; use Hyperf\Snowflake\RandomMetaGenerator; @@ -29,14 +29,14 @@ class GeneratorTest extends TestCase public function testGenerateReturnInt() { $config = new Config(); - $generator = new MilliSecondIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); + $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); $this->assertTrue(is_int($generator->generate())); } public function testDegenerateInstanceofMeta() { $config = new Config(); - $generator = new MilliSecondIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); + $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); $id = $generator->generate(); @@ -47,7 +47,7 @@ class GeneratorTest extends TestCase { $config = new Config(); $metaGenerator = new RandomMilliSecondMetaGenerator($config); - $generator = new MilliSecondIdGenerator($metaGenerator, $config); + $generator = new SnowflakeIdGenerator($metaGenerator, $config); $meta = $metaGenerator->generate(); $id = $generator->generate($meta); @@ -58,11 +58,11 @@ class GeneratorTest extends TestCase { $config = new Config(); $metaGenerator = new RandomMilliSecondMetaGenerator($config); - $generator = new MilliSecondIdGenerator($metaGenerator, $config); + $generator = new SnowflakeIdGenerator($metaGenerator, $config); $meta = $generator->degenerate(PHP_INT_MAX); - $days = intval(($meta->timestamp) / (3600 * 24 * 1000)); - $this->assertSame(43573, $days); + $days = intval(($meta->getTimeInterval()) / (3600 * 24 * 1000)); + $this->assertSame(25451, $days); // 70 years. // $generator = new Snowflake(new RandomMetaGenerator(), Snowflake::LEVEL_SECOND, 0); // $meta = $generator->degenerate(PHP_INT_MAX); From 646c382eda86b646ac549aefd8c53cd2fb07ea53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 14:38:42 +0800 Subject: [PATCH 03/79] Added RedisMilliSecondMetaGenerator. --- src/snowflake/composer.json | 5 +- src/snowflake/publish/snowflake.php | 4 + src/snowflake/src/MetaGenerator.php | 4 +- .../RandomMilliSecondMetaGenerator.php | 5 + .../RedisMilliSecondMetaGenerator.php | 73 ++++++++++++ src/snowflake/src/MetaGeneratorFactory.php | 4 +- .../RedisMilliSecondMetaGeneratorTest.php | 106 ++++++++++++++++++ ...torTest.php => SnowflakeGeneratorTest.php} | 9 +- 8 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php create mode 100644 src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php rename src/snowflake/tests/{GeneratorTest.php => SnowflakeGeneratorTest.php} (83%) diff --git a/src/snowflake/composer.json b/src/snowflake/composer.json index 708507e71..9706844da 100644 --- a/src/snowflake/composer.json +++ b/src/snowflake/composer.json @@ -18,8 +18,9 @@ "phpunit/phpunit": "^7.0" }, "suggest": { - "psr/container": "Required to use SnowflakeFactory.", - "hyperf/config": "Required to read snowflake config." + "psr/container": "Required to use MetaGeneratorFactory.", + "hyperf/config": "Required to read snowflake config.", + "hyperf/redis": "Required to use RedisMilliSecondMetaGenerator." }, "autoload": { "psr-4": { diff --git a/src/snowflake/publish/snowflake.php b/src/snowflake/publish/snowflake.php index 2ea0515aa..49e577035 100644 --- a/src/snowflake/publish/snowflake.php +++ b/src/snowflake/publish/snowflake.php @@ -10,8 +10,12 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ +use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator; use Hyperf\Snowflake\MetaGeneratorInterface; return [ 'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND, + RedisMilliSecondMetaGenerator::class => [ + 'pool' => 'default', + ], ]; diff --git a/src/snowflake/src/MetaGenerator.php b/src/snowflake/src/MetaGenerator.php index 7e8bdf735..1690f85c0 100644 --- a/src/snowflake/src/MetaGenerator.php +++ b/src/snowflake/src/MetaGenerator.php @@ -31,7 +31,7 @@ abstract class MetaGenerator implements MetaGeneratorInterface { $this->config = $config; $this->lastTimeStamp = $this->getTimeStamp(); - $this->beginTimeStamp = $beginTimeStamp * 1000; + $this->beginTimeStamp = $this->getBeginTimeStampFromSeconds($beginTimeStamp); } public function generate(): Meta @@ -70,4 +70,6 @@ abstract class MetaGenerator implements MetaGeneratorInterface abstract public function getTimeStamp(): int; abstract public function getNextTimeStamp(): int; + + abstract protected function getBeginTimeStampFromSeconds(int $seconds): int; } diff --git a/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php index 733bb8191..c11620369 100644 --- a/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php +++ b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php @@ -40,4 +40,9 @@ class RandomMilliSecondMetaGenerator extends MetaGenerator return $timestamp; } + + protected function getBeginTimeStampFromSeconds(int $seconds): int + { + return $seconds * 1000; + } } diff --git a/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php new file mode 100644 index 000000000..ceebc6e7b --- /dev/null +++ b/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php @@ -0,0 +1,73 @@ +get('snowflake.' . static::class . '.pool', 'default'); + /** @var \Redis $redis */ + $redis = make(RedisProxy::class, [ + 'pool' => $pool, + ]); + + $id = $redis->incr(static::REDIS_KEY); + + $this->workerId = $id % $config->maxWorkerId(); + $this->dataCenterId = intval($id / $config->maxWorkerId()) % $config->maxDataCenterId(); + } + + public function getDataCenterId(): int + { + return $this->dataCenterId; + } + + public function getWorkerId(): int + { + return $this->workerId; + } + + public function getTimeStamp(): int + { + return intval(microtime(true) * 1000); + } + + public function getNextTimeStamp(): int + { + $timestamp = $this->getTimeStamp(); + while ($timestamp <= $this->lastTimeStamp) { + $timestamp = $this->getTimeStamp(); + } + + return $timestamp; + } + + protected function getBeginTimeStampFromSeconds(int $seconds): int + { + return $seconds * 1000; + } +} diff --git a/src/snowflake/src/MetaGeneratorFactory.php b/src/snowflake/src/MetaGeneratorFactory.php index aad59dea9..3c5438f7e 100644 --- a/src/snowflake/src/MetaGeneratorFactory.php +++ b/src/snowflake/src/MetaGeneratorFactory.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Snowflake; use Hyperf\Contract\ConfigInterface; +use Hyperf\Snowflake\ConfigInterface as SnowflakeConfigInterface; use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; use Psr\Container\ContainerInterface; @@ -24,7 +25,8 @@ class MetaGeneratorFactory $beginSecond = $config->get('snowflake.begin_second', MetaGeneratorInterface::DEFAULT_BEGIN_SECOND); return make(RandomMilliSecondMetaGenerator::class, [ - 'beginTimeStamp' => $beginSecond, + $container->get(SnowflakeConfigInterface::class), + $beginSecond, ]); } } diff --git a/src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php b/src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php new file mode 100644 index 000000000..f24f3b3a3 --- /dev/null +++ b/src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php @@ -0,0 +1,106 @@ +getContainer(); + $redis = $container->make(RedisProxy::class, ['pool' => 'snowflake']); + $redis->del(RedisMilliSecondMetaGenerator::REDIS_KEY); + } + + public function testGenerateMeta() + { + $container = $this->getContainer(); + $config = $container->get(ConfigInterface::class); + $metaGenerator = new RedisMilliSecondMetaGenerator($config, new SnowflakeConfig()); + + $meta = $metaGenerator->generate(); + $this->assertInstanceOf(Meta::class, $meta); + $this->assertSame(0, $meta->getDataCenterId()); + $this->assertSame(1, $meta->getWorkerId()); + $this->assertSame(0, $meta->getSequence()); + } + + protected function getContainer() + { + $config = new Config([ + 'redis' => [ + 'snowflake' => [ + 'host' => 'localhost', + 'auth' => '910123', + 'port' => 6379, + 'db' => 0, + 'timeout' => 0.0, + 'reserved' => null, + 'retry_interval' => 0, + 'pool' => [ + 'min_connections' => 1, + 'max_connections' => 10, + 'connect_timeout' => 10.0, + 'wait_timeout' => 3.0, + 'heartbeat' => -1, + 'max_idle_time' => 60, + ], + ], + ], + 'snowflake' => [ + 'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND, + RedisMilliSecondMetaGenerator::class => [ + 'pool' => 'snowflake', + ], + ], + ]); + + $container = Mockery::mock(Container::class); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn($config); + $container->shouldReceive('make')->with(Channel::class, Mockery::any())->andReturnUsing(function ($class, $args) { + return new Channel($args['size']); + }); + $container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) { + return new PoolOption(...array_values($args)); + }); + $container->shouldReceive('make')->with(RedisPool::class, Mockery::any())->andReturnUsing(function ($class, $args) use ($container) { + return new RedisPool($container, $args['name']); + }); + $factory = new PoolFactory($container); + $container->shouldReceive('make')->with(RedisProxy::class, Mockery::any())->andReturnUsing(function ($class, $args) use ($factory) { + return new RedisProxy($factory, $args['pool']); + }); + + ApplicationContext::setContainer($container); + return $container; + } +} diff --git a/src/snowflake/tests/GeneratorTest.php b/src/snowflake/tests/SnowflakeGeneratorTest.php similarity index 83% rename from src/snowflake/tests/GeneratorTest.php rename to src/snowflake/tests/SnowflakeGeneratorTest.php index 3b663c01a..c64edce05 100644 --- a/src/snowflake/tests/GeneratorTest.php +++ b/src/snowflake/tests/SnowflakeGeneratorTest.php @@ -16,15 +16,13 @@ use Hyperf\Snowflake\Config; use Hyperf\Snowflake\IdGenerator\SnowflakeIdGenerator; use Hyperf\Snowflake\Meta; use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; -use Hyperf\Snowflake\RandomMetaGenerator; -use Hyperf\Snowflake\Snowflake; use PHPUnit\Framework\TestCase; /** * @internal * @coversNothing */ -class GeneratorTest extends TestCase +class SnowflakeGeneratorTest extends TestCase { public function testGenerateReturnInt() { @@ -63,10 +61,5 @@ class GeneratorTest extends TestCase $meta = $generator->degenerate(PHP_INT_MAX); $days = intval(($meta->getTimeInterval()) / (3600 * 24 * 1000)); $this->assertSame(25451, $days); // 70 years. - - // $generator = new Snowflake(new RandomMetaGenerator(), Snowflake::LEVEL_SECOND, 0); - // $meta = $generator->degenerate(PHP_INT_MAX); - // $years = intval($meta->timestamp / (3600 * 24 * 365)); - // $this->assertSame(8716, $years); } } From 80020c1e217ac2175eb1975bb6bff836f58c9feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 15:23:57 +0800 Subject: [PATCH 04/79] Added RedisSecondMetaGenerator. --- src/snowflake/src/IdGenerator.php | 4 +- src/snowflake/src/MetaGenerator.php | 18 +++-- .../RandomMilliSecondMetaGenerator.php | 11 +-- .../RedisMilliSecondMetaGenerator.php | 8 +-- .../RedisSecondMetaGenerator.php | 68 +++++++++++++++++++ src/snowflake/src/MetaGeneratorFactory.php | 5 +- src/snowflake/src/MetaGeneratorInterface.php | 2 + ...torTest.php => RedisMetaGeneratorTest.php} | 54 ++++++++++++++- .../tests/SnowflakeGeneratorTest.php | 13 ++-- 9 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 src/snowflake/src/MetaGenerator/RedisSecondMetaGenerator.php rename src/snowflake/tests/{RedisMilliSecondMetaGeneratorTest.php => RedisMetaGeneratorTest.php} (64%) diff --git a/src/snowflake/src/IdGenerator.php b/src/snowflake/src/IdGenerator.php index a8197c255..78dde6b9e 100644 --- a/src/snowflake/src/IdGenerator.php +++ b/src/snowflake/src/IdGenerator.php @@ -24,10 +24,10 @@ abstract class IdGenerator implements IdGeneratorInterface */ protected $config; - public function __construct(MetaGeneratorInterface $metaGenerator, ConfigInterface $config) + public function __construct(MetaGeneratorInterface $metaGenerator) { $this->metaGenerator = $metaGenerator; - $this->config = $config; + $this->config = $metaGenerator->getConfig(); } public function generate(?Meta $meta = null): int diff --git a/src/snowflake/src/MetaGenerator.php b/src/snowflake/src/MetaGenerator.php index 1690f85c0..961e7e946 100644 --- a/src/snowflake/src/MetaGenerator.php +++ b/src/snowflake/src/MetaGenerator.php @@ -27,11 +27,11 @@ abstract class MetaGenerator implements MetaGeneratorInterface protected $beginTimeStamp = 0; - public function __construct(ConfigInterface $config, int $beginTimeStamp = self::DEFAULT_BEGIN_SECOND) + public function __construct(ConfigInterface $config, int $beginTimeStamp) { $this->config = $config; $this->lastTimeStamp = $this->getTimeStamp(); - $this->beginTimeStamp = $this->getBeginTimeStampFromSeconds($beginTimeStamp); + $this->beginTimeStamp = $beginTimeStamp; } public function generate(): Meta @@ -39,7 +39,7 @@ abstract class MetaGenerator implements MetaGeneratorInterface $timestamp = $this->getTimeStamp(); if ($timestamp < $this->lastTimeStamp) { - throw new SnowflakeException(sprintf('Clock moved backwards. Refusing to generate id for %d milliseconds.', $this->lastTimeStamp - $timestamp)); + $this->clockMovedBackwards($timestamp, $this->lastTimeStamp); } if ($timestamp == $this->lastTimeStamp) { @@ -55,6 +55,8 @@ abstract class MetaGenerator implements MetaGeneratorInterface throw new SnowflakeException(sprintf('The beginTimeStamp %d is invalid, because it smaller than timestamp %d.', $this->beginTimeStamp, $timestamp)); } + $this->lastTimeStamp = $timestamp; + return new Meta($this->getDataCenterId(), $this->getWorkerId(), $this->sequence, $timestamp, $this->beginTimeStamp); } @@ -63,6 +65,11 @@ abstract class MetaGenerator implements MetaGeneratorInterface return $this->beginTimeStamp; } + public function getConfig(): ConfigInterface + { + return $this->config; + } + abstract public function getDataCenterId(): int; abstract public function getWorkerId(): int; @@ -71,5 +78,8 @@ abstract class MetaGenerator implements MetaGeneratorInterface abstract public function getNextTimeStamp(): int; - abstract protected function getBeginTimeStampFromSeconds(int $seconds): int; + protected function clockMovedBackwards($timestamp, $lastTimeStamp) + { + throw new SnowflakeException(sprintf('Clock moved backwards. Refusing to generate id for %d milliseconds.', $lastTimeStamp - $timestamp)); + } } diff --git a/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php index c11620369..d6d5d8cee 100644 --- a/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php +++ b/src/snowflake/src/MetaGenerator/RandomMilliSecondMetaGenerator.php @@ -12,10 +12,16 @@ declare(strict_types=1); namespace Hyperf\Snowflake\MetaGenerator; +use Hyperf\Snowflake\ConfigInterface; use Hyperf\Snowflake\MetaGenerator; class RandomMilliSecondMetaGenerator extends MetaGenerator { + public function __construct(ConfigInterface $config, int $beginTimeStamp) + { + parent::__construct($config, $beginTimeStamp * 1000); + } + public function getDataCenterId(): int { return rand(0, 31); @@ -40,9 +46,4 @@ class RandomMilliSecondMetaGenerator extends MetaGenerator return $timestamp; } - - protected function getBeginTimeStampFromSeconds(int $seconds): int - { - return $seconds * 1000; - } } diff --git a/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php index ceebc6e7b..dc35f8409 100644 --- a/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php +++ b/src/snowflake/src/MetaGenerator/RedisMilliSecondMetaGenerator.php @@ -27,9 +27,10 @@ class RedisMilliSecondMetaGenerator extends MetaGenerator public function __construct(HyperfConfig $hConfig, ConfigInterface $config, int $beginTimeStamp = self::DEFAULT_BEGIN_SECOND) { - parent::__construct($config, $beginTimeStamp); + parent::__construct($config, $beginTimeStamp * 1000); $pool = $hConfig->get('snowflake.' . static::class . '.pool', 'default'); + /** @var \Redis $redis */ $redis = make(RedisProxy::class, [ 'pool' => $pool, @@ -65,9 +66,4 @@ class RedisMilliSecondMetaGenerator extends MetaGenerator return $timestamp; } - - protected function getBeginTimeStampFromSeconds(int $seconds): int - { - return $seconds * 1000; - } } diff --git a/src/snowflake/src/MetaGenerator/RedisSecondMetaGenerator.php b/src/snowflake/src/MetaGenerator/RedisSecondMetaGenerator.php new file mode 100644 index 000000000..af5059f9a --- /dev/null +++ b/src/snowflake/src/MetaGenerator/RedisSecondMetaGenerator.php @@ -0,0 +1,68 @@ +get('snowflake.' . static::class . '.pool', 'default'); + + /** @var \Redis $redis */ + $redis = make(RedisProxy::class, [ + 'pool' => $pool, + ]); + + $id = $redis->incr(static::REDIS_KEY); + + $this->workerId = $id % $config->maxWorkerId(); + $this->dataCenterId = intval($id / $config->maxWorkerId()) % $config->maxDataCenterId(); + } + + public function getDataCenterId(): int + { + return $this->dataCenterId; + } + + public function getWorkerId(): int + { + return $this->workerId; + } + + public function getTimeStamp(): int + { + return time(); + } + + public function getNextTimeStamp(): int + { + return $this->lastTimeStamp + 1; + } + + protected function clockMovedBackwards($timestamp, $lastTimeStamp) + { + } +} diff --git a/src/snowflake/src/MetaGeneratorFactory.php b/src/snowflake/src/MetaGeneratorFactory.php index 3c5438f7e..8ce3bf1da 100644 --- a/src/snowflake/src/MetaGeneratorFactory.php +++ b/src/snowflake/src/MetaGeneratorFactory.php @@ -14,7 +14,7 @@ namespace Hyperf\Snowflake; use Hyperf\Contract\ConfigInterface; use Hyperf\Snowflake\ConfigInterface as SnowflakeConfigInterface; -use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; +use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator; use Psr\Container\ContainerInterface; class MetaGeneratorFactory @@ -24,7 +24,8 @@ class MetaGeneratorFactory $config = $container->get(ConfigInterface::class); $beginSecond = $config->get('snowflake.begin_second', MetaGeneratorInterface::DEFAULT_BEGIN_SECOND); - return make(RandomMilliSecondMetaGenerator::class, [ + return make(RedisMilliSecondMetaGenerator::class, [ + $config, $container->get(SnowflakeConfigInterface::class), $beginSecond, ]); diff --git a/src/snowflake/src/MetaGeneratorInterface.php b/src/snowflake/src/MetaGeneratorInterface.php index 198936a17..68eeece65 100644 --- a/src/snowflake/src/MetaGeneratorInterface.php +++ b/src/snowflake/src/MetaGeneratorInterface.php @@ -19,4 +19,6 @@ interface MetaGeneratorInterface public function generate(): Meta; public function getBeginTimeStamp(): int; + + public function getConfig(): ConfigInterface; } diff --git a/src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php b/src/snowflake/tests/RedisMetaGeneratorTest.php similarity index 64% rename from src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php rename to src/snowflake/tests/RedisMetaGeneratorTest.php index f24f3b3a3..8a84b30b0 100644 --- a/src/snowflake/tests/RedisMilliSecondMetaGeneratorTest.php +++ b/src/snowflake/tests/RedisMetaGeneratorTest.php @@ -21,8 +21,10 @@ use Hyperf\Redis\Pool\PoolFactory; use Hyperf\Redis\Pool\RedisPool; use Hyperf\Redis\RedisProxy; use Hyperf\Snowflake\Config as SnowflakeConfig; +use Hyperf\Snowflake\IdGenerator\SnowflakeIdGenerator; use Hyperf\Snowflake\Meta; use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator; +use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator; use Hyperf\Snowflake\MetaGeneratorInterface; use Hyperf\Utils\ApplicationContext; use Mockery; @@ -32,7 +34,7 @@ use PHPUnit\Framework\TestCase; * @internal * @coversNothing */ -class RedisMilliSecondMetaGeneratorTest extends TestCase +class RedisMetaGeneratorTest extends TestCase { protected function tearDown() { @@ -51,7 +53,52 @@ class RedisMilliSecondMetaGeneratorTest extends TestCase $this->assertInstanceOf(Meta::class, $meta); $this->assertSame(0, $meta->getDataCenterId()); $this->assertSame(1, $meta->getWorkerId()); - $this->assertSame(0, $meta->getSequence()); + } + + public function testGenerateId() + { + $container = $this->getContainer(); + $hConfig = $container->get(ConfigInterface::class); + $config = new SnowflakeConfig(); + $metaGenerator = new RedisMilliSecondMetaGenerator($hConfig, $config); + $generator = new SnowflakeIdGenerator($metaGenerator); + + $id = $generator->generate(); + $this->assertTrue(is_int($id)); + + $meta = $generator->degenerate($id); + $this->assertInstanceOf(Meta::class, $meta); + $this->assertSame(0, $meta->getDataCenterId()); + $this->assertSame(1, $meta->getWorkerId()); + } + + public function testGenerateMetaSeconds() + { + $container = $this->getContainer(); + $hConfig = $container->get(ConfigInterface::class); + $config = new SnowflakeConfig(); + $metaGenerator = new RedisSecondMetaGenerator($hConfig, $config); + $meta = $metaGenerator->generate(); + $this->assertInstanceOf(Meta::class, $meta); + $this->assertSame(0, $meta->getDataCenterId()); + $this->assertSame(1, $meta->getWorkerId()); + } + + public function testGenerateAndDeGenerateSeconds() + { + $container = $this->getContainer(); + $hConfig = $container->get(ConfigInterface::class); + $config = new SnowflakeConfig(); + $metaGenerator = new RedisSecondMetaGenerator($hConfig, $config); + $generator = new SnowflakeIdGenerator($metaGenerator); + + $id = $generator->generate(); + $this->assertTrue(is_int($id)); + + $meta = $generator->degenerate($id); + $this->assertInstanceOf(Meta::class, $meta); + $this->assertSame(0, $meta->getDataCenterId()); + $this->assertSame(1, $meta->getWorkerId()); } protected function getContainer() @@ -81,6 +128,9 @@ class RedisMilliSecondMetaGeneratorTest extends TestCase RedisMilliSecondMetaGenerator::class => [ 'pool' => 'snowflake', ], + RedisSecondMetaGenerator::class => [ + 'pool' => 'snowflake', + ], ], ]); diff --git a/src/snowflake/tests/SnowflakeGeneratorTest.php b/src/snowflake/tests/SnowflakeGeneratorTest.php index c64edce05..fe128cc31 100644 --- a/src/snowflake/tests/SnowflakeGeneratorTest.php +++ b/src/snowflake/tests/SnowflakeGeneratorTest.php @@ -16,6 +16,7 @@ use Hyperf\Snowflake\Config; use Hyperf\Snowflake\IdGenerator\SnowflakeIdGenerator; use Hyperf\Snowflake\Meta; use Hyperf\Snowflake\MetaGenerator\RandomMilliSecondMetaGenerator; +use Hyperf\Snowflake\MetaGeneratorInterface; use PHPUnit\Framework\TestCase; /** @@ -27,14 +28,14 @@ class SnowflakeGeneratorTest extends TestCase public function testGenerateReturnInt() { $config = new Config(); - $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); + $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config, MetaGeneratorInterface::DEFAULT_BEGIN_SECOND)); $this->assertTrue(is_int($generator->generate())); } public function testDegenerateInstanceofMeta() { $config = new Config(); - $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config), $config); + $generator = new SnowflakeIdGenerator(new RandomMilliSecondMetaGenerator($config, MetaGeneratorInterface::DEFAULT_BEGIN_SECOND)); $id = $generator->generate(); @@ -44,8 +45,8 @@ class SnowflakeGeneratorTest extends TestCase public function testGenerateAndDegenerate() { $config = new Config(); - $metaGenerator = new RandomMilliSecondMetaGenerator($config); - $generator = new SnowflakeIdGenerator($metaGenerator, $config); + $metaGenerator = new RandomMilliSecondMetaGenerator($config, MetaGeneratorInterface::DEFAULT_BEGIN_SECOND); + $generator = new SnowflakeIdGenerator($metaGenerator); $meta = $metaGenerator->generate(); $id = $generator->generate($meta); @@ -55,8 +56,8 @@ class SnowflakeGeneratorTest extends TestCase public function testDegenerateMaxId() { $config = new Config(); - $metaGenerator = new RandomMilliSecondMetaGenerator($config); - $generator = new SnowflakeIdGenerator($metaGenerator, $config); + $metaGenerator = new RandomMilliSecondMetaGenerator($config, MetaGeneratorInterface::DEFAULT_BEGIN_SECOND); + $generator = new SnowflakeIdGenerator($metaGenerator); $meta = $generator->degenerate(PHP_INT_MAX); $days = intval(($meta->getTimeInterval()) / (3600 * 24 * 1000)); From 53c584f28ece25ec45487bc3320f0e7ac0d4b14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 15:26:05 +0800 Subject: [PATCH 05/79] Update composer.json --- src/snowflake/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snowflake/composer.json b/src/snowflake/composer.json index 9706844da..c9801ef22 100644 --- a/src/snowflake/composer.json +++ b/src/snowflake/composer.json @@ -20,7 +20,7 @@ "suggest": { "psr/container": "Required to use MetaGeneratorFactory.", "hyperf/config": "Required to read snowflake config.", - "hyperf/redis": "Required to use RedisMilliSecondMetaGenerator." + "hyperf/redis": "Required to use RedisMilliSecondMetaGenerator or RedisSecondMetaGenerator." }, "autoload": { "psr-4": { From ccc6af13a6601d1de124d2a50d56997ab8ee6012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 15:34:19 +0800 Subject: [PATCH 06/79] Added config. --- src/snowflake/publish/snowflake.php | 4 ++++ src/snowflake/tests/RedisMetaGeneratorTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/snowflake/publish/snowflake.php b/src/snowflake/publish/snowflake.php index 49e577035..cb93192b1 100644 --- a/src/snowflake/publish/snowflake.php +++ b/src/snowflake/publish/snowflake.php @@ -11,6 +11,7 @@ declare(strict_types=1); */ use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator; +use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator; use Hyperf\Snowflake\MetaGeneratorInterface; return [ @@ -18,4 +19,7 @@ return [ RedisMilliSecondMetaGenerator::class => [ 'pool' => 'default', ], + RedisSecondMetaGenerator::class => [ + 'pool' => 'default', + ], ]; diff --git a/src/snowflake/tests/RedisMetaGeneratorTest.php b/src/snowflake/tests/RedisMetaGeneratorTest.php index 8a84b30b0..4810d26b9 100644 --- a/src/snowflake/tests/RedisMetaGeneratorTest.php +++ b/src/snowflake/tests/RedisMetaGeneratorTest.php @@ -101,6 +101,23 @@ class RedisMetaGeneratorTest extends TestCase $this->assertSame(1, $meta->getWorkerId()); } + public function testDeGenerateMaxId() + { + $container = $this->getContainer(); + $hConfig = $container->get(ConfigInterface::class); + $config = new SnowflakeConfig(); + $metaGenerator = new RedisSecondMetaGenerator($hConfig, $config); + $generator = new SnowflakeIdGenerator($metaGenerator); + + $meta = $generator->degenerate(PHP_INT_MAX); + $interval = $meta->getTimeInterval(); + + $this->assertSame(31, $meta->getDataCenterId()); + $this->assertSame(31, $meta->getWorkerId()); + $this->assertSame(4095, $meta->getSequence()); + $this->assertSame(69730, intval($interval / (3600 * 24 * 365))); // 70W years + } + protected function getContainer() { $config = new Config([ From 6a04699d6fbf0d218f77c996b12ebafa15d7d69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 21 Aug 2019 16:19:09 +0800 Subject: [PATCH 07/79] Added doc. --- doc/zh/snowflake.md | 103 ++++++++++++++++++ src/snowflake/src/IdGenerator.php | 8 ++ src/snowflake/src/Meta.php | 30 +++++ .../tests/RedisMetaGeneratorTest.php | 21 +++- .../tests/Stub/UserDefinedIdGenerator.php | 40 +++++++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 doc/zh/snowflake.md create mode 100644 src/snowflake/tests/Stub/UserDefinedIdGenerator.php diff --git a/doc/zh/snowflake.md b/doc/zh/snowflake.md new file mode 100644 index 000000000..b103ffe70 --- /dev/null +++ b/doc/zh/snowflake.md @@ -0,0 +1,103 @@ +# Snowflake + +## 安装 + +``` +composer require hyperf/snowflake +``` + +## 使用 + +框架提供了 `MetaGeneratorInterface` 和 `IdGeneratorInterface`,`MetaGeneratorInterface` 会生成 `ID` 的 `Meta` 文件,`IdGeneratorInterface` 则会根据对应的 `Meta` 文件生成 `分布式ID`。 + +框架默认使用的 `MetaGeneratorInterface` 是基于 `Redis` 实现的 `毫秒级别生成器`。配置如下: + +```php + MetaGeneratorInterface::DEFAULT_BEGIN_SECOND, + RedisMilliSecondMetaGenerator::class => [ + 'pool' => 'default', + ], +]; + +``` + +框架中使用 `Snowfalke` 十分简单,只需要从 `DI` 中取出 `IdGeneratorInterface` 对象即可。 + +```php +get(IdGeneratorInterface::class); + +$id = $generator->generate(); +``` + +当知道 `ID` 需要反推对应的 `Meta` 时,只需要调用 `degenerate` 即可。 + +```php +get(IdGeneratorInterface::class); + +$meta = $generator->degenerate($id); +``` + +## 重写 `Meta` 生成器 + +`分布式ID` 的实现方式多种多样,虽然都是 `Snowflake` 算法,但也不尽相同。比如有人可能会根据 `UserId` 生成 `Meta`,而非 `WorkerId`。接下来,让我们实现一个简单的 `MetaGenerator`。 +简单的来讲,`UserId` 绝对会超过 `10 bit`,所以默认的 `DataCenterId` 和 `WorkerId` 肯定是装不过来的,所以就需要对 `UserId` 取模。 + +```php +idGenerator = $idGenerator; + } + + public function generate(int $userId) + { + $meta = $this->idGenerator->getMetaGenerator()->generate(); + + return $this->idGenerator->generate($meta->setWorkerId($userId % 31)); + } + + public function degenerate(int $id) + { + return $this->idGenerator->degenerate($id); + } +} + +use Hyperf\Utils\ApplicationContext; + +$container = ApplicationContext::getContainer(); +$generator = $container->get(UserDefinedIdGenerator::class); +$userId = 20190620; + +$id = $generator->generate($userId); + +``` \ No newline at end of file diff --git a/src/snowflake/src/IdGenerator.php b/src/snowflake/src/IdGenerator.php index 78dde6b9e..4494510d2 100644 --- a/src/snowflake/src/IdGenerator.php +++ b/src/snowflake/src/IdGenerator.php @@ -56,6 +56,14 @@ abstract class IdGenerator implements IdGeneratorInterface ); } + /** + * @return MetaGeneratorInterface + */ + public function getMetaGenerator(): MetaGeneratorInterface + { + return $this->metaGenerator; + } + protected function meta(?Meta $meta = null): Meta { if (is_null($meta)) { diff --git a/src/snowflake/src/Meta.php b/src/snowflake/src/Meta.php index fd727e996..d80d65e15 100644 --- a/src/snowflake/src/Meta.php +++ b/src/snowflake/src/Meta.php @@ -85,6 +85,36 @@ class Meta return $this->sequence; } + /** + * @param int $dataCenterId + * @return Meta + */ + public function setDataCenterId(int $dataCenterId): self + { + $this->dataCenterId = $dataCenterId; + return $this; + } + + /** + * @param int $workerId + * @return Meta + */ + public function setWorkerId(int $workerId): self + { + $this->workerId = $workerId; + return $this; + } + + /** + * @param int $sequence + * @return Meta + */ + public function setSequence(int $sequence): self + { + $this->sequence = $sequence; + return $this; + } + /** * @return int */ diff --git a/src/snowflake/tests/RedisMetaGeneratorTest.php b/src/snowflake/tests/RedisMetaGeneratorTest.php index 4810d26b9..2e4d4bb5e 100644 --- a/src/snowflake/tests/RedisMetaGeneratorTest.php +++ b/src/snowflake/tests/RedisMetaGeneratorTest.php @@ -27,6 +27,7 @@ use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator; use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator; use Hyperf\Snowflake\MetaGeneratorInterface; use Hyperf\Utils\ApplicationContext; +use HyperfTest\Snowflake\Stub\UserDefinedIdGenerator; use Mockery; use PHPUnit\Framework\TestCase; @@ -115,7 +116,25 @@ class RedisMetaGeneratorTest extends TestCase $this->assertSame(31, $meta->getDataCenterId()); $this->assertSame(31, $meta->getWorkerId()); $this->assertSame(4095, $meta->getSequence()); - $this->assertSame(69730, intval($interval / (3600 * 24 * 365))); // 70W years + $this->assertSame(69730, intval($interval / (3600 * 24 * 365))); // 7W years + } + + public function testUserDefinedIdGenerator() + { + $container = $this->getContainer(); + $hConfig = $container->get(ConfigInterface::class); + $config = new SnowflakeConfig(); + $metaGenerator = new RedisSecondMetaGenerator($hConfig, $config); + $generator = new SnowflakeIdGenerator($metaGenerator); + $generator = new UserDefinedIdGenerator($generator); + + $userId = 20190620; + + $id = $generator->generate($userId); + + $meta = $generator->degenerate($id); + + $this->assertSame($meta->getWorkerId(), $userId % 31); } protected function getContainer() diff --git a/src/snowflake/tests/Stub/UserDefinedIdGenerator.php b/src/snowflake/tests/Stub/UserDefinedIdGenerator.php new file mode 100644 index 000000000..7bf19c7b7 --- /dev/null +++ b/src/snowflake/tests/Stub/UserDefinedIdGenerator.php @@ -0,0 +1,40 @@ +idGenerator = $idGenerator; + } + + public function generate(int $userId) + { + $meta = $this->idGenerator->getMetaGenerator()->generate(); + + return $this->idGenerator->generate($meta->setWorkerId($userId % 31)); + } + + public function degenerate(int $id) + { + return $this->idGenerator->degenerate($id); + } +} From b50b12bdf47129aaf811f58b8fdd0b9c741b9311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 10:30:18 +0800 Subject: [PATCH 08/79] Deleted useless code. --- composer.json | 3 - phpunit.xml | 1 - src/graphql/src/AnnotationReader.php | 6 - src/translation/.gitattributes | 1 - src/translation/.gitignore | 11 - src/translation/LICENSE.md | 9 - src/translation/README.MD | 64 --- src/translation/composer.json | 48 -- src/translation/publish/translation.php | 17 - src/translation/src/ArrayLoader.php | 87 --- src/translation/src/ConfigProvider.php | 42 -- .../src/Contracts/HasLocalePreference.php | 23 - src/translation/src/Contracts/Loader.php | 48 -- src/translation/src/Contracts/Translator.php | 51 -- src/translation/src/FileLoader.php | 193 ------- src/translation/src/FileLoaderFactory.php | 29 - src/translation/src/MessageSelector.php | 424 --------------- .../src/Support/NamespacedItemResolver.php | 112 ---- src/translation/src/Translator.php | 505 ------------------ src/translation/src/TranslatorFactory.php | 38 -- .../tests/Cases/AbstractTestCase.php | 22 - .../tests/Cases/TranslationFileLoaderTest.php | 100 ---- .../Cases/TranslationMessageSelectorTest.php | 85 --- .../tests/Cases/TranslationTranslatorTest.php | 199 ------- src/translation/tests/bootstrap.php | 13 - src/translation/tests/ci.ini | 8 - src/translation/tests/swoole.install.sh | 10 - 27 files changed, 2149 deletions(-) delete mode 100644 src/translation/.gitattributes delete mode 100644 src/translation/.gitignore delete mode 100644 src/translation/LICENSE.md delete mode 100644 src/translation/README.MD delete mode 100644 src/translation/composer.json delete mode 100644 src/translation/publish/translation.php delete mode 100644 src/translation/src/ArrayLoader.php delete mode 100644 src/translation/src/ConfigProvider.php delete mode 100644 src/translation/src/Contracts/HasLocalePreference.php delete mode 100755 src/translation/src/Contracts/Loader.php delete mode 100644 src/translation/src/Contracts/Translator.php delete mode 100755 src/translation/src/FileLoader.php delete mode 100644 src/translation/src/FileLoaderFactory.php delete mode 100755 src/translation/src/MessageSelector.php delete mode 100755 src/translation/src/Support/NamespacedItemResolver.php delete mode 100755 src/translation/src/Translator.php delete mode 100644 src/translation/src/TranslatorFactory.php delete mode 100755 src/translation/tests/Cases/AbstractTestCase.php delete mode 100755 src/translation/tests/Cases/TranslationFileLoaderTest.php delete mode 100755 src/translation/tests/Cases/TranslationMessageSelectorTest.php delete mode 100755 src/translation/tests/Cases/TranslationTranslatorTest.php delete mode 100755 src/translation/tests/bootstrap.php delete mode 100755 src/translation/tests/ci.ini delete mode 100755 src/translation/tests/swoole.install.sh diff --git a/composer.json b/composer.json index 67c0832b1..273b94aea 100644 --- a/composer.json +++ b/composer.json @@ -161,7 +161,6 @@ "Hyperf\\Task\\": "src/task/src/", "Hyperf\\Testing\\": "src/testing/src/", "Hyperf\\Tracer\\": "src/tracer/src/", - "Hyperf\\Translation\\": "src/translation/src/", "Hyperf\\Utils\\": "src/utils/src/", "Hyperf\\Validation\\": "src/validation/src/", "Hyperf\\View\\": "src/view/src/", @@ -207,7 +206,6 @@ "HyperfTest\\ServiceGovernance\\": "src/service-governance/tests/", "HyperfTest\\Snowflake\\": "src/snowflake/tests/", "HyperfTest\\Task\\": "src/task/tests/", - "HyperfTest\\Translation\\": "src/translation/tests/", "HyperfTest\\Utils\\": "src/utils/tests/", "HyperfTest\\Validation\\": "src/validation/tests/", "HyperfTest\\WebSocketClient\\": "src/websocket-client/tests/" @@ -261,7 +259,6 @@ "Hyperf\\SwooleEnterprise\\ConfigProvider", "Hyperf\\Task\\ConfigProvider", "Hyperf\\Tracer\\ConfigProvider", - "Hyperf\\Translation\\ConfigProvider", "Hyperf\\Utils\\ConfigProvider", "Hyperf\\Validation\\ConfigProvider", "Hyperf\\View\\ConfigProvider", diff --git a/phpunit.xml b/phpunit.xml index 758fec5b3..cab85b70b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -36,7 +36,6 @@ ./src/service-governance/tests ./src/snowflake/tests ./src/task/tests - ./src/translation/tests ./src/utils/tests ./src/validation/tests ./src/websocket-client/tests diff --git a/src/graphql/src/AnnotationReader.php b/src/graphql/src/AnnotationReader.php index d01f6d90b..3ecd25fea 100644 --- a/src/graphql/src/AnnotationReader.php +++ b/src/graphql/src/AnnotationReader.php @@ -101,25 +101,21 @@ class AnnotationReader public function getRequestAnnotation(ReflectionMethod $refMethod, string $annotationName): ?AbstractRequest { - /* @var null|AbstractRequest $queryAnnotation */ return $this->getMethodAnnotation($refMethod, $annotationName); } public function getLoggedAnnotation(ReflectionMethod $refMethod): ?Logged { - /* @var null|Logged $loggedAnnotation */ return $this->getMethodAnnotation($refMethod, Logged::class); } public function getRightAnnotation(ReflectionMethod $refMethod): ?Right { - /* @var null|Right $rightAnnotation */ return $this->getMethodAnnotation($refMethod, Right::class); } public function getFailWithAnnotation(ReflectionMethod $refMethod): ?FailWith { - /* @var null|FailWith $failWithAnnotation */ return $this->getMethodAnnotation($refMethod, FailWith::class); } @@ -128,13 +124,11 @@ class AnnotationReader */ public function getSourceFields(ReflectionClass $refClass): array { - /* @var SourceField[] $sourceFields */ return $this->getClassAnnotations($refClass, SourceField::class); } public function getFactoryAnnotation(ReflectionMethod $refMethod): ?Factory { - /* @var null|Factory $factoryAnnotation */ return $this->getMethodAnnotation($refMethod, Factory::class); } diff --git a/src/translation/.gitattributes b/src/translation/.gitattributes deleted file mode 100644 index bdd4ea29c..000000000 --- a/src/translation/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -/tests export-ignore \ No newline at end of file diff --git a/src/translation/.gitignore b/src/translation/.gitignore deleted file mode 100644 index f72f9fd06..000000000 --- a/src/translation/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.buildpath -.settings/ -.project -*.patch -.idea/ -.git/ -.phpintel/ -.DS_Store -*.lock -.phpunit* -vendor \ No newline at end of file diff --git a/src/translation/LICENSE.md b/src/translation/LICENSE.md deleted file mode 100644 index eb14702a3..000000000 --- a/src/translation/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Hyperf - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/translation/README.MD b/src/translation/README.MD deleted file mode 100644 index 050cb26e0..000000000 --- a/src/translation/README.MD +++ /dev/null @@ -1,64 +0,0 @@ -# Hyperf Translation - -## About - -hyperf/translation 是对Laravel Translation的移植(不包含门面和快捷函数部分),具体使用方法可以参考Laravel Lang的使用。 - -## Install - -``` -composer require hyperf/translation - -``` - -## Config - - -### publish config -``` -php bin/hyperf.php vendor:publish hyperf/translation - -``` - -### config path - -``` -your/config/path/autoload/translation.php - -``` - -### config content - -``` - 'en', - 'fallback_locale' => '', - 'lang' => BASE_PATH . '/resources/lang', -]; - -``` - -## Usage - - -``` - -$translator = $this->container->get(\Hyperf\Translation\Contracts\Translator::class); - -$translator->trans('validation.accepted'), - - -``` \ No newline at end of file diff --git a/src/translation/composer.json b/src/translation/composer.json deleted file mode 100644 index 2e4937ddf..000000000 --- a/src/translation/composer.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "hyperf/translation", - "type": "library", - "license": "MIT", - "keywords": [ - "translation", - "hyperf" - ], - "description": "", - "autoload": { - "psr-4": { - "Hyperf\\Translation\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "HyperfTest\\Translation\\": "tests" - } - }, - "require": { - "php": ">=7.2", - "ext-swoole": ">=4.3", - "hyperf/utils": "1.0.*", - "hyperf/framework": "1.0.*", - "hyperf/di": "1.0.*", - "psr/container": "^1.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "hyperf/testing": "1.0.*", - "mockery/mockery": "^1.2", - "phpstan/phpstan": "^0.10.5", - "swoft/swoole-ide-helper": "^4.4.0" - }, - "config": { - "sort-packages": true - }, - "scripts": { - "test": "co-phpunit -c phpunit.xml --colors=always", - "analyze": "phpstan analyse --memory-limit 300M -l 0 ./src", - "cs-fix": "php-cs-fixer fix $1" - }, - "extra": { - "hyperf": { - "config": "Hyperf\\Translation\\ConfigProvider" - } - } -} diff --git a/src/translation/publish/translation.php b/src/translation/publish/translation.php deleted file mode 100644 index 9278bd458..000000000 --- a/src/translation/publish/translation.php +++ /dev/null @@ -1,17 +0,0 @@ - 'zh_CN', - 'fallback_locale' => 'en', - 'lang' => BASE_PATH . '/resources/lang', -]; diff --git a/src/translation/src/ArrayLoader.php b/src/translation/src/ArrayLoader.php deleted file mode 100644 index 75d7825a6..000000000 --- a/src/translation/src/ArrayLoader.php +++ /dev/null @@ -1,87 +0,0 @@ -messages[$namespace][$locale][$group] ?? []; - } - - /** - * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint - */ - public function addNamespace(string $namespace, string $hint) - { - } - - /** - * Add a new JSON path to the loader. - * - * @param string $path - */ - public function addJsonPath(string $path) - { - } - - /** - * Add messages to the loader. - * - * @param string $locale - * @param string $group - * @param array $messages - * @param null|string $namespace - * @return $this - */ - public function addMessages(string $locale, string $group, array $messages, $namespace = null) - { - $namespace = $namespace ?: '*'; - - $this->messages[$namespace][$locale][$group] = $messages; - - return $this; - } - - /** - * Get an array of all the registered namespaces. - * - * @return array - */ - public function namespaces(): array - { - return []; - } -} diff --git a/src/translation/src/ConfigProvider.php b/src/translation/src/ConfigProvider.php deleted file mode 100644 index e7fd6f83b..000000000 --- a/src/translation/src/ConfigProvider.php +++ /dev/null @@ -1,42 +0,0 @@ - [ - Loader::class => FileLoaderFactory::class, - Translator::class => TranslatorFactory::class, - ], - 'scan' => [ - 'paths' => [ - __DIR__, - ], - ], - 'publish' => [ - [ - 'id' => 'config', - 'description' => 'The config for translation.', - 'source' => __DIR__ . '/../publish/translation.php', - 'destination' => BASE_PATH . '/config/autoload/translation.php', - ], - ], - ]; - } -} diff --git a/src/translation/src/Contracts/HasLocalePreference.php b/src/translation/src/Contracts/HasLocalePreference.php deleted file mode 100644 index 430de5950..000000000 --- a/src/translation/src/Contracts/HasLocalePreference.php +++ /dev/null @@ -1,23 +0,0 @@ -path = $path; - $this->files = $files; - } - - /** - * Load the messages for the given locale. - * - * @param string $locale - * @param string $group - * @param null|string $namespace - * @return array - */ - public function load(string $locale, string $group, $namespace = null): array - { - if ($group === '*' && $namespace === '*') { - return $this->loadJsonPaths($locale); - } - - if (is_null($namespace) || $namespace === '*') { - return $this->loadPath($this->path, $locale, $group); - } - - return $this->loadNamespaced($locale, $group, $namespace); - } - - /** - * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint - */ - public function addNamespace(string $namespace, string $hint) - { - $this->hints[$namespace] = $hint; - } - - /** - * Add a new JSON path to the loader. - * - * @param string $path - */ - public function addJsonPath(string $path) - { - $this->jsonPaths[] = $path; - } - - /** - * Get an array of all the registered namespaces. - * - * @return array - */ - public function namespaces(): array - { - return $this->hints; - } - - /** - * Load a namespaced translation group. - * - * @param string $locale - * @param string $group - * @param string $namespace - * @return array - */ - protected function loadNamespaced(string $locale, string $group, string $namespace): array - { - if (isset($this->hints[$namespace])) { - $lines = $this->loadPath($this->hints[$namespace], $locale, $group); - - return $this->loadNamespaceOverrides($lines, $locale, $group, $namespace); - } - - return []; - } - - /** - * Load a local namespaced translation group for overrides. - * - * @param array $lines - * @param string $locale - * @param string $group - * @param string $namespace - * @return array - */ - protected function loadNamespaceOverrides(array $lines, string $locale, string $group, string $namespace): array - { - $file = "{$this->path}/vendor/{$namespace}/{$locale}/{$group}.php"; - - if ($this->files->exists($file)) { - return array_replace_recursive($lines, $this->files->getRequire($file)); - } - - return $lines; - } - - /** - * Load a locale from a given path. - * - * @param string $path - * @param string $locale - * @param string $group - * @return array - */ - protected function loadPath(string $path, string $locale, string $group): array - { - if ($this->files->exists($full = "{$path}/{$locale}/{$group}.php")) { - return $this->files->getRequire($full); - } - - return []; - } - - /** - * Load a locale from the given JSON file path. - * - * @param string $locale - * @throws \RuntimeException - * @return array - */ - protected function loadJsonPaths(string $locale) - { - return collect(array_merge($this->jsonPaths, [$this->path])) - ->reduce(function ($output, $path) use ($locale) { - if ($this->files->exists($full = "{$path}/{$locale}.json")) { - $decoded = json_decode($this->files->get($full), true); - - if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) { - throw new RuntimeException("Translation file [{$full}] contains an invalid JSON structure."); - } - - $output = array_merge($output, $decoded); - } - - return $output; - }, []); - } -} diff --git a/src/translation/src/FileLoaderFactory.php b/src/translation/src/FileLoaderFactory.php deleted file mode 100644 index 60c387fbc..000000000 --- a/src/translation/src/FileLoaderFactory.php +++ /dev/null @@ -1,29 +0,0 @@ -get(ConfigInterface::class); - $files = $container->get(Filesystem::class); - $path = $config->get('translation.lang'); - - return make(FileLoader::class, compact('files', 'path')); - } -} diff --git a/src/translation/src/MessageSelector.php b/src/translation/src/MessageSelector.php deleted file mode 100755 index 0672e9d78..000000000 --- a/src/translation/src/MessageSelector.php +++ /dev/null @@ -1,424 +0,0 @@ -extract($segments, $number)) !== null) { - return trim($value); - } - - $segments = $this->stripConditions($segments); - - $pluralIndex = $this->getPluralIndex($locale, $number); - - if (count($segments) === 1 || ! isset($segments[$pluralIndex])) { - return $segments[0]; - } - - return $segments[$pluralIndex]; - } - - /** - * Get the index to use for pluralization. - * - * The plural rules are derived from code of the Zend Framework (2010-09-25), which - * is subject to the new BSD license (http://framework.zend.com/license/new-bsd) - * Copyright (c) 2005-2010 - Zend Technologies USA Inc. (http://www.zend.com) - * - * @param string $locale - * @param int $number - * @return int - */ - public function getPluralIndex(string $locale, int $number): int - { - switch ($locale) { - case 'az': - case 'az_AZ': - case 'bo': - case 'bo_CN': - case 'bo_IN': - case 'dz': - case 'dz_BT': - case 'id': - case 'id_ID': - case 'ja': - case 'ja_JP': - case 'jv': - case 'ka': - case 'ka_GE': - case 'km': - case 'km_KH': - case 'kn': - case 'kn_IN': - case 'ko': - case 'ko_KR': - case 'ms': - case 'ms_MY': - case 'th': - case 'th_TH': - case 'tr': - case 'tr_CY': - case 'tr_TR': - case 'vi': - case 'vi_VN': - case 'zh': - case 'zh_CN': - case 'zh_HK': - case 'zh_SG': - case 'zh_TW': - return 0; - case 'af': - case 'af_ZA': - case 'bn': - case 'bn_BD': - case 'bn_IN': - case 'bg': - case 'bg_BG': - case 'ca': - case 'ca_AD': - case 'ca_ES': - case 'ca_FR': - case 'ca_IT': - case 'da': - case 'da_DK': - case 'de': - case 'de_AT': - case 'de_BE': - case 'de_CH': - case 'de_DE': - case 'de_LI': - case 'de_LU': - case 'el': - case 'el_CY': - case 'el_GR': - case 'en': - case 'en_AG': - case 'en_AU': - case 'en_BW': - case 'en_CA': - case 'en_DK': - case 'en_GB': - case 'en_HK': - case 'en_IE': - case 'en_IN': - case 'en_NG': - case 'en_NZ': - case 'en_PH': - case 'en_SG': - case 'en_US': - case 'en_ZA': - case 'en_ZM': - case 'en_ZW': - case 'eo': - case 'eo_US': - case 'es': - case 'es_AR': - case 'es_BO': - case 'es_CL': - case 'es_CO': - case 'es_CR': - case 'es_CU': - case 'es_DO': - case 'es_EC': - case 'es_ES': - case 'es_GT': - case 'es_HN': - case 'es_MX': - case 'es_NI': - case 'es_PA': - case 'es_PE': - case 'es_PR': - case 'es_PY': - case 'es_SV': - case 'es_US': - case 'es_UY': - case 'es_VE': - case 'et': - case 'et_EE': - case 'eu': - case 'eu_ES': - case 'eu_FR': - case 'fa': - case 'fa_IR': - case 'fi': - case 'fi_FI': - case 'fo': - case 'fo_FO': - case 'fur': - case 'fur_IT': - case 'fy': - case 'fy_DE': - case 'fy_NL': - case 'gl': - case 'gl_ES': - case 'gu': - case 'gu_IN': - case 'ha': - case 'ha_NG': - case 'he': - case 'he_IL': - case 'hu': - case 'hu_HU': - case 'is': - case 'is_IS': - case 'it': - case 'it_CH': - case 'it_IT': - case 'ku': - case 'ku_TR': - case 'lb': - case 'lb_LU': - case 'ml': - case 'ml_IN': - case 'mn': - case 'mn_MN': - case 'mr': - case 'mr_IN': - case 'nah': - case 'nb': - case 'nb_NO': - case 'ne': - case 'ne_NP': - case 'nl': - case 'nl_AW': - case 'nl_BE': - case 'nl_NL': - case 'nn': - case 'nn_NO': - case 'no': - case 'om': - case 'om_ET': - case 'om_KE': - case 'or': - case 'or_IN': - case 'pa': - case 'pa_IN': - case 'pa_PK': - case 'pap': - case 'pap_AN': - case 'pap_AW': - case 'pap_CW': - case 'ps': - case 'ps_AF': - case 'pt': - case 'pt_BR': - case 'pt_PT': - case 'so': - case 'so_DJ': - case 'so_ET': - case 'so_KE': - case 'so_SO': - case 'sq': - case 'sq_AL': - case 'sq_MK': - case 'sv': - case 'sv_FI': - case 'sv_SE': - case 'sw': - case 'sw_KE': - case 'sw_TZ': - case 'ta': - case 'ta_IN': - case 'ta_LK': - case 'te': - case 'te_IN': - case 'tk': - case 'tk_TM': - case 'ur': - case 'ur_IN': - case 'ur_PK': - case 'zu': - case 'zu_ZA': - return ($number == 1) ? 0 : 1; - case 'am': - case 'am_ET': - case 'bh': - case 'fil': - case 'fil_PH': - case 'fr': - case 'fr_BE': - case 'fr_CA': - case 'fr_CH': - case 'fr_FR': - case 'fr_LU': - case 'gun': - case 'hi': - case 'hi_IN': - case 'hy': - case 'hy_AM': - case 'ln': - case 'ln_CD': - case 'mg': - case 'mg_MG': - case 'nso': - case 'nso_ZA': - case 'ti': - case 'ti_ER': - case 'ti_ET': - case 'wa': - case 'wa_BE': - case 'xbr': - return (($number == 0) || ($number == 1)) ? 0 : 1; - case 'be': - case 'be_BY': - case 'bs': - case 'bs_BA': - case 'hr': - case 'hr_HR': - case 'ru': - case 'ru_RU': - case 'ru_UA': - case 'sr': - case 'sr_ME': - case 'sr_RS': - case 'uk': - case 'uk_UA': - return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - case 'cs': - case 'cs_CZ': - case 'sk': - case 'sk_SK': - return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); - case 'ga': - case 'ga_IE': - return ($number == 1) ? 0 : (($number == 2) ? 1 : 2); - case 'lt': - case 'lt_LT': - return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - case 'sl': - case 'sl_SI': - return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3)); - case 'mk': - case 'mk_MK': - return ($number % 10 == 1) ? 0 : 1; - case 'mt': - case 'mt_MT': - return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); - case 'lv': - case 'lv_LV': - return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2); - case 'pl': - case 'pl_PL': - return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); - case 'cy': - case 'cy_GB': - return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3)); - case 'ro': - case 'ro_RO': - return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); - case 'ar': - case 'ar_AE': - case 'ar_BH': - case 'ar_DZ': - case 'ar_EG': - case 'ar_IN': - case 'ar_IQ': - case 'ar_JO': - case 'ar_KW': - case 'ar_LB': - case 'ar_LY': - case 'ar_MA': - case 'ar_OM': - case 'ar_QA': - case 'ar_SA': - case 'ar_SD': - case 'ar_SS': - case 'ar_SY': - case 'ar_TN': - case 'ar_YE': - return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); - default: - return 0; - } - } - - /** - * Extract a translation string using inline conditions. - * - * @param array $segments - * @param int $number - * @return mixed - */ - private function extract(array $segments, $number) - { - foreach ($segments as $part) { - if (! is_null($line = $this->extractFromString($part, $number))) { - return $line; - } - } - } - - /** - * Get the translation string if the condition matches. - * - * @param string $part - * @param int $number - * @return mixed - */ - private function extractFromString(string $part, $number) - { - preg_match('/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/s', $part, $matches); - - if (count($matches) !== 3) { - return; - } - - $condition = $matches[1]; - - $value = $matches[2]; - - if (Str::contains($condition, ',')) { - [$from, $to] = explode(',', $condition, 2); - - if ($to === '*' && $number >= $from) { - return $value; - } - if ($from === '*' && $number <= $to) { - return $value; - } - if ($number >= $from && $number <= $to) { - return $value; - } - } - - return $condition == $number ? $value : null; - } - - /** - * Strip the inline conditions from each segment, just leaving the text. - * - * @param array $segments - * @return array - */ - private function stripConditions(array $segments): array - { - return collect($segments)->map(function ($part) { - return preg_replace('/^[\{\[]([^\[\]\{\}]*)[\}\]]/', '', $part); - })->all(); - } -} diff --git a/src/translation/src/Support/NamespacedItemResolver.php b/src/translation/src/Support/NamespacedItemResolver.php deleted file mode 100755 index a65421770..000000000 --- a/src/translation/src/Support/NamespacedItemResolver.php +++ /dev/null @@ -1,112 +0,0 @@ -parsed[$key])) { - return $this->parsed[$key]; - } - - // If the key does not contain a double colon, it means the key is not in a - // namespace, and is just a regular configuration item. Namespaces are a - // tool for organizing configuration items for things such as modules. - if (strpos($key, '::') === false) { - $segments = explode('.', $key); - - $parsed = $this->parseBasicSegments($segments); - } else { - $parsed = $this->parseNamespacedSegments($key); - } - - // Once we have the parsed array of this key's elements, such as its groups - // and namespace, we will cache each array inside a simple list that has - // the key and the parsed array for quick look-ups for later requests. - return $this->parsed[$key] = $parsed; - } - - /** - * Set the parsed value of a key. - * - * @param string $key - * @param array $parsed - */ - public function setParsedKey(string $key, array $parsed) - { - $this->parsed[$key] = $parsed; - } - - /** - * Parse an array of basic segments. - * - * @param array $segments - * @return array - */ - protected function parseBasicSegments(array $segments) - { - // The first segment in a basic array will always be the group, so we can go - // ahead and grab that segment. If there is only one total segment we are - // just pulling an entire group out of the array and not a single item. - $group = $segments[0]; - - // If there is more than one segment in this group, it means we are pulling - // a specific item out of a group and will need to return this item name - // as well as the group so we know which item to pull from the arrays. - $item = count($segments) === 1 - ? null - : implode('.', array_slice($segments, 1)); - - return [null, $group, $item]; - } - - /** - * Parse an array of namespaced segments. - * - * @param string $key - * @return array - */ - protected function parseNamespacedSegments(string $key): array - { - [$namespace, $item] = explode('::', $key); - - // First we'll just explode the first segment to get the namespace and group - // since the item should be in the remaining segments. Once we have these - // two pieces of data we can proceed with parsing out the item's value. - $itemSegments = explode('.', $item); - - $groupAndItem = array_slice( - $this->parseBasicSegments($itemSegments), - 1 - ); - - return array_merge([$namespace], $groupAndItem); - } -} diff --git a/src/translation/src/Translator.php b/src/translation/src/Translator.php deleted file mode 100755 index e6df440ef..000000000 --- a/src/translation/src/Translator.php +++ /dev/null @@ -1,505 +0,0 @@ -loader = $loader; - $this->locale = $locale; - } - - /** - * Determine if a translation exists for a given locale. - * - * @param string $key - * @param null|string $locale - * @return bool - */ - public function hasForLocale(string $key, $locale = null): bool - { - return $this->has($key, $locale, false); - } - - /** - * Determine if a translation exists. - * - * @param string $key - * @param null|string $locale - * @param bool $fallback - * @return bool - */ - public function has(string $key, $locale = null, bool $fallback = true): bool - { - return $this->get($key, [], $locale, $fallback) !== $key; - } - - /** - * Get the translation for a given key. - * - * @param string $key - * @param array $replace - * @param null|string $locale - * @return array|string - */ - public function trans(string $key, array $replace = [], $locale = null) - { - return $this->get($key, $replace, $locale); - } - - /** - * Get the translation for the given key. - * - * @param string $key - * @param array $replace - * @param null|string $locale - * @param bool $fallback - * @return array|string - */ - public function get(string $key, array $replace = [], $locale = null, $fallback = true) - { - [$namespace, $group, $item] = $this->parseKey($key); - - // Here we will get the locale that should be used for the language line. If one - // was not passed, we will use the default locales which was given to us when - // the translator was instantiated. Then, we can load the lines and return. - $locales = $fallback ? $this->localeArray($locale) - : [$locale ?: $this->locale]; - - foreach ($locales as $locale) { - if (! is_null($line = $this->getLine( - $namespace, - $group, - $locale, - $item, - $replace - ))) { - break; - } - } - - // If the line doesn't exist, we will return back the key which was requested as - // that will be quick to spot in the UI if language keys are wrong or missing - // from the application's language files. Otherwise we can return the line. - return $line ?? $key; - } - - /** - * Get the translation for a given key from the JSON translation files. - * - * @param string $key - * @param array $replace - * @param null|string $locale - * @return array|string - */ - public function getFromJson(string $key, array $replace = [], $locale = null) - { - $locale = $locale ?: $this->locale; - - // For JSON translations, there is only one file per locale, so we will simply load - // that file and then we will be ready to check the array for the key. These are - // only one level deep so we do not need to do any fancy searching through it. - $this->load('*', '*', $locale); - - $line = $this->loaded['*']['*'][$locale][$key] ?? null; - - // If we can't find a translation for the JSON key, we will attempt to translate it - // using the typical translation file. This way developers can always just use a - // helper such as __ instead of having to pick between trans or __ with views. - if (! isset($line)) { - $fallback = $this->get($key, $replace, $locale); - - if ($fallback !== $key) { - return $fallback; - } - } - - return $this->makeReplacements($line ?: $key, $replace); - } - - /** - * Get a translation according to an integer value. - * - * @param string $key - * @param array|\Countable|int $number - * @param array $replace - * @param null|string $locale - * @return string - */ - public function transChoice(string $key, $number, array $replace = [], $locale = null): string - { - return $this->choice($key, $number, $replace, $locale); - } - - /** - * Get a translation according to an integer value. - * - * @param string $key - * @param array|\Countable|int $number - * @param array $replace - * @param null|string $locale - * @return string - */ - public function choice(string $key, $number, array $replace = [], $locale = null): string - { - $line = $this->get( - $key, - $replace, - $locale = $this->localeForChoice($locale) - ); - - // If the given "number" is actually an array or countable we will simply count the - // number of elements in an instance. This allows developers to pass an array of - // items without having to count it on their end first which gives bad syntax. - if (is_array($number) || $number instanceof Countable) { - $number = count($number); - } - - $replace['count'] = $number; - - return $this->makeReplacements( - $this->getSelector()->choose($line, $number, $locale), - $replace - ); - } - - /** - * Add translation lines to the given locale. - * - * @param array $lines - * @param string $locale - * @param string $namespace - */ - public function addLines(array $lines, string $locale, string $namespace = '*') - { - foreach ($lines as $key => $value) { - [$group, $item] = explode('.', $key, 2); - - Arr::set($this->loaded, "{$namespace}.{$group}.{$locale}.{$item}", $value); - } - } - - /** - * Load the specified language group. - * - * @param string $namespace - * @param string $group - * @param string $locale - */ - public function load(string $namespace, string $group, string $locale) - { - if ($this->isLoaded($namespace, $group, $locale)) { - return; - } - - // The loader is responsible for returning the array of language lines for the - // given namespace, group, and locale. We'll set the lines in this array of - // lines that have already been loaded so that we can easily access them. - $lines = $this->loader->load($locale, $group, $namespace); - - $this->loaded[$namespace][$group][$locale] = $lines; - } - - /** - * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint - */ - public function addNamespace(string $namespace, string $hint) - { - $this->loader->addNamespace($namespace, $hint); - } - - /** - * Add a new JSON path to the loader. - * - * @param string $path - */ - public function addJsonPath(string $path) - { - $this->loader->addJsonPath($path); - } - - /** - * Parse a key into namespace, group, and item. - * - * @param string $key - * @return array - */ - public function parseKey(string $key): array - { - $segments = parent::parseKey($key); - - if (is_null($segments[0])) { - $segments[0] = '*'; - } - - return $segments; - } - - /** - * Get the message selector instance. - * - * @return \Hyperf\Translation\MessageSelector - */ - public function getSelector() - { - if (! isset($this->selector)) { - $this->selector = new MessageSelector(); - } - - return $this->selector; - } - - /** - * Set the message selector instance. - * - * @param \Hyperf\Translation\MessageSelector $selector - */ - public function setSelector(MessageSelector $selector) - { - $this->selector = $selector; - } - - /** - * Get the language line loader implementation. - * - * @return \Hyperf\Translation\Contracts\Loader - */ - public function getLoader() - { - return $this->loader; - } - - /** - * Get the default locale being used. - * - * @return string - */ - public function locale(): string - { - return $this->getLocale(); - } - - /** - * Get the default locale being used. - * - * @return string - */ - public function getLocale(): string - { - return $this->locale; - } - - /** - * Set the default locale. - * - * @param string $locale - */ - public function setLocale(string $locale) - { - $this->locale = $locale; - } - - /** - * Get the fallback locale being used. - * - * @return string - */ - public function getFallback(): string - { - return $this->fallback; - } - - /** - * Set the fallback locale being used. - * - * @param string $fallback - */ - public function setFallback(string $fallback) - { - $this->fallback = $fallback; - } - - /** - * Set the loaded translation groups. - * - * @param array $loaded - */ - public function setLoaded(array $loaded) - { - $this->loaded = $loaded; - } - - /** - * Get the proper locale for a choice operation. - * - * @param null|string $locale - * @return string - */ - protected function localeForChoice($locale): string - { - return $locale ?: $this->locale ?: $this->fallback; - } - - /** - * Retrieve a language line out the loaded array. - * - * @param string $namespace - * @param string $group - * @param string $locale - * @param mixed $item - * @param array $replace - * @return null|array|string - */ - protected function getLine(string $namespace, string $group, string $locale, $item, array $replace) - { - $this->load($namespace, $group, $locale); - if (! is_null($item)) { - $line = Arr::get($this->loaded[$namespace][$group][$locale], $item); - } else { - // do for hyperf Arr::get - $line = $this->loaded[$namespace][$group][$locale]; - } - - if (is_string($line)) { - return $this->makeReplacements($line, $replace); - } - if (is_array($line) && count($line) > 0) { - foreach ($line as $key => $value) { - $line[$key] = $this->makeReplacements($value, $replace); - } - - return $line; - } - } - - /** - * Make the place-holder replacements on a line. - * - * @param string $line - * @param array $replace - * @return string - */ - protected function makeReplacements($line, array $replace) - { - if (empty($replace)) { - return $line; - } - - $replace = $this->sortReplacements($replace); - - foreach ($replace as $key => $value) { - $key = (string) $key; - $value = (string) $value; - $line = str_replace( - [':' . $key, ':' . Str::upper($key), ':' . Str::ucfirst($key)], - [$value, Str::upper($value), Str::ucfirst($value)], - $line - ); - } - - return $line; - } - - /** - * Sort the replacements array. - * - * @param array $replace - * @return array - */ - protected function sortReplacements(array $replace): array - { - return (new Collection($replace))->sortBy(function ($value, $key) { - return mb_strlen((string) $key) * -1; - })->all(); - } - - /** - * Determine if the given group has been loaded. - * - * @param string $namespace - * @param string $group - * @param string $locale - * @return bool - */ - protected function isLoaded(string $namespace, string $group, string $locale) - { - return isset($this->loaded[$namespace][$group][$locale]); - } - - /** - * Get the array of locales to be checked. - * - * @param null|string $locale - * @return array - */ - protected function localeArray($locale): array - { - return array_filter([$locale ?: $this->locale, $this->fallback]); - } -} diff --git a/src/translation/src/TranslatorFactory.php b/src/translation/src/TranslatorFactory.php deleted file mode 100644 index 4e10f689f..000000000 --- a/src/translation/src/TranslatorFactory.php +++ /dev/null @@ -1,38 +0,0 @@ -get(ConfigInterface::class); - $locale = $config->get('translation.locale'); - $fallbackLocale = $config->get('translation.fallback_locale'); - - $loader = $container->get(Loader::class); - - $trans = make(Translator::class, compact('loader', 'locale')); - $trans->setFallback((string) $fallbackLocale); - - return $trans; - } -} diff --git a/src/translation/tests/Cases/AbstractTestCase.php b/src/translation/tests/Cases/AbstractTestCase.php deleted file mode 100755 index 7174e4a7a..000000000 --- a/src/translation/tests/Cases/AbstractTestCase.php +++ /dev/null @@ -1,22 +0,0 @@ -shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(true); - $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/en/foo.php')->andReturn(['messages']); - - $this->assertEquals(['messages'], $loader->load('en', 'foo', null)); - } - - public function testLoadMethodWithNamespacesProperlyCallsLoader() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); - $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(false); - $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); - $loader->addNamespace('namespace', 'bar'); - - $this->assertEquals(['foo' => 'bar'], $loader->load('en', 'foo', 'namespace')); - } - - public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOverrides() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); - $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(true); - $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); - $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(['foo' => 'override', 'baz' => 'boom']); - $loader->addNamespace('namespace', 'bar'); - - $this->assertEquals(['foo' => 'override', 'baz' => 'boom'], $loader->load('en', 'foo', 'namespace')); - } - - public function testEmptyArraysReturnedWhenFilesDontExist() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(false); - $files->shouldReceive('getRequire')->never(); - - $this->assertEquals([], $loader->load('en', 'foo', null)); - } - - public function testEmptyArraysReturnedWhenFilesDontExistForNamespacedItems() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('getRequire')->never(); - - $this->assertEquals([], $loader->load('en', 'foo', 'bar')); - } - - public function testLoadMethodForJSONProperlyCallsLoader() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); - $files->shouldReceive('get')->once()->with(__DIR__ . '/en.json')->andReturn('{"foo":"bar"}'); - - $this->assertEquals(['foo' => 'bar'], $loader->load('en', '*', '*')); - } - - public function testLoadMethodForJSONProperlyCallsLoaderForMultiplePaths() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $loader->addJsonPath(__DIR__ . '/another'); - - $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); - $files->shouldReceive('exists')->once()->with(__DIR__ . '/another/en.json')->andReturn(true); - $files->shouldReceive('get')->once()->with(__DIR__ . '/en.json')->andReturn('{"foo":"bar"}'); - $files->shouldReceive('get')->once()->with(__DIR__ . '/another/en.json')->andReturn('{"foo":"backagebar", "baz": "backagesplash"}'); - - $this->assertEquals(['foo' => 'bar', 'baz' => 'backagesplash'], $loader->load('en', '*', '*')); - } -} diff --git a/src/translation/tests/Cases/TranslationMessageSelectorTest.php b/src/translation/tests/Cases/TranslationMessageSelectorTest.php deleted file mode 100755 index 65adea470..000000000 --- a/src/translation/tests/Cases/TranslationMessageSelectorTest.php +++ /dev/null @@ -1,85 +0,0 @@ -assertEquals($expected, $selector->choose($id, $number, 'en')); - } - - public function chooseTestData() - { - return [ - ['first', 'first', 1], - ['first', 'first', 10], - ['first', 'first|second', 1], - ['second', 'first|second', 10], - ['second', 'first|second', 0], - - ['first', '{0} first|{1}second', 0], - ['first', '{1}first|{2}second', 1], - ['second', '{1}first|{2}second', 2], - ['first', '{2}first|{1}second', 2], - ['second', '{9}first|{10}second', 0], - ['first', '{9}first|{10}second', 1], - ['', '{0}|{1}second', 0], - ['', '{0}first|{1}', 1], - ['first', '{1.3}first|{2.3}second', 1.3], - ['second', '{1.3}first|{2.3}second', 2.3], - ['first - line', '{1}first - line|{2}second', 1], - ["first \n - line", "{1}first \n - line|{2}second", 1], - - ['first', '{0} first|[1,9]second', 0], - ['second', '{0}first|[1,9]second', 1], - ['second', '{0}first|[1,9]second', 10], - ['first', '{0}first|[2,9]second', 1], - ['second', '[4,*]first|[1,3]second', 1], - ['first', '[4,*]first|[1,3]second', 100], - ['second', '[1,5]first|[6,10]second', 7], - ['first', '[*,4]first|[5,*]second', 1], - ['second', '[5,*]first|[*,4]second', 1], - ['second', '[5,*]first|[*,4]second', 0], - - ['first', '{0}first|[1,3]second|[4,*]third', 0], - ['second', '{0}first|[1,3]second|[4,*]third', 1], - ['third', '{0}first|[1,3]second|[4,*]third', 9], - - ['first', 'first|second|third', 1], - ['second', 'first|second|third', 9], - ['second', 'first|second|third', 0], - - ['first', '{0} first | { 1 } second', 0], - ['first', '[4,*]first | [1,3]second', 100], - ]; - } -} diff --git a/src/translation/tests/Cases/TranslationTranslatorTest.php b/src/translation/tests/Cases/TranslationTranslatorTest.php deleted file mode 100755 index 5a6e6f24a..000000000 --- a/src/translation/tests/Cases/TranslationTranslatorTest.php +++ /dev/null @@ -1,199 +0,0 @@ -getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('foo')); - $this->assertFalse($t->has('foo', 'bar')); - - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en', 'sp'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('bar')); - $this->assertTrue($t->has('foo', 'bar')); - - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('bar')); - $this->assertTrue($t->hasForLocale('foo', 'bar')); - - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('foo')); - $this->assertFalse($t->hasForLocale('foo', 'bar')); - - $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); - $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('bar')); - $this->assertTrue($t->hasForLocale('foo')); - - $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); - $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('foo')); - $this->assertFalse($t->hasForLocale('foo')); - } - - public function testGetMethodProperlyLoadsAndRetrievesItem() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo', 'qux' => ['tree :foo', 'breeze :foo']]); - $this->assertEquals(['tree bar', 'breeze bar'], $t->get('foo::bar.qux', ['foo' => 'bar'], 'en')); - $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - public function testTransMethodProperlyLoadsAndRetrievesItemWithHTMLInTheMessage() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze

test

']); - $this->assertSame('breeze

test

', $t->trans('foo.bar', [], 'en')); - } - - public function testGetMethodProperlyLoadsAndRetrievesItemWithCapitalization() - { - $t = $this->getMockBuilder(Translator::class)->setMethods(null)->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :Foo :BAR']); - $this->assertEquals('breeze Bar FOO', $t->get('foo::bar.baz', ['foo' => 'bar', 'bar' => 'foo'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - public function testGetMethodProperlyLoadsAndRetrievesItemWithLongestReplacementsFirst() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo :foobar']); - $this->assertEquals('breeze bar taylor', $t->get('foo::bar.baz', ['foo' => 'bar', 'foobar' => 'taylor'], 'en')); - $this->assertEquals('breeze foo bar baz taylor', $t->get('foo::bar.baz', ['foo' => 'foo bar baz', 'foobar' => 'taylor'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - public function testGetMethodProperlyLoadsAndRetrievesItemForFallback() - { - $t = new Translator($this->getLoader(), 'en'); - $t->setFallback('lv'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('lv', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo']); - $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - public function testGetMethodProperlyLoadsAndRetrievesItemForGlobalNamespace() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze :foo']); - $this->assertEquals('breeze bar', $t->get('foo.bar', ['foo' => 'bar'])); - } - - public function testChoiceMethodProperlyLoadsAndRetrievesItem() - { - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); - $t->setSelector($selector = m::mock(MessageSelector::class)); - $selector->shouldReceive('choose')->once()->with('line', 10, 'en')->andReturn('choiced'); - - $t->choice('foo', 10, ['replace']); - } - - public function testChoiceMethodProperlyCountsCollectionsAndLoadsAndRetrievesItem() - { - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->exactly(2))->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); - $t->setSelector($selector = m::mock(MessageSelector::class)); - $selector->shouldReceive('choose')->twice()->with('line', 3, 'en')->andReturn('choiced'); - - $values = ['foo', 'bar', 'baz']; - $t->choice('foo', $values, ['replace']); - - $values = new Collection(['foo', 'bar', 'baz']); - $t->choice('foo', $values, ['replace']); - } - - public function testGetJsonMethod() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo' => 'one']); - $this->assertEquals('one', $t->getFromJson('foo')); - } - - public function testGetJsonReplaces() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo :i:c :u' => 'bar :i:c :u']); - $this->assertEquals('bar onetwo three', $t->getFromJson('foo :i:c :u', ['i' => 'one', 'c' => 'two', 'u' => 'three'])); - } - - public function testGetJsonReplacesForAssociativeInput() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo :i :c' => 'bar :i :c']); - $this->assertEquals('bar eye see', $t->getFromJson('foo :i :c', ['i' => 'eye', 'c' => 'see'])); - } - - public function testGetJsonPreservesOrder() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['to :name I give :greeting' => ':greeting :name']); - $this->assertEquals('Greetings David', $t->getFromJson('to :name I give :greeting', ['name' => 'David', 'greeting' => 'Greetings'])); - } - - public function testGetJsonForNonExistingJsonKeyLooksForRegularKeys() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'one']); - $this->assertEquals('one', $t->getFromJson('foo.bar')); - } - - public function testGetJsonForNonExistingJsonKeyLooksForRegularKeysAndReplace() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'one :message']); - $this->assertEquals('one two', $t->getFromJson('foo.bar', ['message' => 'two'])); - } - - public function testGetJsonForNonExistingReturnsSameKey() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'Foo that bar', '*')->andReturn([]); - $this->assertEquals('Foo that bar', $t->getFromJson('Foo that bar')); - } - - public function testGetJsonForNonExistingReturnsSameKeyAndReplaces() - { - $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo :message', '*')->andReturn([]); - $this->assertEquals('foo baz', $t->getFromJson('foo :message', ['message' => 'baz'])); - } - - protected function getLoader() - { - return m::mock(Loader::class); - } -} diff --git a/src/translation/tests/bootstrap.php b/src/translation/tests/bootstrap.php deleted file mode 100755 index 210da6cde..000000000 --- a/src/translation/tests/bootstrap.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Thu, 22 Aug 2019 10:39:46 +0800 Subject: [PATCH 09/79] Revert "Deleted useless code." This reverts commit b50b12bdf47129aaf811f58b8fdd0b9c741b9311. --- composer.json | 3 + phpunit.xml | 1 + src/graphql/src/AnnotationReader.php | 6 + src/translation/.gitattributes | 1 + src/translation/.gitignore | 11 + src/translation/LICENSE.md | 9 + src/translation/README.MD | 64 +++ src/translation/composer.json | 48 ++ src/translation/publish/translation.php | 17 + src/translation/src/ArrayLoader.php | 87 +++ src/translation/src/ConfigProvider.php | 42 ++ .../src/Contracts/HasLocalePreference.php | 23 + src/translation/src/Contracts/Loader.php | 48 ++ src/translation/src/Contracts/Translator.php | 51 ++ src/translation/src/FileLoader.php | 193 +++++++ src/translation/src/FileLoaderFactory.php | 29 + src/translation/src/MessageSelector.php | 424 +++++++++++++++ .../src/Support/NamespacedItemResolver.php | 112 ++++ src/translation/src/Translator.php | 505 ++++++++++++++++++ src/translation/src/TranslatorFactory.php | 38 ++ .../tests/Cases/AbstractTestCase.php | 22 + .../tests/Cases/TranslationFileLoaderTest.php | 100 ++++ .../Cases/TranslationMessageSelectorTest.php | 85 +++ .../tests/Cases/TranslationTranslatorTest.php | 199 +++++++ src/translation/tests/bootstrap.php | 13 + src/translation/tests/ci.ini | 8 + src/translation/tests/swoole.install.sh | 10 + 27 files changed, 2149 insertions(+) create mode 100644 src/translation/.gitattributes create mode 100644 src/translation/.gitignore create mode 100644 src/translation/LICENSE.md create mode 100644 src/translation/README.MD create mode 100644 src/translation/composer.json create mode 100644 src/translation/publish/translation.php create mode 100644 src/translation/src/ArrayLoader.php create mode 100644 src/translation/src/ConfigProvider.php create mode 100644 src/translation/src/Contracts/HasLocalePreference.php create mode 100755 src/translation/src/Contracts/Loader.php create mode 100644 src/translation/src/Contracts/Translator.php create mode 100755 src/translation/src/FileLoader.php create mode 100644 src/translation/src/FileLoaderFactory.php create mode 100755 src/translation/src/MessageSelector.php create mode 100755 src/translation/src/Support/NamespacedItemResolver.php create mode 100755 src/translation/src/Translator.php create mode 100644 src/translation/src/TranslatorFactory.php create mode 100755 src/translation/tests/Cases/AbstractTestCase.php create mode 100755 src/translation/tests/Cases/TranslationFileLoaderTest.php create mode 100755 src/translation/tests/Cases/TranslationMessageSelectorTest.php create mode 100755 src/translation/tests/Cases/TranslationTranslatorTest.php create mode 100755 src/translation/tests/bootstrap.php create mode 100755 src/translation/tests/ci.ini create mode 100755 src/translation/tests/swoole.install.sh diff --git a/composer.json b/composer.json index 273b94aea..67c0832b1 100644 --- a/composer.json +++ b/composer.json @@ -161,6 +161,7 @@ "Hyperf\\Task\\": "src/task/src/", "Hyperf\\Testing\\": "src/testing/src/", "Hyperf\\Tracer\\": "src/tracer/src/", + "Hyperf\\Translation\\": "src/translation/src/", "Hyperf\\Utils\\": "src/utils/src/", "Hyperf\\Validation\\": "src/validation/src/", "Hyperf\\View\\": "src/view/src/", @@ -206,6 +207,7 @@ "HyperfTest\\ServiceGovernance\\": "src/service-governance/tests/", "HyperfTest\\Snowflake\\": "src/snowflake/tests/", "HyperfTest\\Task\\": "src/task/tests/", + "HyperfTest\\Translation\\": "src/translation/tests/", "HyperfTest\\Utils\\": "src/utils/tests/", "HyperfTest\\Validation\\": "src/validation/tests/", "HyperfTest\\WebSocketClient\\": "src/websocket-client/tests/" @@ -259,6 +261,7 @@ "Hyperf\\SwooleEnterprise\\ConfigProvider", "Hyperf\\Task\\ConfigProvider", "Hyperf\\Tracer\\ConfigProvider", + "Hyperf\\Translation\\ConfigProvider", "Hyperf\\Utils\\ConfigProvider", "Hyperf\\Validation\\ConfigProvider", "Hyperf\\View\\ConfigProvider", diff --git a/phpunit.xml b/phpunit.xml index cab85b70b..758fec5b3 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -36,6 +36,7 @@ ./src/service-governance/tests ./src/snowflake/tests ./src/task/tests + ./src/translation/tests ./src/utils/tests ./src/validation/tests ./src/websocket-client/tests diff --git a/src/graphql/src/AnnotationReader.php b/src/graphql/src/AnnotationReader.php index 3ecd25fea..d01f6d90b 100644 --- a/src/graphql/src/AnnotationReader.php +++ b/src/graphql/src/AnnotationReader.php @@ -101,21 +101,25 @@ class AnnotationReader public function getRequestAnnotation(ReflectionMethod $refMethod, string $annotationName): ?AbstractRequest { + /* @var null|AbstractRequest $queryAnnotation */ return $this->getMethodAnnotation($refMethod, $annotationName); } public function getLoggedAnnotation(ReflectionMethod $refMethod): ?Logged { + /* @var null|Logged $loggedAnnotation */ return $this->getMethodAnnotation($refMethod, Logged::class); } public function getRightAnnotation(ReflectionMethod $refMethod): ?Right { + /* @var null|Right $rightAnnotation */ return $this->getMethodAnnotation($refMethod, Right::class); } public function getFailWithAnnotation(ReflectionMethod $refMethod): ?FailWith { + /* @var null|FailWith $failWithAnnotation */ return $this->getMethodAnnotation($refMethod, FailWith::class); } @@ -124,11 +128,13 @@ class AnnotationReader */ public function getSourceFields(ReflectionClass $refClass): array { + /* @var SourceField[] $sourceFields */ return $this->getClassAnnotations($refClass, SourceField::class); } public function getFactoryAnnotation(ReflectionMethod $refMethod): ?Factory { + /* @var null|Factory $factoryAnnotation */ return $this->getMethodAnnotation($refMethod, Factory::class); } diff --git a/src/translation/.gitattributes b/src/translation/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/translation/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/translation/.gitignore b/src/translation/.gitignore new file mode 100644 index 000000000..f72f9fd06 --- /dev/null +++ b/src/translation/.gitignore @@ -0,0 +1,11 @@ +.buildpath +.settings/ +.project +*.patch +.idea/ +.git/ +.phpintel/ +.DS_Store +*.lock +.phpunit* +vendor \ No newline at end of file diff --git a/src/translation/LICENSE.md b/src/translation/LICENSE.md new file mode 100644 index 000000000..eb14702a3 --- /dev/null +++ b/src/translation/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) Hyperf + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/translation/README.MD b/src/translation/README.MD new file mode 100644 index 000000000..050cb26e0 --- /dev/null +++ b/src/translation/README.MD @@ -0,0 +1,64 @@ +# Hyperf Translation + +## About + +hyperf/translation 是对Laravel Translation的移植(不包含门面和快捷函数部分),具体使用方法可以参考Laravel Lang的使用。 + +## Install + +``` +composer require hyperf/translation + +``` + +## Config + + +### publish config +``` +php bin/hyperf.php vendor:publish hyperf/translation + +``` + +### config path + +``` +your/config/path/autoload/translation.php + +``` + +### config content + +``` + 'en', + 'fallback_locale' => '', + 'lang' => BASE_PATH . '/resources/lang', +]; + +``` + +## Usage + + +``` + +$translator = $this->container->get(\Hyperf\Translation\Contracts\Translator::class); + +$translator->trans('validation.accepted'), + + +``` \ No newline at end of file diff --git a/src/translation/composer.json b/src/translation/composer.json new file mode 100644 index 000000000..2e4937ddf --- /dev/null +++ b/src/translation/composer.json @@ -0,0 +1,48 @@ +{ + "name": "hyperf/translation", + "type": "library", + "license": "MIT", + "keywords": [ + "translation", + "hyperf" + ], + "description": "", + "autoload": { + "psr-4": { + "Hyperf\\Translation\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "HyperfTest\\Translation\\": "tests" + } + }, + "require": { + "php": ">=7.2", + "ext-swoole": ">=4.3", + "hyperf/utils": "1.0.*", + "hyperf/framework": "1.0.*", + "hyperf/di": "1.0.*", + "psr/container": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "hyperf/testing": "1.0.*", + "mockery/mockery": "^1.2", + "phpstan/phpstan": "^0.10.5", + "swoft/swoole-ide-helper": "^4.4.0" + }, + "config": { + "sort-packages": true + }, + "scripts": { + "test": "co-phpunit -c phpunit.xml --colors=always", + "analyze": "phpstan analyse --memory-limit 300M -l 0 ./src", + "cs-fix": "php-cs-fixer fix $1" + }, + "extra": { + "hyperf": { + "config": "Hyperf\\Translation\\ConfigProvider" + } + } +} diff --git a/src/translation/publish/translation.php b/src/translation/publish/translation.php new file mode 100644 index 000000000..9278bd458 --- /dev/null +++ b/src/translation/publish/translation.php @@ -0,0 +1,17 @@ + 'zh_CN', + 'fallback_locale' => 'en', + 'lang' => BASE_PATH . '/resources/lang', +]; diff --git a/src/translation/src/ArrayLoader.php b/src/translation/src/ArrayLoader.php new file mode 100644 index 000000000..75d7825a6 --- /dev/null +++ b/src/translation/src/ArrayLoader.php @@ -0,0 +1,87 @@ +messages[$namespace][$locale][$group] ?? []; + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string $hint + */ + public function addNamespace(string $namespace, string $hint) + { + } + + /** + * Add a new JSON path to the loader. + * + * @param string $path + */ + public function addJsonPath(string $path) + { + } + + /** + * Add messages to the loader. + * + * @param string $locale + * @param string $group + * @param array $messages + * @param null|string $namespace + * @return $this + */ + public function addMessages(string $locale, string $group, array $messages, $namespace = null) + { + $namespace = $namespace ?: '*'; + + $this->messages[$namespace][$locale][$group] = $messages; + + return $this; + } + + /** + * Get an array of all the registered namespaces. + * + * @return array + */ + public function namespaces(): array + { + return []; + } +} diff --git a/src/translation/src/ConfigProvider.php b/src/translation/src/ConfigProvider.php new file mode 100644 index 000000000..e7fd6f83b --- /dev/null +++ b/src/translation/src/ConfigProvider.php @@ -0,0 +1,42 @@ + [ + Loader::class => FileLoaderFactory::class, + Translator::class => TranslatorFactory::class, + ], + 'scan' => [ + 'paths' => [ + __DIR__, + ], + ], + 'publish' => [ + [ + 'id' => 'config', + 'description' => 'The config for translation.', + 'source' => __DIR__ . '/../publish/translation.php', + 'destination' => BASE_PATH . '/config/autoload/translation.php', + ], + ], + ]; + } +} diff --git a/src/translation/src/Contracts/HasLocalePreference.php b/src/translation/src/Contracts/HasLocalePreference.php new file mode 100644 index 000000000..430de5950 --- /dev/null +++ b/src/translation/src/Contracts/HasLocalePreference.php @@ -0,0 +1,23 @@ +path = $path; + $this->files = $files; + } + + /** + * Load the messages for the given locale. + * + * @param string $locale + * @param string $group + * @param null|string $namespace + * @return array + */ + public function load(string $locale, string $group, $namespace = null): array + { + if ($group === '*' && $namespace === '*') { + return $this->loadJsonPaths($locale); + } + + if (is_null($namespace) || $namespace === '*') { + return $this->loadPath($this->path, $locale, $group); + } + + return $this->loadNamespaced($locale, $group, $namespace); + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string $hint + */ + public function addNamespace(string $namespace, string $hint) + { + $this->hints[$namespace] = $hint; + } + + /** + * Add a new JSON path to the loader. + * + * @param string $path + */ + public function addJsonPath(string $path) + { + $this->jsonPaths[] = $path; + } + + /** + * Get an array of all the registered namespaces. + * + * @return array + */ + public function namespaces(): array + { + return $this->hints; + } + + /** + * Load a namespaced translation group. + * + * @param string $locale + * @param string $group + * @param string $namespace + * @return array + */ + protected function loadNamespaced(string $locale, string $group, string $namespace): array + { + if (isset($this->hints[$namespace])) { + $lines = $this->loadPath($this->hints[$namespace], $locale, $group); + + return $this->loadNamespaceOverrides($lines, $locale, $group, $namespace); + } + + return []; + } + + /** + * Load a local namespaced translation group for overrides. + * + * @param array $lines + * @param string $locale + * @param string $group + * @param string $namespace + * @return array + */ + protected function loadNamespaceOverrides(array $lines, string $locale, string $group, string $namespace): array + { + $file = "{$this->path}/vendor/{$namespace}/{$locale}/{$group}.php"; + + if ($this->files->exists($file)) { + return array_replace_recursive($lines, $this->files->getRequire($file)); + } + + return $lines; + } + + /** + * Load a locale from a given path. + * + * @param string $path + * @param string $locale + * @param string $group + * @return array + */ + protected function loadPath(string $path, string $locale, string $group): array + { + if ($this->files->exists($full = "{$path}/{$locale}/{$group}.php")) { + return $this->files->getRequire($full); + } + + return []; + } + + /** + * Load a locale from the given JSON file path. + * + * @param string $locale + * @throws \RuntimeException + * @return array + */ + protected function loadJsonPaths(string $locale) + { + return collect(array_merge($this->jsonPaths, [$this->path])) + ->reduce(function ($output, $path) use ($locale) { + if ($this->files->exists($full = "{$path}/{$locale}.json")) { + $decoded = json_decode($this->files->get($full), true); + + if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) { + throw new RuntimeException("Translation file [{$full}] contains an invalid JSON structure."); + } + + $output = array_merge($output, $decoded); + } + + return $output; + }, []); + } +} diff --git a/src/translation/src/FileLoaderFactory.php b/src/translation/src/FileLoaderFactory.php new file mode 100644 index 000000000..60c387fbc --- /dev/null +++ b/src/translation/src/FileLoaderFactory.php @@ -0,0 +1,29 @@ +get(ConfigInterface::class); + $files = $container->get(Filesystem::class); + $path = $config->get('translation.lang'); + + return make(FileLoader::class, compact('files', 'path')); + } +} diff --git a/src/translation/src/MessageSelector.php b/src/translation/src/MessageSelector.php new file mode 100755 index 000000000..0672e9d78 --- /dev/null +++ b/src/translation/src/MessageSelector.php @@ -0,0 +1,424 @@ +extract($segments, $number)) !== null) { + return trim($value); + } + + $segments = $this->stripConditions($segments); + + $pluralIndex = $this->getPluralIndex($locale, $number); + + if (count($segments) === 1 || ! isset($segments[$pluralIndex])) { + return $segments[0]; + } + + return $segments[$pluralIndex]; + } + + /** + * Get the index to use for pluralization. + * + * The plural rules are derived from code of the Zend Framework (2010-09-25), which + * is subject to the new BSD license (http://framework.zend.com/license/new-bsd) + * Copyright (c) 2005-2010 - Zend Technologies USA Inc. (http://www.zend.com) + * + * @param string $locale + * @param int $number + * @return int + */ + public function getPluralIndex(string $locale, int $number): int + { + switch ($locale) { + case 'az': + case 'az_AZ': + case 'bo': + case 'bo_CN': + case 'bo_IN': + case 'dz': + case 'dz_BT': + case 'id': + case 'id_ID': + case 'ja': + case 'ja_JP': + case 'jv': + case 'ka': + case 'ka_GE': + case 'km': + case 'km_KH': + case 'kn': + case 'kn_IN': + case 'ko': + case 'ko_KR': + case 'ms': + case 'ms_MY': + case 'th': + case 'th_TH': + case 'tr': + case 'tr_CY': + case 'tr_TR': + case 'vi': + case 'vi_VN': + case 'zh': + case 'zh_CN': + case 'zh_HK': + case 'zh_SG': + case 'zh_TW': + return 0; + case 'af': + case 'af_ZA': + case 'bn': + case 'bn_BD': + case 'bn_IN': + case 'bg': + case 'bg_BG': + case 'ca': + case 'ca_AD': + case 'ca_ES': + case 'ca_FR': + case 'ca_IT': + case 'da': + case 'da_DK': + case 'de': + case 'de_AT': + case 'de_BE': + case 'de_CH': + case 'de_DE': + case 'de_LI': + case 'de_LU': + case 'el': + case 'el_CY': + case 'el_GR': + case 'en': + case 'en_AG': + case 'en_AU': + case 'en_BW': + case 'en_CA': + case 'en_DK': + case 'en_GB': + case 'en_HK': + case 'en_IE': + case 'en_IN': + case 'en_NG': + case 'en_NZ': + case 'en_PH': + case 'en_SG': + case 'en_US': + case 'en_ZA': + case 'en_ZM': + case 'en_ZW': + case 'eo': + case 'eo_US': + case 'es': + case 'es_AR': + case 'es_BO': + case 'es_CL': + case 'es_CO': + case 'es_CR': + case 'es_CU': + case 'es_DO': + case 'es_EC': + case 'es_ES': + case 'es_GT': + case 'es_HN': + case 'es_MX': + case 'es_NI': + case 'es_PA': + case 'es_PE': + case 'es_PR': + case 'es_PY': + case 'es_SV': + case 'es_US': + case 'es_UY': + case 'es_VE': + case 'et': + case 'et_EE': + case 'eu': + case 'eu_ES': + case 'eu_FR': + case 'fa': + case 'fa_IR': + case 'fi': + case 'fi_FI': + case 'fo': + case 'fo_FO': + case 'fur': + case 'fur_IT': + case 'fy': + case 'fy_DE': + case 'fy_NL': + case 'gl': + case 'gl_ES': + case 'gu': + case 'gu_IN': + case 'ha': + case 'ha_NG': + case 'he': + case 'he_IL': + case 'hu': + case 'hu_HU': + case 'is': + case 'is_IS': + case 'it': + case 'it_CH': + case 'it_IT': + case 'ku': + case 'ku_TR': + case 'lb': + case 'lb_LU': + case 'ml': + case 'ml_IN': + case 'mn': + case 'mn_MN': + case 'mr': + case 'mr_IN': + case 'nah': + case 'nb': + case 'nb_NO': + case 'ne': + case 'ne_NP': + case 'nl': + case 'nl_AW': + case 'nl_BE': + case 'nl_NL': + case 'nn': + case 'nn_NO': + case 'no': + case 'om': + case 'om_ET': + case 'om_KE': + case 'or': + case 'or_IN': + case 'pa': + case 'pa_IN': + case 'pa_PK': + case 'pap': + case 'pap_AN': + case 'pap_AW': + case 'pap_CW': + case 'ps': + case 'ps_AF': + case 'pt': + case 'pt_BR': + case 'pt_PT': + case 'so': + case 'so_DJ': + case 'so_ET': + case 'so_KE': + case 'so_SO': + case 'sq': + case 'sq_AL': + case 'sq_MK': + case 'sv': + case 'sv_FI': + case 'sv_SE': + case 'sw': + case 'sw_KE': + case 'sw_TZ': + case 'ta': + case 'ta_IN': + case 'ta_LK': + case 'te': + case 'te_IN': + case 'tk': + case 'tk_TM': + case 'ur': + case 'ur_IN': + case 'ur_PK': + case 'zu': + case 'zu_ZA': + return ($number == 1) ? 0 : 1; + case 'am': + case 'am_ET': + case 'bh': + case 'fil': + case 'fil_PH': + case 'fr': + case 'fr_BE': + case 'fr_CA': + case 'fr_CH': + case 'fr_FR': + case 'fr_LU': + case 'gun': + case 'hi': + case 'hi_IN': + case 'hy': + case 'hy_AM': + case 'ln': + case 'ln_CD': + case 'mg': + case 'mg_MG': + case 'nso': + case 'nso_ZA': + case 'ti': + case 'ti_ER': + case 'ti_ET': + case 'wa': + case 'wa_BE': + case 'xbr': + return (($number == 0) || ($number == 1)) ? 0 : 1; + case 'be': + case 'be_BY': + case 'bs': + case 'bs_BA': + case 'hr': + case 'hr_HR': + case 'ru': + case 'ru_RU': + case 'ru_UA': + case 'sr': + case 'sr_ME': + case 'sr_RS': + case 'uk': + case 'uk_UA': + return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + case 'cs': + case 'cs_CZ': + case 'sk': + case 'sk_SK': + return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); + case 'ga': + case 'ga_IE': + return ($number == 1) ? 0 : (($number == 2) ? 1 : 2); + case 'lt': + case 'lt_LT': + return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + case 'sl': + case 'sl_SI': + return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3)); + case 'mk': + case 'mk_MK': + return ($number % 10 == 1) ? 0 : 1; + case 'mt': + case 'mt_MT': + return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); + case 'lv': + case 'lv_LV': + return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2); + case 'pl': + case 'pl_PL': + return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); + case 'cy': + case 'cy_GB': + return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3)); + case 'ro': + case 'ro_RO': + return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); + case 'ar': + case 'ar_AE': + case 'ar_BH': + case 'ar_DZ': + case 'ar_EG': + case 'ar_IN': + case 'ar_IQ': + case 'ar_JO': + case 'ar_KW': + case 'ar_LB': + case 'ar_LY': + case 'ar_MA': + case 'ar_OM': + case 'ar_QA': + case 'ar_SA': + case 'ar_SD': + case 'ar_SS': + case 'ar_SY': + case 'ar_TN': + case 'ar_YE': + return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); + default: + return 0; + } + } + + /** + * Extract a translation string using inline conditions. + * + * @param array $segments + * @param int $number + * @return mixed + */ + private function extract(array $segments, $number) + { + foreach ($segments as $part) { + if (! is_null($line = $this->extractFromString($part, $number))) { + return $line; + } + } + } + + /** + * Get the translation string if the condition matches. + * + * @param string $part + * @param int $number + * @return mixed + */ + private function extractFromString(string $part, $number) + { + preg_match('/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/s', $part, $matches); + + if (count($matches) !== 3) { + return; + } + + $condition = $matches[1]; + + $value = $matches[2]; + + if (Str::contains($condition, ',')) { + [$from, $to] = explode(',', $condition, 2); + + if ($to === '*' && $number >= $from) { + return $value; + } + if ($from === '*' && $number <= $to) { + return $value; + } + if ($number >= $from && $number <= $to) { + return $value; + } + } + + return $condition == $number ? $value : null; + } + + /** + * Strip the inline conditions from each segment, just leaving the text. + * + * @param array $segments + * @return array + */ + private function stripConditions(array $segments): array + { + return collect($segments)->map(function ($part) { + return preg_replace('/^[\{\[]([^\[\]\{\}]*)[\}\]]/', '', $part); + })->all(); + } +} diff --git a/src/translation/src/Support/NamespacedItemResolver.php b/src/translation/src/Support/NamespacedItemResolver.php new file mode 100755 index 000000000..a65421770 --- /dev/null +++ b/src/translation/src/Support/NamespacedItemResolver.php @@ -0,0 +1,112 @@ +parsed[$key])) { + return $this->parsed[$key]; + } + + // If the key does not contain a double colon, it means the key is not in a + // namespace, and is just a regular configuration item. Namespaces are a + // tool for organizing configuration items for things such as modules. + if (strpos($key, '::') === false) { + $segments = explode('.', $key); + + $parsed = $this->parseBasicSegments($segments); + } else { + $parsed = $this->parseNamespacedSegments($key); + } + + // Once we have the parsed array of this key's elements, such as its groups + // and namespace, we will cache each array inside a simple list that has + // the key and the parsed array for quick look-ups for later requests. + return $this->parsed[$key] = $parsed; + } + + /** + * Set the parsed value of a key. + * + * @param string $key + * @param array $parsed + */ + public function setParsedKey(string $key, array $parsed) + { + $this->parsed[$key] = $parsed; + } + + /** + * Parse an array of basic segments. + * + * @param array $segments + * @return array + */ + protected function parseBasicSegments(array $segments) + { + // The first segment in a basic array will always be the group, so we can go + // ahead and grab that segment. If there is only one total segment we are + // just pulling an entire group out of the array and not a single item. + $group = $segments[0]; + + // If there is more than one segment in this group, it means we are pulling + // a specific item out of a group and will need to return this item name + // as well as the group so we know which item to pull from the arrays. + $item = count($segments) === 1 + ? null + : implode('.', array_slice($segments, 1)); + + return [null, $group, $item]; + } + + /** + * Parse an array of namespaced segments. + * + * @param string $key + * @return array + */ + protected function parseNamespacedSegments(string $key): array + { + [$namespace, $item] = explode('::', $key); + + // First we'll just explode the first segment to get the namespace and group + // since the item should be in the remaining segments. Once we have these + // two pieces of data we can proceed with parsing out the item's value. + $itemSegments = explode('.', $item); + + $groupAndItem = array_slice( + $this->parseBasicSegments($itemSegments), + 1 + ); + + return array_merge([$namespace], $groupAndItem); + } +} diff --git a/src/translation/src/Translator.php b/src/translation/src/Translator.php new file mode 100755 index 000000000..e6df440ef --- /dev/null +++ b/src/translation/src/Translator.php @@ -0,0 +1,505 @@ +loader = $loader; + $this->locale = $locale; + } + + /** + * Determine if a translation exists for a given locale. + * + * @param string $key + * @param null|string $locale + * @return bool + */ + public function hasForLocale(string $key, $locale = null): bool + { + return $this->has($key, $locale, false); + } + + /** + * Determine if a translation exists. + * + * @param string $key + * @param null|string $locale + * @param bool $fallback + * @return bool + */ + public function has(string $key, $locale = null, bool $fallback = true): bool + { + return $this->get($key, [], $locale, $fallback) !== $key; + } + + /** + * Get the translation for a given key. + * + * @param string $key + * @param array $replace + * @param null|string $locale + * @return array|string + */ + public function trans(string $key, array $replace = [], $locale = null) + { + return $this->get($key, $replace, $locale); + } + + /** + * Get the translation for the given key. + * + * @param string $key + * @param array $replace + * @param null|string $locale + * @param bool $fallback + * @return array|string + */ + public function get(string $key, array $replace = [], $locale = null, $fallback = true) + { + [$namespace, $group, $item] = $this->parseKey($key); + + // Here we will get the locale that should be used for the language line. If one + // was not passed, we will use the default locales which was given to us when + // the translator was instantiated. Then, we can load the lines and return. + $locales = $fallback ? $this->localeArray($locale) + : [$locale ?: $this->locale]; + + foreach ($locales as $locale) { + if (! is_null($line = $this->getLine( + $namespace, + $group, + $locale, + $item, + $replace + ))) { + break; + } + } + + // If the line doesn't exist, we will return back the key which was requested as + // that will be quick to spot in the UI if language keys are wrong or missing + // from the application's language files. Otherwise we can return the line. + return $line ?? $key; + } + + /** + * Get the translation for a given key from the JSON translation files. + * + * @param string $key + * @param array $replace + * @param null|string $locale + * @return array|string + */ + public function getFromJson(string $key, array $replace = [], $locale = null) + { + $locale = $locale ?: $this->locale; + + // For JSON translations, there is only one file per locale, so we will simply load + // that file and then we will be ready to check the array for the key. These are + // only one level deep so we do not need to do any fancy searching through it. + $this->load('*', '*', $locale); + + $line = $this->loaded['*']['*'][$locale][$key] ?? null; + + // If we can't find a translation for the JSON key, we will attempt to translate it + // using the typical translation file. This way developers can always just use a + // helper such as __ instead of having to pick between trans or __ with views. + if (! isset($line)) { + $fallback = $this->get($key, $replace, $locale); + + if ($fallback !== $key) { + return $fallback; + } + } + + return $this->makeReplacements($line ?: $key, $replace); + } + + /** + * Get a translation according to an integer value. + * + * @param string $key + * @param array|\Countable|int $number + * @param array $replace + * @param null|string $locale + * @return string + */ + public function transChoice(string $key, $number, array $replace = [], $locale = null): string + { + return $this->choice($key, $number, $replace, $locale); + } + + /** + * Get a translation according to an integer value. + * + * @param string $key + * @param array|\Countable|int $number + * @param array $replace + * @param null|string $locale + * @return string + */ + public function choice(string $key, $number, array $replace = [], $locale = null): string + { + $line = $this->get( + $key, + $replace, + $locale = $this->localeForChoice($locale) + ); + + // If the given "number" is actually an array or countable we will simply count the + // number of elements in an instance. This allows developers to pass an array of + // items without having to count it on their end first which gives bad syntax. + if (is_array($number) || $number instanceof Countable) { + $number = count($number); + } + + $replace['count'] = $number; + + return $this->makeReplacements( + $this->getSelector()->choose($line, $number, $locale), + $replace + ); + } + + /** + * Add translation lines to the given locale. + * + * @param array $lines + * @param string $locale + * @param string $namespace + */ + public function addLines(array $lines, string $locale, string $namespace = '*') + { + foreach ($lines as $key => $value) { + [$group, $item] = explode('.', $key, 2); + + Arr::set($this->loaded, "{$namespace}.{$group}.{$locale}.{$item}", $value); + } + } + + /** + * Load the specified language group. + * + * @param string $namespace + * @param string $group + * @param string $locale + */ + public function load(string $namespace, string $group, string $locale) + { + if ($this->isLoaded($namespace, $group, $locale)) { + return; + } + + // The loader is responsible for returning the array of language lines for the + // given namespace, group, and locale. We'll set the lines in this array of + // lines that have already been loaded so that we can easily access them. + $lines = $this->loader->load($locale, $group, $namespace); + + $this->loaded[$namespace][$group][$locale] = $lines; + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string $hint + */ + public function addNamespace(string $namespace, string $hint) + { + $this->loader->addNamespace($namespace, $hint); + } + + /** + * Add a new JSON path to the loader. + * + * @param string $path + */ + public function addJsonPath(string $path) + { + $this->loader->addJsonPath($path); + } + + /** + * Parse a key into namespace, group, and item. + * + * @param string $key + * @return array + */ + public function parseKey(string $key): array + { + $segments = parent::parseKey($key); + + if (is_null($segments[0])) { + $segments[0] = '*'; + } + + return $segments; + } + + /** + * Get the message selector instance. + * + * @return \Hyperf\Translation\MessageSelector + */ + public function getSelector() + { + if (! isset($this->selector)) { + $this->selector = new MessageSelector(); + } + + return $this->selector; + } + + /** + * Set the message selector instance. + * + * @param \Hyperf\Translation\MessageSelector $selector + */ + public function setSelector(MessageSelector $selector) + { + $this->selector = $selector; + } + + /** + * Get the language line loader implementation. + * + * @return \Hyperf\Translation\Contracts\Loader + */ + public function getLoader() + { + return $this->loader; + } + + /** + * Get the default locale being used. + * + * @return string + */ + public function locale(): string + { + return $this->getLocale(); + } + + /** + * Get the default locale being used. + * + * @return string + */ + public function getLocale(): string + { + return $this->locale; + } + + /** + * Set the default locale. + * + * @param string $locale + */ + public function setLocale(string $locale) + { + $this->locale = $locale; + } + + /** + * Get the fallback locale being used. + * + * @return string + */ + public function getFallback(): string + { + return $this->fallback; + } + + /** + * Set the fallback locale being used. + * + * @param string $fallback + */ + public function setFallback(string $fallback) + { + $this->fallback = $fallback; + } + + /** + * Set the loaded translation groups. + * + * @param array $loaded + */ + public function setLoaded(array $loaded) + { + $this->loaded = $loaded; + } + + /** + * Get the proper locale for a choice operation. + * + * @param null|string $locale + * @return string + */ + protected function localeForChoice($locale): string + { + return $locale ?: $this->locale ?: $this->fallback; + } + + /** + * Retrieve a language line out the loaded array. + * + * @param string $namespace + * @param string $group + * @param string $locale + * @param mixed $item + * @param array $replace + * @return null|array|string + */ + protected function getLine(string $namespace, string $group, string $locale, $item, array $replace) + { + $this->load($namespace, $group, $locale); + if (! is_null($item)) { + $line = Arr::get($this->loaded[$namespace][$group][$locale], $item); + } else { + // do for hyperf Arr::get + $line = $this->loaded[$namespace][$group][$locale]; + } + + if (is_string($line)) { + return $this->makeReplacements($line, $replace); + } + if (is_array($line) && count($line) > 0) { + foreach ($line as $key => $value) { + $line[$key] = $this->makeReplacements($value, $replace); + } + + return $line; + } + } + + /** + * Make the place-holder replacements on a line. + * + * @param string $line + * @param array $replace + * @return string + */ + protected function makeReplacements($line, array $replace) + { + if (empty($replace)) { + return $line; + } + + $replace = $this->sortReplacements($replace); + + foreach ($replace as $key => $value) { + $key = (string) $key; + $value = (string) $value; + $line = str_replace( + [':' . $key, ':' . Str::upper($key), ':' . Str::ucfirst($key)], + [$value, Str::upper($value), Str::ucfirst($value)], + $line + ); + } + + return $line; + } + + /** + * Sort the replacements array. + * + * @param array $replace + * @return array + */ + protected function sortReplacements(array $replace): array + { + return (new Collection($replace))->sortBy(function ($value, $key) { + return mb_strlen((string) $key) * -1; + })->all(); + } + + /** + * Determine if the given group has been loaded. + * + * @param string $namespace + * @param string $group + * @param string $locale + * @return bool + */ + protected function isLoaded(string $namespace, string $group, string $locale) + { + return isset($this->loaded[$namespace][$group][$locale]); + } + + /** + * Get the array of locales to be checked. + * + * @param null|string $locale + * @return array + */ + protected function localeArray($locale): array + { + return array_filter([$locale ?: $this->locale, $this->fallback]); + } +} diff --git a/src/translation/src/TranslatorFactory.php b/src/translation/src/TranslatorFactory.php new file mode 100644 index 000000000..4e10f689f --- /dev/null +++ b/src/translation/src/TranslatorFactory.php @@ -0,0 +1,38 @@ +get(ConfigInterface::class); + $locale = $config->get('translation.locale'); + $fallbackLocale = $config->get('translation.fallback_locale'); + + $loader = $container->get(Loader::class); + + $trans = make(Translator::class, compact('loader', 'locale')); + $trans->setFallback((string) $fallbackLocale); + + return $trans; + } +} diff --git a/src/translation/tests/Cases/AbstractTestCase.php b/src/translation/tests/Cases/AbstractTestCase.php new file mode 100755 index 000000000..7174e4a7a --- /dev/null +++ b/src/translation/tests/Cases/AbstractTestCase.php @@ -0,0 +1,22 @@ +shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(true); + $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/en/foo.php')->andReturn(['messages']); + + $this->assertEquals(['messages'], $loader->load('en', 'foo', null)); + } + + public function testLoadMethodWithNamespacesProperlyCallsLoader() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(false); + $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); + $loader->addNamespace('namespace', 'bar'); + + $this->assertEquals(['foo' => 'bar'], $loader->load('en', 'foo', 'namespace')); + } + + public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOverrides() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(true); + $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); + $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(['foo' => 'override', 'baz' => 'boom']); + $loader->addNamespace('namespace', 'bar'); + + $this->assertEquals(['foo' => 'override', 'baz' => 'boom'], $loader->load('en', 'foo', 'namespace')); + } + + public function testEmptyArraysReturnedWhenFilesDontExist() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $files->shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(false); + $files->shouldReceive('getRequire')->never(); + + $this->assertEquals([], $loader->load('en', 'foo', null)); + } + + public function testEmptyArraysReturnedWhenFilesDontExistForNamespacedItems() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $files->shouldReceive('getRequire')->never(); + + $this->assertEquals([], $loader->load('en', 'foo', 'bar')); + } + + public function testLoadMethodForJSONProperlyCallsLoader() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); + $files->shouldReceive('get')->once()->with(__DIR__ . '/en.json')->andReturn('{"foo":"bar"}'); + + $this->assertEquals(['foo' => 'bar'], $loader->load('en', '*', '*')); + } + + public function testLoadMethodForJSONProperlyCallsLoaderForMultiplePaths() + { + $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader->addJsonPath(__DIR__ . '/another'); + + $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); + $files->shouldReceive('exists')->once()->with(__DIR__ . '/another/en.json')->andReturn(true); + $files->shouldReceive('get')->once()->with(__DIR__ . '/en.json')->andReturn('{"foo":"bar"}'); + $files->shouldReceive('get')->once()->with(__DIR__ . '/another/en.json')->andReturn('{"foo":"backagebar", "baz": "backagesplash"}'); + + $this->assertEquals(['foo' => 'bar', 'baz' => 'backagesplash'], $loader->load('en', '*', '*')); + } +} diff --git a/src/translation/tests/Cases/TranslationMessageSelectorTest.php b/src/translation/tests/Cases/TranslationMessageSelectorTest.php new file mode 100755 index 000000000..65adea470 --- /dev/null +++ b/src/translation/tests/Cases/TranslationMessageSelectorTest.php @@ -0,0 +1,85 @@ +assertEquals($expected, $selector->choose($id, $number, 'en')); + } + + public function chooseTestData() + { + return [ + ['first', 'first', 1], + ['first', 'first', 10], + ['first', 'first|second', 1], + ['second', 'first|second', 10], + ['second', 'first|second', 0], + + ['first', '{0} first|{1}second', 0], + ['first', '{1}first|{2}second', 1], + ['second', '{1}first|{2}second', 2], + ['first', '{2}first|{1}second', 2], + ['second', '{9}first|{10}second', 0], + ['first', '{9}first|{10}second', 1], + ['', '{0}|{1}second', 0], + ['', '{0}first|{1}', 1], + ['first', '{1.3}first|{2.3}second', 1.3], + ['second', '{1.3}first|{2.3}second', 2.3], + ['first + line', '{1}first + line|{2}second', 1], + ["first \n + line", "{1}first \n + line|{2}second", 1], + + ['first', '{0} first|[1,9]second', 0], + ['second', '{0}first|[1,9]second', 1], + ['second', '{0}first|[1,9]second', 10], + ['first', '{0}first|[2,9]second', 1], + ['second', '[4,*]first|[1,3]second', 1], + ['first', '[4,*]first|[1,3]second', 100], + ['second', '[1,5]first|[6,10]second', 7], + ['first', '[*,4]first|[5,*]second', 1], + ['second', '[5,*]first|[*,4]second', 1], + ['second', '[5,*]first|[*,4]second', 0], + + ['first', '{0}first|[1,3]second|[4,*]third', 0], + ['second', '{0}first|[1,3]second|[4,*]third', 1], + ['third', '{0}first|[1,3]second|[4,*]third', 9], + + ['first', 'first|second|third', 1], + ['second', 'first|second|third', 9], + ['second', 'first|second|third', 0], + + ['first', '{0} first | { 1 } second', 0], + ['first', '[4,*]first | [1,3]second', 100], + ]; + } +} diff --git a/src/translation/tests/Cases/TranslationTranslatorTest.php b/src/translation/tests/Cases/TranslationTranslatorTest.php new file mode 100755 index 000000000..5a6e6f24a --- /dev/null +++ b/src/translation/tests/Cases/TranslationTranslatorTest.php @@ -0,0 +1,199 @@ +getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('foo')); + $this->assertFalse($t->has('foo', 'bar')); + + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en', 'sp'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('bar')); + $this->assertTrue($t->has('foo', 'bar')); + + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('bar')); + $this->assertTrue($t->hasForLocale('foo', 'bar')); + + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('foo')); + $this->assertFalse($t->hasForLocale('foo', 'bar')); + + $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); + $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('bar')); + $this->assertTrue($t->hasForLocale('foo')); + + $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); + $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('foo')); + $this->assertFalse($t->hasForLocale('foo')); + } + + public function testGetMethodProperlyLoadsAndRetrievesItem() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo', 'qux' => ['tree :foo', 'breeze :foo']]); + $this->assertEquals(['tree bar', 'breeze bar'], $t->get('foo::bar.qux', ['foo' => 'bar'], 'en')); + $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); + $this->assertEquals('foo', $t->get('foo::bar.foo')); + } + + public function testTransMethodProperlyLoadsAndRetrievesItemWithHTMLInTheMessage() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze

test

']); + $this->assertSame('breeze

test

', $t->trans('foo.bar', [], 'en')); + } + + public function testGetMethodProperlyLoadsAndRetrievesItemWithCapitalization() + { + $t = $this->getMockBuilder(Translator::class)->setMethods(null)->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :Foo :BAR']); + $this->assertEquals('breeze Bar FOO', $t->get('foo::bar.baz', ['foo' => 'bar', 'bar' => 'foo'], 'en')); + $this->assertEquals('foo', $t->get('foo::bar.foo')); + } + + public function testGetMethodProperlyLoadsAndRetrievesItemWithLongestReplacementsFirst() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo :foobar']); + $this->assertEquals('breeze bar taylor', $t->get('foo::bar.baz', ['foo' => 'bar', 'foobar' => 'taylor'], 'en')); + $this->assertEquals('breeze foo bar baz taylor', $t->get('foo::bar.baz', ['foo' => 'foo bar baz', 'foobar' => 'taylor'], 'en')); + $this->assertEquals('foo', $t->get('foo::bar.foo')); + } + + public function testGetMethodProperlyLoadsAndRetrievesItemForFallback() + { + $t = new Translator($this->getLoader(), 'en'); + $t->setFallback('lv'); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([]); + $t->getLoader()->shouldReceive('load')->once()->with('lv', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo']); + $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); + $this->assertEquals('foo', $t->get('foo::bar.foo')); + } + + public function testGetMethodProperlyLoadsAndRetrievesItemForGlobalNamespace() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze :foo']); + $this->assertEquals('breeze bar', $t->get('foo.bar', ['foo' => 'bar'])); + } + + public function testChoiceMethodProperlyLoadsAndRetrievesItem() + { + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); + $t->setSelector($selector = m::mock(MessageSelector::class)); + $selector->shouldReceive('choose')->once()->with('line', 10, 'en')->andReturn('choiced'); + + $t->choice('foo', 10, ['replace']); + } + + public function testChoiceMethodProperlyCountsCollectionsAndLoadsAndRetrievesItem() + { + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->exactly(2))->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); + $t->setSelector($selector = m::mock(MessageSelector::class)); + $selector->shouldReceive('choose')->twice()->with('line', 3, 'en')->andReturn('choiced'); + + $values = ['foo', 'bar', 'baz']; + $t->choice('foo', $values, ['replace']); + + $values = new Collection(['foo', 'bar', 'baz']); + $t->choice('foo', $values, ['replace']); + } + + public function testGetJsonMethod() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo' => 'one']); + $this->assertEquals('one', $t->getFromJson('foo')); + } + + public function testGetJsonReplaces() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo :i:c :u' => 'bar :i:c :u']); + $this->assertEquals('bar onetwo three', $t->getFromJson('foo :i:c :u', ['i' => 'one', 'c' => 'two', 'u' => 'three'])); + } + + public function testGetJsonReplacesForAssociativeInput() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo :i :c' => 'bar :i :c']); + $this->assertEquals('bar eye see', $t->getFromJson('foo :i :c', ['i' => 'eye', 'c' => 'see'])); + } + + public function testGetJsonPreservesOrder() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['to :name I give :greeting' => ':greeting :name']); + $this->assertEquals('Greetings David', $t->getFromJson('to :name I give :greeting', ['name' => 'David', 'greeting' => 'Greetings'])); + } + + public function testGetJsonForNonExistingJsonKeyLooksForRegularKeys() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'one']); + $this->assertEquals('one', $t->getFromJson('foo.bar')); + } + + public function testGetJsonForNonExistingJsonKeyLooksForRegularKeysAndReplace() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'one :message']); + $this->assertEquals('one two', $t->getFromJson('foo.bar', ['message' => 'two'])); + } + + public function testGetJsonForNonExistingReturnsSameKey() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'Foo that bar', '*')->andReturn([]); + $this->assertEquals('Foo that bar', $t->getFromJson('Foo that bar')); + } + + public function testGetJsonForNonExistingReturnsSameKeyAndReplaces() + { + $t = new Translator($this->getLoader(), 'en'); + $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo :message', '*')->andReturn([]); + $this->assertEquals('foo baz', $t->getFromJson('foo :message', ['message' => 'baz'])); + } + + protected function getLoader() + { + return m::mock(Loader::class); + } +} diff --git a/src/translation/tests/bootstrap.php b/src/translation/tests/bootstrap.php new file mode 100755 index 000000000..210da6cde --- /dev/null +++ b/src/translation/tests/bootstrap.php @@ -0,0 +1,13 @@ + Date: Thu, 22 Aug 2019 10:40:28 +0800 Subject: [PATCH 10/79] Update AnnotationReader.php --- src/graphql/src/AnnotationReader.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/graphql/src/AnnotationReader.php b/src/graphql/src/AnnotationReader.php index d01f6d90b..3ecd25fea 100644 --- a/src/graphql/src/AnnotationReader.php +++ b/src/graphql/src/AnnotationReader.php @@ -101,25 +101,21 @@ class AnnotationReader public function getRequestAnnotation(ReflectionMethod $refMethod, string $annotationName): ?AbstractRequest { - /* @var null|AbstractRequest $queryAnnotation */ return $this->getMethodAnnotation($refMethod, $annotationName); } public function getLoggedAnnotation(ReflectionMethod $refMethod): ?Logged { - /* @var null|Logged $loggedAnnotation */ return $this->getMethodAnnotation($refMethod, Logged::class); } public function getRightAnnotation(ReflectionMethod $refMethod): ?Right { - /* @var null|Right $rightAnnotation */ return $this->getMethodAnnotation($refMethod, Right::class); } public function getFailWithAnnotation(ReflectionMethod $refMethod): ?FailWith { - /* @var null|FailWith $failWithAnnotation */ return $this->getMethodAnnotation($refMethod, FailWith::class); } @@ -128,13 +124,11 @@ class AnnotationReader */ public function getSourceFields(ReflectionClass $refClass): array { - /* @var SourceField[] $sourceFields */ return $this->getClassAnnotations($refClass, SourceField::class); } public function getFactoryAnnotation(ReflectionMethod $refMethod): ?Factory { - /* @var null|Factory $factoryAnnotation */ return $this->getMethodAnnotation($refMethod, Factory::class); } From 3ccd79147355ebd6695621887832f42638cdc17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 10:43:14 +0800 Subject: [PATCH 11/79] Update composer.json --- src/validation/composer.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/validation/composer.json b/src/validation/composer.json index c3d9078b9..aecdbb0a4 100755 --- a/src/validation/composer.json +++ b/src/validation/composer.json @@ -20,15 +20,15 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/translation": "^1.0", "egulias/email-validator": "^2.1", - "hyperf/command": "^1.0", - "hyperf/database": "^1.0", - "hyperf/devtool": "^1.0", - "hyperf/di": "1.0.*", - "hyperf/framework": "1.0.*", + "hyperf/command": "~1.0.0", + "hyperf/database": "~1.0.0", + "hyperf/devtool": "~1.0.0", + "hyperf/di": "~1.0.0", + "hyperf/framework": "~1.0.0", "hyperf/http-server": "~1.0.0", - "hyperf/utils": "1.0.*", + "hyperf/utils": "~1.0.0", + "hyperf/translation": "~1.0.0", "nesbot/carbon": "^2.21", "psr/container": "^1.0", "psr/http-message": "^1.0", From 41b53a76a0fd4dfabcef83214f48c90e0238ed3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 11:26:55 +0800 Subject: [PATCH 12/79] Using ContainerInterface instead of Container. --- .../src/Concerns/FormatsMessages.php | 2 +- src/validation/src/Factory.php | 5 ++- src/validation/src/Validator.php | 7 ++-- .../tests/Cases/ValidationValidatorTest.php | 41 ++++++++++++------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/validation/src/Concerns/FormatsMessages.php b/src/validation/src/Concerns/FormatsMessages.php index 9fa887eeb..a3384bc89 100755 --- a/src/validation/src/Concerns/FormatsMessages.php +++ b/src/validation/src/Concerns/FormatsMessages.php @@ -398,6 +398,6 @@ trait FormatsMessages { [$class, $method] = Str::parseCallback($callback, 'replace'); - return call_user_func_array([$this->container->make($class), $method], array_slice(func_get_args(), 1)); + return call_user_func_array([make($class), $method], array_slice(func_get_args(), 1)); } } diff --git a/src/validation/src/Factory.php b/src/validation/src/Factory.php index 11b5985aa..49b5014a5 100755 --- a/src/validation/src/Factory.php +++ b/src/validation/src/Factory.php @@ -17,6 +17,7 @@ use Hyperf\Di\Container; use Hyperf\Translation\Contracts\Translator; use Hyperf\Utils\Str; use Hyperf\Validation\Contracts\Validation\Factory as FactoryContract; +use Psr\Container\ContainerInterface; class Factory implements FactoryContract { @@ -37,7 +38,7 @@ class Factory implements FactoryContract /** * The IoC container instance. * - * @var Container + * @var ContainerInterface */ protected $container; @@ -89,7 +90,7 @@ class Factory implements FactoryContract * @param null|\Hyperf\Translation\Contracts\Translator $translator * @param Container */ - public function __construct(Translator $translator, Container $container = null) + public function __construct(Translator $translator, ContainerInterface $container = null) { $this->container = $container; $this->translator = $translator; diff --git a/src/validation/src/Validator.php b/src/validation/src/Validator.php index 307baf4a6..ee6c412ee 100755 --- a/src/validation/src/Validator.php +++ b/src/validation/src/Validator.php @@ -22,6 +22,7 @@ use Hyperf\Validation\Contracts\Validation\ImplicitRule; use Hyperf\Validation\Contracts\Validation\Rule as RuleContract; use Hyperf\Validation\Contracts\Validation\Validator as ValidatorContract; use Hyperf\Validation\Support\MessageBag; +use Psr\Container\ContainerInterface; use RuntimeException; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -82,7 +83,7 @@ class Validator implements ValidatorContract /** * The container instance. * - * @var Container + * @var ContainerInterface */ protected $container; @@ -847,7 +848,7 @@ class Validator implements ValidatorContract * * @param Container $container */ - public function setContainer(Container $container) + public function setContainer(ContainerInterface $container) { $this->container = $container; } @@ -1191,6 +1192,6 @@ class Validator implements ValidatorContract { [$class, $method] = Str::parseCallback($callback, 'validate'); - return call_user_func_array([$this->container->make($class), $method], $parameters); + return call_user_func_array([make($class), $method], $parameters); } } diff --git a/src/validation/tests/Cases/ValidationValidatorTest.php b/src/validation/tests/Cases/ValidationValidatorTest.php index 99f65fe4f..a8b5b220c 100755 --- a/src/validation/tests/Cases/ValidationValidatorTest.php +++ b/src/validation/tests/Cases/ValidationValidatorTest.php @@ -20,6 +20,7 @@ use Hyperf\Di\Definition\DefinitionSourceInterface; use Hyperf\Translation\ArrayLoader; use Hyperf\Translation\Contracts\Translator as TranslatorContract; use Hyperf\Translation\Translator; +use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\Arr; use Hyperf\Validation\Contracts\Validation\ImplicitRule; use Hyperf\Validation\Contracts\Validation\Rule; @@ -61,10 +62,12 @@ class ValidationValidatorTest extends TestCase public function testAfterCallbacksAreCalledWithValidatorInstance() { + $definitionSource = m::mock(DefinitionSourceInterface::class); + $container = new Container($definitionSource); + ApplicationContext::setContainer($container); + $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['foo' => 'bar', 'baz' => 'boom'], ['foo' => 'Same:baz']); - $definitionSource = m::mock(DefinitionSourceInterface::class); - $v->setContainer(new Container($definitionSource)); $v->after(function ($validator) { $_SERVER['__validator.after.test'] = true; @@ -106,7 +109,7 @@ class ValidationValidatorTest extends TestCase $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, ['foo' => 'bar'], ['foo' => 'required']); - $v->validate(); + $this->assertSame(['foo' => 'bar'], $v->validate()); } public function testHasFailedValidationRules() @@ -263,15 +266,19 @@ class ValidationValidatorTest extends TestCase public function testClassBasedCustomReplacers() { + $container = m::mock(Container::class); + $container->shouldReceive('make')->once()->with('Foo', m::any())->andReturn($foo = m::mock(stdClass::class)); + $foo->shouldReceive('bar')->once()->andReturn('replaced!'); + + ApplicationContext::setContainer($container); + $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.foo' => 'foo!'], 'en'); $v = new Validator($trans, [], ['name' => 'required']); - $v->setContainer($container = m::mock(Container::class)); $v->addReplacer('required', 'Foo@bar'); - $container->shouldReceive('make')->once()->with('Foo')->andReturn($foo = m::mock(stdClass::class)); - $foo->shouldReceive('bar')->once()->andReturn('replaced!'); $v->passes(); $v->messages()->setFormat(':message'); + $this->assertEquals('replaced!', $v->messages()->first('name')); } @@ -3307,13 +3314,15 @@ class ValidationValidatorTest extends TestCase public function testClassBasedCustomValidators() { + $container = m::mock(Container::class); + $container->shouldReceive('make')->once()->with('Foo', m::any())->andReturn($foo = m::mock(stdClass::class)); + $foo->shouldReceive('bar')->once()->andReturn(false); + ApplicationContext::setContainer($container); + $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.foo' => 'foo!'], 'en'); $v = new Validator($trans, ['name' => 'taylor'], ['name' => 'foo']); - $v->setContainer($container = m::mock(Container::class)); $v->addExtension('foo', 'Foo@bar'); - $container->shouldReceive('make')->once()->with('Foo')->andReturn($foo = m::mock(stdClass::class)); - $foo->shouldReceive('bar')->once()->andReturn(false); $this->assertFalse($v->passes()); $v->messages()->setFormat(':message'); $this->assertEquals('foo!', $v->messages()->first('name')); @@ -3321,13 +3330,15 @@ class ValidationValidatorTest extends TestCase public function testClassBasedCustomValidatorsUsingConventionalMethod() { + $container = m::mock(Container::class); + $container->shouldReceive('make')->once()->with('Foo', m::any())->andReturn($foo = m::mock(stdClass::class)); + $foo->shouldReceive('validate')->once()->andReturn(false); + ApplicationContext::setContainer($container); + $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.foo' => 'foo!'], 'en'); $v = new Validator($trans, ['name' => 'taylor'], ['name' => 'foo']); - $v->setContainer($container = m::mock(Container::class)); $v->addExtension('foo', 'Foo'); - $container->shouldReceive('make')->once()->with('Foo')->andReturn($foo = m::mock(stdClass::class)); - $foo->shouldReceive('validate')->once()->andReturn(false); $this->assertFalse($v->passes()); $v->messages()->setFormat(':message'); $this->assertEquals('foo!', $v->messages()->first('name')); @@ -4386,7 +4397,7 @@ class ValidationValidatorTest extends TestCase public function testValidateReturnsValidatedData() { - $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; + $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred' => 'required']); $v->sometimes('type', 'required', function () { @@ -4440,7 +4451,7 @@ class ValidationValidatorTest extends TestCase public function testValidateAndValidatedData() { - $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; + $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred' => 'required']); $v->sometimes('type', 'required', function () { @@ -4455,7 +4466,7 @@ class ValidationValidatorTest extends TestCase public function testValidatedNotValidateTwiceData() { - $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; + $post = ['first' => 'john', 'preferred' => 'john', 'last' => 'doe', 'type' => 'admin']; $validateCount = 0; $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred' => 'required']); From baba702d6aa913f32206dcbd66f1bff77b75b1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 16:28:59 +0800 Subject: [PATCH 13/79] Using hyperf/http-message instead of symfony/http-foundation. --- composer.json | 1 - src/http-message/src/Upload/UploadedFile.php | 13 + src/validation/composer.json | 3 +- .../src/Concerns/FormatsMessages.php | 2 +- .../src/Concerns/ValidatesAttributes.php | 38 +-- src/validation/src/Request/FormRequest.php | 82 +----- src/validation/src/ValidationException.php | 7 +- src/validation/src/Validator.php | 2 +- .../tests/Cases/ValidationValidatorTest.php | 265 +++++++++--------- 9 files changed, 179 insertions(+), 234 deletions(-) diff --git a/composer.json b/composer.json index 67c0832b1..989936a98 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,6 @@ "squizlabs/php_codesniffer": "^3.4", "symfony/console": "^4.2", "symfony/finder": "^4.1", - "symfony/http-foundation": "^4.3", "vlucas/phpdotenv": "^3.1" }, "require-dev": { diff --git a/src/http-message/src/Upload/UploadedFile.php b/src/http-message/src/Upload/UploadedFile.php index 8fb16e601..64a4ce49e 100755 --- a/src/http-message/src/Upload/UploadedFile.php +++ b/src/http-message/src/Upload/UploadedFile.php @@ -61,6 +61,11 @@ class UploadedFile extends \SplFileInfo implements UploadedFileInterface */ private $size; + /** + * @var string + */ + private $mimeType; + /** * @param string $tmpFile * @param null|int $size @@ -98,6 +103,14 @@ class UploadedFile extends \SplFileInfo implements UploadedFileInterface return end($segments) ?? null; } + public function getMimeType(): string + { + if (is_string($this->mimeType)) { + return $this->mimeType; + } + return $this->mimeType = mime_content_type($this->tmpFile); + } + /** * Returns whether the file was uploaded successfully. * diff --git a/src/validation/composer.json b/src/validation/composer.json index aecdbb0a4..80e87a78d 100755 --- a/src/validation/composer.json +++ b/src/validation/composer.json @@ -31,8 +31,7 @@ "hyperf/translation": "~1.0.0", "nesbot/carbon": "^2.21", "psr/container": "^1.0", - "psr/http-message": "^1.0", - "symfony/http-foundation": "^4.3" + "psr/http-message": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", diff --git a/src/validation/src/Concerns/FormatsMessages.php b/src/validation/src/Concerns/FormatsMessages.php index a3384bc89..4b100aa66 100755 --- a/src/validation/src/Concerns/FormatsMessages.php +++ b/src/validation/src/Concerns/FormatsMessages.php @@ -13,9 +13,9 @@ declare(strict_types=1); namespace Hyperf\Validation\Concerns; use Closure; +use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Utils\Arr; use Hyperf\Utils\Str; -use Symfony\Component\HttpFoundation\File\UploadedFile; trait FormatsMessages { diff --git a/src/validation/src/Concerns/ValidatesAttributes.php b/src/validation/src/Concerns/ValidatesAttributes.php index 7d87d1b57..b007b69a2 100755 --- a/src/validation/src/Concerns/ValidatesAttributes.php +++ b/src/validation/src/Concerns/ValidatesAttributes.php @@ -21,14 +21,14 @@ use DateTimeZone; use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\RFCValidation; use Exception; +use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Utils\Arr; use Hyperf\Utils\Str; use Hyperf\Validation\Rules\Exists; use Hyperf\Validation\Rules\Unique; use Hyperf\Validation\ValidationData; use InvalidArgumentException; -use Symfony\Component\HttpFoundation\File\File; -use Symfony\Component\HttpFoundation\File\UploadedFile; +use SplFileInfo; use Throwable; trait ValidatesAttributes @@ -382,10 +382,6 @@ trait ValidatesAttributes */ public function validateDimensions(string $attribute, $value, array $parameters): bool { - if ($this->isValidFileInstance($value) && $value->getClientMimeType() === 'image/svg+xml') { - return true; - } - if (! $this->isValidFileInstance($value) || ! $sizeDetails = @getimagesize($value->getRealPath())) { return false; } @@ -844,7 +840,7 @@ trait ValidatesAttributes * Validate the guessed extension of a file upload is in a set of file extensions. * * @param string $attribute - * @param mixed $value + * @param SplFileInfo $value * @param array $parameters * @return bool */ @@ -858,14 +854,26 @@ trait ValidatesAttributes return false; } - return $value->getPath() !== '' && in_array($value->guessExtension(), $parameters); + if (empty($value->getPath())) { + return false; + } + + if (in_array($value->getExtension(), $parameters)) { + return true; + } + + if ($value instanceof UploadedFile) { + return in_array($value->getMimeType(), $parameters); + } + + return false; } /** * Validate the MIME type of a file upload attribute is in a set of MIME types. * * @param string $attribute - * @param mixed $value + * @param SplFileInfo $value * @param array $parameters * @return bool */ @@ -1004,7 +1012,7 @@ trait ValidatesAttributes if ((is_array($value) || $value instanceof Countable) && count($value) < 1) { return false; } - if ($value instanceof File) { + if ($value instanceof SplFileInfo) { return (string) $value->getPath() !== ''; } @@ -1296,7 +1304,7 @@ trait ValidatesAttributes return false; } - return $value instanceof File; + return $value instanceof SplFileInfo; } /** @@ -1627,7 +1635,7 @@ trait ValidatesAttributes /** * Check if PHP uploads are explicitly allowed. * - * @param mixed $value + * @param SplFileInfo $value * @param array $parameters * @return bool */ @@ -1641,9 +1649,7 @@ trait ValidatesAttributes 'php', 'php3', 'php4', 'php5', 'phtml', ]; - return ($value instanceof UploadedFile) - ? in_array(trim(strtolower($value->getClientOriginalExtension())), $phpExtensions) - : in_array(trim(strtolower($value->getExtension())), $phpExtensions); + return in_array(trim(strtolower($value->getExtension())), $phpExtensions); } /** @@ -1721,7 +1727,7 @@ trait ValidatesAttributes if (is_array($value)) { return count($value); } - if ($value instanceof File) { + if ($value instanceof SplFileInfo) { return $value->getSize() / 1024; } diff --git a/src/validation/src/Request/FormRequest.php b/src/validation/src/Request/FormRequest.php index 0c42012f3..d968b22f1 100755 --- a/src/validation/src/Request/FormRequest.php +++ b/src/validation/src/Request/FormRequest.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Validation\Request; use Hyperf\HttpServer\Request; +use Hyperf\Utils\Context; use Hyperf\Validation\Contracts\Validation\Factory; use Hyperf\Validation\Contracts\Validation\Factory as ValidationFactory; use Hyperf\Validation\Contracts\Validation\ValidatesWhenResolved; @@ -20,7 +21,7 @@ use Hyperf\Validation\Contracts\Validation\Validator; use Hyperf\Validation\ValidatesWhenResolvedTrait; use Hyperf\Validation\ValidationException; use Psr\Container\ContainerInterface; -use Symfony\Component\HttpFoundation\JsonResponse; +use Psr\Http\Message\ResponseInterface; class FormRequest extends Request implements ValidatesWhenResolved { @@ -33,34 +34,6 @@ class FormRequest extends Request implements ValidatesWhenResolved */ protected $container; -// /** -// * The redirector instance. -// * -// * @var \Illuminate\Routing\Redirector -// */ -// protected $redirector; -// -// /** -// * The URI to redirect to if validation fails. -// * -// * @var string -// */ -// protected $redirect; -// -// /** -// * The route to redirect to if validation fails. -// * -// * @var string -// */ -// protected $redirectRoute; -// -// /** -// * The controller action to redirect to if validation fails. -// * -// * @var string -// */ -// protected $redirectAction; - /** * The key to be used for the view error bag. * @@ -84,18 +57,14 @@ class FormRequest extends Request implements ValidatesWhenResolved * Get the proper failed validation response for the request. * * @param array $errors - * @return \Symfony\Component\HttpFoundation\Response + * @return ResponseInterface */ - public function response(array $errors) + public function response() { -// if ($this->expectsJson()) { -// return new JsonResponse($errors, 422); -// } + /** @var ResponseInterface $response */ + $response = Context::get(ResponseInterface::class); -// return $this->redirector->to($this->getRedirectUrl()) -// ->withInput($this->except($this->dontFlash)) -// ->withErrors($errors, $this->errorBag); - return new JsonResponse($errors, 422); + return $response->withStatus(422); } /** @@ -118,19 +87,6 @@ class FormRequest extends Request implements ValidatesWhenResolved return []; } -// /** -// * Set the Redirector instance. -// * -// * @param \Illuminate\Routing\Redirector $redirector -// * @return $this -// */ -// public function setRedirector(Redirector $redirector) -// { -// $this->redirector = $redirector; -// -// return $this; -// } - /** * Set the container implementation. * @@ -201,9 +157,7 @@ class FormRequest extends Request implements ValidatesWhenResolved */ protected function failedValidation(Validator $validator) { - throw new ValidationException($validator, $this->response( - $this->formatErrors($validator) - )); + throw new ValidationException($validator, $this->response()); } /** @@ -217,26 +171,6 @@ class FormRequest extends Request implements ValidatesWhenResolved return $validator->getMessageBag()->toArray(); } -// /** -// * Get the URL to redirect to on a validation error. -// * -// * @return string -// */ -// protected function getRedirectUrl() -// { -// $url = $this->redirector->getUrlGenerator(); -// -// if ($this->redirect) { -// return $url->to($this->redirect); -// } elseif ($this->redirectRoute) { -// return $url->route($this->redirectRoute); -// } elseif ($this->redirectAction) { -// return $url->action($this->redirectAction); -// } -// -// return $url->previous(); -// } - /** * Determine if the request passes the authorization check. * diff --git a/src/validation/src/ValidationException.php b/src/validation/src/ValidationException.php index 856812693..0531b3a99 100755 --- a/src/validation/src/ValidationException.php +++ b/src/validation/src/ValidationException.php @@ -14,6 +14,7 @@ namespace Hyperf\Validation; use Hyperf\Server\Exception\ServerException; use Hyperf\Utils\Arr; +use Psr\Http\Message\ResponseInterface; class ValidationException extends ServerException { @@ -27,7 +28,7 @@ class ValidationException extends ServerException /** * The recommended response to send to the client. * - * @var null|\Symfony\Component\HttpFoundation\Response + * @var ResponseInterface */ public $response; @@ -56,7 +57,7 @@ class ValidationException extends ServerException * Create a new exception instance. * * @param \Hyperf\Validation\Contracts\Validation\Validator $validator - * @param null|\Symfony\Component\HttpFoundation\Response $response + * @param null|ResponseInterface $response * @param string $errorBag */ public function __construct($validator, $response = null, string $errorBag = 'default') @@ -137,7 +138,7 @@ class ValidationException extends ServerException /** * Get the underlying response instance. * - * @return null|\Symfony\Component\HttpFoundation\Response + * @return ResponseInterface */ public function getResponse() { diff --git a/src/validation/src/Validator.php b/src/validation/src/Validator.php index ee6c412ee..ca16f474d 100755 --- a/src/validation/src/Validator.php +++ b/src/validation/src/Validator.php @@ -14,6 +14,7 @@ namespace Hyperf\Validation; use BadMethodCallException; use Hyperf\Di\Container; +use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Translation\Contracts\Translator; use Hyperf\Utils\Arr; use Hyperf\Utils\Fluent; @@ -24,7 +25,6 @@ use Hyperf\Validation\Contracts\Validation\Validator as ValidatorContract; use Hyperf\Validation\Support\MessageBag; use Psr\Container\ContainerInterface; use RuntimeException; -use Symfony\Component\HttpFoundation\File\UploadedFile; class Validator implements ValidatorContract { diff --git a/src/validation/tests/Cases/ValidationValidatorTest.php b/src/validation/tests/Cases/ValidationValidatorTest.php index a8b5b220c..9a791963a 100755 --- a/src/validation/tests/Cases/ValidationValidatorTest.php +++ b/src/validation/tests/Cases/ValidationValidatorTest.php @@ -17,6 +17,7 @@ use DateTime; use DateTimeImmutable; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSourceInterface; +use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Translation\ArrayLoader; use Hyperf\Translation\Contracts\Translator as TranslatorContract; use Hyperf\Translation\Translator; @@ -33,8 +34,7 @@ use Hyperf\Validation\Validator; use InvalidArgumentException; use Mockery as m; use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\File\File; -use Symfony\Component\HttpFoundation\File\UploadedFile; +use SplFileInfo; /** * @internal @@ -285,7 +285,8 @@ class ValidationValidatorTest extends TestCase public function testNestedAttributesAreReplacedInDimensions() { // Knowing that demo image.png has width = 3 and height = 2 - $uploadedFile = new UploadedFile(__DIR__ . '/fixtures/image.png', '', null, null, null, true); + $uploadedFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs([__DIR__ . '/fixtures/image.png', 0, 0])->getMock(); + $uploadedFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.dimensions' => ':min_width :max_height :ratio'], 'en'); @@ -648,7 +649,7 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['foo' => [1, 2, 3]], ['foo' => 'Array']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['foo' => new File('/tmp/foo', false)], ['foo' => 'Array']); + $v = new Validator($trans, ['foo' => new SplFileInfo('/tmp/foo')], ['foo' => 'Array']); $this->assertFalse($v->passes()); } @@ -732,16 +733,16 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['name' => 'foo'], ['name' => 'Required']); $this->assertTrue($v->passes()); - $file = new File('', false); + $file = new SplFileInfo(''); $v = new Validator($trans, ['name' => $file], ['name' => 'Required']); $this->assertFalse($v->passes()); - $file = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); $v = new Validator($trans, ['name' => $file], ['name' => 'Required']); $this->assertTrue($v->passes()); - $file = new File(__FILE__, false); - $file2 = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); + $file2 = new SplFileInfo(__FILE__); $v = new Validator($trans, ['files' => [$file, $file2]], ['files.0' => 'Required', 'files.1' => 'Required']); $this->assertTrue($v->passes()); @@ -767,17 +768,17 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['first' => 'Taylor', 'last' => 'Otwell'], ['last' => 'required_with:first']); $this->assertTrue($v->passes()); - $file = new File('', false); + $file = new SplFileInfo(''); $v = new Validator($trans, ['file' => $file, 'foo' => ''], ['foo' => 'required_with:file']); $this->assertTrue($v->passes()); - $file = new File(__FILE__, false); - $foo = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); + $foo = new SplFileInfo(__FILE__); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_with:file']); $this->assertTrue($v->passes()); - $file = new File(__FILE__, false); - $foo = new File('', false); + $file = new SplFileInfo(__FILE__); + $foo = new SplFileInfo(''); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_with:file']); $this->assertFalse($v->passes()); } @@ -813,35 +814,35 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['last' => 'Otwell'], ['last' => 'required_without:first']); $this->assertTrue($v->passes()); - $file = new File('', false); + $file = new SplFileInfo(''); $v = new Validator($trans, ['file' => $file], ['foo' => 'required_without:file']); $this->assertFalse($v->passes()); - $foo = new File('', false); + $foo = new SplFileInfo(''); $v = new Validator($trans, ['foo' => $foo], ['foo' => 'required_without:file']); $this->assertFalse($v->passes()); - $foo = new File(__FILE__, false); + $foo = new SplFileInfo(__FILE__); $v = new Validator($trans, ['foo' => $foo], ['foo' => 'required_without:file']); $this->assertTrue($v->passes()); - $file = new File(__FILE__, false); - $foo = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); + $foo = new SplFileInfo(__FILE__); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_without:file']); $this->assertTrue($v->passes()); - $file = new File(__FILE__, false); - $foo = new File('', false); + $file = new SplFileInfo(__FILE__); + $foo = new SplFileInfo(''); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_without:file']); $this->assertTrue($v->passes()); - $file = new File('', false); - $foo = new File(__FILE__, false); + $file = new SplFileInfo(''); + $foo = new SplFileInfo(__FILE__); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_without:file']); $this->assertTrue($v->passes()); - $file = new File('', false); - $foo = new File('', false); + $file = new SplFileInfo(''); + $foo = new SplFileInfo(''); $v = new Validator($trans, ['file' => $file, 'foo' => $foo], ['foo' => 'required_without:file']); $this->assertFalse($v->passes()); } @@ -1120,9 +1121,9 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['lhs' => ['string'], 'rhs' => [1, 'string']], ['lhs' => 'gt:rhs']); $this->assertTrue($v->fails()); - $fileOne = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileOne = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileOne->expects($this->any())->method('getSize')->will($this->returnValue(5472)); - $fileTwo = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileTwo = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileTwo->expects($this->any())->method('getSize')->will($this->returnValue(3151)); $v = new Validator($trans, ['lhs' => $fileOne, 'rhs' => $fileTwo], ['lhs' => 'gt:rhs']); $this->assertTrue($v->passes()); @@ -1149,9 +1150,9 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['lhs' => ['string'], 'rhs' => [1, 'string']], ['lhs' => 'lt:rhs']); $this->assertTrue($v->passes()); - $fileOne = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileOne = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileOne->expects($this->any())->method('getSize')->will($this->returnValue(5472)); - $fileTwo = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileTwo = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileTwo->expects($this->any())->method('getSize')->will($this->returnValue(3151)); $v = new Validator($trans, ['lhs' => $fileOne, 'rhs' => $fileTwo], ['lhs' => 'lt:rhs']); $this->assertTrue($v->fails()); @@ -1178,9 +1179,9 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['lhs' => ['string'], 'rhs' => [1, 'string']], ['lhs' => 'gte:rhs']); $this->assertTrue($v->fails()); - $fileOne = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileOne = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileOne->expects($this->any())->method('getSize')->will($this->returnValue(5472)); - $fileTwo = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileTwo = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileTwo->expects($this->any())->method('getSize')->will($this->returnValue(5472)); $v = new Validator($trans, ['lhs' => $fileOne, 'rhs' => $fileTwo], ['lhs' => 'gte:rhs']); $this->assertTrue($v->passes()); @@ -1207,9 +1208,9 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['lhs' => ['string'], 'rhs' => [1, 'string']], ['lhs' => 'lte:rhs']); $this->assertTrue($v->passes()); - $fileOne = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileOne = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileOne->expects($this->any())->method('getSize')->will($this->returnValue(5472)); - $fileTwo = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $fileTwo = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $fileTwo->expects($this->any())->method('getSize')->will($this->returnValue(5472)); $v = new Validator($trans, ['lhs' => $fileOne, 'rhs' => $fileTwo], ['lhs' => 'lte:rhs']); $this->assertTrue($v->passes()); @@ -1510,12 +1511,12 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['foo' => [1, 2, 3]], ['foo' => 'Array|Size:4']); $this->assertFalse($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(3072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Size:3']); $this->assertTrue($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Size:3']); $this->assertFalse($v->passes()); @@ -1548,12 +1549,12 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['foo' => [1, 2, 3]], ['foo' => 'Array|Between:1,2']); $this->assertFalse($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(3072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Between:1,5']); $this->assertTrue($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Between:1,2']); $this->assertFalse($v->passes()); @@ -1580,12 +1581,12 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['foo' => [1, 2]], ['foo' => 'Array|Min:3']); $this->assertFalse($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(3072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Min:2']); $this->assertTrue($v->passes()); - $file = $this->getMockBuilder(File::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(SplFileInfo::class)->setMethods(['getSize'])->setConstructorArgs([__FILE__])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Min:10']); $this->assertFalse($v->passes()); @@ -1612,19 +1613,19 @@ class ValidationValidatorTest extends TestCase $v = new Validator($trans, ['foo' => [1, 2, 3]], ['foo' => 'Array|Max:2']); $this->assertFalse($v->passes()); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getSize'])->setConstructorArgs([__FILE__, basename(__FILE__)])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getSize'])->setConstructorArgs([__FILE__, 3072, 0])->getMock(); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $file->expects($this->at(1))->method('getSize')->will($this->returnValue(3072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Max:10']); $this->assertTrue($v->passes()); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getSize'])->setConstructorArgs([__FILE__, basename(__FILE__)])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getSize'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->at(0))->method('isValid')->will($this->returnValue(true)); $file->expects($this->at(1))->method('getSize')->will($this->returnValue(4072)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Max:2']); $this->assertFalse($v->passes()); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs([__FILE__, basename(__FILE__)])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->any())->method('isValid')->will($this->returnValue(false)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Max:10']); $this->assertFalse($v->passes()); @@ -1644,7 +1645,7 @@ class ValidationValidatorTest extends TestCase $v->messages()->setFormat(':message'); $this->assertEquals('string', $v->messages()->first('name')); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 4072, 0])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['photo' => $file], ['photo' => 'Max:3']); @@ -1675,10 +1676,10 @@ class ValidationValidatorTest extends TestCase $this->assertFalse($v->passes()); $this->assertEquals(5, $v->messages()->first('items')); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); - $biggerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gt:bigger']); @@ -1712,10 +1713,10 @@ class ValidationValidatorTest extends TestCase $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('items')); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); - $smallerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lt:smaller']); @@ -1749,10 +1750,10 @@ class ValidationValidatorTest extends TestCase $this->assertFalse($v->passes()); $this->assertEquals(5, $v->messages()->first('items')); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); - $biggerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gte:bigger']); @@ -1786,10 +1787,10 @@ class ValidationValidatorTest extends TestCase $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('items')); - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); - $smallerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile = $this->getMockBuilder(UploadedFile::class)->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, 0, 0])->getMock(); $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lte:smaller']); @@ -2423,47 +2424,40 @@ class ValidationValidatorTest extends TestCase public function testValidateImage() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__FILE__, '', null, null, null, true]; + $uploadedFile = [__FILE__, 0, 0, 'ValidationValidatorTest.php']; - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file->expects($this->any())->method('guessExtension')->will($this->returnValue('php')); - $file->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('php')); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => $file], ['x' => 'Image']); $this->assertFalse($v->passes()); - $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file2->expects($this->any())->method('guessExtension')->will($this->returnValue('jpeg')); - $file2->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('jpeg')); + $uploadedFile = [__DIR__ . '/fixtures/image2.png', 0, 0, 'image2.png']; + $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file2->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => $file2], ['x' => 'Image']); $this->assertTrue($v->passes()); - $file3 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file3->expects($this->any())->method('guessExtension')->will($this->returnValue('gif')); - $file3->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('gif')); + $file3 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file3->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file3->expects($this->any())->method('getExtension')->will($this->returnValue('gif')); $v = new Validator($trans, ['x' => $file3], ['x' => 'Image']); $this->assertTrue($v->passes()); - $file4 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file4->expects($this->any())->method('guessExtension')->will($this->returnValue('bmp')); - $file4->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('bmp')); + $file4 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file4->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file4->expects($this->any())->method('getExtension')->will($this->returnValue('bmp')); $v = new Validator($trans, ['x' => $file4], ['x' => 'Image']); $this->assertTrue($v->passes()); - $file5 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file5->expects($this->any())->method('guessExtension')->will($this->returnValue('png')); - $file5->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('png')); + $file5 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file5->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file5->expects($this->any())->method('getExtension')->will($this->returnValue('png')); $v = new Validator($trans, ['x' => $file5], ['x' => 'Image']); $this->assertTrue($v->passes()); - $file6 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file6->expects($this->any())->method('guessExtension')->will($this->returnValue('svg')); - $file6->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('svg')); - $v = new Validator($trans, ['x' => $file6], ['x' => 'Image']); - $this->assertTrue($v->passes()); - - $file7 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file7->expects($this->any())->method('guessExtension')->will($this->returnValue('webp')); - $file7->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('webp')); + $file7 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file7->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file7->expects($this->any())->method('getExtension')->will($this->returnValue('webp')); $v = new Validator($trans, ['x' => $file7], ['x' => 'Image']); $this->assertTrue($v->passes()); } @@ -2471,11 +2465,11 @@ class ValidationValidatorTest extends TestCase public function testValidateImageDoesNotAllowPhpExtensionsOnImageMime() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__FILE__, '', null, null, null, true]; + $uploadedFile = [__FILE__, 0, 0]; - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file->expects($this->any())->method('guessExtension')->will($this->returnValue('jpeg')); - $file->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('php')); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getExtension'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file->expects($this->any())->method('getExtension')->will($this->returnValue('php')); $v = new Validator($trans, ['x' => $file], ['x' => 'Image']); $this->assertFalse($v->passes()); } @@ -2483,82 +2477,76 @@ class ValidationValidatorTest extends TestCase public function testValidateImageDimensions() { // Knowing that demo image.png has width = 3 and height = 2 - $uploadedFile = new UploadedFile(__DIR__ . '/fixtures/image.png', '', null, null, null, true); $trans = $this->getIlluminateArrayTranslator(); + $uploadedFile = [__DIR__ . '/fixtures/image.png', 0, 0, 'image.png']; + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => 'file'], ['x' => 'dimensions']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_width=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_width=1']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_width=5']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_width=5']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_width=10']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:max_width=10']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_width=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:max_width=1']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_height=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_height=1']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_height=5']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_height=5']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_height=10']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:max_height=10']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_height=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:max_height=1']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:width=3']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:width=3']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:height=2']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:height=2']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_height=2,ratio=3/2']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_height=2,ratio=3/2']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=1.5']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:ratio=1.5']); $this->assertTrue($v->passes()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=1/1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:ratio=1/1']); $this->assertTrue($v->fails()); - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:ratio=1']); $this->assertTrue($v->fails()); - // Knowing that demo image2.png has width = 4 and height = 2 - $uploadedFile = new UploadedFile(__DIR__ . '/fixtures/image2.png', '', null, null, null, true); - $trans = $this->getIlluminateArrayTranslator(); - // Ensure validation doesn't erroneously fail when ratio has no fractional part - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=2/1']); + $uploadedFile = [__DIR__ . '/fixtures/image2.png', 0, 0, 'image2.png']; + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:ratio=2/1']); $this->assertTrue($v->passes()); // This test fails without suppressing warnings on getimagesize() due to a read error. - $emptyUploadedFile = new UploadedFile(__DIR__ . '/fixtures/empty.png', '', null, null, null, true); - $trans = $this->getIlluminateArrayTranslator(); - - $v = new Validator($trans, ['x' => $emptyUploadedFile], ['x' => 'dimensions:min_width=1']); + $uploadedFile = [__DIR__ . '/fixtures/empty.png', 0, 0, 'empty.png']; + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:min_width=1']); $this->assertTrue($v->fails()); // Knowing that demo image3.png has width = 7 and height = 10 - $uploadedFile = new UploadedFile(__DIR__ . '/fixtures/image3.png', '', null, null, null, true); - $trans = $this->getIlluminateArrayTranslator(); - + $uploadedFile = [__DIR__ . '/fixtures/image3.png', 0, 0, 'image3.png']; + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); // Ensure validation doesn't erroneously fail when ratio has no fractional part - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=2/3']); - $this->assertTrue($v->passes()); - - // Ensure svg images always pass as size is irreleveant - $uploadedFile = new UploadedFile(__DIR__ . '/fixtures/image.svg', '', 'image/svg+xml', null, null, true); - $trans = $this->getIlluminateArrayTranslator(); - - $v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_width=1,max_height=1']); + $v = new Validator($trans, ['x' => $file], ['x' => 'dimensions:ratio=2/3']); $this->assertTrue($v->passes()); } @@ -2568,11 +2556,11 @@ class ValidationValidatorTest extends TestCase public function testValidatePhpMimetypes() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__DIR__ . '/ValidationRuleTest.php', '', null, null, null, true]; + $uploadedFile = [__DIR__ . '/ValidationRuleTest.php', 0, 0]; - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file->expects($this->any())->method('guessExtension')->will($this->returnValue('rtf')); - $file->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('rtf')); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getExtension', 'isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('getExtension')->will($this->returnValue('rtf')); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => $file], ['x' => 'mimetypes:text/*']); $this->assertTrue($v->passes()); @@ -2581,17 +2569,17 @@ class ValidationValidatorTest extends TestCase public function testValidateMime() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__FILE__, '', null, null, null, true]; + $uploadedFile = [__FILE__, 0, 0, 'aa.pdf']; - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file->expects($this->any())->method('guessExtension')->will($this->returnValue('pdf')); - $file->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('pdf')); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getMimeType'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('getMimeType')->will($this->returnValue('pdf')); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => $file], ['x' => 'mimes:pdf']); $this->assertTrue($v->passes()); - $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'isValid'])->setConstructorArgs($uploadedFile)->getMock(); - $file2->expects($this->any())->method('guessExtension')->will($this->returnValue('pdf')); - $file2->expects($this->any())->method('isValid')->will($this->returnValue(false)); + $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid', 'getMimeType'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('getMimeType')->will($this->returnValue('pdf')); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => $file2], ['x' => 'mimes:pdf']); $this->assertFalse($v->passes()); } @@ -2599,17 +2587,19 @@ class ValidationValidatorTest extends TestCase public function testValidateMimeEnforcesPhpCheck() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__FILE__, '', null, null, null, true]; + $uploadedFile = [__FILE__, 0, 0]; - $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file->expects($this->any())->method('guessExtension')->will($this->returnValue('pdf')); - $file->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('php')); + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['getExtension', 'getMimeType', 'isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('getExtension')->will($this->returnValue('php')); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file->expects($this->any())->method('getMimeType')->will($this->returnValue('pdf')); $v = new Validator($trans, ['x' => $file], ['x' => 'mimes:pdf']); $this->assertFalse($v->passes()); - $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); - $file2->expects($this->any())->method('guessExtension')->will($this->returnValue('php')); - $file2->expects($this->any())->method('getClientOriginalExtension')->will($this->returnValue('php')); + $file2 = $this->getMockBuilder(UploadedFile::class)->setMethods(['getExtension', 'getMimeType', 'isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file2->expects($this->any())->method('getExtension')->will($this->returnValue('php')); + $file2->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $file2->expects($this->any())->method('getMimeType')->will($this->returnValue('pdf')); $v = new Validator($trans, ['x' => $file2], ['x' => 'mimes:pdf,php']); $this->assertTrue($v->passes()); } @@ -2620,7 +2610,10 @@ class ValidationValidatorTest extends TestCase public function testValidateFile() { $trans = $this->getIlluminateArrayTranslator(); - $file = new UploadedFile(__FILE__, '', null, null, null, true); + $uploadedFile = [__FILE__, 0, 0]; + + $file = $this->getMockBuilder(UploadedFile::class)->setMethods(['isValid'])->setConstructorArgs($uploadedFile)->getMock(); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $v = new Validator($trans, ['x' => '1'], ['x' => 'file']); $this->assertTrue($v->fails()); @@ -4204,8 +4197,8 @@ class ValidationValidatorTest extends TestCase public function testMultipleFileUploads() { $trans = $this->getIlluminateArrayTranslator(); - $file = new File(__FILE__, false); - $file2 = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); + $file2 = new SplFileInfo(__FILE__); $v = new Validator($trans, ['file' => [$file, $file2]], ['file.*' => 'Required|mimes:xls']); $this->assertFalse($v->passes()); } @@ -4213,7 +4206,7 @@ class ValidationValidatorTest extends TestCase public function testFileUploads() { $trans = $this->getIlluminateArrayTranslator(); - $file = new File(__FILE__, false); + $file = new SplFileInfo(__FILE__); $v = new Validator($trans, ['file' => $file], ['file' => 'Required|mimes:xls']); $this->assertFalse($v->passes()); } From 5fef020ab39927977efb90d2c10fb2f107e606cc Mon Sep 17 00:00:00 2001 From: "York.GU" Date: Sat, 24 Aug 2019 17:52:13 +0800 Subject: [PATCH 14/79] add support of Standard error model in grpc-server --- .../src/Exception/GrpcException.php | 21 ++ .../Handler/GrpcExceptionHandler.php | 12 +- src/grpc-server/src/StatusCode.php | 188 ++++++++++++++++++ 3 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/grpc-server/src/Exception/GrpcException.php create mode 100644 src/grpc-server/src/StatusCode.php diff --git a/src/grpc-server/src/Exception/GrpcException.php b/src/grpc-server/src/Exception/GrpcException.php new file mode 100644 index 000000000..17c74b85f --- /dev/null +++ b/src/grpc-server/src/Exception/GrpcException.php @@ -0,0 +1,21 @@ +logger->warning($this->formatter->format($throwable)); + if ($throwable instanceof GrpcException) { + $this->logger->debug($this->formatter->format($throwable)); + } else { + $this->logger->warning($this->formatter->format($throwable)); + } return $this->transferToResponse($throwable->getCode(), $throwable->getMessage(), $response); } @@ -55,11 +61,13 @@ class GrpcExceptionHandler extends ExceptionHandler * @param int|string $code * @param string $message * @param ResponseInterface $response + * @return ResponseInterface */ protected function transferToResponse($code, $message, ResponseInterface $response): ResponseInterface { $response = $response->withAddedHeader('Content-Type', 'application/grpc') - ->withAddedHeader('trailer', 'grpc-status, grpc-message'); + ->withAddedHeader('trailer', 'grpc-status, grpc-message') + ->withStatus(StatusCode::HTTP_CODE_MAPPING[$code] ?: 500); $response->getSwooleResponse()->trailer('grpc-status', (string) $code); $response->getSwooleResponse()->trailer('grpc-message', (string) $message); diff --git a/src/grpc-server/src/StatusCode.php b/src/grpc-server/src/StatusCode.php new file mode 100644 index 000000000..9cea2ba15 --- /dev/null +++ b/src/grpc-server/src/StatusCode.php @@ -0,0 +1,188 @@ +A litmus test that may help a service implementor in deciding + * between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: + * (a) Use UNAVAILABLE if the client can retry just the failing call. + * (b) Use ABORTED if the client should retry at a higher-level + * (e.g., restarting a read-modify-write sequence). + * (c) Use FAILED_PRECONDITION if the client should not retry until + * the system state has been explicitly fixed. E.g., if an "rmdir" + * fails because the directory is non-empty, FAILED_PRECONDITION + * should be returned since the client should not retry unless + * they have first fixed up the directory by deleting files from it. + */ + const FAILED_PRECONDITION = 9; + + /** + * The operation was aborted, typically due to a concurrency issue + * like sequencer check failures, transaction aborts, etc. + * + *

See litmus test above for deciding between FAILED_PRECONDITION, + * ABORTED, and UNAVAILABLE. + */ + const ABORTED = 10; + + /** + * Operation was attempted past the valid range. E.g., seeking or + * reading past end of file. + * + *

Unlike INVALID_ARGUMENT, this error indicates a problem that may + * be fixed if the system state changes. For example, a 32-bit file + * system will generate INVALID_ARGUMENT if asked to read at an + * offset that is not in the range [0,2^32-1], but it will generate + * OUT_OF_RANGE if asked to read from an offset past the current + * file size. + * + *

There is a fair bit of overlap between FAILED_PRECONDITION and OUT_OF_RANGE. + * We recommend using OUT_OF_RANGE (the more specific error) when it applies + * so that callers who are iterating through + * a space can easily look for an OUT_OF_RANGE error to detect when they are done. + */ + const OUT_OF_RANGE = 11; + + /** + * Operation is not implemented or not supported/enabled in this service. + */ + const UNIMPLEMENTED = 12; + + /** + * Internal errors. Means some invariants expected by underlying + * system has been broken. If you see one of these errors, + * something is very broken. + */ + const INTERNAL = 13; + + /** + * The service is currently unavailable. This is a most likely a + * transient condition and may be corrected by retrying with + * a backoff. Note that it is not always safe to retry + * non-idempotent operations. + * + *

See litmus test above for deciding between FAILED_PRECONDITION, + * ABORTED, and UNAVAILABLE. + */ + const UNAVAILABLE = 14; + + /** + * Unrecoverable data loss or corruption. + */ + const DATA_LOSS = 15; + + /** + * The request does not have valid authentication credentials for the + * operation. + */ + const UNAUTHENTICATED = 16; + + + /** + * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html + */ + const HTTP_CODE_MAPPING = [ + self::OK => 200, + self::CANCELLED => 499, + self::UNKNOWN => 500, + self::INVALID_ARGUMENT => 400, + self::DEADLINE_EXCEEDED => 504, + self::NOT_FOUND => 404, + self::ALREADY_EXISTS => 409, + self::PERMISSION_DENIED => 403, + self::RESOURCE_EXHAUSTED => 429, + self::FAILED_PRECONDITION => 400, + self::ABORTED => 409, + self::OUT_OF_RANGE => 400, + self::UNIMPLEMENTED => 501, + self::INTERNAL => 500, + self::UNAVAILABLE => 503, + self::DATA_LOSS => 500, + self::UNAUTHENTICATED => 401, + ]; +} From d22e2330b944232264022173244f51095c18a2bd Mon Sep 17 00:00:00 2001 From: "York.GU" Date: Sat, 24 Aug 2019 18:14:48 +0800 Subject: [PATCH 15/79] add phpdoc of static moethods for class Hyperf\Database\Schema\Schema --- src/database/src/Schema/Schema.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/database/src/Schema/Schema.php b/src/database/src/Schema/Schema.php index ddb40ff5a..2ac969f4b 100644 --- a/src/database/src/Schema/Schema.php +++ b/src/database/src/Schema/Schema.php @@ -16,6 +16,28 @@ use Hyperf\Database\ConnectionInterface; use Hyperf\Database\ConnectionResolverInterface; use Hyperf\Utils\ApplicationContext; +/** + * @method static bool hasTable(string $table) + * @method static array getColumnListing(string $table) + * @method static array getColumnTypeListing(string $table) + * @method static dropAllTables() + * @method static dropAllViews() + * @method static array getAllTables() + * @method static array getAllViews() + * @method static bool hasColumn(string $table, string $column) + * @method static bool hasColumns(string $table, array $columns) + * @method static string getColumnType(string $table, string $column) + * @method static table(string $table, \Closure $callback) + * @method static create(string $table, \Closure $callback)) + * @method static drop(string $table) + * @method static dropIfExists(string $table) + * @method static rename(string $from, string $to) + * @method static enableForeignKeyConstraints(): bool + * @method static disableForeignKeyConstraints(): bool + * @method static \Hyperf\Database\Connection getConnection() + * @method static setConnection(\Hyperf\Database\Connection $connection) + * @method static blueprintResolver(\Closure $resolver) + */ class Schema { public static function __callStatic($name, $arguments) From d5f3fe8998ebda7e261bcd44ae08ba1b2a61f313 Mon Sep 17 00:00:00 2001 From: "York.GU" Date: Sat, 24 Aug 2019 18:14:48 +0800 Subject: [PATCH 16/79] add phpdoc of static moethods for class Hyperf\Database\Schema\Schema --- src/database/src/Schema/Schema.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/database/src/Schema/Schema.php b/src/database/src/Schema/Schema.php index ddb40ff5a..2ac969f4b 100644 --- a/src/database/src/Schema/Schema.php +++ b/src/database/src/Schema/Schema.php @@ -16,6 +16,28 @@ use Hyperf\Database\ConnectionInterface; use Hyperf\Database\ConnectionResolverInterface; use Hyperf\Utils\ApplicationContext; +/** + * @method static bool hasTable(string $table) + * @method static array getColumnListing(string $table) + * @method static array getColumnTypeListing(string $table) + * @method static dropAllTables() + * @method static dropAllViews() + * @method static array getAllTables() + * @method static array getAllViews() + * @method static bool hasColumn(string $table, string $column) + * @method static bool hasColumns(string $table, array $columns) + * @method static string getColumnType(string $table, string $column) + * @method static table(string $table, \Closure $callback) + * @method static create(string $table, \Closure $callback)) + * @method static drop(string $table) + * @method static dropIfExists(string $table) + * @method static rename(string $from, string $to) + * @method static enableForeignKeyConstraints(): bool + * @method static disableForeignKeyConstraints(): bool + * @method static \Hyperf\Database\Connection getConnection() + * @method static setConnection(\Hyperf\Database\Connection $connection) + * @method static blueprintResolver(\Closure $resolver) + */ class Schema { public static function __callStatic($name, $arguments) From 9ed3912c23eafa586fa8f855cb293bdea83f4a53 Mon Sep 17 00:00:00 2001 From: "York.GU" Date: Sat, 24 Aug 2019 18:49:35 +0800 Subject: [PATCH 17/79] remove __construct methods in router from AutoController, see issue #442 --- src/http-server/src/Router/DispatcherFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index 5a0e850f7..82d8cd362 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -116,6 +116,7 @@ class DispatcherFactory $autoMethods = ['GET', 'POST', 'HEAD']; $defaultAction = '/index'; foreach ($methods as $method) { + if ($method === '__construct') continue; $path = $this->parsePath($prefix, $method); $methodName = $method->getName(); $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); From a5c8742c0127b27da6ba88356aed11156fedbbec Mon Sep 17 00:00:00 2001 From: YorkGu Date: Sun, 25 Aug 2019 00:40:08 +0800 Subject: [PATCH 18/79] remove all magic methods starts with __ in @AutoController sorry about the previous mistake --- src/http-server/src/Router/DispatcherFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index 82d8cd362..0de852796 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -116,9 +116,9 @@ class DispatcherFactory $autoMethods = ['GET', 'POST', 'HEAD']; $defaultAction = '/index'; foreach ($methods as $method) { - if ($method === '__construct') continue; $path = $this->parsePath($prefix, $method); $methodName = $method->getName(); + if (substr($methodName, 0, 2) === '__') continue; $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); $methodMiddlewares = $middlewares; From c85349fd5bcee9ae679e255b7be4e68ec19d0ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 13:06:35 +0800 Subject: [PATCH 19/79] Added testing. --- .../src/Router/DispatcherFactory.php | 4 +++- .../tests/Router/DispatcherFactoryTest.php | 18 ++++++++++++++++++ src/http-server/tests/Stub/DemoController.php | 4 ++++ .../tests/Stub/DispatcherFactory.php | 15 ++++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index 0de852796..4b5332a8e 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -118,7 +118,9 @@ class DispatcherFactory foreach ($methods as $method) { $path = $this->parsePath($prefix, $method); $methodName = $method->getName(); - if (substr($methodName, 0, 2) === '__') continue; + if (substr($methodName, 0, 2) === '__') { + continue; + } $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); $methodMiddlewares = $middlewares; diff --git a/src/http-server/tests/Router/DispatcherFactoryTest.php b/src/http-server/tests/Router/DispatcherFactoryTest.php index e70d4084f..0bb071bfc 100644 --- a/src/http-server/tests/Router/DispatcherFactoryTest.php +++ b/src/http-server/tests/Router/DispatcherFactoryTest.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace HyperfTest\HttpServer\Router; +use Hyperf\HttpServer\Annotation\AutoController; +use HyperfTest\HttpServer\Stub\DemoController; use HyperfTest\HttpServer\Stub\DispatcherFactory; use PHPUnit\Framework\TestCase; @@ -31,4 +33,20 @@ class DispatcherFactoryTest extends TestCase $res = $factory->getPrefix('App\\Controller\\Admin\\UserAuthController', ''); $this->assertSame('/admin/user_auth', $res); } + + public function testRemoveMagicMethods() + { + $factory = new DispatcherFactory(); + $annotation = new AutoController(['prefix' => 'test']); + $factory->handleAutoController(DemoController::class, $annotation); + + $router = $factory->getRouter('http'); + + [$routers] = $router->getData(); + + $this->assertSame(['GET', 'POST', 'HEAD'], array_keys($routers)); + foreach ($routers as $method => $items) { + $this->assertFalse(in_array('/test/__construct', array_keys($items))); + } + } } diff --git a/src/http-server/tests/Stub/DemoController.php b/src/http-server/tests/Stub/DemoController.php index 01e3f27b1..31d7dbeed 100644 --- a/src/http-server/tests/Stub/DemoController.php +++ b/src/http-server/tests/Stub/DemoController.php @@ -14,6 +14,10 @@ namespace HyperfTest\HttpServer\Stub; class DemoController { + public function __construct() + { + } + public function index(int $id, string $name = 'Hyperf', array $params = []) { return [$id, $name, $params]; diff --git a/src/http-server/tests/Stub/DispatcherFactory.php b/src/http-server/tests/Stub/DispatcherFactory.php index e4d4b908e..0ee8af34e 100644 --- a/src/http-server/tests/Stub/DispatcherFactory.php +++ b/src/http-server/tests/Stub/DispatcherFactory.php @@ -12,10 +12,23 @@ declare(strict_types=1); namespace HyperfTest\HttpServer\Stub; +use Hyperf\HttpServer\Annotation\AutoController; +use Hyperf\HttpServer\Router\RouteCollector; + class DispatcherFactory extends \Hyperf\HttpServer\Router\DispatcherFactory { public function getPrefix(string $className, string $prefix): string { - return parent::getPrefix($className, $prefix); // TODO: Change the autogenerated stub + return parent::getPrefix($className, $prefix); + } + + public function handleAutoController(string $className, AutoController $annotation, array $middlewares = [], array $methodMetadata = []): void + { + parent::handleAutoController($className, $annotation, $middlewares, $methodMetadata); + } + + public function getRouter(string $serverName): RouteCollector + { + return parent::getRouter($serverName); } } From c053740cb8b1c992e374ce03a06eb2f880cb682b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 13:09:51 +0800 Subject: [PATCH 20/79] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 533731388..52ff7b78c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.0.13 - TBD +## Changed + +- [#451](https://github.com/hyperf-cloud/hyperf/pull/451) Removed routes of magic methods from `AuthController`. + # v1.0.12 - 2019-08-21 ## Added From ad3d973f7131e2d0123089f2e0c99a4d99251039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 13:48:21 +0800 Subject: [PATCH 21/79] Fixed . --- CHANGELOG.md | 4 ++++ src/database/src/Schema/Schema.php | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 533731388..81517e502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.0.13 - TBD +## Added + +- [#450](https://github.com/hyperf-cloud/hyperf/pull/450) Added comments of static methods for `Hyperf\Database\Schema\Schema`. + # v1.0.12 - 2019-08-21 ## Added diff --git a/src/database/src/Schema/Schema.php b/src/database/src/Schema/Schema.php index 2ac969f4b..c48987da5 100644 --- a/src/database/src/Schema/Schema.php +++ b/src/database/src/Schema/Schema.php @@ -20,23 +20,23 @@ use Hyperf\Utils\ApplicationContext; * @method static bool hasTable(string $table) * @method static array getColumnListing(string $table) * @method static array getColumnTypeListing(string $table) - * @method static dropAllTables() - * @method static dropAllViews() + * @method static void dropAllTables() + * @method static void dropAllViews() * @method static array getAllTables() * @method static array getAllViews() * @method static bool hasColumn(string $table, string $column) * @method static bool hasColumns(string $table, array $columns) * @method static string getColumnType(string $table, string $column) - * @method static table(string $table, \Closure $callback) - * @method static create(string $table, \Closure $callback)) - * @method static drop(string $table) - * @method static dropIfExists(string $table) - * @method static rename(string $from, string $to) - * @method static enableForeignKeyConstraints(): bool - * @method static disableForeignKeyConstraints(): bool + * @method static void table(string $table, \Closure $callback) + * @method static void create(string $table, \Closure $callback)) + * @method static void drop(string $table) + * @method static void dropIfExists(string $table) + * @method static void rename(string $from, string $to) + * @method static bool enableForeignKeyConstraints() + * @method static bool disableForeignKeyConstraints() * @method static \Hyperf\Database\Connection getConnection() - * @method static setConnection(\Hyperf\Database\Connection $connection) - * @method static blueprintResolver(\Closure $resolver) + * @method static Builder setConnection(\Hyperf\Database\Connection $connection) + * @method static void blueprintResolver(\Closure $resolver) */ class Schema { From 551d25c7581e277387806e7ad485a2ea5f9848b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 14:00:40 +0800 Subject: [PATCH 22/79] Format code. --- src/grpc-server/src/Exception/GrpcException.php | 2 -- src/grpc-server/src/StatusCode.php | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/grpc-server/src/Exception/GrpcException.php b/src/grpc-server/src/Exception/GrpcException.php index 17c74b85f..0dd36fa14 100644 --- a/src/grpc-server/src/Exception/GrpcException.php +++ b/src/grpc-server/src/Exception/GrpcException.php @@ -10,10 +10,8 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ - namespace Hyperf\GrpcServer\Exception; - use Hyperf\Server\Exception\ServerException; class GrpcException extends ServerException diff --git a/src/grpc-server/src/StatusCode.php b/src/grpc-server/src/StatusCode.php index 9cea2ba15..9d133e159 100644 --- a/src/grpc-server/src/StatusCode.php +++ b/src/grpc-server/src/StatusCode.php @@ -10,12 +10,11 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ - namespace Hyperf\GrpcServer; /** - * the const inside this class is copied from this address - * @link https://github.com/grpc/grpc-java/blob/b363f80764bcc8452ef54511b6c6d6b596f5f177/api/src/main/java/io/grpc/Status.java + * the const inside this class is copied from this address. + * @see https://github.com/grpc/grpc-java/blob/b363f80764bcc8452ef54511b6c6d6b596f5f177/api/src/main/java/io/grpc/Status.java * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html */ class StatusCode @@ -162,7 +161,6 @@ class StatusCode */ const UNAUTHENTICATED = 16; - /** * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html */ From 315ba20ad2c8106a16cf71906ea4c54ec006aaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 14:29:44 +0800 Subject: [PATCH 23/79] Added testing. --- composer.json | 1 + phpunit.xml | 1 + src/grpc-server/composer.json | 1 + .../Handler/GrpcExceptionHandler.php | 6 +- .../tests/GrpcExceptionHandlerTest.php | 98 +++++++++++++++++++ .../tests/Stub/GrpcExceptionHandlerStub.php | 24 +++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/grpc-server/tests/GrpcExceptionHandlerTest.php create mode 100644 src/grpc-server/tests/Stub/GrpcExceptionHandlerStub.php diff --git a/composer.json b/composer.json index 22cc80dca..2b34cb497 100644 --- a/composer.json +++ b/composer.json @@ -185,6 +185,7 @@ "HyperfTest\\Etcd\\": "src/etcd/tests/", "HyperfTest\\Event\\": "src/event/tests/", "HyperfTest\\GrpcClient\\": "src/grpc-client/tests/", + "HyperfTest\\GrpcServer\\": "src/grpc-server/tests/", "HyperfTest\\Guzzle\\": "src/guzzle/tests/", "HyperfTest\\HttpMessage\\": "src/http-message/tests/", "HyperfTest\\HttpServer\\": "src/http-server/tests/", diff --git a/phpunit.xml b/phpunit.xml index 445a54672..efcff06e0 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,6 +23,7 @@ ./src/elasticsearch/tests ./src/event/tests ./src/grpc-client/tests + ./src/grpc-server/tests ./src/guzzle/tests ./src/http-message/tests ./src/http-server/tests diff --git a/src/grpc-server/composer.json b/src/grpc-server/composer.json index 234fc249a..4f1b74877 100644 --- a/src/grpc-server/composer.json +++ b/src/grpc-server/composer.json @@ -34,6 +34,7 @@ }, "autoload-dev": { "psr-4": { + "HyperfTest\\GrpcServer\\": "tests/" } }, "config": { diff --git a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php index 2c2fd923b..b359484d4 100644 --- a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php +++ b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php @@ -58,16 +58,14 @@ class GrpcExceptionHandler extends ExceptionHandler /** * Transfer the non-standard response content to a standard response object. * - * @param int|string $code + * @param int $code * @param string $message - * @param ResponseInterface $response - * @return ResponseInterface */ protected function transferToResponse($code, $message, ResponseInterface $response): ResponseInterface { $response = $response->withAddedHeader('Content-Type', 'application/grpc') ->withAddedHeader('trailer', 'grpc-status, grpc-message') - ->withStatus(StatusCode::HTTP_CODE_MAPPING[$code] ?: 500); + ->withStatus(StatusCode::HTTP_CODE_MAPPING[$code] ?? 500); $response->getSwooleResponse()->trailer('grpc-status', (string) $code); $response->getSwooleResponse()->trailer('grpc-message', (string) $message); diff --git a/src/grpc-server/tests/GrpcExceptionHandlerTest.php b/src/grpc-server/tests/GrpcExceptionHandlerTest.php new file mode 100644 index 000000000..b915e3276 --- /dev/null +++ b/src/grpc-server/tests/GrpcExceptionHandlerTest.php @@ -0,0 +1,98 @@ +getContainer(); + + $logger = $container->get(StdoutLoggerInterface::class); + $formatter = $container->get(FormatterInterface::class); + $swooleResponse = Mockery::mock(\Swoole\Http\Response::class); + $data = []; + $swooleResponse->shouldReceive('trailer')->andReturnUsing(function (...$args) use (&$data) { + $data[] = $args; + }); + $response = new Response($swooleResponse); + $handler = new GrpcExceptionHandlerStub($logger, $formatter); + $response = $handler->transferToResponse(StatusCode::OK, 'OK', $response); + $this->assertSame([['grpc-status', '0'], ['grpc-message', 'OK']], $data); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testTransferToResponse499() + { + $container = $this->getContainer(); + + $logger = $container->get(StdoutLoggerInterface::class); + $formatter = $container->get(FormatterInterface::class); + $swooleResponse = Mockery::mock(\Swoole\Http\Response::class); + $data = []; + $swooleResponse->shouldReceive('trailer')->andReturnUsing(function (...$args) use (&$data) { + $data[] = $args; + }); + $response = new Response($swooleResponse); + $handler = new GrpcExceptionHandlerStub($logger, $formatter); + $response = $handler->transferToResponse(StatusCode::CANCELLED, 'The operation was cancelled', $response); + $this->assertSame([['grpc-status', '1'], ['grpc-message', 'The operation was cancelled']], $data); + $this->assertSame(499, $response->getStatusCode()); + } + + public function testTransferToResponseUnKnown() + { + $container = $this->getContainer(); + + $logger = $container->get(StdoutLoggerInterface::class); + $formatter = $container->get(FormatterInterface::class); + $swooleResponse = Mockery::mock(\Swoole\Http\Response::class); + $data = []; + $swooleResponse->shouldReceive('trailer')->andReturnUsing(function (...$args) use (&$data) { + $data[] = $args; + }); + $response = new Response($swooleResponse); + $handler = new GrpcExceptionHandlerStub($logger, $formatter); + $response = $handler->transferToResponse(123, 'UNKNOWN', $response); + $this->assertSame([['grpc-status', '123'], ['grpc-message', 'UNKNOWN']], $data); + $this->assertSame(500, $response->getStatusCode()); + } + + protected function getContainer() + { + $container = Mockery::mock(ContainerInterface::class); + + $logger = Mockery::mock(StdoutLoggerInterface::class); + $logger->shouldReceive(Mockery::any())->with(Mockery::any())->andReturn(null); + $container->shouldReceive('get')->with(StdoutLoggerInterface::class)->andReturn($logger); + + $formatter = Mockery::mock(FormatterInterface::class); + $formatter->shouldReceive(Mockery::any())->with(Mockery::any())->andReturn(''); + $container->shouldReceive('get')->with(FormatterInterface::class)->andReturn($formatter); + + return $container; + } +} diff --git a/src/grpc-server/tests/Stub/GrpcExceptionHandlerStub.php b/src/grpc-server/tests/Stub/GrpcExceptionHandlerStub.php new file mode 100644 index 000000000..36c6e843a --- /dev/null +++ b/src/grpc-server/tests/Stub/GrpcExceptionHandlerStub.php @@ -0,0 +1,24 @@ + Date: Sun, 25 Aug 2019 14:34:23 +0800 Subject: [PATCH 24/79] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81517e502..2ef3522ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Added +- [#449](https://github.com/hyperf-cloud/hyperf/pull/449) Added standard error code for grpc-server. - [#450](https://github.com/hyperf-cloud/hyperf/pull/450) Added comments of static methods for `Hyperf\Database\Schema\Schema`. # v1.0.12 - 2019-08-21 From 22228f5633afb352de53d5c2136ec47226f07225 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 25 Aug 2019 15:09:49 +0800 Subject: [PATCH 25/79] Move Contracts\ to Contract\ and Optimized --- src/translation/src/ArrayLoader.php | 24 ++---------- src/translation/src/ConfigProvider.php | 4 +- .../HasLocalePreference.php | 6 +-- .../src/{Contracts => Contract}/Loader.php | 16 +------- .../{Contracts => Contract}/Translator.php | 2 +- src/translation/src/FileLoader.php | 37 ++----------------- src/translation/src/Translator.php | 10 ++--- src/translation/src/TranslatorFactory.php | 2 +- .../tests/Cases/TranslationTranslatorTest.php | 2 +- 9 files changed, 21 insertions(+), 82 deletions(-) rename src/translation/src/{Contracts => Contract}/HasLocalePreference.php (75%) rename src/translation/src/{Contracts => Contract}/Loader.php (64%) rename src/translation/src/{Contracts => Contract}/Translator.php (96%) diff --git a/src/translation/src/ArrayLoader.php b/src/translation/src/ArrayLoader.php index 75d7825a6..205fbf187 100644 --- a/src/translation/src/ArrayLoader.php +++ b/src/translation/src/ArrayLoader.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Hyperf\Translation; -use Hyperf\Translation\Contracts\Loader; +use Hyperf\Translation\Contract\Loader; class ArrayLoader implements Loader { @@ -25,13 +25,8 @@ class ArrayLoader implements Loader /** * Load the messages for the given locale. - * - * @param string $locale - * @param string $group - * @param null|string $namespace - * @return array */ - public function load(string $locale, string $group, $namespace = null): array + public function load(string $locale, string $group, ?string $namespace = null): array { $namespace = $namespace ?: '*'; @@ -40,9 +35,6 @@ class ArrayLoader implements Loader /** * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint */ public function addNamespace(string $namespace, string $hint) { @@ -50,8 +42,6 @@ class ArrayLoader implements Loader /** * Add a new JSON path to the loader. - * - * @param string $path */ public function addJsonPath(string $path) { @@ -59,14 +49,8 @@ class ArrayLoader implements Loader /** * Add messages to the loader. - * - * @param string $locale - * @param string $group - * @param array $messages - * @param null|string $namespace - * @return $this */ - public function addMessages(string $locale, string $group, array $messages, $namespace = null) + public function addMessages(string $locale, string $group, array $messages, ?string $namespace = null): self { $namespace = $namespace ?: '*'; @@ -77,8 +61,6 @@ class ArrayLoader implements Loader /** * Get an array of all the registered namespaces. - * - * @return array */ public function namespaces(): array { diff --git a/src/translation/src/ConfigProvider.php b/src/translation/src/ConfigProvider.php index e7fd6f83b..1c0b506a9 100644 --- a/src/translation/src/ConfigProvider.php +++ b/src/translation/src/ConfigProvider.php @@ -12,8 +12,8 @@ declare(strict_types=1); namespace Hyperf\Translation; -use Hyperf\Translation\Contracts\Loader; -use Hyperf\Translation\Contracts\Translator; +use Hyperf\Translation\Contract\Loader; +use Hyperf\Translation\Contract\Translator; class ConfigProvider { diff --git a/src/translation/src/Contracts/HasLocalePreference.php b/src/translation/src/Contract/HasLocalePreference.php similarity index 75% rename from src/translation/src/Contracts/HasLocalePreference.php rename to src/translation/src/Contract/HasLocalePreference.php index 430de5950..121fa92eb 100644 --- a/src/translation/src/Contracts/HasLocalePreference.php +++ b/src/translation/src/Contract/HasLocalePreference.php @@ -10,14 +10,12 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Translation\Contracts; +namespace Hyperf\Translation\Contract; interface HasLocalePreference { /** * Get the preferred locale of the entity. - * - * @return null|string */ - public function preferredLocale(); + public function preferredLocale(): ?string; } diff --git a/src/translation/src/Contracts/Loader.php b/src/translation/src/Contract/Loader.php similarity index 64% rename from src/translation/src/Contracts/Loader.php rename to src/translation/src/Contract/Loader.php index dcb8498e7..ffec5cd4e 100755 --- a/src/translation/src/Contracts/Loader.php +++ b/src/translation/src/Contract/Loader.php @@ -10,39 +10,27 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Translation\Contracts; +namespace Hyperf\Translation\Contract; interface Loader { /** * Load the messages for the given locale. - * - * @param string $locale - * @param string $group - * @param null|string $namespace - * @return array */ - public function load(string $locale, string $group, $namespace = null): array; + public function load(string $locale, string $group, ?string $namespace = null): array; /** * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint */ public function addNamespace(string $namespace, string $hint); /** * Add a new JSON path to the loader. - * - * @param string $path */ public function addJsonPath(string $path); /** * Get an array of all the registered namespaces. - * - * @return array */ public function namespaces(): array; } diff --git a/src/translation/src/Contracts/Translator.php b/src/translation/src/Contract/Translator.php similarity index 96% rename from src/translation/src/Contracts/Translator.php rename to src/translation/src/Contract/Translator.php index e979fc715..ea1b789ac 100644 --- a/src/translation/src/Contracts/Translator.php +++ b/src/translation/src/Contract/Translator.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Translation\Contracts; +namespace Hyperf\Translation\Contract; interface Translator { diff --git a/src/translation/src/FileLoader.php b/src/translation/src/FileLoader.php index 60eceb297..e7d212e71 100755 --- a/src/translation/src/FileLoader.php +++ b/src/translation/src/FileLoader.php @@ -12,7 +12,8 @@ declare(strict_types=1); namespace Hyperf\Translation; -use Hyperf\Translation\Contracts\Loader; +use Hyperf\Translation\Contract\Loader; +use Hyperf\Utils\Collection; use Hyperf\Utils\Filesystem\Filesystem; use RuntimeException; @@ -60,13 +61,8 @@ class FileLoader implements Loader /** * Load the messages for the given locale. - * - * @param string $locale - * @param string $group - * @param null|string $namespace - * @return array */ - public function load(string $locale, string $group, $namespace = null): array + public function load(string $locale, string $group, ?string $namespace = null): array { if ($group === '*' && $namespace === '*') { return $this->loadJsonPaths($locale); @@ -81,9 +77,6 @@ class FileLoader implements Loader /** * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint */ public function addNamespace(string $namespace, string $hint) { @@ -92,8 +85,6 @@ class FileLoader implements Loader /** * Add a new JSON path to the loader. - * - * @param string $path */ public function addJsonPath(string $path) { @@ -102,8 +93,6 @@ class FileLoader implements Loader /** * Get an array of all the registered namespaces. - * - * @return array */ public function namespaces(): array { @@ -112,11 +101,6 @@ class FileLoader implements Loader /** * Load a namespaced translation group. - * - * @param string $locale - * @param string $group - * @param string $namespace - * @return array */ protected function loadNamespaced(string $locale, string $group, string $namespace): array { @@ -131,12 +115,6 @@ class FileLoader implements Loader /** * Load a local namespaced translation group for overrides. - * - * @param array $lines - * @param string $locale - * @param string $group - * @param string $namespace - * @return array */ protected function loadNamespaceOverrides(array $lines, string $locale, string $group, string $namespace): array { @@ -151,11 +129,6 @@ class FileLoader implements Loader /** * Load a locale from a given path. - * - * @param string $path - * @param string $locale - * @param string $group - * @return array */ protected function loadPath(string $path, string $locale, string $group): array { @@ -169,11 +142,9 @@ class FileLoader implements Loader /** * Load a locale from the given JSON file path. * - * @param string $locale * @throws \RuntimeException - * @return array */ - protected function loadJsonPaths(string $locale) + protected function loadJsonPaths(string $locale): Collection { return collect(array_merge($this->jsonPaths, [$this->path])) ->reduce(function ($output, $path) use ($locale) { diff --git a/src/translation/src/Translator.php b/src/translation/src/Translator.php index e6df440ef..e0d695e7f 100755 --- a/src/translation/src/Translator.php +++ b/src/translation/src/Translator.php @@ -13,8 +13,8 @@ declare(strict_types=1); namespace Hyperf\Translation; use Countable; -use Hyperf\Translation\Contracts\Loader; -use Hyperf\Translation\Contracts\Translator as TranslatorContract; +use Hyperf\Translation\Contract\Loader; +use Hyperf\Translation\Contract\Translator as TranslatorContract; use Hyperf\Translation\Support\NamespacedItemResolver; use Hyperf\Utils\Arr; use Hyperf\Utils\Collection; @@ -28,7 +28,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * The loader implementation. * - * @var \Hyperf\Translation\Contracts\Loader + * @var \Hyperf\Translation\Contract\Loader */ protected $loader; @@ -63,7 +63,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Create a new translator instance. * - * @param \Hyperf\Translation\Contracts\Loader $loader + * @param \Hyperf\Translation\Contract\Loader $loader * @param string $locale */ public function __construct(Loader $loader, string $locale) @@ -328,7 +328,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the language line loader implementation. * - * @return \Hyperf\Translation\Contracts\Loader + * @return \Hyperf\Translation\Contract\Loader */ public function getLoader() { diff --git a/src/translation/src/TranslatorFactory.php b/src/translation/src/TranslatorFactory.php index 4e10f689f..2e5d972b1 100644 --- a/src/translation/src/TranslatorFactory.php +++ b/src/translation/src/TranslatorFactory.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Hyperf\Translation; use Hyperf\Contract\ConfigInterface; -use Hyperf\Translation\Contracts\Loader; +use Hyperf\Translation\Contract\Loader; use Psr\Container\ContainerInterface; class TranslatorFactory diff --git a/src/translation/tests/Cases/TranslationTranslatorTest.php b/src/translation/tests/Cases/TranslationTranslatorTest.php index 5a6e6f24a..934c17d74 100755 --- a/src/translation/tests/Cases/TranslationTranslatorTest.php +++ b/src/translation/tests/Cases/TranslationTranslatorTest.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace HyperfTest\Translation\Cases; -use Hyperf\Translation\Contracts\Loader; +use Hyperf\Translation\Contract\Loader; use Hyperf\Translation\MessageSelector; use Hyperf\Translation\Translator; use Hyperf\Utils\Collection; From f683b0b5f3fb745e030c8eab35e5ffb6033c8e07 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 25 Aug 2019 15:09:54 +0800 Subject: [PATCH 26/79] Update README.MD --- src/translation/README.MD | 47 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/src/translation/README.MD b/src/translation/README.MD index 050cb26e0..7a53a0c77 100644 --- a/src/translation/README.MD +++ b/src/translation/README.MD @@ -1,64 +1,43 @@ # Hyperf Translation -## About +[hyperf/translation](https://github.com/hyperf-cloud/translation) 组件衍生于 `Laravel Translation` 组件的,我们对它进行了一些改造,大部分功能保持了相同。在这里感谢一下 Laravel 开发组,实现了如此强大好用的 Translation 组件。 -hyperf/translation 是对Laravel Translation的移植(不包含门面和快捷函数部分),具体使用方法可以参考Laravel Lang的使用。 +## Installation -## Install - -``` +```bash composer require hyperf/translation - ``` -## Config +## Configuration +### Publish config -### publish config -``` -php bin/hyperf.php vendor:publish hyperf/translation - +```bash +php bin/hyperf.php vendor:publish hyperf/translation ``` -### config path - +Config files: ``` -your/config/path/autoload/translation.php - ++ ./config/path/autoload/translation.php ``` -### config content +### Configuration ``` 'en', 'fallback_locale' => '', 'lang' => BASE_PATH . '/resources/lang', ]; - ``` ## Usage - ``` - -$translator = $this->container->get(\Hyperf\Translation\Contracts\Translator::class); - -$translator->trans('validation.accepted'), - - +$container = ApplicationContext::getContainer(); +$translator = $container->get(\Hyperf\Translation\Contracts\Translator::class); +$translator->trans('validation.accepted'); ``` \ No newline at end of file From 7494def88188055d8b2f94851b00b628da7bb312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 15:34:13 +0800 Subject: [PATCH 27/79] Added user defined magic methods. --- src/http-server/tests/Router/DispatcherFactoryTest.php | 1 + src/http-server/tests/Stub/DemoController.php | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/http-server/tests/Router/DispatcherFactoryTest.php b/src/http-server/tests/Router/DispatcherFactoryTest.php index 0bb071bfc..b471d1585 100644 --- a/src/http-server/tests/Router/DispatcherFactoryTest.php +++ b/src/http-server/tests/Router/DispatcherFactoryTest.php @@ -47,6 +47,7 @@ class DispatcherFactoryTest extends TestCase $this->assertSame(['GET', 'POST', 'HEAD'], array_keys($routers)); foreach ($routers as $method => $items) { $this->assertFalse(in_array('/test/__construct', array_keys($items))); + $this->assertFalse(in_array('/test/__return', array_keys($items))); } } } diff --git a/src/http-server/tests/Stub/DemoController.php b/src/http-server/tests/Stub/DemoController.php index 31d7dbeed..9561eae5e 100644 --- a/src/http-server/tests/Stub/DemoController.php +++ b/src/http-server/tests/Stub/DemoController.php @@ -20,6 +20,11 @@ class DemoController public function index(int $id, string $name = 'Hyperf', array $params = []) { - return [$id, $name, $params]; + return $this->__return($id, $name, $params); + } + + public function __return(...$args) + { + return $args; } } From c97eebfba9d76f4d52d6f0ebc1478e986142cd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 26 Aug 2019 10:07:50 +0800 Subject: [PATCH 28/79] Moved StatusCode into grpc. --- src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php | 2 +- src/grpc-server/tests/GrpcExceptionHandlerTest.php | 2 +- src/{grpc-server => grpc}/src/StatusCode.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{grpc-server => grpc}/src/StatusCode.php (99%) diff --git a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php index b359484d4..2b5b4bb1c 100644 --- a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php +++ b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php @@ -15,8 +15,8 @@ namespace Hyperf\GrpcServer\Exception\Handler; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\ExceptionHandler\Formatter\FormatterInterface; +use Hyperf\Grpc\StatusCode; use Hyperf\GrpcServer\Exception\GrpcException; -use Hyperf\GrpcServer\StatusCode; use Hyperf\Server\Exception\ServerException; use Psr\Http\Message\ResponseInterface; use Throwable; diff --git a/src/grpc-server/tests/GrpcExceptionHandlerTest.php b/src/grpc-server/tests/GrpcExceptionHandlerTest.php index b915e3276..b3480541a 100644 --- a/src/grpc-server/tests/GrpcExceptionHandlerTest.php +++ b/src/grpc-server/tests/GrpcExceptionHandlerTest.php @@ -14,7 +14,7 @@ namespace HyperfTest\GrpcServer; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\ExceptionHandler\Formatter\FormatterInterface; -use Hyperf\GrpcServer\StatusCode; +use Hyperf\Grpc\StatusCode; use Hyperf\HttpMessage\Server\Response; use HyperfTest\GrpcServer\Stub\GrpcExceptionHandlerStub; use Mockery; diff --git a/src/grpc-server/src/StatusCode.php b/src/grpc/src/StatusCode.php similarity index 99% rename from src/grpc-server/src/StatusCode.php rename to src/grpc/src/StatusCode.php index 9d133e159..8e6df89c2 100644 --- a/src/grpc-server/src/StatusCode.php +++ b/src/grpc/src/StatusCode.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\GrpcServer; +namespace Hyperf\Grpc; /** * the const inside this class is copied from this address. From a22ed6d83b26a2958c66c30347098c3e3d9b38ab Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Tue, 27 Aug 2019 01:15:02 +0800 Subject: [PATCH 29/79] Update FileLoader.php --- src/translation/src/FileLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translation/src/FileLoader.php b/src/translation/src/FileLoader.php index e7d212e71..bd52eb764 100755 --- a/src/translation/src/FileLoader.php +++ b/src/translation/src/FileLoader.php @@ -144,7 +144,7 @@ class FileLoader implements Loader * * @throws \RuntimeException */ - protected function loadJsonPaths(string $locale): Collection + protected function loadJsonPaths(string $locale): iterable { return collect(array_merge($this->jsonPaths, [$this->path])) ->reduce(function ($output, $path) use ($locale) { From 13303701a2dbf3e02537b07e389f41df8bd8164a Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Tue, 27 Aug 2019 01:21:55 +0800 Subject: [PATCH 30/79] Update AnnotationReader.php --- src/graphql/src/AnnotationReader.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/graphql/src/AnnotationReader.php b/src/graphql/src/AnnotationReader.php index d01f6d90b..55ddb8879 100644 --- a/src/graphql/src/AnnotationReader.php +++ b/src/graphql/src/AnnotationReader.php @@ -56,6 +56,9 @@ class AnnotationReader */ private $mode; + /** + * @var array + */ private $methodAnnotationCache = []; /** @@ -101,25 +104,21 @@ class AnnotationReader public function getRequestAnnotation(ReflectionMethod $refMethod, string $annotationName): ?AbstractRequest { - /* @var null|AbstractRequest $queryAnnotation */ return $this->getMethodAnnotation($refMethod, $annotationName); } public function getLoggedAnnotation(ReflectionMethod $refMethod): ?Logged { - /* @var null|Logged $loggedAnnotation */ return $this->getMethodAnnotation($refMethod, Logged::class); } public function getRightAnnotation(ReflectionMethod $refMethod): ?Right { - /* @var null|Right $rightAnnotation */ return $this->getMethodAnnotation($refMethod, Right::class); } public function getFailWithAnnotation(ReflectionMethod $refMethod): ?FailWith { - /* @var null|FailWith $failWithAnnotation */ return $this->getMethodAnnotation($refMethod, FailWith::class); } @@ -128,13 +127,11 @@ class AnnotationReader */ public function getSourceFields(ReflectionClass $refClass): array { - /* @var SourceField[] $sourceFields */ return $this->getClassAnnotations($refClass, SourceField::class); } public function getFactoryAnnotation(ReflectionMethod $refMethod): ?Factory { - /* @var null|Factory $factoryAnnotation */ return $this->getMethodAnnotation($refMethod, Factory::class); } From 23a7210fd3a9d3da1a579c7248dd3e466587b10b Mon Sep 17 00:00:00 2001 From: daydaygo Date: Tue, 27 Aug 2019 15:38:54 +0800 Subject: [PATCH 31/79] set param type --- .../src/Exception/Handler/GrpcExceptionHandler.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php index 2b5b4bb1c..606f45973 100644 --- a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php +++ b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php @@ -57,11 +57,8 @@ class GrpcExceptionHandler extends ExceptionHandler /** * Transfer the non-standard response content to a standard response object. - * - * @param int $code - * @param string $message */ - protected function transferToResponse($code, $message, ResponseInterface $response): ResponseInterface + protected function transferToResponse(int $code, string $message, ResponseInterface $response): ResponseInterface { $response = $response->withAddedHeader('Content-Type', 'application/grpc') ->withAddedHeader('trailer', 'grpc-status, grpc-message') From 2b1f76e66e50000d5597096aa2c9dd34bbcff374 Mon Sep 17 00:00:00 2001 From: LiHan Date: Tue, 27 Aug 2019 16:32:08 +0800 Subject: [PATCH 32/79] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=A1=E6=95=B0?= =?UTF-8?q?=E4=B8=8D=E5=A4=9F=E5=88=86=E9=A1=B5=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=20=E8=B0=83=E7=94=A8simplePaginate=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/paginator/src/Paginator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/paginator/src/Paginator.php b/src/paginator/src/Paginator.php index e345d6680..55fb85921 100644 --- a/src/paginator/src/Paginator.php +++ b/src/paginator/src/Paginator.php @@ -61,6 +61,7 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou if ($this->hasMorePages()) { return $this->url($this->currentPage() + 1); } + return null; } /** From f6be3f8eda85b5eacfbd2b962af7cdff66e822f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 17:05:34 +0800 Subject: [PATCH 33/79] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd12de806..34de5ee1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - [#451](https://github.com/hyperf-cloud/hyperf/pull/451) Removed routes of magic methods from `AuthController`. +## Fixed + +- [#466](https://github.com/hyperf-cloud/hyperf/pull/466) Fixed error when the number of data is not enough to paginate. + # v1.0.12 - 2019-08-21 ## Added From 1c3091af7d291f6c5f7e585b07d580020207df0f Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Tue, 27 Aug 2019 17:43:45 +0800 Subject: [PATCH 34/79] Optimized --- .../src/TranslatorInterface.php} | 21 +- .../src/TranslatorLoaderInterface.php} | 4 +- src/translation/src/ArrayLoader.php | 4 +- src/translation/src/ConfigProvider.php | 8 +- .../src/Contract/HasLocalePreference.php | 21 -- src/translation/src/FileLoader.php | 5 +- .../src/Support/NamespacedItemResolver.php | 112 ---------- src/translation/src/Translator.php | 205 +++++++++--------- src/translation/src/TranslatorFactory.php | 10 +- .../tests/Cases/AbstractTestCase.php | 22 -- ...nFileLoaderTest.php => FileLoaderTest.php} | 3 +- ...lectorTest.php => MessageSelectorTest.php} | 3 +- ...nTranslatorTest.php => TranslatorTest.php} | 158 +++++++++++--- 13 files changed, 250 insertions(+), 326 deletions(-) rename src/{translation/src/Contract/Translator.php => contract/src/TranslatorInterface.php} (59%) rename src/{translation/src/Contract/Loader.php => contract/src/TranslatorLoaderInterface.php} (92%) mode change 100755 => 100644 delete mode 100644 src/translation/src/Contract/HasLocalePreference.php delete mode 100755 src/translation/src/Support/NamespacedItemResolver.php delete mode 100755 src/translation/tests/Cases/AbstractTestCase.php rename src/translation/tests/Cases/{TranslationFileLoaderTest.php => FileLoaderTest.php} (98%) rename src/translation/tests/Cases/{TranslationMessageSelectorTest.php => MessageSelectorTest.php} (97%) rename src/translation/tests/Cases/{TranslationTranslatorTest.php => TranslatorTest.php} (60%) diff --git a/src/translation/src/Contract/Translator.php b/src/contract/src/TranslatorInterface.php similarity index 59% rename from src/translation/src/Contract/Translator.php rename to src/contract/src/TranslatorInterface.php index ea1b789ac..c22d1f37a 100644 --- a/src/translation/src/Contract/Translator.php +++ b/src/contract/src/TranslatorInterface.php @@ -10,42 +10,29 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Translation\Contract; +namespace Hyperf\Contract; -interface Translator +interface TranslatorInterface { /** * Get the translation for a given key. - * - * @param string $key - * @param array $replace - * @param null|string $locale - * @return mixed */ - public function trans(string $key, array $replace = [], $locale = null); + public function trans(string $key, array $replace = [], ?string $locale = null); /** * Get a translation according to an integer value. * - * @param string $key * @param array|\Countable|int $number - * @param array $replace - * @param null|string $locale - * @return string */ - public function transChoice(string $key, $number, array $replace = [], $locale = null): string; + public function transChoice(string $key, $number, array $replace = [], ?string $locale = null): string; /** * Get the default locale being used. - * - * @return string */ public function getLocale(): string; /** * Set the default locale. - * - * @param string $locale */ public function setLocale(string $locale); } diff --git a/src/translation/src/Contract/Loader.php b/src/contract/src/TranslatorLoaderInterface.php old mode 100755 new mode 100644 similarity index 92% rename from src/translation/src/Contract/Loader.php rename to src/contract/src/TranslatorLoaderInterface.php index ffec5cd4e..34eaf4718 --- a/src/translation/src/Contract/Loader.php +++ b/src/contract/src/TranslatorLoaderInterface.php @@ -10,9 +10,9 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Translation\Contract; +namespace Hyperf\Contract; -interface Loader +interface TranslatorLoaderInterface { /** * Load the messages for the given locale. diff --git a/src/translation/src/ArrayLoader.php b/src/translation/src/ArrayLoader.php index 205fbf187..8ad03feca 100644 --- a/src/translation/src/ArrayLoader.php +++ b/src/translation/src/ArrayLoader.php @@ -12,9 +12,9 @@ declare(strict_types=1); namespace Hyperf\Translation; -use Hyperf\Translation\Contract\Loader; +use Hyperf\Contract\TranslatorLoaderInterface; -class ArrayLoader implements Loader +class ArrayLoader implements TranslatorLoaderInterface { /** * All of the translation messages. diff --git a/src/translation/src/ConfigProvider.php b/src/translation/src/ConfigProvider.php index 1c0b506a9..b49d34535 100644 --- a/src/translation/src/ConfigProvider.php +++ b/src/translation/src/ConfigProvider.php @@ -12,8 +12,8 @@ declare(strict_types=1); namespace Hyperf\Translation; -use Hyperf\Translation\Contract\Loader; -use Hyperf\Translation\Contract\Translator; +use Hyperf\Contract\TranslatorInterface; +use Hyperf\Contract\TranslatorLoaderInterface; class ConfigProvider { @@ -21,8 +21,8 @@ class ConfigProvider { return [ 'dependencies' => [ - Loader::class => FileLoaderFactory::class, - Translator::class => TranslatorFactory::class, + TranslatorLoaderInterface::class => FileLoaderFactory::class, + TranslatorInterface::class => TranslatorFactory::class, ], 'scan' => [ 'paths' => [ diff --git a/src/translation/src/Contract/HasLocalePreference.php b/src/translation/src/Contract/HasLocalePreference.php deleted file mode 100644 index 121fa92eb..000000000 --- a/src/translation/src/Contract/HasLocalePreference.php +++ /dev/null @@ -1,21 +0,0 @@ -parsed[$key])) { - return $this->parsed[$key]; - } - - // If the key does not contain a double colon, it means the key is not in a - // namespace, and is just a regular configuration item. Namespaces are a - // tool for organizing configuration items for things such as modules. - if (strpos($key, '::') === false) { - $segments = explode('.', $key); - - $parsed = $this->parseBasicSegments($segments); - } else { - $parsed = $this->parseNamespacedSegments($key); - } - - // Once we have the parsed array of this key's elements, such as its groups - // and namespace, we will cache each array inside a simple list that has - // the key and the parsed array for quick look-ups for later requests. - return $this->parsed[$key] = $parsed; - } - - /** - * Set the parsed value of a key. - * - * @param string $key - * @param array $parsed - */ - public function setParsedKey(string $key, array $parsed) - { - $this->parsed[$key] = $parsed; - } - - /** - * Parse an array of basic segments. - * - * @param array $segments - * @return array - */ - protected function parseBasicSegments(array $segments) - { - // The first segment in a basic array will always be the group, so we can go - // ahead and grab that segment. If there is only one total segment we are - // just pulling an entire group out of the array and not a single item. - $group = $segments[0]; - - // If there is more than one segment in this group, it means we are pulling - // a specific item out of a group and will need to return this item name - // as well as the group so we know which item to pull from the arrays. - $item = count($segments) === 1 - ? null - : implode('.', array_slice($segments, 1)); - - return [null, $group, $item]; - } - - /** - * Parse an array of namespaced segments. - * - * @param string $key - * @return array - */ - protected function parseNamespacedSegments(string $key): array - { - [$namespace, $item] = explode('::', $key); - - // First we'll just explode the first segment to get the namespace and group - // since the item should be in the remaining segments. Once we have these - // two pieces of data we can proceed with parsing out the item's value. - $itemSegments = explode('.', $item); - - $groupAndItem = array_slice( - $this->parseBasicSegments($itemSegments), - 1 - ); - - return array_merge([$namespace], $groupAndItem); - } -} diff --git a/src/translation/src/Translator.php b/src/translation/src/Translator.php index e0d695e7f..1b1018a3b 100755 --- a/src/translation/src/Translator.php +++ b/src/translation/src/Translator.php @@ -13,22 +13,21 @@ declare(strict_types=1); namespace Hyperf\Translation; use Countable; -use Hyperf\Translation\Contract\Loader; -use Hyperf\Translation\Contract\Translator as TranslatorContract; -use Hyperf\Translation\Support\NamespacedItemResolver; +use Hyperf\Contract\TranslatorInterface; +use Hyperf\Contract\TranslatorLoaderInterface; use Hyperf\Utils\Arr; use Hyperf\Utils\Collection; use Hyperf\Utils\Str; use Hyperf\Utils\Traits\Macroable; -class Translator extends NamespacedItemResolver implements TranslatorContract +class Translator implements TranslatorInterface { use Macroable; /** * The loader implementation. * - * @var \Hyperf\Translation\Contract\Loader + * @var TranslatorLoaderInterface */ protected $loader; @@ -61,12 +60,13 @@ class Translator extends NamespacedItemResolver implements TranslatorContract protected $selector; /** - * Create a new translator instance. + * A cache of the parsed items. * - * @param \Hyperf\Translation\Contract\Loader $loader - * @param string $locale + * @var array */ - public function __construct(Loader $loader, string $locale) + protected $parsed = []; + + public function __construct(TranslatorLoaderInterface $loader, string $locale) { $this->loader = $loader; $this->locale = $locale; @@ -74,25 +74,16 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Determine if a translation exists for a given locale. - * - * @param string $key - * @param null|string $locale - * @return bool */ - public function hasForLocale(string $key, $locale = null): bool + public function hasForLocale(string $key, ?string $locale = null): bool { return $this->has($key, $locale, false); } /** * Determine if a translation exists. - * - * @param string $key - * @param null|string $locale - * @param bool $fallback - * @return bool */ - public function has(string $key, $locale = null, bool $fallback = true): bool + public function has(string $key, ?string $locale = null, bool $fallback = true): bool { return $this->get($key, [], $locale, $fallback) !== $key; } @@ -100,12 +91,9 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the translation for a given key. * - * @param string $key - * @param array $replace - * @param null|string $locale * @return array|string */ - public function trans(string $key, array $replace = [], $locale = null) + public function trans(string $key, array $replace = [], ?string $locale = null) { return $this->get($key, $replace, $locale); } @@ -113,13 +101,9 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the translation for the given key. * - * @param string $key - * @param array $replace - * @param null|string $locale - * @param bool $fallback * @return array|string */ - public function get(string $key, array $replace = [], $locale = null, $fallback = true) + public function get(string $key, array $replace = [], ?string $locale = null, bool $fallback = true) { [$namespace, $group, $item] = $this->parseKey($key); @@ -150,12 +134,9 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the translation for a given key from the JSON translation files. * - * @param string $key - * @param array $replace - * @param null|string $locale * @return array|string */ - public function getFromJson(string $key, array $replace = [], $locale = null) + public function getFromJson(string $key, array $replace = [], ?string $locale = null) { $locale = $locale ?: $this->locale; @@ -183,13 +164,9 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get a translation according to an integer value. * - * @param string $key * @param array|\Countable|int $number - * @param array $replace - * @param null|string $locale - * @return string */ - public function transChoice(string $key, $number, array $replace = [], $locale = null): string + public function transChoice(string $key, $number, array $replace = [], ?string $locale = null): string { return $this->choice($key, $number, $replace, $locale); } @@ -197,13 +174,9 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get a translation according to an integer value. * - * @param string $key * @param array|\Countable|int $number - * @param array $replace - * @param null|string $locale - * @return string */ - public function choice(string $key, $number, array $replace = [], $locale = null): string + public function choice(string $key, $number, array $replace = [], ?string $locale = null): string { $line = $this->get( $key, @@ -228,10 +201,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Add translation lines to the given locale. - * - * @param array $lines - * @param string $locale - * @param string $namespace */ public function addLines(array $lines, string $locale, string $namespace = '*') { @@ -244,10 +213,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Load the specified language group. - * - * @param string $namespace - * @param string $group - * @param string $locale */ public function load(string $namespace, string $group, string $locale) { @@ -265,9 +230,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Add a new namespace to the loader. - * - * @param string $namespace - * @param string $hint */ public function addNamespace(string $namespace, string $hint) { @@ -276,8 +238,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Add a new JSON path to the loader. - * - * @param string $path */ public function addJsonPath(string $path) { @@ -286,13 +246,31 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Parse a key into namespace, group, and item. - * - * @param string $key - * @return array */ public function parseKey(string $key): array { - $segments = parent::parseKey($key); + // If we've already parsed the given key, we'll return the cached version we + // already have, as this will save us some processing. We cache off every + // key we parse so we can quickly return it on all subsequent requests. + if (isset($this->parsed[$key])) { + return $this->parsed[$key]; + } + + // If the key does not contain a double colon, it means the key is not in a + // namespace, and is just a regular configuration item. Namespaces are a + // tool for organizing configuration items for things such as modules. + if (strpos($key, '::') === false) { + $segments = explode('.', $key); + + $parsed = $this->parseBasicSegments($segments); + } else { + $parsed = $this->parseNamespacedSegments($key); + } + + // Once we have the parsed array of this key's elements, such as its groups + // and namespace, we will cache each array inside a simple list that has + // the key and the parsed array for quick look-ups for later requests. + $segments = $this->parsed[$key] = $parsed; if (is_null($segments[0])) { $segments[0] = '*'; @@ -303,10 +281,8 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the message selector instance. - * - * @return \Hyperf\Translation\MessageSelector */ - public function getSelector() + public function getSelector(): MessageSelector { if (! isset($this->selector)) { $this->selector = new MessageSelector(); @@ -317,8 +293,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Set the message selector instance. - * - * @param \Hyperf\Translation\MessageSelector $selector */ public function setSelector(MessageSelector $selector) { @@ -328,7 +302,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the language line loader implementation. * - * @return \Hyperf\Translation\Contract\Loader + * @return TranslatorLoaderInterface */ public function getLoader() { @@ -337,8 +311,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the default locale being used. - * - * @return string */ public function locale(): string { @@ -347,8 +319,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the default locale being used. - * - * @return string */ public function getLocale(): string { @@ -357,8 +327,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Set the default locale. - * - * @param string $locale */ public function setLocale(string $locale) { @@ -367,8 +335,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Get the fallback locale being used. - * - * @return string */ public function getFallback(): string { @@ -377,8 +343,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Set the fallback locale being used. - * - * @param string $fallback */ public function setFallback(string $fallback) { @@ -387,8 +351,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Set the loaded translation groups. - * - * @param array $loaded */ public function setLoaded(array $loaded) { @@ -396,12 +358,20 @@ class Translator extends NamespacedItemResolver implements TranslatorContract } /** - * Get the proper locale for a choice operation. + * Set the parsed value of a key. * - * @param null|string $locale - * @return string + * @param string $key + * @param array $parsed */ - protected function localeForChoice($locale): string + public function setParsedKey(string $key, array $parsed) + { + $this->parsed[$key] = $parsed; + } + + /** + * Get the proper locale for a choice operation. + */ + protected function localeForChoice(?string $locale): string { return $locale ?: $this->locale ?: $this->fallback; } @@ -409,11 +379,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Retrieve a language line out the loaded array. * - * @param string $namespace - * @param string $group - * @param string $locale * @param mixed $item - * @param array $replace * @return null|array|string */ protected function getLine(string $namespace, string $group, string $locale, $item, array $replace) @@ -440,12 +406,8 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Make the place-holder replacements on a line. - * - * @param string $line - * @param array $replace - * @return string */ - protected function makeReplacements($line, array $replace) + protected function makeReplacements(string $line, array $replace): string { if (empty($replace)) { return $line; @@ -468,9 +430,6 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Sort the replacements array. - * - * @param array $replace - * @return array */ protected function sortReplacements(array $replace): array { @@ -481,25 +440,63 @@ class Translator extends NamespacedItemResolver implements TranslatorContract /** * Determine if the given group has been loaded. - * - * @param string $namespace - * @param string $group - * @param string $locale - * @return bool */ - protected function isLoaded(string $namespace, string $group, string $locale) + protected function isLoaded(string $namespace, string $group, string $locale): bool { return isset($this->loaded[$namespace][$group][$locale]); } /** * Get the array of locales to be checked. - * - * @param null|string $locale - * @return array */ - protected function localeArray($locale): array + protected function localeArray(?string $locale): array { return array_filter([$locale ?: $this->locale, $this->fallback]); } + + /** + * Parse an array of basic segments. + * + * @param array $segments + * @return array + */ + protected function parseBasicSegments(array $segments) + { + // The first segment in a basic array will always be the group, so we can go + // ahead and grab that segment. If there is only one total segment we are + // just pulling an entire group out of the array and not a single item. + $group = $segments[0]; + + // If there is more than one segment in this group, it means we are pulling + // a specific item out of a group and will need to return this item name + // as well as the group so we know which item to pull from the arrays. + $item = count($segments) === 1 + ? null + : implode('.', array_slice($segments, 1)); + + return [null, $group, $item]; + } + + /** + * Parse an array of namespaced segments. + * + * @param string $key + * @return array + */ + protected function parseNamespacedSegments(string $key): array + { + [$namespace, $item] = explode('::', $key); + + // First we'll just explode the first segment to get the namespace and group + // since the item should be in the remaining segments. Once we have these + // two pieces of data we can proceed with parsing out the item's value. + $itemSegments = explode('.', $item); + + $groupAndItem = array_slice( + $this->parseBasicSegments($itemSegments), + 1 + ); + + return array_merge([$namespace], $groupAndItem); + } } diff --git a/src/translation/src/TranslatorFactory.php b/src/translation/src/TranslatorFactory.php index 2e5d972b1..c781e9dad 100644 --- a/src/translation/src/TranslatorFactory.php +++ b/src/translation/src/TranslatorFactory.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Hyperf\Translation; use Hyperf\Contract\ConfigInterface; -use Hyperf\Translation\Contract\Loader; +use Hyperf\Contract\TranslatorLoaderInterface; use Psr\Container\ContainerInterface; class TranslatorFactory @@ -28,11 +28,11 @@ class TranslatorFactory $locale = $config->get('translation.locale'); $fallbackLocale = $config->get('translation.fallback_locale'); - $loader = $container->get(Loader::class); + $loader = $container->get(TranslatorLoaderInterface::class); - $trans = make(Translator::class, compact('loader', 'locale')); - $trans->setFallback((string) $fallbackLocale); + $translator = make(Translator::class, compact('loader', 'locale')); + $translator->setFallback((string) $fallbackLocale); - return $trans; + return $translator; } } diff --git a/src/translation/tests/Cases/AbstractTestCase.php b/src/translation/tests/Cases/AbstractTestCase.php deleted file mode 100755 index 7174e4a7a..000000000 --- a/src/translation/tests/Cases/AbstractTestCase.php +++ /dev/null @@ -1,22 +0,0 @@ -getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('foo')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + ])->getMock(); + $t->expects($this->once()) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar')) + ->will($this->returnValue('foo')); $this->assertFalse($t->has('foo', 'bar')); - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en', 'sp'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->will($this->returnValue('bar')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + 'sp', + ])->getMock(); + $t->expects($this->once()) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar')) + ->will($this->returnValue('bar')); $this->assertTrue($t->has('foo', 'bar')); - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('bar')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + ])->getMock(); + $t->expects($this->once()) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false) + ->will($this->returnValue('bar')); $this->assertTrue($t->hasForLocale('foo', 'bar')); - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false)->will($this->returnValue('foo')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + ])->getMock(); + $t->expects($this->once()) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'), false) + ->will($this->returnValue('foo')); $this->assertFalse($t->hasForLocale('foo', 'bar')); - $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); - $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('bar')); + $t = $this->getMockBuilder(Translator::class) + ->setMethods(['load', 'getLine']) + ->setConstructorArgs([$this->getLoader(), 'en']) + ->getMock(); + $t->expects($this->any()) + ->method('load') + ->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en')) + ->will($this->returnValue(null)); + $t->expects($this->once()) + ->method('getLine') + ->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([])) + ->will($this->returnValue('bar')); $this->assertTrue($t->hasForLocale('foo')); - $t = $this->getMockBuilder(Translator::class)->setMethods(['load', 'getLine'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->any())->method('load')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'))->will($this->returnValue(null)); - $t->expects($this->once())->method('getLine')->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([]))->will($this->returnValue('foo')); + $t = $this->getMockBuilder(Translator::class) + ->setMethods(['load', 'getLine']) + ->setConstructorArgs([$this->getLoader(), 'en']) + ->getMock(); + $t->expects($this->any()) + ->method('load') + ->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en')) + ->will($this->returnValue(null)); + $t->expects($this->once()) + ->method('getLine') + ->with($this->equalTo('*'), $this->equalTo('foo'), $this->equalTo('en'), null, $this->equalTo([])) + ->will($this->returnValue('foo')); $this->assertFalse($t->hasForLocale('foo')); } public function testGetMethodProperlyLoadsAndRetrievesItem() { $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo', 'qux' => ['tree :foo', 'breeze :foo']]); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([ + 'foo' => 'foo', + 'baz' => 'breeze :foo', + 'qux' => ['tree :foo', 'breeze :foo'], + ]); $this->assertEquals(['tree bar', 'breeze bar'], $t->get('foo::bar.qux', ['foo' => 'bar'], 'en')); $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); $this->assertEquals('foo', $t->get('foo::bar.foo')); @@ -70,14 +118,24 @@ class TranslationTranslatorTest extends AbstractTestCase public function testTransMethodProperlyLoadsAndRetrievesItemWithHTMLInTheMessage() { $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze

test

']); + $t->getLoader() + ->shouldReceive('load') + ->once() + ->with('en', 'foo', '*') + ->andReturn(['bar' => 'breeze

test

']); $this->assertSame('breeze

test

', $t->trans('foo.bar', [], 'en')); } public function testGetMethodProperlyLoadsAndRetrievesItemWithCapitalization() { - $t = $this->getMockBuilder(Translator::class)->setMethods(null)->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :Foo :BAR']); + $t = $this->getMockBuilder(Translator::class) + ->setMethods(null) + ->setConstructorArgs([$this->getLoader(), 'en']) + ->getMock(); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([ + 'foo' => 'foo', + 'baz' => 'breeze :Foo :BAR', + ]); $this->assertEquals('breeze Bar FOO', $t->get('foo::bar.baz', ['foo' => 'bar', 'bar' => 'foo'], 'en')); $this->assertEquals('foo', $t->get('foo::bar.foo')); } @@ -85,9 +143,15 @@ class TranslationTranslatorTest extends AbstractTestCase public function testGetMethodProperlyLoadsAndRetrievesItemWithLongestReplacementsFirst() { $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo :foobar']); + $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([ + 'foo' => 'foo', + 'baz' => 'breeze :foo :foobar', + ]); $this->assertEquals('breeze bar taylor', $t->get('foo::bar.baz', ['foo' => 'bar', 'foobar' => 'taylor'], 'en')); - $this->assertEquals('breeze foo bar baz taylor', $t->get('foo::bar.baz', ['foo' => 'foo bar baz', 'foobar' => 'taylor'], 'en')); + $this->assertEquals('breeze foo bar baz taylor', $t->get('foo::bar.baz', [ + 'foo' => 'foo bar baz', + 'foobar' => 'taylor', + ], 'en')); $this->assertEquals('foo', $t->get('foo::bar.foo')); } @@ -96,7 +160,10 @@ class TranslationTranslatorTest extends AbstractTestCase $t = new Translator($this->getLoader(), 'en'); $t->setFallback('lv'); $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn([]); - $t->getLoader()->shouldReceive('load')->once()->with('lv', 'bar', 'foo')->andReturn(['foo' => 'foo', 'baz' => 'breeze :foo']); + $t->getLoader()->shouldReceive('load')->once()->with('lv', 'bar', 'foo')->andReturn([ + 'foo' => 'foo', + 'baz' => 'breeze :foo', + ]); $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); $this->assertEquals('foo', $t->get('foo::bar.foo')); } @@ -110,8 +177,14 @@ class TranslationTranslatorTest extends AbstractTestCase public function testChoiceMethodProperlyLoadsAndRetrievesItem() { - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + ])->getMock(); + $t->expects($this->once()) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en')) + ->will($this->returnValue('line')); $t->setSelector($selector = m::mock(MessageSelector::class)); $selector->shouldReceive('choose')->once()->with('line', 10, 'en')->andReturn('choiced'); @@ -120,8 +193,14 @@ class TranslationTranslatorTest extends AbstractTestCase public function testChoiceMethodProperlyCountsCollectionsAndLoadsAndRetrievesItem() { - $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); - $t->expects($this->exactly(2))->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->will($this->returnValue('line')); + $t = $this->getMockBuilder(Translator::class)->setMethods(['get'])->setConstructorArgs([ + $this->getLoader(), + 'en', + ])->getMock(); + $t->expects($this->exactly(2)) + ->method('get') + ->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en')) + ->will($this->returnValue('line')); $t->setSelector($selector = m::mock(MessageSelector::class)); $selector->shouldReceive('choose')->twice()->with('line', 3, 'en')->andReturn('choiced'); @@ -142,8 +221,16 @@ class TranslationTranslatorTest extends AbstractTestCase public function testGetJsonReplaces() { $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['foo :i:c :u' => 'bar :i:c :u']); - $this->assertEquals('bar onetwo three', $t->getFromJson('foo :i:c :u', ['i' => 'one', 'c' => 'two', 'u' => 'three'])); + $t->getLoader() + ->shouldReceive('load') + ->once() + ->with('en', '*', '*') + ->andReturn(['foo :i:c :u' => 'bar :i:c :u']); + $this->assertEquals('bar onetwo three', $t->getFromJson('foo :i:c :u', [ + 'i' => 'one', + 'c' => 'two', + 'u' => 'three', + ])); } public function testGetJsonReplacesForAssociativeInput() @@ -156,8 +243,15 @@ class TranslationTranslatorTest extends AbstractTestCase public function testGetJsonPreservesOrder() { $t = new Translator($this->getLoader(), 'en'); - $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn(['to :name I give :greeting' => ':greeting :name']); - $this->assertEquals('Greetings David', $t->getFromJson('to :name I give :greeting', ['name' => 'David', 'greeting' => 'Greetings'])); + $t->getLoader() + ->shouldReceive('load') + ->once() + ->with('en', '*', '*') + ->andReturn(['to :name I give :greeting' => ':greeting :name']); + $this->assertEquals('Greetings David', $t->getFromJson('to :name I give :greeting', [ + 'name' => 'David', + 'greeting' => 'Greetings', + ])); } public function testGetJsonForNonExistingJsonKeyLooksForRegularKeys() @@ -194,6 +288,6 @@ class TranslationTranslatorTest extends AbstractTestCase protected function getLoader() { - return m::mock(Loader::class); + return m::mock(TranslatorLoaderInterface::class); } } From dccaaae05dc3200af695acbc4b5a41bde2233c51 Mon Sep 17 00:00:00 2001 From: "York.GU" Date: Tue, 27 Aug 2019 22:12:42 +0800 Subject: [PATCH 35/79] set the default exception handler to handle all exceptions, not only ServerException --- src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php | 2 +- src/http-server/src/Exception/Handler/HttpExceptionHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php index 606f45973..6c6e8aaea 100644 --- a/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php +++ b/src/grpc-server/src/Exception/Handler/GrpcExceptionHandler.php @@ -52,7 +52,7 @@ class GrpcExceptionHandler extends ExceptionHandler public function isValid(Throwable $throwable): bool { - return $throwable instanceof ServerException; + return true; } /** diff --git a/src/http-server/src/Exception/Handler/HttpExceptionHandler.php b/src/http-server/src/Exception/Handler/HttpExceptionHandler.php index fd4bbc38c..ae171adf9 100644 --- a/src/http-server/src/Exception/Handler/HttpExceptionHandler.php +++ b/src/http-server/src/Exception/Handler/HttpExceptionHandler.php @@ -51,6 +51,6 @@ class HttpExceptionHandler extends ExceptionHandler */ public function isValid(Throwable $throwable): bool { - return $throwable instanceof ServerException; + return true; } } From f751eee31b2057c406201283b206459229862b4a Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 00:56:45 +0800 Subject: [PATCH 36/79] Remove useless test files and remove Cases folder --- .../tests/{Cases => }/FileLoaderTest.php | 21 +++++++++---------- .../tests/{Cases => }/MessageSelectorTest.php | 3 +-- .../tests/{Cases => }/TranslatorTest.php | 13 ++++++------ src/translation/tests/bootstrap.php | 13 ------------ src/translation/tests/ci.ini | 8 ------- src/translation/tests/swoole.install.sh | 10 --------- 6 files changed, 17 insertions(+), 51 deletions(-) rename src/translation/tests/{Cases => }/FileLoaderTest.php (84%) rename src/translation/tests/{Cases => }/MessageSelectorTest.php (97%) rename src/translation/tests/{Cases => }/TranslatorTest.php (97%) delete mode 100755 src/translation/tests/bootstrap.php delete mode 100755 src/translation/tests/ci.ini delete mode 100755 src/translation/tests/swoole.install.sh diff --git a/src/translation/tests/Cases/FileLoaderTest.php b/src/translation/tests/FileLoaderTest.php similarity index 84% rename from src/translation/tests/Cases/FileLoaderTest.php rename to src/translation/tests/FileLoaderTest.php index a66fa903d..46f7f3f4e 100755 --- a/src/translation/tests/Cases/FileLoaderTest.php +++ b/src/translation/tests/FileLoaderTest.php @@ -10,27 +10,26 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\Translation\Cases; +namespace HyperfTest\Translation; use Hyperf\Translation\FileLoader; use Hyperf\Utils\Filesystem\Filesystem; -use Mockery as m; +use Mockery; use PHPUnit\Framework\TestCase; /** * @internal - * @coversNothing */ class FileLoaderTest extends TestCase { protected function tearDown(): void { - m::close(); + Mockery::close(); } public function testLoadMethodWithoutNamespacesProperlyCallsLoader() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(true); $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/en/foo.php')->andReturn(['messages']); @@ -39,7 +38,7 @@ class FileLoaderTest extends TestCase public function testLoadMethodWithNamespacesProperlyCallsLoader() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(false); $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); @@ -50,7 +49,7 @@ class FileLoaderTest extends TestCase public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOverrides() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); $files->shouldReceive('exists')->once()->with(__DIR__ . '/vendor/namespace/en/foo.php')->andReturn(true); $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); @@ -62,7 +61,7 @@ class FileLoaderTest extends TestCase public function testEmptyArraysReturnedWhenFilesDontExist() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(false); $files->shouldReceive('getRequire')->never(); @@ -71,7 +70,7 @@ class FileLoaderTest extends TestCase public function testEmptyArraysReturnedWhenFilesDontExistForNamespacedItems() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('getRequire')->never(); $this->assertEquals([], $loader->load('en', 'foo', 'bar')); @@ -79,7 +78,7 @@ class FileLoaderTest extends TestCase public function testLoadMethodForJSONProperlyCallsLoader() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); $files->shouldReceive('get')->once()->with(__DIR__ . '/en.json')->andReturn('{"foo":"bar"}'); @@ -88,7 +87,7 @@ class FileLoaderTest extends TestCase public function testLoadMethodForJSONProperlyCallsLoaderForMultiplePaths() { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); + $loader = new FileLoader($files = Mockery::mock(Filesystem::class), __DIR__); $loader->addJsonPath(__DIR__ . '/another'); $files->shouldReceive('exists')->once()->with(__DIR__ . '/en.json')->andReturn(true); diff --git a/src/translation/tests/Cases/MessageSelectorTest.php b/src/translation/tests/MessageSelectorTest.php similarity index 97% rename from src/translation/tests/Cases/MessageSelectorTest.php rename to src/translation/tests/MessageSelectorTest.php index 391db57eb..98c98217a 100755 --- a/src/translation/tests/Cases/MessageSelectorTest.php +++ b/src/translation/tests/MessageSelectorTest.php @@ -10,14 +10,13 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\Translation\Cases; +namespace HyperfTest\Translation; use Hyperf\Translation\MessageSelector; use PHPUnit\Framework\TestCase; /** * @internal - * @coversNothing */ class MessageSelectorTest extends TestCase { diff --git a/src/translation/tests/Cases/TranslatorTest.php b/src/translation/tests/TranslatorTest.php similarity index 97% rename from src/translation/tests/Cases/TranslatorTest.php rename to src/translation/tests/TranslatorTest.php index e9a8cdc35..626e8409e 100755 --- a/src/translation/tests/Cases/TranslatorTest.php +++ b/src/translation/tests/TranslatorTest.php @@ -10,24 +10,23 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\Translation\Cases; +namespace HyperfTest\Translation; use Hyperf\Contract\TranslatorLoaderInterface; use Hyperf\Translation\MessageSelector; use Hyperf\Translation\Translator; use Hyperf\Utils\Collection; -use Mockery as m; +use Mockery; use PHPUnit\Framework\TestCase; /** * @internal - * @coversNothing */ class TranslatorTest extends TestCase { protected function tearDown(): void { - m::close(); + Mockery::close(); } public function testHasMethodReturnsFalseWhenReturnedTranslationIsNull() @@ -185,7 +184,7 @@ class TranslatorTest extends TestCase ->method('get') ->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en')) ->will($this->returnValue('line')); - $t->setSelector($selector = m::mock(MessageSelector::class)); + $t->setSelector($selector = Mockery::mock(MessageSelector::class)); $selector->shouldReceive('choose')->once()->with('line', 10, 'en')->andReturn('choiced'); $t->choice('foo', 10, ['replace']); @@ -201,7 +200,7 @@ class TranslatorTest extends TestCase ->method('get') ->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en')) ->will($this->returnValue('line')); - $t->setSelector($selector = m::mock(MessageSelector::class)); + $t->setSelector($selector = Mockery::mock(MessageSelector::class)); $selector->shouldReceive('choose')->twice()->with('line', 3, 'en')->andReturn('choiced'); $values = ['foo', 'bar', 'baz']; @@ -288,6 +287,6 @@ class TranslatorTest extends TestCase protected function getLoader() { - return m::mock(TranslatorLoaderInterface::class); + return Mockery::mock(TranslatorLoaderInterface::class); } } diff --git a/src/translation/tests/bootstrap.php b/src/translation/tests/bootstrap.php deleted file mode 100755 index 210da6cde..000000000 --- a/src/translation/tests/bootstrap.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Wed, 28 Aug 2019 01:14:04 +0800 Subject: [PATCH 37/79] Update composer.json --- src/translation/composer.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/translation/composer.json b/src/translation/composer.json index 2e4937ddf..f2668cb03 100644 --- a/src/translation/composer.json +++ b/src/translation/composer.json @@ -1,12 +1,12 @@ { "name": "hyperf/translation", "type": "library", + "description": "An independent translation component, forked by illuminate/translation.", "license": "MIT", "keywords": [ "translation", "hyperf" ], - "description": "", "autoload": { "psr-4": { "Hyperf\\Translation\\": "src/" @@ -19,18 +19,15 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", + "hyperf/contract": "1.0.*", "hyperf/utils": "1.0.*", - "hyperf/framework": "1.0.*", - "hyperf/di": "1.0.*", "psr/container": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", "hyperf/testing": "1.0.*", "mockery/mockery": "^1.2", - "phpstan/phpstan": "^0.10.5", - "swoft/swoole-ide-helper": "^4.4.0" + "phpstan/phpstan": "^0.10.5" }, "config": { "sort-packages": true From cdb79a534c39526f3cfafe77b9c35bff24a90941 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 01:18:22 +0800 Subject: [PATCH 38/79] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5ce5c6e0..4d4c7e3e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,13 @@ ## Added +- [#449](https://github.com/hyperf-cloud/hyperf/pull/428) Added an independent component [hyperf/translation](https://github.com/hyperf-cloud/translation), forked by illuminate/translation. - [#449](https://github.com/hyperf-cloud/hyperf/pull/449) Added standard error code for grpc-server. - [#450](https://github.com/hyperf-cloud/hyperf/pull/450) Added comments of static methods for `Hyperf\Database\Schema\Schema`. ## Changed -- [#451](https://github.com/hyperf-cloud/hyperf/pull/451) Removed routes of magic methods from `AuthController`. +- [#451](https://github.com/hyperf-cloud/hyperf/pull/451) Removed routes of magic methods from `AutoController`. ## Fixed From 88705817eb057ae4375f9cda3b99ec28bd7a74ac Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 01:22:08 +0800 Subject: [PATCH 39/79] Modify the configuration structure of Translation --- src/translation/publish/translation.php | 2 +- src/translation/src/FileLoaderFactory.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/translation/publish/translation.php b/src/translation/publish/translation.php index 9278bd458..e30389e7e 100644 --- a/src/translation/publish/translation.php +++ b/src/translation/publish/translation.php @@ -13,5 +13,5 @@ declare(strict_types=1); return [ 'locale' => 'zh_CN', 'fallback_locale' => 'en', - 'lang' => BASE_PATH . '/resources/lang', + 'path' => BASE_PATH . '/storage/languages', ]; diff --git a/src/translation/src/FileLoaderFactory.php b/src/translation/src/FileLoaderFactory.php index 60c387fbc..855eed069 100644 --- a/src/translation/src/FileLoaderFactory.php +++ b/src/translation/src/FileLoaderFactory.php @@ -22,7 +22,7 @@ class FileLoaderFactory { $config = $container->get(ConfigInterface::class); $files = $container->get(Filesystem::class); - $path = $config->get('translation.lang'); + $path = $config->get('translation.path'); return make(FileLoader::class, compact('files', 'path')); } From 7faea6efff062003e0d1ce53213221ffe6a58755 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 02:13:37 +0800 Subject: [PATCH 40/79] Add __(), trans() and trans_choice() functions --- composer.json | 1 + src/translation/composer.json | 3 +++ src/translation/src/Functions.php | 37 +++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/translation/src/Functions.php diff --git a/composer.json b/composer.json index 5eb88be23..d270d6b72 100644 --- a/composer.json +++ b/composer.json @@ -104,6 +104,7 @@ "files": [ "src/config/src/Functions.php", "src/di/src/Functions.php", + "src/translation/src/Functions.php", "src/utils/src/Functions.php" ], "psr-4": { diff --git a/src/translation/composer.json b/src/translation/composer.json index f2668cb03..0527ee253 100644 --- a/src/translation/composer.json +++ b/src/translation/composer.json @@ -8,6 +8,9 @@ "hyperf" ], "autoload": { + "files": [ + "src/Functions.php" + ], "psr-4": { "Hyperf\\Translation\\": "src/" } diff --git a/src/translation/src/Functions.php b/src/translation/src/Functions.php new file mode 100644 index 000000000..9eff53fcb --- /dev/null +++ b/src/translation/src/Functions.php @@ -0,0 +1,37 @@ +get(TranslatorInterface::class); + return $translator->trans($key, $replace, $locale); + } +} + +if (! function_exists('trans')) { + function trans(string $key, array $replace = [], ?string $locale = null) + { + return __($key, $replace, $locale); + } +} + +if (! function_exists('trans_choice')) { + function trans_choice(string $key, $number, array $replace = [], ?string $locale = null): string + { + $translator = ApplicationContext::getContainer()->get(TranslatorInterface::class); + return $translator->transChoice($key, $number, $replace, $locale); + } +} From 6f7e06c56d178c00e9d3c5a4b3af623206d208d0 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 02:41:46 +0800 Subject: [PATCH 41/79] Create translation.md --- doc/zh/translation.md | 138 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 doc/zh/translation.md diff --git a/doc/zh/translation.md b/doc/zh/translation.md new file mode 100644 index 000000000..25c2dc32a --- /dev/null +++ b/doc/zh/translation.md @@ -0,0 +1,138 @@ +# 国际化 + +Hyperf 对国际化的支持是非常友好的,允许让您的项目支持多种语言。 + +# 安装 + +```bash +composer require hyperf/translation +``` + +> 该组件为一个独立组件,无框架相关依赖,可独立复用于其它项目或框架。 + +# 语言文件 + +Hyperf 的语言文件默认都放在 `storage/languages` 下面,您也可以在 `config/autoload/translation.php` 内更改语言文件的文件夹,每种语言对应其中的一个子文件夹,例如 `en` 指英文语言文件,`zh-CN` 指中文简体的语言文件,你可以按照实际需要创建新的语言文件夹和里面的语言文件。示例如下: + +``` +/storage + /languages + /en + messages.php + /zh-CN + messages.php +``` + +所有的语言文件都是返回一个数组,数组的键是字符串类型的: + +```php + 'Welcome to our application', +]; +``` + +## 配置语言环境 + +关于国际化组件的相关配置都是在 `config/autoload/translation.php` 配置文件里设定的,你可以按照实际需要修改它。 + +```php + 'zh_CN', + // 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本 + 'fallback_locale' => 'en', + // 语言文件存放的文件夹 + 'path' => BASE_PATH . '/storage/languages', +]; +``` + +# 翻译字符串 + +## 通过 TranslatorInterface 翻译 + +可直接通过注入 `Hyperf\Contact\TranslatorInterface` 并调用实例的 `trans` 方法实现对字符串的翻译: + +```php +translator->trans('messages.welcome', [], 'zh-CN'); + } +} +``` + +## 通过全局函数翻译 + +您也可以通过全局函数 `__()` 或 `trans()` 来对字符串进行翻译。 +函数的第一个参数使用 `键`(指使用翻译字符串作为键的键) 或者是 `文件.键` 的形式。 + +```php +echo __('messages.welcome'); +echo trans('messages.welcome'); +``` + +# 翻译字符串中定义占位符 + +您也可以在语言字符串中定义占位符,所有的占位符使用 `:` 作为前缀。例如,把用户名作为占位符: + +```php + 'Welcome :name', +]; +``` + +替换占位符使用函数的第二个参数: + +```php +echo __('messages.welcome', ['name' => 'Hyperf']); +``` + +如果占位符全部是大写字母,或者是首字母大写。那么翻译过来的字符串也会是相应的大写形式: + +```php +'welcome' => 'Welcome, :NAME', // Welcome, HYPERF +'goodbye' => 'Goodbye, :Name', // Goodbye, HYPERF +``` + +# 处理复数 + +不同语言的复数规则是不同的,在中文中可能不太关注这一点,但在翻译其它语言时我们需要处理复数形式的用词。我们可以使用 `「管道」` 字符,可以用来区分字符串的单数和复数形式: + +```php +'apples' => 'There is one apple|There are many apples', +``` + +也可以指定数字范围,创建更加复杂的复数规则: + +```php +'apples' => '{0} There are none|[1,19] There are some|[20,*] There are many', +``` + +使用 `「管道」` 字符,定义好复数规则后,就可以使用全局函数 `trans_choice` 来获得给定 `「数量」` 的字符串文本。在下面的例子中,因为数量大于 `1`,所以就会返回翻译字符串的复数形式: + +```php +echo trans_choice('messages.apples', 10); +``` + +当然除了全局函数 `trans_choice()`,您也可以使用 `Hyperf\Contract\TranslatorInterface` 的 `transChoice` 方法。 \ No newline at end of file From a8d4f630fb797cf10c3c1df32681f4c3da4ae513 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 02:44:08 +0800 Subject: [PATCH 42/79] Update README.MD --- src/translation/README.MD | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/translation/README.MD b/src/translation/README.MD index 7a53a0c77..fc9d97e00 100644 --- a/src/translation/README.MD +++ b/src/translation/README.MD @@ -18,26 +18,26 @@ php bin/hyperf.php vendor:publish hyperf/translation Config files: ``` -+ ./config/path/autoload/translation.php ++ ./config/autoload/translation.php ``` ### Configuration -``` +```php 'en', + 'locale' => 'en', 'fallback_locale' => '', - 'lang' => BASE_PATH . '/resources/lang', + 'path' => BASE_PATH . '/storage/languages', ]; ``` ## Usage -``` +```php $container = ApplicationContext::getContainer(); -$translator = $container->get(\Hyperf\Translation\Contracts\Translator::class); +$translator = $container->get(\Hyperf\Contract\TranslatorInterface::class); $translator->trans('validation.accepted'); ``` \ No newline at end of file From 8cfec0cf35afa0806b1a93f3994f853c5a345889 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 03:54:37 +0800 Subject: [PATCH 43/79] If the folder exist, then should not create it --- src/devtool/src/VendorPublishCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devtool/src/VendorPublishCommand.php b/src/devtool/src/VendorPublishCommand.php index 42f57b4fa..47b208206 100644 --- a/src/devtool/src/VendorPublishCommand.php +++ b/src/devtool/src/VendorPublishCommand.php @@ -113,7 +113,9 @@ class VendorPublishCommand extends SymfonyCommand continue; } - mkdir(dirname($destination), 0755, true); + if (! file_exists(dirname($destination))) { + mkdir(dirname($destination), 0755, true); + } copy($source, $destination); $this->output->writeln(sprintf('[%s] publish [%s] success.', $package, $id)); From 79605218e376e5c65e83454c959c6bcbc65da116 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 03:57:01 +0800 Subject: [PATCH 44/79] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5ce5c6e0..eecfb0aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ## Fixed - [#466](https://github.com/hyperf-cloud/hyperf/pull/466) Fixed error when the number of data is not enough to paginate. +- [#466](https://github.com/hyperf-cloud/hyperf/pull/470) Optimized `vendor:publish` command, if the destination folder exist, then will not repeatedly create the folder. # v1.0.12 - 2019-08-21 From b9a857188fb31593c83f0e4bfc91b7df8ba0f80c Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 28 Aug 2019 03:58:12 +0800 Subject: [PATCH 45/79] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eecfb0aa6..b790fa8eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ ## Fixed - [#466](https://github.com/hyperf-cloud/hyperf/pull/466) Fixed error when the number of data is not enough to paginate. -- [#466](https://github.com/hyperf-cloud/hyperf/pull/470) Optimized `vendor:publish` command, if the destination folder exist, then will not repeatedly create the folder. +- [#466](https://github.com/hyperf-cloud/hyperf/pull/470) Optimized `vendor:publish` command, if the destination folder exists, then will not repeatedly create the folder. # v1.0.12 - 2019-08-21 From 59ba857100a5d23b742c11f100f7aed0ca5f63ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 09:32:14 +0800 Subject: [PATCH 46/79] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5ce5c6e0..f6656d43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ## Changed - [#451](https://github.com/hyperf-cloud/hyperf/pull/451) Removed routes of magic methods from `AuthController`. +- [#468](https://github.com/hyperf-cloud/hyperf/pull/468) Default exception handlers catch all exceptions. ## Fixed From 615229aa13858c009ba6cdc299e56ebdb59f4f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 11:04:25 +0800 Subject: [PATCH 47/79] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 349244e8e..fce426d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -# v1.0.13 - TBD +# v1.0.14 - TBD + +# v1.0.13 - 2019-08-28 ## Added From 69c8f1e06d4270d3b4565d1e7d6a3bdbe43cd766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 18:54:06 +0800 Subject: [PATCH 48/79] Fixed typehint error when host does not reached. --- src/guzzle/src/RingPHP/CoroutineHandler.php | 25 ++++++++++++++++----- src/guzzle/src/RingPHP/PoolHandler.php | 7 +----- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/guzzle/src/RingPHP/CoroutineHandler.php b/src/guzzle/src/RingPHP/CoroutineHandler.php index cba687972..5e0d20543 100644 --- a/src/guzzle/src/RingPHP/CoroutineHandler.php +++ b/src/guzzle/src/RingPHP/CoroutineHandler.php @@ -67,12 +67,7 @@ class CoroutineHandler $ex = $this->checkStatusCode($client, $request); if ($ex !== true) { - return [ - 'status' => null, - 'reason' => null, - 'headers' => [], - 'error' => $ex, - ]; + return $this->getErrorResponse($ex, $btime, $effectiveUrl); } return $this->getResponse($client, $btime, $effectiveUrl); @@ -116,6 +111,24 @@ class CoroutineHandler $client->setHeaders($headers); } + protected function getErrorResponse(\Throwable $throwable, $btime, $effectiveUrl) + { + return new CompletedFutureArray([ + 'curl' => [ + 'errno' => 0, + ], + 'transfer_stats' => [ + 'total_time' => microtime(true) - $btime, + ], + 'effective_url' => $effectiveUrl, + 'body' => '', + 'status' => null, + 'reason' => null, + 'headers' => [], + 'error' => $throwable, + ]); + } + protected function getResponse(Client $client, $btime, $effectiveUrl) { return new CompletedFutureArray([ diff --git a/src/guzzle/src/RingPHP/PoolHandler.php b/src/guzzle/src/RingPHP/PoolHandler.php index eb013d94c..ad5794b31 100644 --- a/src/guzzle/src/RingPHP/PoolHandler.php +++ b/src/guzzle/src/RingPHP/PoolHandler.php @@ -74,12 +74,7 @@ class PoolHandler extends CoroutineHandler if ($ex !== true) { $connection->close(); $connection->release(); - return [ - 'status' => null, - 'reason' => null, - 'headers' => [], - 'error' => $ex, - ]; + return $this->getErrorResponse($ex, $btime, $effectiveUrl); } $response = $this->getResponse($client, $btime, $effectiveUrl); From f92d6edfc9ffcbba37f44181a8cf61c625cf0cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 18:57:40 +0800 Subject: [PATCH 49/79] Added testing. --- CHANGELOG.md | 4 ++++ src/elasticsearch/tests/ClientFactoryTest.php | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fce426d2d..fcc821435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.0.14 - TBD +## Fixed + +- [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host does not reached. + # v1.0.13 - 2019-08-28 ## Added diff --git a/src/elasticsearch/tests/ClientFactoryTest.php b/src/elasticsearch/tests/ClientFactoryTest.php index 13d9d00f0..523386f37 100644 --- a/src/elasticsearch/tests/ClientFactoryTest.php +++ b/src/elasticsearch/tests/ClientFactoryTest.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace HyperfTest\Elasticsearch; use Elasticsearch\ClientBuilder; +use Elasticsearch\Common\Exceptions\NoNodesAvailableException; use Hyperf\Elasticsearch\ClientBuilderFactory; use PHPUnit\Framework\TestCase; @@ -30,4 +31,15 @@ class ClientFactoryTest extends TestCase $this->assertInstanceOf(ClientBuilder::class, $client); } + + public function testHostNotReached() + { + $this->expectException(NoNodesAvailableException::class); + + $clientFactory = new ClientBuilderFactory(); + + $client = $clientFactory->create()->setHosts(['http://127.0.0.1:9201'])->build(); + + $client->info(); + } } From 82afd1e117bf418faf477b976018e04881888c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 28 Aug 2019 19:10:07 +0800 Subject: [PATCH 50/79] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc821435..4662e0569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Fixed -- [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host does not reached. +- [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. # v1.0.13 - 2019-08-28 From e90a2f228008082244ff36b863fe78fb27a30efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 10:22:18 +0800 Subject: [PATCH 51/79] Added option no-fillable for db:model. --- .../src/Commands/Ast/ModelUpdateVisitor.php | 14 +++++++++-- src/database/src/Commands/ModelCommand.php | 11 ++++++--- src/database/src/Commands/ModelOption.php | 23 +++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/database/src/Commands/Ast/ModelUpdateVisitor.php b/src/database/src/Commands/Ast/ModelUpdateVisitor.php index a0a06e2df..048c246b6 100644 --- a/src/database/src/Commands/Ast/ModelUpdateVisitor.php +++ b/src/database/src/Commands/Ast/ModelUpdateVisitor.php @@ -12,24 +12,34 @@ declare(strict_types=1); namespace Hyperf\Database\Commands\Ast; +use Hyperf\Database\Commands\ModelOption; use PhpParser\Comment\Doc; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; class ModelUpdateVisitor extends NodeVisitorAbstract { + /** + * @var array + */ protected $columns = []; - public function __construct($columns = []) + /** + * @var ModelOption + */ + protected $option; + + public function __construct($columns = [], ModelOption $option) { $this->columns = $columns; + $this->option = $option; } public function leaveNode(Node $node) { switch ($node) { case $node instanceof Node\Stmt\PropertyProperty: - if ($node->name == 'fillable') { + if ($node->name == 'fillable' && ! $this->option->isNoFillable()) { $node = $this->rewriteFillable($node); } elseif ($node->name == 'casts') { $node = $this->rewriteCasts($node); diff --git a/src/database/src/Commands/ModelCommand.php b/src/database/src/Commands/ModelCommand.php index 79a5a0263..1a628988a 100644 --- a/src/database/src/Commands/ModelCommand.php +++ b/src/database/src/Commands/ModelCommand.php @@ -93,7 +93,8 @@ class ModelCommand extends Command ->setPrefix($this->getOption('prefix', 'prefix', $pool, '')) ->setInheritance($this->getOption('inheritance', 'commands.db:model.inheritance', $pool, 'Model')) ->setUses($this->getOption('uses', 'commands.db:model.uses', $pool, 'Hyperf\DbConnection\Model\Model')) - ->setForceCasts($this->getOption('force-casts', 'commands.db:model.force_casts', $pool, false)); + ->setForceCasts($this->getOption('force-casts', 'commands.db:model.force_casts', $pool, false)) + ->setNoFillable($this->getOption('no-fillable', 'commands.db:model.no_fillable', $pool, false)); if ($table) { $this->createModel($table, $option); @@ -112,6 +113,7 @@ class ModelCommand extends Command $this->addOption('prefix', 'P', InputOption::VALUE_OPTIONAL, 'What prefix that you want the Model set.'); $this->addOption('inheritance', 'i', InputOption::VALUE_OPTIONAL, 'The inheritance that you want the Model extends.'); $this->addOption('uses', 'U', InputOption::VALUE_OPTIONAL, 'The default class uses of the Model.'); + $this->addOption('no-fillable', null, InputOption::VALUE_NONE, 'Whether generate fillable argement for model.'); } protected function getSchemaBuilder(string $poolName): MySqlBuilder @@ -158,7 +160,10 @@ class ModelCommand extends Command $stms = $this->astParser->parse(file_get_contents($path)); $traverser = new NodeTraverser(); - $visitor = make(ModelUpdateVisitor::class, ['columns' => $columns]); + $visitor = make(ModelUpdateVisitor::class, [ + 'columns' => $columns, + 'option' => $option, + ]); $traverser->addVisitor($visitor); $stms = $traverser->traverse($stms); $code = $this->printer->prettyPrintFile($stms); @@ -203,7 +208,7 @@ class ModelCommand extends Command protected function getOption(string $name, string $key, string $pool = 'default', $default = null) { $result = $this->input->getOption($name); - $nonInput = $name === 'force-casts' ? false : null; + $nonInput = in_array($name, ['force-casts', 'no-fillable']) ? false : null; if ($result === $nonInput) { $result = $this->config->get("databases.{$pool}.{$key}", $default); } diff --git a/src/database/src/Commands/ModelOption.php b/src/database/src/Commands/ModelOption.php index 1a1b35625..05f90bd49 100644 --- a/src/database/src/Commands/ModelOption.php +++ b/src/database/src/Commands/ModelOption.php @@ -44,6 +44,11 @@ class ModelOption */ protected $uses; + /** + * @var bool + */ + protected $noFillable; + public function getPool(): string { return $this->pool; @@ -116,4 +121,22 @@ class ModelOption $this->uses = $uses; return $this; } + + /** + * @return bool + */ + public function isNoFillable(): bool + { + return $this->noFillable; + } + + /** + * @param bool $noFillable + * @return ModelOption + */ + public function setNoFillable(bool $noFillable): ModelOption + { + $this->noFillable = $noFillable; + return $this; + } } From 5036db21191d13e457b38a66e606ff2d21755ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 10:27:20 +0800 Subject: [PATCH 52/79] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4662e0569..d908b7879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.0.14 - TBD +## Added + +- [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Don't auto rewrite fillable argument when using no-fillable option. + ## Fixed - [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. From ef78ddb08f5ce4d3c382a715f660d3a77f10aceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 14:38:28 +0800 Subject: [PATCH 53/79] Added refresh-fillable option. --- CHANGELOG.md | 4 ++-- src/database/src/Commands/Ast/ModelUpdateVisitor.php | 2 +- src/database/src/Commands/ModelCommand.php | 6 +++--- src/database/src/Commands/ModelOption.php | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d908b7879..0e17e83e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # v1.0.14 - TBD -## Added +## Changed -- [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Don't auto rewrite fillable argument when using no-fillable option. +- [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Don't auto rewrite fillable argument unless using refresh-fillable option. ## Fixed diff --git a/src/database/src/Commands/Ast/ModelUpdateVisitor.php b/src/database/src/Commands/Ast/ModelUpdateVisitor.php index 048c246b6..b0f9f07cb 100644 --- a/src/database/src/Commands/Ast/ModelUpdateVisitor.php +++ b/src/database/src/Commands/Ast/ModelUpdateVisitor.php @@ -39,7 +39,7 @@ class ModelUpdateVisitor extends NodeVisitorAbstract { switch ($node) { case $node instanceof Node\Stmt\PropertyProperty: - if ($node->name == 'fillable' && ! $this->option->isNoFillable()) { + if ($node->name == 'fillable' && $this->option->isRefreshFillable()) { $node = $this->rewriteFillable($node); } elseif ($node->name == 'casts') { $node = $this->rewriteCasts($node); diff --git a/src/database/src/Commands/ModelCommand.php b/src/database/src/Commands/ModelCommand.php index 1a628988a..cee45436a 100644 --- a/src/database/src/Commands/ModelCommand.php +++ b/src/database/src/Commands/ModelCommand.php @@ -94,7 +94,7 @@ class ModelCommand extends Command ->setInheritance($this->getOption('inheritance', 'commands.db:model.inheritance', $pool, 'Model')) ->setUses($this->getOption('uses', 'commands.db:model.uses', $pool, 'Hyperf\DbConnection\Model\Model')) ->setForceCasts($this->getOption('force-casts', 'commands.db:model.force_casts', $pool, false)) - ->setNoFillable($this->getOption('no-fillable', 'commands.db:model.no_fillable', $pool, false)); + ->setRefreshFillable($this->getOption('refresh-fillable', 'commands.db:model.refresh_fillable', $pool, false)); if ($table) { $this->createModel($table, $option); @@ -113,7 +113,7 @@ class ModelCommand extends Command $this->addOption('prefix', 'P', InputOption::VALUE_OPTIONAL, 'What prefix that you want the Model set.'); $this->addOption('inheritance', 'i', InputOption::VALUE_OPTIONAL, 'The inheritance that you want the Model extends.'); $this->addOption('uses', 'U', InputOption::VALUE_OPTIONAL, 'The default class uses of the Model.'); - $this->addOption('no-fillable', null, InputOption::VALUE_NONE, 'Whether generate fillable argement for model.'); + $this->addOption('refresh-fillable', null, InputOption::VALUE_NONE, 'Whether generate fillable argement for model.'); } protected function getSchemaBuilder(string $poolName): MySqlBuilder @@ -208,7 +208,7 @@ class ModelCommand extends Command protected function getOption(string $name, string $key, string $pool = 'default', $default = null) { $result = $this->input->getOption($name); - $nonInput = in_array($name, ['force-casts', 'no-fillable']) ? false : null; + $nonInput = in_array($name, ['force-casts', 'refresh-fillable']) ? false : null; if ($result === $nonInput) { $result = $this->config->get("databases.{$pool}.{$key}", $default); } diff --git a/src/database/src/Commands/ModelOption.php b/src/database/src/Commands/ModelOption.php index 05f90bd49..89d0881d3 100644 --- a/src/database/src/Commands/ModelOption.php +++ b/src/database/src/Commands/ModelOption.php @@ -47,7 +47,7 @@ class ModelOption /** * @var bool */ - protected $noFillable; + protected $refreshFillable; public function getPool(): string { @@ -125,18 +125,18 @@ class ModelOption /** * @return bool */ - public function isNoFillable(): bool + public function isRefreshFillable(): bool { - return $this->noFillable; + return $this->refreshFillable; } /** - * @param bool $noFillable + * @param bool $refreshFillable * @return ModelOption */ - public function setNoFillable(bool $noFillable): ModelOption + public function setRefreshFillable(bool $refreshFillable): ModelOption { - $this->noFillable = $noFillable; + $this->refreshFillable = $refreshFillable; return $this; } } From 254c4b3730b0b259d9cf7ed61fc4ada0d6e6b6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Thu, 29 Aug 2019 15:15:24 +0800 Subject: [PATCH 54/79] Update ModelOption.php --- src/database/src/Commands/ModelOption.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/database/src/Commands/ModelOption.php b/src/database/src/Commands/ModelOption.php index 89d0881d3..9c2eba451 100644 --- a/src/database/src/Commands/ModelOption.php +++ b/src/database/src/Commands/ModelOption.php @@ -104,36 +104,22 @@ class ModelOption return $this; } - /** - * @return string - */ public function getUses(): string { return $this->uses; } - /** - * @param string $uses - * @return ModelOption - */ public function setUses(string $uses): ModelOption { $this->uses = $uses; return $this; } - /** - * @return bool - */ public function isRefreshFillable(): bool { return $this->refreshFillable; } - /** - * @param bool $refreshFillable - * @return ModelOption - */ public function setRefreshFillable(bool $refreshFillable): ModelOption { $this->refreshFillable = $refreshFillable; From b386df56300cad14ad16d52ab45e2f79c288f305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Thu, 29 Aug 2019 15:19:17 +0800 Subject: [PATCH 55/79] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e17e83e9..073898333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Changed -- [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Don't auto rewrite fillable argument unless using refresh-fillable option. +- [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Re-generate the `fillable` argument of Model when use `refresh-fillable` option, at the same time, the command will keep the `fillable` argument as default behaviours. ## Fixed From e8a6d8238d35fc7fec093d950d299d6949911275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 16:27:46 +0800 Subject: [PATCH 56/79] Fixed bug. --- src/translation/src/Translator.php | 18 ++++++++++-------- .../src/Concerns/ValidatesAttributes.php | 6 +++--- src/validation/src/Factory.php | 12 ++++-------- src/validation/src/Validator.php | 14 +++++++------- src/validation/src/ValidatorFactory.php | 4 ++-- .../tests/Cases/ValidationFactoryTest.php | 2 +- .../tests/Cases/ValidationValidatorTest.php | 2 +- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/translation/src/Translator.php b/src/translation/src/Translator.php index 1b1018a3b..2e562386f 100755 --- a/src/translation/src/Translator.php +++ b/src/translation/src/Translator.php @@ -267,16 +267,14 @@ class Translator implements TranslatorInterface $parsed = $this->parseNamespacedSegments($key); } + if (is_null($parsed[0])) { + $parsed[0] = '*'; + } + // Once we have the parsed array of this key's elements, such as its groups // and namespace, we will cache each array inside a simple list that has // the key and the parsed array for quick look-ups for later requests. - $segments = $this->parsed[$key] = $parsed; - - if (is_null($segments[0])) { - $segments[0] = '*'; - } - - return $segments; + return $this->parsed[$key] = $parsed; } /** @@ -395,6 +393,7 @@ class Translator implements TranslatorInterface if (is_string($line)) { return $this->makeReplacements($line, $replace); } + if (is_array($line) && count($line) > 0) { foreach ($line as $key => $value) { $line[$key] = $this->makeReplacements($value, $replace); @@ -406,8 +405,11 @@ class Translator implements TranslatorInterface /** * Make the place-holder replacements on a line. + * + * @param array|string $line + * @return array|string */ - protected function makeReplacements(string $line, array $replace): string + protected function makeReplacements($line, array $replace) { if (empty($replace)) { return $line; diff --git a/src/validation/src/Concerns/ValidatesAttributes.php b/src/validation/src/Concerns/ValidatesAttributes.php index b007b69a2..9e7061f52 100755 --- a/src/validation/src/Concerns/ValidatesAttributes.php +++ b/src/validation/src/Concerns/ValidatesAttributes.php @@ -462,7 +462,7 @@ trait ValidatesAttributes $column, $value, $parameters - ) >= $expected; + ) >= $expected; } /** @@ -514,7 +514,7 @@ trait ValidatesAttributes $id, $idColumn, $extra - ) == 0; + ) == 0; } /** @@ -1449,7 +1449,7 @@ trait ValidatesAttributes { return Carbon::hasTestNow() && is_string($value) && ( $value === 'now' || Carbon::hasRelativeKeywords($value) - ); + ); } /** diff --git a/src/validation/src/Factory.php b/src/validation/src/Factory.php index 49b5014a5..1907f6db0 100755 --- a/src/validation/src/Factory.php +++ b/src/validation/src/Factory.php @@ -13,8 +13,7 @@ declare(strict_types=1); namespace Hyperf\Validation; use Closure; -use Hyperf\Di\Container; -use Hyperf\Translation\Contracts\Translator; +use Hyperf\Contract\TranslatorInterface; use Hyperf\Utils\Str; use Hyperf\Validation\Contracts\Validation\Factory as FactoryContract; use Psr\Container\ContainerInterface; @@ -24,7 +23,7 @@ class Factory implements FactoryContract /** * The Translator implementation. * - * @var \Hyperf\Translation\Contracts\Translator + * @var TranslatorInterface */ protected $translator; @@ -86,11 +85,8 @@ class Factory implements FactoryContract /** * Create a new Validator factory instance. - * - * @param null|\Hyperf\Translation\Contracts\Translator $translator - * @param Container */ - public function __construct(Translator $translator, ContainerInterface $container = null) + public function __construct(TranslatorInterface $translator, ContainerInterface $container = null) { $this->container = $container; $this->translator = $translator; @@ -220,7 +216,7 @@ class Factory implements FactoryContract /** * Get the Translator implementation. * - * @return \Hyperf\Translation\Contracts\Translator + * @return TranslatorInterface */ public function getTranslator() { diff --git a/src/validation/src/Validator.php b/src/validation/src/Validator.php index ca16f474d..1f52d4b72 100755 --- a/src/validation/src/Validator.php +++ b/src/validation/src/Validator.php @@ -13,9 +13,9 @@ declare(strict_types=1); namespace Hyperf\Validation; use BadMethodCallException; +use Hyperf\Contract\TranslatorInterface; use Hyperf\Di\Container; use Hyperf\HttpMessage\Upload\UploadedFile; -use Hyperf\Translation\Contracts\Translator; use Hyperf\Utils\Arr; use Hyperf\Utils\Fluent; use Hyperf\Utils\Str; @@ -76,7 +76,7 @@ class Validator implements ValidatorContract /** * The Translator implementation. * - * @var \Hyperf\Translation\Contracts\Translator + * @var TranslatorInterface */ protected $translator; @@ -205,14 +205,14 @@ class Validator implements ValidatorContract /** * Create a new Validator instance. * - * @param \Hyperf\Translation\Contracts\Translator $translator + * @param TranslatorInterface $translator * @param array $data * @param array $rules * @param array $messages * @param array $customAttributes */ public function __construct( - Translator $translator, + TranslatorInterface $translator, array $data, array $rules, array $messages = [], @@ -826,7 +826,7 @@ class Validator implements ValidatorContract /** * Get the Translator implementation. * - * @return \Hyperf\Translation\Contracts\Translator + * @return TranslatorInterface */ public function getTranslator() { @@ -836,9 +836,9 @@ class Validator implements ValidatorContract /** * Set the Translator implementation. * - * @param \Hyperf\Translation\Contracts\Translator $translator + * @param TranslatorInterface $translator */ - public function setTranslator(Translator $translator) + public function setTranslator(TranslatorInterface $translator) { $this->translator = $translator; } diff --git a/src/validation/src/ValidatorFactory.php b/src/validation/src/ValidatorFactory.php index 24ea2e4ac..9a5ba7ef3 100755 --- a/src/validation/src/ValidatorFactory.php +++ b/src/validation/src/ValidatorFactory.php @@ -12,15 +12,15 @@ declare(strict_types=1); namespace Hyperf\Validation; +use Hyperf\Contract\TranslatorInterface; use Hyperf\Database\ConnectionResolverInterface; -use Hyperf\Translation\Contracts\Translator; use Psr\Container\ContainerInterface; class ValidatorFactory { public function __invoke(ContainerInterface $container) { - $translator = $container->get(Translator::class); + $translator = $container->get(TranslatorInterface::class); $validator = make(Factory::class, compact('translator', 'container')); diff --git a/src/validation/tests/Cases/ValidationFactoryTest.php b/src/validation/tests/Cases/ValidationFactoryTest.php index ed17ed64b..4853b6eb3 100755 --- a/src/validation/tests/Cases/ValidationFactoryTest.php +++ b/src/validation/tests/Cases/ValidationFactoryTest.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace HyperfTest\Validation\Cases; -use Hyperf\Translation\Contracts\Translator as TranslatorInterface; +use Hyperf\Contract\TranslatorInterface; use Hyperf\Validation\Factory; use Hyperf\Validation\PresenceVerifierInterface; use Hyperf\Validation\Validator; diff --git a/src/validation/tests/Cases/ValidationValidatorTest.php b/src/validation/tests/Cases/ValidationValidatorTest.php index 9a791963a..e53027272 100755 --- a/src/validation/tests/Cases/ValidationValidatorTest.php +++ b/src/validation/tests/Cases/ValidationValidatorTest.php @@ -15,11 +15,11 @@ namespace HyperfTest\Validation\Cases; use Carbon\Carbon; use DateTime; use DateTimeImmutable; +use Hyperf\Contract\TranslatorInterface as TranslatorContract; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSourceInterface; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Translation\ArrayLoader; -use Hyperf\Translation\Contracts\Translator as TranslatorContract; use Hyperf\Translation\Translator; use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\Arr; From 10512456896a21b5275ebd3f80edd535287e01fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 31 Aug 2019 20:04:44 +0800 Subject: [PATCH 57/79] Deleted useless comments. --- src/validation/src/ClosureValidationRule.php | 4 +- .../src/Concerns/FormatsMessages.php | 56 ---- .../src/Concerns/ReplacesAttributes.php | 194 +------------ .../src/Concerns/ValidatesAttributes.php | 255 +----------------- 4 files changed, 6 insertions(+), 503 deletions(-) diff --git a/src/validation/src/ClosureValidationRule.php b/src/validation/src/ClosureValidationRule.php index 93975ca9a..ee73bcb9d 100755 --- a/src/validation/src/ClosureValidationRule.php +++ b/src/validation/src/ClosureValidationRule.php @@ -69,10 +69,8 @@ class ClosureValidationRule implements RuleContract /** * Get the validation error message. - * - * @return string */ - public function message() + public function message(): string { return $this->message; } diff --git a/src/validation/src/Concerns/FormatsMessages.php b/src/validation/src/Concerns/FormatsMessages.php index 4b100aa66..6e1017a1b 100755 --- a/src/validation/src/Concerns/FormatsMessages.php +++ b/src/validation/src/Concerns/FormatsMessages.php @@ -23,12 +23,6 @@ trait FormatsMessages /** * Replace all error message place-holders with actual values. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ public function makeReplacements(string $message, string $attribute, string $rule, array $parameters): string { @@ -51,9 +45,6 @@ trait FormatsMessages /** * Get the displayable name of the attribute. - * - * @param string $attribute - * @return string */ public function getDisplayableAttribute(string $attribute): string { @@ -112,10 +103,6 @@ trait FormatsMessages /** * Get the validation message for an attribute and rule. - * - * @param string $attribute - * @param string $rule - * @return string */ protected function getMessage(string $attribute, string $rule): string { @@ -167,8 +154,6 @@ trait FormatsMessages /** * Get the proper inline error message for standard and size rules. * - * @param string $attribute - * @param string $rule * @return null|string */ protected function getInlineMessage(string $attribute, string $rule) @@ -183,8 +168,6 @@ trait FormatsMessages /** * Get the inline message for a rule if it exists. * - * @param string $attribute - * @param string $lowerRule * @param null|array $source * @return null|string */ @@ -208,9 +191,6 @@ trait FormatsMessages /** * Get the custom error message from translator. - * - * @param string $key - * @return string */ protected function getCustomMessageFromTranslator(string $key): string { @@ -234,11 +214,6 @@ trait FormatsMessages /** * Check the given messages for a wildcard key. - * - * @param array $messages - * @param string $search - * @param string $default - * @return string */ protected function getWildcardCustomMessages(array $messages, string $search, string $default): string { @@ -253,10 +228,6 @@ trait FormatsMessages /** * Get the proper error message for an attribute and size rule. - * - * @param string $attribute - * @param string $rule - * @return string */ protected function getSizeMessage(string $attribute, string $rule): string { @@ -274,9 +245,6 @@ trait FormatsMessages /** * Get the data type of the given attribute. - * - * @param string $attribute - * @return string */ protected function getAttributeType(string $attribute): string { @@ -298,9 +266,6 @@ trait FormatsMessages /** * Get the given attribute from the attribute translations. - * - * @param string $name - * @return string */ protected function getAttributeFromTranslations(string $name): string { @@ -309,10 +274,6 @@ trait FormatsMessages /** * Replace the :attribute placeholder in the given message. - * - * @param string $message - * @param string $value - * @return string */ protected function replaceAttributePlaceholder(string $message, string $value): string { @@ -325,10 +286,6 @@ trait FormatsMessages /** * Replace the :input placeholder in the given message. - * - * @param string $message - * @param string $attribute - * @return string */ protected function replaceInputPlaceholder(string $message, string $attribute): string { @@ -343,9 +300,6 @@ trait FormatsMessages /** * Transform an array of attributes to their displayable form. - * - * @param array $values - * @return array */ protected function getAttributeList(array $values): array { @@ -364,10 +318,6 @@ trait FormatsMessages /** * Call a custom validator message replacer. * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters * @param \Hyperf\Validation\Validator $validator * @return null|string */ @@ -386,13 +336,7 @@ trait FormatsMessages /** * Call a class based validator message replacer. * - * @param string $callback - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters * @param \Hyperf\Validation\Validator $validator - * @return string */ protected function callClassBasedReplacer(string $callback, string $message, string $attribute, string $rule, array $parameters, $validator): string { diff --git a/src/validation/src/Concerns/ReplacesAttributes.php b/src/validation/src/Concerns/ReplacesAttributes.php index 0b0137543..006e5b35c 100755 --- a/src/validation/src/Concerns/ReplacesAttributes.php +++ b/src/validation/src/Concerns/ReplacesAttributes.php @@ -18,12 +18,6 @@ trait ReplacesAttributes { /** * Replace all place-holders for the between rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceBetween(string $message, string $attribute, string $rule, array $parameters): string { @@ -32,12 +26,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the date_format rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDateFormat(string $message, string $attribute, string $rule, array $parameters): string { @@ -46,12 +34,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the different rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDifferent(string $message, string $attribute, string $rule, array $parameters): string { @@ -60,12 +42,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the digits rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDigits(string $message, string $attribute, string $rule, array $parameters): string { @@ -74,12 +50,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the digits (between) rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDigitsBetween(string $message, string $attribute, string $rule, array $parameters): string { @@ -88,12 +58,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the min rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceMin(string $message, string $attribute, string $rule, array $parameters): string { @@ -102,26 +66,14 @@ trait ReplacesAttributes /** * Replace all place-holders for the max rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ - protected function replaceMax(string $message, string $attribute, string $rule, array $parameters) + protected function replaceMax(string $message, string $attribute, string $rule, array $parameters): string { return str_replace(':max', $parameters[0], $message); } /** * Replace all place-holders for the in rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceIn(string $message, string $attribute, string $rule, array $parameters): string { @@ -134,12 +86,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the not_in rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceNotIn(string $message, string $attribute, string $rule, array $parameters): string { @@ -148,12 +94,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the in_array rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceInArray(string $message, string $attribute, string $rule, array $parameters): string { @@ -162,12 +102,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the mimetypes rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceMimetypes(string $message, string $attribute, string $rule, array $parameters): string { @@ -176,12 +110,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the mimes rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceMimes(string $message, string $attribute, string $rule, array $parameters): string { @@ -190,12 +118,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_with rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredWith(string $message, string $attribute, string $rule, array $parameters): string { @@ -204,12 +126,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_with_all rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredWithAll(string $message, string $attribute, string $rule, array $parameters): string { @@ -218,12 +134,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_without rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredWithout(string $message, string $attribute, string $rule, array $parameters): string { @@ -232,12 +142,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_without_all rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredWithoutAll(string $message, string $attribute, string $rule, array $parameters): string { @@ -246,12 +150,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the size rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceSize(string $message, string $attribute, string $rule, array $parameters): string { @@ -260,12 +158,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the gt rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceGt(string $message, string $attribute, string $rule, array $parameters): string { @@ -278,12 +170,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the lt rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceLt(string $message, string $attribute, string $rule, array $parameters): string { @@ -296,12 +182,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the gte rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceGte(string $message, string $attribute, string $rule, array $parameters): string { @@ -314,12 +194,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the lte rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceLte(string $message, string $attribute, string $rule, array $parameters): string { @@ -332,12 +206,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_if rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredIf(string $message, string $attribute, string $rule, array $parameters): string { @@ -350,12 +218,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the required_unless rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceRequiredUnless(string $message, string $attribute, string $rule, array $parameters): string { @@ -372,12 +234,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the same rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceSame(string $message, string $attribute, string $rule, array $parameters): string { @@ -386,12 +242,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the before rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceBefore(string $message, string $attribute, string $rule, array $parameters): string { @@ -404,12 +254,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the before_or_equal rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceBeforeOrEqual(string $message, string $attribute, string $rule, array $parameters): string { @@ -418,12 +262,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the after rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceAfter(string $message, string $attribute, string $rule, array $parameters): string { @@ -432,12 +270,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the after_or_equal rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceAfterOrEqual(string $message, string $attribute, string $rule, array $parameters): string { @@ -446,12 +278,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the date_equals rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDateEquals(string $message, string $attribute, string $rule, array $parameters): string { @@ -460,12 +286,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the dimensions rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceDimensions(string $message, string $attribute, string $rule, array $parameters): string { @@ -482,12 +302,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the ends_with rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceEndsWith(string $message, string $attribute, string $rule, array $parameters): string { @@ -500,12 +314,6 @@ trait ReplacesAttributes /** * Replace all place-holders for the starts_with rule. - * - * @param string $message - * @param string $attribute - * @param string $rule - * @param array $parameters - * @return string */ protected function replaceStartsWith(string $message, string $attribute, string $rule, array $parameters): string { diff --git a/src/validation/src/Concerns/ValidatesAttributes.php b/src/validation/src/Concerns/ValidatesAttributes.php index 9e7061f52..79c827a27 100755 --- a/src/validation/src/Concerns/ValidatesAttributes.php +++ b/src/validation/src/Concerns/ValidatesAttributes.php @@ -38,9 +38,7 @@ trait ValidatesAttributes * * This validation rule implies the attribute is "required". * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateAccepted(string $attribute, $value): bool { @@ -52,9 +50,7 @@ trait ValidatesAttributes /** * Validate that an attribute is an active URL. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateActiveUrl(string $attribute, $value): bool { @@ -77,8 +73,6 @@ trait ValidatesAttributes * "Break" on first validation fail. * * Always returns true, just lets us put "bail" in rules. - * - * @return bool */ public function validateBail(): bool { @@ -88,10 +82,7 @@ trait ValidatesAttributes /** * Validate the date is before a given date. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateBefore(string $attribute, $value, array $parameters): bool { @@ -103,10 +94,7 @@ trait ValidatesAttributes /** * Validate the date is before or equal a given date. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateBeforeOrEqual(string $attribute, $value, array $parameters): bool { @@ -118,10 +106,7 @@ trait ValidatesAttributes /** * Validate the date is after a given date. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateAfter(string $attribute, $value, array $parameters): bool { @@ -133,10 +118,7 @@ trait ValidatesAttributes /** * Validate the date is equal or after a given date. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateAfterOrEqual(string $attribute, $value, array $parameters): bool { @@ -148,9 +130,7 @@ trait ValidatesAttributes /** * Validate that an attribute contains only alphabetic characters. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateAlpha(string $attribute, $value): bool { @@ -160,9 +140,7 @@ trait ValidatesAttributes /** * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateAlphaDash(string $attribute, $value): bool { @@ -176,9 +154,7 @@ trait ValidatesAttributes /** * Validate that an attribute contains only alpha-numeric characters. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateAlphaNum(string $attribute, $value): bool { @@ -192,9 +168,7 @@ trait ValidatesAttributes /** * Validate that an attribute is an array. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateArray(string $attribute, $value): bool { @@ -204,10 +178,7 @@ trait ValidatesAttributes /** * Validate the size of an attribute is between a set of values. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateBetween(string $attribute, $value, array $parameters): bool { @@ -221,9 +192,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a boolean. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateBoolean(string $attribute, $value): bool { @@ -235,9 +204,7 @@ trait ValidatesAttributes /** * Validate that an attribute has a matching confirmation. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateConfirmed(string $attribute, $value): bool { @@ -247,9 +214,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid date. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateDate(string $attribute, $value): bool { @@ -276,10 +241,7 @@ trait ValidatesAttributes /** * Validate that an attribute matches a date format. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDateFormat(string $attribute, $value, array $parameters): bool { @@ -299,10 +261,7 @@ trait ValidatesAttributes /** * Validate that an attribute is equal to another date. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDateEquals(string $attribute, $value, array $parameters): bool { @@ -314,10 +273,7 @@ trait ValidatesAttributes /** * Validate that an attribute is different from another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDifferent(string $attribute, $value, array $parameters): bool { @@ -341,10 +297,7 @@ trait ValidatesAttributes /** * Validate that an attribute has a given number of digits. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDigits(string $attribute, $value, array $parameters): bool { @@ -357,10 +310,7 @@ trait ValidatesAttributes /** * Validate that an attribute is between a given number of digits. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDigitsBetween(string $attribute, $value, array $parameters): bool { @@ -375,10 +325,7 @@ trait ValidatesAttributes /** * Validate the dimensions of an image matches the given values. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDimensions(string $attribute, $value, array $parameters): bool { @@ -403,10 +350,7 @@ trait ValidatesAttributes /** * Validate an attribute is unique among other values. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateDistinct(string $attribute, $value, array $parameters): bool { @@ -422,9 +366,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid e-mail address. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateEmail(string $attribute, $value): bool { @@ -438,10 +380,7 @@ trait ValidatesAttributes /** * Validate the existence of an attribute value in a database table. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateExists(string $attribute, $value, array $parameters): bool { @@ -470,10 +409,7 @@ trait ValidatesAttributes * * If a database column is not specified, the attribute will be used. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateUnique(string $attribute, $value, array $parameters): bool { @@ -519,23 +455,16 @@ trait ValidatesAttributes /** * Parse the connection / table for the unique / exists rules. - * - * @param string $table - * @return array */ - public function parseTable($table): array + public function parseTable(string $table): array { return Str::contains($table, '.') ? explode('.', $table, 2) : [null, $table]; } /** * Get the column name for an exists / unique query. - * - * @param array $parameters - * @param string $attribute - * @return bool */ - public function getQueryColumn($parameters, $attribute): string + public function getQueryColumn(array $parameters, string $attribute): string { return isset($parameters[1]) && $parameters[1] !== 'NULL' ? $parameters[1] : $this->guessColumnForQuery($attribute); @@ -543,9 +472,6 @@ trait ValidatesAttributes /** * Guess the database column from the given attribute name. - * - * @param string $attribute - * @return string */ public function guessColumnForQuery(string $attribute): string { @@ -560,9 +486,7 @@ trait ValidatesAttributes /** * Validate the given value is a valid file. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateFile(string $attribute, $value): bool { @@ -572,9 +496,7 @@ trait ValidatesAttributes /** * Validate the given attribute is filled if it is present. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateFilled(string $attribute, $value): bool { @@ -588,10 +510,7 @@ trait ValidatesAttributes /** * Validate that an attribute is greater than another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateGt(string $attribute, $value, array $parameters): bool { @@ -615,10 +534,7 @@ trait ValidatesAttributes /** * Validate that an attribute is less than another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateLt(string $attribute, $value, array $parameters): bool { @@ -642,10 +558,7 @@ trait ValidatesAttributes /** * Validate that an attribute is greater than or equal another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateGte(string $attribute, $value, array $parameters): bool { @@ -669,10 +582,7 @@ trait ValidatesAttributes /** * Validate that an attribute is less than or equal another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateLte(string $attribute, $value, array $parameters): bool { @@ -696,9 +606,7 @@ trait ValidatesAttributes /** * Validate the MIME type of a file is an image MIME type. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateImage(string $attribute, $value): bool { @@ -708,10 +616,7 @@ trait ValidatesAttributes /** * Validate an attribute is contained within a list of values. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateIn(string $attribute, $value, array $parameters): bool { @@ -731,10 +636,7 @@ trait ValidatesAttributes /** * Validate that the values of an attribute is in another attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateInArray(string $attribute, $value, array $parameters): bool { @@ -754,9 +656,7 @@ trait ValidatesAttributes /** * Validate that an attribute is an integer. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateInteger(string $attribute, $value): bool { @@ -766,9 +666,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid IP. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateIp(string $attribute, $value): bool { @@ -778,9 +676,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid IPv4. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateIpv4(string $attribute, $value): bool { @@ -790,9 +686,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid IPv6. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateIpv6(string $attribute, $value): bool { @@ -802,9 +696,7 @@ trait ValidatesAttributes /** * Validate the attribute is a valid JSON string. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateJson(string $attribute, $value): bool { @@ -820,10 +712,7 @@ trait ValidatesAttributes /** * Validate the size of an attribute is less than a maximum value. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateMax(string $attribute, $value, array $parameters): bool { @@ -839,10 +728,7 @@ trait ValidatesAttributes /** * Validate the guessed extension of a file upload is in a set of file extensions. * - * @param string $attribute * @param SplFileInfo $value - * @param array $parameters - * @return bool */ public function validateMimes(string $attribute, $value, array $parameters): bool { @@ -872,10 +758,7 @@ trait ValidatesAttributes /** * Validate the MIME type of a file upload attribute is in a set of MIME types. * - * @param string $attribute * @param SplFileInfo $value - * @param array $parameters - * @return bool */ public function validateMimetypes(string $attribute, $value, array $parameters): bool { @@ -895,10 +778,7 @@ trait ValidatesAttributes /** * Validate the size of an attribute is greater than a minimum value. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateMin(string $attribute, $value, array $parameters): bool { @@ -911,8 +791,6 @@ trait ValidatesAttributes * "Indicate" validation should pass if value is null. * * Always returns true, just lets us put "nullable" in rules. - * - * @return bool */ public function validateNullable(): bool { @@ -922,10 +800,7 @@ trait ValidatesAttributes /** * Validate an attribute is not contained within a list of values. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateNotIn(string $attribute, $value, array $parameters): bool { @@ -935,9 +810,7 @@ trait ValidatesAttributes /** * Validate that an attribute is numeric. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateNumeric(string $attribute, $value): bool { @@ -947,9 +820,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists even if not filled. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validatePresent(string $attribute, $value): bool { @@ -959,10 +830,7 @@ trait ValidatesAttributes /** * Validate that an attribute passes a regular expression check. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateRegex(string $attribute, $value, array $parameters): bool { @@ -978,10 +846,7 @@ trait ValidatesAttributes /** * Validate that an attribute does not pass a regular expression check. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateNotRegex(string $attribute, $value, array $parameters): bool { @@ -997,9 +862,7 @@ trait ValidatesAttributes /** * Validate that a required attribute exists. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateRequired(string $attribute, $value): bool { @@ -1022,10 +885,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when another attribute has a given value. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredIf(string $attribute, $value, array $parameters): bool { @@ -1049,10 +909,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when another attribute does not have a given value. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredUnless(string $attribute, $value, array $parameters): bool { @@ -1072,10 +929,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when any other attribute exists. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredWith(string $attribute, $value, array $parameters): bool { @@ -1089,10 +943,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when all other attributes exists. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredWithAll(string $attribute, $value, array $parameters): bool { @@ -1106,10 +957,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when another attribute does not. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredWithout(string $attribute, $value, array $parameters): bool { @@ -1123,10 +971,7 @@ trait ValidatesAttributes /** * Validate that an attribute exists when all other attributes do not. * - * @param string $attribute * @param mixed $value - * @param mixed $parameters - * @return bool */ public function validateRequiredWithoutAll(string $attribute, $value, array $parameters): bool { @@ -1140,10 +985,7 @@ trait ValidatesAttributes /** * Validate that two attributes match. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateSame(string $attribute, $value, array $parameters): bool { @@ -1157,10 +999,7 @@ trait ValidatesAttributes /** * Validate the size of an attribute. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateSize(string $attribute, $value, array $parameters): bool { @@ -1173,8 +1012,6 @@ trait ValidatesAttributes * "Validate" optional attributes. * * Always returns true, just lets us put sometimes in rules. - * - * @return bool */ public function validateSometimes() { @@ -1184,10 +1021,7 @@ trait ValidatesAttributes /** * Validate the attribute starts with a given substring. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateStartsWith(string $attribute, $value, array $parameters): bool { @@ -1197,10 +1031,7 @@ trait ValidatesAttributes /** * Validate the attribute ends with a given substring. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @return bool */ public function validateEndsWith(string $attribute, $value, array $parameters): bool { @@ -1210,9 +1041,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a string. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateString(string $attribute, $value): bool { @@ -1222,9 +1051,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid timezone. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateTimezone(string $attribute, $value): bool { @@ -1242,9 +1069,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid URL. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateUrl(string $attribute, $value): bool { @@ -1279,9 +1104,7 @@ trait ValidatesAttributes /** * Validate that an attribute is a valid UUID. * - * @param string $attribute * @param mixed $value - * @return bool */ public function validateUuid(string $attribute, $value): bool { @@ -1296,7 +1119,6 @@ trait ValidatesAttributes * Check that the given value is a valid file instance. * * @param mixed $value - * @return bool */ public function isValidFileInstance($value): bool { @@ -1310,10 +1132,6 @@ trait ValidatesAttributes /** * Require a certain number of parameters to be present. * - * @param int $count - * @param array $parameters - * @param string $rule - * * @throws \InvalidArgumentException */ public function requireParameterCount(int $count, array $parameters, string $rule) @@ -1326,11 +1144,7 @@ trait ValidatesAttributes /** * Compare a given date against another using an operator. * - * @param string $attribute * @param mixed $value - * @param array $parameters - * @param string $operator - * @return bool */ protected function compareDates(string $attribute, $value, array $parameters, string $operator): bool { @@ -1352,7 +1166,6 @@ trait ValidatesAttributes /** * Get the date format for an attribute if it has one. * - * @param string $attribute * @return null|string */ protected function getDateFormat(string $attribute) @@ -1366,9 +1179,8 @@ trait ValidatesAttributes * Get the date timestamp. * * @param mixed $value - * @return int */ - protected function getDateTimestamp($value) + protected function getDateTimestamp($value): int { if ($value instanceof DateTimeInterface) { return $value->getTimestamp(); @@ -1387,12 +1199,6 @@ trait ValidatesAttributes /** * Given two date/time strings, check that one is after the other. - * - * @param string $format - * @param string $first - * @param string $second - * @param string $operator - * @return bool */ protected function checkDateTimeOrder(string $format, string $first, string $second, string $operator): bool { @@ -1408,8 +1214,6 @@ trait ValidatesAttributes /** * Get a DateTime instance from a string. * - * @param string $format - * @param string $value * @return null|\DateTime */ protected function getDateTimeWithOptionalFormat(string $format, string $value) @@ -1424,7 +1228,6 @@ trait ValidatesAttributes /** * Get a DateTime instance from a string with no format. * - * @param string $value * @return null|\DateTime */ protected function getDateTime(string $value) @@ -1443,7 +1246,6 @@ trait ValidatesAttributes * Check if the given value should be adjusted to Carbon::getTestNow(). * * @param mixed $value - * @return bool */ protected function isTestingRelativeDateTime($value): bool { @@ -1454,11 +1256,6 @@ trait ValidatesAttributes /** * Test if the given width and height fail any conditions. - * - * @param array $parameters - * @param int $width - * @param int $height - * @return bool */ protected function failsBasicDimensionChecks(array $parameters, int $width, int $height): bool { @@ -1472,11 +1269,6 @@ trait ValidatesAttributes /** * Determine if the given parameters fail a dimension ratio check. - * - * @param array $parameters - * @param int $width - * @param int $height - * @return bool */ protected function failsRatioCheck(array $parameters, int $width, int $height): bool { @@ -1496,9 +1288,6 @@ trait ValidatesAttributes /** * Get the values to distinct between. - * - * @param string $attribute - * @return array */ protected function getDistinctValues(string $attribute): array { @@ -1517,9 +1306,6 @@ trait ValidatesAttributes /** * Extract the distinct values from the data. - * - * @param string $attribute - * @return array */ protected function extractDistinctValues(string $attribute): array { @@ -1539,11 +1325,7 @@ trait ValidatesAttributes * Get the number of records that exist in storage. * * @param mixed $connection - * @param string $table - * @param string $column * @param mixed $value - * @param array $parameters - * @return int */ protected function getExistCount($connection, string $table, string $column, $value, array $parameters): int { @@ -1564,9 +1346,6 @@ trait ValidatesAttributes /** * Get the excluded ID column and value for the unique rule. - * - * @param array $parameters - * @return array */ protected function getUniqueIds(array $parameters): array { @@ -1600,9 +1379,6 @@ trait ValidatesAttributes /** * Get the extra conditions for a unique rule. - * - * @param array $parameters - * @return array */ protected function getUniqueExtra(array $parameters): array { @@ -1615,9 +1391,6 @@ trait ValidatesAttributes /** * Get the extra conditions for a unique / exists rule. - * - * @param array $segments - * @return array */ protected function getExtraConditions(array $segments): array { @@ -1636,8 +1409,6 @@ trait ValidatesAttributes * Check if PHP uploads are explicitly allowed. * * @param SplFileInfo $value - * @param array $parameters - * @return bool */ protected function shouldBlockPhpUpload($value, array $parameters): bool { @@ -1654,9 +1425,6 @@ trait ValidatesAttributes /** * Convert the given values to boolean if they are string "true" / "false". - * - * @param array $values - * @return array */ protected function convertValuesToBoolean(array $values): array { @@ -1674,9 +1442,6 @@ trait ValidatesAttributes /** * Determine if any of the given attributes fail the required test. - * - * @param array $attributes - * @return bool */ protected function anyFailingRequired(array $attributes): bool { @@ -1691,9 +1456,6 @@ trait ValidatesAttributes /** * Determine if all of the given attributes fail the required test. - * - * @param array $attributes - * @return bool */ protected function allFailingRequired(array $attributes): bool { @@ -1709,7 +1471,6 @@ trait ValidatesAttributes /** * Get the size of an attribute. * - * @param string $attribute * @param mixed $value * @return mixed */ @@ -1739,7 +1500,6 @@ trait ValidatesAttributes * * @param mixed $first * @param mixed $second - * @param string $operator * @throws \InvalidArgumentException * @return bool */ @@ -1763,11 +1523,8 @@ trait ValidatesAttributes /** * Parse named parameters to $key => $value items. - * - * @param array $parameters - * @return array */ - protected function parseNamedParameters(array $parameters) + protected function parseNamedParameters(array $parameters): array { return array_reduce($parameters, function ($result, $item) { [$key, $value] = array_pad(explode('=', $item, 2), 2, null); @@ -1783,7 +1540,6 @@ trait ValidatesAttributes * * @param mixed $first * @param mixed $second - * @return bool */ protected function isSameType($first, $second): bool { @@ -1792,9 +1548,6 @@ trait ValidatesAttributes /** * Adds the existing rule to the numericRules array if the attribute's value is numeric. - * - * @param string $attribute - * @param string $rule */ protected function shouldBeNumeric(string $attribute, string $rule) { From 038a4fe551fd1d276f206ee9a31562becb8aa8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 31 Aug 2019 20:19:00 +0800 Subject: [PATCH 58/79] Optimized code. --- src/validation/src/ConfigProvider.php | 9 +++++--- .../src/Contracts/Support/MessageBag.php | 20 ------------------ .../src/Contracts/Validation/Factory.php | 7 ------- .../src/Contracts/Validation/Rule.php | 2 -- .../src/Contracts/Validation/Validator.php | 9 -------- .../src/DatabasePresenceVerifier.php | 17 +-------------- src/validation/src/Factory.php | 21 ------------------- .../src/PresenceVerifierInterface.php | 11 ---------- src/validation/src/Request/FormRequest.php | 21 +++---------------- 9 files changed, 10 insertions(+), 107 deletions(-) diff --git a/src/validation/src/ConfigProvider.php b/src/validation/src/ConfigProvider.php index d4cb92128..0df7c4300 100644 --- a/src/validation/src/ConfigProvider.php +++ b/src/validation/src/ConfigProvider.php @@ -12,15 +12,18 @@ declare(strict_types=1); namespace Hyperf\Validation; +use Hyperf\Validation\Contracts\Validation\Factory as FactoryInterface; +use Hyperf\Validation\Contracts\Validation\Validator as ValidatorInterface; + class ConfigProvider { public function __invoke(): array { return [ 'dependencies' => [ - \Hyperf\Validation\Contracts\Validation\Validator::class => \Hyperf\Validation\ValidatorFactory::class, - \Hyperf\Validation\PresenceVerifierInterface::class => \Hyperf\Validation\DatabasePresenceVerifierFactory::class, - \Hyperf\Validation\Contracts\Validation\Factory::class => \Hyperf\Validation\ValidatorFactory::class, + ValidatorInterface::class => ValidatorFactory::class, + PresenceVerifierInterface::class => DatabasePresenceVerifierFactory::class, + FactoryInterface::class => ValidatorFactory::class, ], 'scan' => [ 'paths' => [ diff --git a/src/validation/src/Contracts/Support/MessageBag.php b/src/validation/src/Contracts/Support/MessageBag.php index c3985fbe8..17b97872a 100755 --- a/src/validation/src/Contracts/Support/MessageBag.php +++ b/src/validation/src/Contracts/Support/MessageBag.php @@ -18,16 +18,12 @@ interface MessageBag extends Arrayable { /** * Get the keys present in the message bag. - * - * @return array */ public function keys(): array; /** * Add a message to the bag. * - * @param string $key - * @param string $message * @return $this */ public function add(string $key, string $message); @@ -44,7 +40,6 @@ interface MessageBag extends Arrayable * Determine if messages exist for a given key. * * @param array|string $key - * @return bool */ public function has($key): bool; @@ -53,16 +48,13 @@ interface MessageBag extends Arrayable * * @param null|string $key * @param null|string $format - * @return string */ public function first($key = null, $format = null): string; /** * Get all of the messages from the bag for a given key. * - * @param string $key * @param null|string $format - * @return array */ public function get(string $key, $format = null): array; @@ -70,50 +62,38 @@ interface MessageBag extends Arrayable * Get all of the messages for every key in the bag. * * @param null|string $format - * @return array */ public function all($format = null): array; /** * Get the raw messages in the container. - * - * @return array */ public function getMessages(): array; /** * Get the default message format. - * - * @return string */ public function getFormat(): string; /** * Set the default message format. * - * @param string $format * @return $this */ public function setFormat(string $format = ':message'); /** * Determine if the message bag has any messages. - * - * @return bool */ public function isEmpty(): bool; /** * Determine if the message bag has any messages. - * - * @return bool */ public function isNotEmpty(): bool; /** * Get the number of messages in the container. - * - * @return int */ public function count(): int; } diff --git a/src/validation/src/Contracts/Validation/Factory.php b/src/validation/src/Contracts/Validation/Factory.php index d68d7cf4b..197d22e82 100755 --- a/src/validation/src/Contracts/Validation/Factory.php +++ b/src/validation/src/Contracts/Validation/Factory.php @@ -17,10 +17,6 @@ interface Factory /** * Create a new Validator instance. * - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes * @return \Hyperf\Validation\Contracts\Validation\Validator */ public function make(array $data, array $rules, array $messages = [], array $customAttributes = []); @@ -28,7 +24,6 @@ interface Factory /** * Register a custom validator extension. * - * @param string $rule * @param \Closure|string $extension * @param null|string $message */ @@ -37,7 +32,6 @@ interface Factory /** * Register a custom implicit validator extension. * - * @param string $rule * @param \Closure|string $extension * @param null|string $message */ @@ -46,7 +40,6 @@ interface Factory /** * Register a custom implicit validator message replacer. * - * @param string $rule * @param \Closure|string $replacer */ public function replacer(string $rule, $replacer); diff --git a/src/validation/src/Contracts/Validation/Rule.php b/src/validation/src/Contracts/Validation/Rule.php index b3050999d..5faef9d8b 100755 --- a/src/validation/src/Contracts/Validation/Rule.php +++ b/src/validation/src/Contracts/Validation/Rule.php @@ -17,9 +17,7 @@ interface Rule /** * Determine if the validation rule passes. * - * @param string $attribute * @param mixed $value - * @return bool */ public function passes(string $attribute, $value): bool; diff --git a/src/validation/src/Contracts/Validation/Validator.php b/src/validation/src/Contracts/Validation/Validator.php index 69fa2d713..13624d1f8 100755 --- a/src/validation/src/Contracts/Validation/Validator.php +++ b/src/validation/src/Contracts/Validation/Validator.php @@ -19,29 +19,21 @@ interface Validator extends MessageProvider { /** * Run the validator's rules against its data. - * - * @return array */ public function validate(): array; /** * Get the attributes and values that were validated. - * - * @return array */ public function validated(): array; /** * Determine if the data fails the validation rules. - * - * @return bool */ public function fails(): bool; /** * Get the failed validation rules. - * - * @return array */ public function failed(): array; @@ -50,7 +42,6 @@ interface Validator extends MessageProvider * * @param array|string $attribute * @param array|string $rules - * @param callable $callback * @return $this */ public function sometimes($attribute, $rules, callable $callback); diff --git a/src/validation/src/DatabasePresenceVerifier.php b/src/validation/src/DatabasePresenceVerifier.php index bf79b9109..2fdbd7447 100755 --- a/src/validation/src/DatabasePresenceVerifier.php +++ b/src/validation/src/DatabasePresenceVerifier.php @@ -45,13 +45,9 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface /** * Count the number of objects in a collection having the given value. * - * @param string $collection - * @param string $column * @param string $value * @param null|int $excludeId * @param null|string $idColumn - * @param array $extra - * @return int */ public function getCount(string $collection, string $column, $value, $excludeId = null, $idColumn = null, array $extra = []): int { @@ -66,12 +62,6 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface /** * Count the number of objects in a collection with the given values. - * - * @param string $collection - * @param string $column - * @param array $values - * @param array $extra - * @return int */ public function getMultiCount(string $collection, string $column, array $values, array $extra = []): int { @@ -83,7 +73,6 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface /** * Get a query builder for the given table. * - * @param string $table * @return \Hyperf\Database\Query\Builder */ public function table(string $table) @@ -93,10 +82,8 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface /** * Set the connection to be used. - * - * @param string $connection */ - public function setConnection($connection) + public function setConnection(string $connection) { $this->connection = $connection; } @@ -105,7 +92,6 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface * Add the given conditions to the query. * * @param \Hyperf\Database\Query\Builder $query - * @param array $conditions * @return \Hyperf\Database\Query\Builder */ protected function addConditions($query, array $conditions) @@ -127,7 +113,6 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface * Add a "where" clause to the given query. * * @param \Hyperf\Database\Query\Builder $query - * @param string $key * @param string $extraValue */ protected function addWhere($query, string $key, $extraValue) diff --git a/src/validation/src/Factory.php b/src/validation/src/Factory.php index 1907f6db0..85559940f 100755 --- a/src/validation/src/Factory.php +++ b/src/validation/src/Factory.php @@ -95,10 +95,6 @@ class Factory implements FactoryContract /** * Create a new Validator instance. * - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes * @return \Hyperf\Validation\Validator */ public function make(array $data, array $rules, array $messages = [], array $customAttributes = []) @@ -132,12 +128,7 @@ class Factory implements FactoryContract /** * Validate the given data against the provided rules. * - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes * @throws \Hyperf\Validation\ValidationException - * @return array */ public function validate(array $data, array $rules, array $messages = [], array $customAttributes = []): array { @@ -147,7 +138,6 @@ class Factory implements FactoryContract /** * Register a custom validator extension. * - * @param string $rule * @param \Closure|string $extension * @param null|string $message */ @@ -163,7 +153,6 @@ class Factory implements FactoryContract /** * Register a custom implicit validator extension. * - * @param string $rule * @param \Closure|string $extension * @param null|string $message */ @@ -179,7 +168,6 @@ class Factory implements FactoryContract /** * Register a custom dependent validator extension. * - * @param string $rule * @param \Closure|string $extension * @param null|string $message */ @@ -195,7 +183,6 @@ class Factory implements FactoryContract /** * Register a custom validator message replacer. * - * @param string $rule * @param \Closure|string $replacer */ public function replacer(string $rule, $replacer) @@ -235,8 +222,6 @@ class Factory implements FactoryContract /** * Set the Presence Verifier implementation. - * - * @param \Hyperf\Validation\PresenceVerifierInterface $presenceVerifier */ public function setPresenceVerifier(PresenceVerifierInterface $presenceVerifier) { @@ -246,10 +231,6 @@ class Factory implements FactoryContract /** * Resolve a new Validator instance. * - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes * @return \Hyperf\Validation\Validator */ protected function resolve(array $data, array $rules, array $messages, array $customAttributes) @@ -263,8 +244,6 @@ class Factory implements FactoryContract /** * Add the extensions to a validator instance. - * - * @param \Hyperf\Validation\Validator $validator */ protected function addExtensions(Validator $validator) { diff --git a/src/validation/src/PresenceVerifierInterface.php b/src/validation/src/PresenceVerifierInterface.php index a711c4530..cc5ded6c6 100755 --- a/src/validation/src/PresenceVerifierInterface.php +++ b/src/validation/src/PresenceVerifierInterface.php @@ -17,24 +17,13 @@ interface PresenceVerifierInterface /** * Count the number of objects in a collection having the given value. * - * @param string $collection - * @param string $column - * @param string $value * @param null|int $excludeId * @param null|string $idColumn - * @param array $extra - * @return int */ public function getCount(string $collection, string $column, string $value, $excludeId = null, $idColumn = null, array $extra = []): int; /** * Count the number of objects in a collection with the given values. - * - * @param string $collection - * @param string $column - * @param array $values - * @param array $extra - * @return int */ public function getMultiCount(string $collection, string $column, array $values, array $extra = []): int; } diff --git a/src/validation/src/Request/FormRequest.php b/src/validation/src/Request/FormRequest.php index d968b22f1..54b24dc4f 100755 --- a/src/validation/src/Request/FormRequest.php +++ b/src/validation/src/Request/FormRequest.php @@ -14,7 +14,6 @@ namespace Hyperf\Validation\Request; use Hyperf\HttpServer\Request; use Hyperf\Utils\Context; -use Hyperf\Validation\Contracts\Validation\Factory; use Hyperf\Validation\Contracts\Validation\Factory as ValidationFactory; use Hyperf\Validation\Contracts\Validation\ValidatesWhenResolved; use Hyperf\Validation\Contracts\Validation\Validator; @@ -56,7 +55,6 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Get the proper failed validation response for the request. * - * @param array $errors * @return ResponseInterface */ public function response() @@ -69,20 +67,16 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Get custom messages for validator errors. - * - * @return array */ - public function messages() + public function messages(): array { return []; } /** * Get custom attributes for validator errors. - * - * @return array */ - public function attributes() + public function attributes(): array { return []; } @@ -90,7 +84,6 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Set the container implementation. * - * @param ContainerInterface $container * @return $this */ public function setContainer(ContainerInterface $container) @@ -125,7 +118,6 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Create the default validator instance. * - * @param Factory $factory * @return \Hyperf\Validation\Contracts\Validation\Validator */ protected function createDefaultValidator(ValidationFactory $factory) @@ -151,8 +143,6 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Handle a failed validation attempt. * - * @param Validator $validator - * * @throws ValidationException */ protected function failedValidation(Validator $validator) @@ -162,11 +152,8 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Format the errors from the given Validator instance. - * - * @param Validator $validator - * @return array */ - protected function formatErrors(Validator $validator) + protected function formatErrors(Validator $validator): array { return $validator->getMessageBag()->toArray(); } @@ -187,8 +174,6 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Handle a failed authorization attempt. - * - * @throws \Illuminate\Auth\Access\AuthorizationException */ protected function failedAuthorization() { From 0983e9ffa69b12f81216f9af5209905a0818dca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 31 Aug 2019 20:22:34 +0800 Subject: [PATCH 59/79] Update ValidatesAttributes.php --- src/validation/src/Concerns/ValidatesAttributes.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/validation/src/Concerns/ValidatesAttributes.php b/src/validation/src/Concerns/ValidatesAttributes.php index 79c827a27..fafa8726f 100755 --- a/src/validation/src/Concerns/ValidatesAttributes.php +++ b/src/validation/src/Concerns/ValidatesAttributes.php @@ -1179,8 +1179,9 @@ trait ValidatesAttributes * Get the date timestamp. * * @param mixed $value + * @return bool|int */ - protected function getDateTimestamp($value): int + protected function getDateTimestamp($value) { if ($value instanceof DateTimeInterface) { return $value->getTimestamp(); @@ -1524,7 +1525,7 @@ trait ValidatesAttributes /** * Parse named parameters to $key => $value items. */ - protected function parseNamedParameters(array $parameters): array + protected function parseNamedParameters(array $parameters): ?array { return array_reduce($parameters, function ($result, $item) { [$key, $value] = array_pad(explode('=', $item, 2), 2, null); From 6f7fe2fbbce803a8e0c867fcf1065afcc4d7b476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 31 Aug 2019 20:33:26 +0800 Subject: [PATCH 60/79] Moved requestCommand into devtool. --- .../src/Request => devtool/src/Generator}/RequestCommand.php | 5 ++--- .../src/Generator/stubs/validation-request.stub} | 0 src/validation/src/DatabasePresenceVerifier.php | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) rename src/{validation/src/Request => devtool/src/Generator}/RequestCommand.php (81%) rename src/{validation/src/Request/stubs/request.stub => devtool/src/Generator/stubs/validation-request.stub} (100%) diff --git a/src/validation/src/Request/RequestCommand.php b/src/devtool/src/Generator/RequestCommand.php similarity index 81% rename from src/validation/src/Request/RequestCommand.php rename to src/devtool/src/Generator/RequestCommand.php index 35187dd96..4266ceabf 100644 --- a/src/validation/src/Request/RequestCommand.php +++ b/src/devtool/src/Generator/RequestCommand.php @@ -10,10 +10,9 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Validation\Request; +namespace Hyperf\Devtool\Generator; use Hyperf\Command\Annotation\Command; -use Hyperf\Devtool\Generator\GeneratorCommand; /** * Class RequestCommand. @@ -29,7 +28,7 @@ class RequestCommand extends GeneratorCommand protected function getStub(): string { - return $this->getConfig()['stub'] ?? __DIR__ . '/stubs/request.stub'; + return $this->getConfig()['stub'] ?? __DIR__ . '/stubs/validation-request.stub'; } protected function getDefaultNamespace(): string diff --git a/src/validation/src/Request/stubs/request.stub b/src/devtool/src/Generator/stubs/validation-request.stub similarity index 100% rename from src/validation/src/Request/stubs/request.stub rename to src/devtool/src/Generator/stubs/validation-request.stub diff --git a/src/validation/src/DatabasePresenceVerifier.php b/src/validation/src/DatabasePresenceVerifier.php index 2fdbd7447..07d73de0f 100755 --- a/src/validation/src/DatabasePresenceVerifier.php +++ b/src/validation/src/DatabasePresenceVerifier.php @@ -83,7 +83,7 @@ class DatabasePresenceVerifier implements PresenceVerifierInterface /** * Set the connection to be used. */ - public function setConnection(string $connection) + public function setConnection(?string $connection) { $this->connection = $connection; } From 77b7549186ccba15e32286383870fa5a64eda460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 31 Aug 2019 20:47:29 +0800 Subject: [PATCH 61/79] Fixed devtool config. --- src/devtool/publish/devtool.php | 5 +- src/devtool/src/Generator/RequestCommand.php | 2 +- src/validation/src/Rule.php | 3 - src/validation/src/Rules/DatabaseRule.php | 15 --- src/validation/src/Rules/Dimensions.php | 11 --- src/validation/src/Rules/Exists.php | 2 - src/validation/src/Rules/In.php | 4 - src/validation/src/Rules/NotIn.php | 4 - src/validation/src/Rules/RequiredIf.php | 2 - src/validation/src/Rules/Unique.php | 2 - src/validation/src/Support/MessageBag.php | 48 --------- .../src/ValidatesWhenResolvedTrait.php | 4 - src/validation/src/ValidationData.php | 14 --- src/validation/src/ValidationException.php | 7 -- src/validation/src/ValidationRuleParser.php | 29 ------ src/validation/src/Validator.php | 98 ------------------- 16 files changed, 5 insertions(+), 245 deletions(-) diff --git a/src/devtool/publish/devtool.php b/src/devtool/publish/devtool.php index 1c72812a8..06edeab9a 100644 --- a/src/devtool/publish/devtool.php +++ b/src/devtool/publish/devtool.php @@ -38,8 +38,11 @@ return [ 'middleware' => [ 'namespace' => 'App\\Middleware', ], - 'Process' => [ + 'process' => [ 'namespace' => 'App\\Process', ], + 'request' => [ + 'namespace' => 'App\\Request', + ], ], ]; diff --git a/src/devtool/src/Generator/RequestCommand.php b/src/devtool/src/Generator/RequestCommand.php index 4266ceabf..12119e048 100644 --- a/src/devtool/src/Generator/RequestCommand.php +++ b/src/devtool/src/Generator/RequestCommand.php @@ -33,6 +33,6 @@ class RequestCommand extends GeneratorCommand protected function getDefaultNamespace(): string { - return $this->getConfig()['namespace'] ?? 'App\\Requests'; + return $this->getConfig()['namespace'] ?? 'App\\Request'; } } diff --git a/src/validation/src/Rule.php b/src/validation/src/Rule.php index 538cc4cf2..8254362db 100755 --- a/src/validation/src/Rule.php +++ b/src/validation/src/Rule.php @@ -22,7 +22,6 @@ class Rule /** * Get a dimensions constraint builder instance. * - * @param array $constraints * @return \Hyperf\Validation\Rules\Dimensions */ public static function dimensions(array $constraints = []) @@ -33,8 +32,6 @@ class Rule /** * Get a exists constraint builder instance. * - * @param string $table - * @param string $column * @return \Hyperf\Validation\Rules\Exists */ public static function exists(string $table, string $column = 'NULL') diff --git a/src/validation/src/Rules/DatabaseRule.php b/src/validation/src/Rules/DatabaseRule.php index 588cfb978..9223e0380 100755 --- a/src/validation/src/Rules/DatabaseRule.php +++ b/src/validation/src/Rules/DatabaseRule.php @@ -46,9 +46,6 @@ trait DatabaseRule /** * Create a new rule instance. - * - * @param string $table - * @param string $column */ public function __construct(string $table, string $column = 'NULL') { @@ -81,7 +78,6 @@ trait DatabaseRule /** * Set a "where not" constraint on the query. * - * @param string $column * @param array|string $value * @return $this */ @@ -97,7 +93,6 @@ trait DatabaseRule /** * Set a "where null" constraint on the query. * - * @param string $column * @return $this */ public function whereNull(string $column) @@ -108,7 +103,6 @@ trait DatabaseRule /** * Set a "where not null" constraint on the query. * - * @param string $column * @return $this */ public function whereNotNull(string $column) @@ -119,8 +113,6 @@ trait DatabaseRule /** * Set a "where in" constraint on the query. * - * @param string $column - * @param array $values * @return $this */ public function whereIn(string $column, array $values) @@ -133,8 +125,6 @@ trait DatabaseRule /** * Set a "where not in" constraint on the query. * - * @param string $column - * @param array $values * @return $this */ public function whereNotIn(string $column, array $values) @@ -147,7 +137,6 @@ trait DatabaseRule /** * Register a custom query callback. * - * @param \Closure $callback * @return $this */ public function using(Closure $callback) @@ -159,8 +148,6 @@ trait DatabaseRule /** * Get the custom query callbacks for the rule. - * - * @return array */ public function queryCallbacks(): array { @@ -169,8 +156,6 @@ trait DatabaseRule /** * Format the where clauses. - * - * @return string */ protected function formatWheres(): string { diff --git a/src/validation/src/Rules/Dimensions.php b/src/validation/src/Rules/Dimensions.php index 060d10e11..5a2f98f0f 100755 --- a/src/validation/src/Rules/Dimensions.php +++ b/src/validation/src/Rules/Dimensions.php @@ -23,8 +23,6 @@ class Dimensions /** * Create a new dimensions rule instance. - * - * @param array $constraints; */ public function __construct(array $constraints = []) { @@ -33,8 +31,6 @@ class Dimensions /** * Convert the rule to a validation string. - * - * @return string */ public function __toString(): string { @@ -50,7 +46,6 @@ class Dimensions /** * Set the "width" constraint. * - * @param int $value * @return $this */ public function width(int $value) @@ -63,7 +58,6 @@ class Dimensions /** * Set the "height" constraint. * - * @param int $value * @return $this */ public function height(int $value) @@ -76,7 +70,6 @@ class Dimensions /** * Set the "min width" constraint. * - * @param int $value * @return $this */ public function minWidth(int $value) @@ -89,7 +82,6 @@ class Dimensions /** * Set the "min height" constraint. * - * @param int $value * @return $this */ public function minHeight(int $value) @@ -102,7 +94,6 @@ class Dimensions /** * Set the "max width" constraint. * - * @param int $value * @return $this */ public function maxWidth(int $value) @@ -115,7 +106,6 @@ class Dimensions /** * Set the "max height" constraint. * - * @param int $value * @return $this */ public function maxHeight(int $value) @@ -128,7 +118,6 @@ class Dimensions /** * Set the "ratio" constraint. * - * @param float $value * @return $this */ public function ratio(float $value) diff --git a/src/validation/src/Rules/Exists.php b/src/validation/src/Rules/Exists.php index 491fb2445..da2acc38d 100755 --- a/src/validation/src/Rules/Exists.php +++ b/src/validation/src/Rules/Exists.php @@ -18,8 +18,6 @@ class Exists /** * Convert the rule to a validation string. - * - * @return string */ public function __toString(): string { diff --git a/src/validation/src/Rules/In.php b/src/validation/src/Rules/In.php index 39998a4b5..9ae3f1441 100755 --- a/src/validation/src/Rules/In.php +++ b/src/validation/src/Rules/In.php @@ -28,8 +28,6 @@ class In /** * Create a new in rule instance. - * - * @param array $values */ public function __construct(array $values) { @@ -39,8 +37,6 @@ class In /** * Convert the rule to a validation string. * - * @return string - * * @see \Hyperf\Validation\ValidationRuleParser::parseParameters */ public function __toString(): string diff --git a/src/validation/src/Rules/NotIn.php b/src/validation/src/Rules/NotIn.php index 3ff3eaa9b..21089b5b5 100755 --- a/src/validation/src/Rules/NotIn.php +++ b/src/validation/src/Rules/NotIn.php @@ -28,8 +28,6 @@ class NotIn /** * Create a new "not in" rule instance. - * - * @param array $values */ public function __construct(array $values) { @@ -38,8 +36,6 @@ class NotIn /** * Convert the rule to a validation string. - * - * @return string */ public function __toString(): string { diff --git a/src/validation/src/Rules/RequiredIf.php b/src/validation/src/Rules/RequiredIf.php index f7f8e5fd4..12411d31b 100755 --- a/src/validation/src/Rules/RequiredIf.php +++ b/src/validation/src/Rules/RequiredIf.php @@ -33,8 +33,6 @@ class RequiredIf /** * Convert the rule to a validation string. - * - * @return string */ public function __toString(): string { diff --git a/src/validation/src/Rules/Unique.php b/src/validation/src/Rules/Unique.php index 8a7972183..2e750ffe1 100755 --- a/src/validation/src/Rules/Unique.php +++ b/src/validation/src/Rules/Unique.php @@ -34,8 +34,6 @@ class Unique /** * Convert the rule to a validation string. - * - * @return string */ public function __toString(): string { diff --git a/src/validation/src/Support/MessageBag.php b/src/validation/src/Support/MessageBag.php index ed25d6de1..686acb4d7 100755 --- a/src/validation/src/Support/MessageBag.php +++ b/src/validation/src/Support/MessageBag.php @@ -39,8 +39,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Create a new message bag instance. - * - * @param array $messages */ public function __construct(array $messages = []) { @@ -53,8 +51,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Convert the message bag to its string representation. - * - * @return string */ public function __toString(): string { @@ -63,8 +59,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the keys present in the message bag. - * - * @return array */ public function keys(): array { @@ -74,8 +68,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Add a message to the message bag. * - * @param string $key - * @param string $message * @return $this */ public function add(string $key, string $message) @@ -108,7 +100,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me * Determine if messages exist for all of the given keys. * * @param array|string $key - * @return bool */ public function has($key): bool { @@ -135,7 +126,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me * Determine if messages exist for any of the given keys. * * @param array|string $keys - * @return bool */ public function hasAny($keys = []): bool { @@ -159,7 +149,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me * * @param string $key * @param string $format - * @return string */ public function first($key = null, $format = null): string { @@ -173,9 +162,7 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get all of the messages from the message bag for a given key. * - * @param string $key * @param string $format - * @return array */ public function get(string $key, $format = null): array { @@ -201,7 +188,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me * Get all of the messages for every key in the message bag. * * @param string $format - * @return array */ public function all($format = null): array { @@ -220,7 +206,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me * Get all of the unique messages for every key in the message bag. * * @param string $format - * @return array */ public function unique($format = null): array { @@ -229,8 +214,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the raw messages in the message bag. - * - * @return array */ public function messages(): array { @@ -239,8 +222,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the raw messages in the message bag. - * - * @return array */ public function getMessages(): array { @@ -259,8 +240,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the default message format. - * - * @return string */ public function getFormat(): string { @@ -270,7 +249,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Set the default message format. * - * @param string $format * @return MessageBag */ public function setFormat(string $format = ':message') @@ -282,8 +260,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Determine if the message bag has any messages. - * - * @return bool */ public function isEmpty(): bool { @@ -292,8 +268,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Determine if the message bag has any messages. - * - * @return bool */ public function isNotEmpty(): bool { @@ -302,8 +276,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Determine if the message bag has any messages. - * - * @return bool */ public function any(): bool { @@ -312,8 +284,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the number of messages in the message bag. - * - * @return int */ public function count(): int { @@ -322,8 +292,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the instance as an array. - * - * @return array */ public function toArray(): array { @@ -332,8 +300,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Convert the object into something JSON serializable. - * - * @return array */ public function jsonSerialize(): array { @@ -342,9 +308,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Convert the object to its JSON representation. - * - * @param int $options - * @return string */ public function toJson(int $options = 0): string { @@ -353,10 +316,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Determine if a key and message combination already exists. - * - * @param string $key - * @param string $message - * @return bool */ protected function isUnique(string $key, string $message): bool { @@ -368,9 +327,7 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Get the messages for a wildcard key. * - * @param string $key * @param null|string $format - * @return array */ protected function getMessagesForWildcardKey(string $key, $format): array { @@ -389,11 +346,6 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me /** * Format an array of messages. - * - * @param array $messages - * @param string $format - * @param string $messageKey - * @return array */ protected function transform(array $messages, string $format, string $messageKey): array { diff --git a/src/validation/src/ValidatesWhenResolvedTrait.php b/src/validation/src/ValidatesWhenResolvedTrait.php index 4ed0e02b2..79aa93186 100755 --- a/src/validation/src/ValidatesWhenResolvedTrait.php +++ b/src/validation/src/ValidatesWhenResolvedTrait.php @@ -56,8 +56,6 @@ trait ValidatesWhenResolvedTrait /** * Handle a failed validation attempt. * - * @param \Hyperf\Validation\Contracts\Validation\Validator $validator - * * @throws \Hyperf\Validation\ValidationException */ protected function failedValidation(Validator $validator) @@ -67,8 +65,6 @@ trait ValidatesWhenResolvedTrait /** * Determine if the request passes the authorization check. - * - * @return bool */ protected function passesAuthorization(): bool { diff --git a/src/validation/src/ValidationData.php b/src/validation/src/ValidationData.php index 1e6a10b7e..8d6f6451f 100755 --- a/src/validation/src/ValidationData.php +++ b/src/validation/src/ValidationData.php @@ -19,10 +19,6 @@ class ValidationData { /** * Initialize and gather data for given attribute. - * - * @param string $attribute - * @param array $masterData - * @return array */ public static function initializeAndGatherData(string $attribute, array $masterData): array { @@ -41,8 +37,6 @@ class ValidationData * Used to extract a sub-section of the data for faster iteration. * * @param string $attribute - * @param array $masterData - * @return array */ public static function extractDataFromPath($attribute, array $masterData): array { @@ -64,7 +58,6 @@ class ValidationData * * Allows us to not spin through all of the flattened data for some operations. * - * @param string $attribute * @return string */ public static function getLeadingExplicitAttributePath(string $attribute) @@ -75,8 +68,6 @@ class ValidationData /** * Gather a copy of the attribute data filled with any missing attributes. * - * @param string $attribute - * @param array $masterData * @return array */ protected static function initializeAttributeOnData(string $attribute, array $masterData) @@ -94,11 +85,6 @@ class ValidationData /** * Get all of the exact attribute values for a given wildcard attribute. - * - * @param array $masterData - * @param array $data - * @param string $attribute - * @return array */ protected static function extractValuesForWildcards(array $masterData, array $data, string $attribute): array { diff --git a/src/validation/src/ValidationException.php b/src/validation/src/ValidationException.php index 0531b3a99..d0c1dfd21 100755 --- a/src/validation/src/ValidationException.php +++ b/src/validation/src/ValidationException.php @@ -58,7 +58,6 @@ class ValidationException extends ServerException * * @param \Hyperf\Validation\Contracts\Validation\Validator $validator * @param null|ResponseInterface $response - * @param string $errorBag */ public function __construct($validator, $response = null, string $errorBag = 'default') { @@ -72,7 +71,6 @@ class ValidationException extends ServerException /** * Create a new validation exception from a plain array of messages. * - * @param array $messages * @return static */ public static function withMessages(array $messages) @@ -88,8 +86,6 @@ class ValidationException extends ServerException /** * Get all of the validation error messages. - * - * @return array */ public function errors(): array { @@ -99,7 +95,6 @@ class ValidationException extends ServerException /** * Set the HTTP status code to be used for the response. * - * @param int $status * @return $this */ public function status(int $status) @@ -112,7 +107,6 @@ class ValidationException extends ServerException /** * Set the error bag on the exception. * - * @param string $errorBag * @return $this */ public function errorBag(string $errorBag) @@ -125,7 +119,6 @@ class ValidationException extends ServerException /** * Set the URL to redirect to on a validation error. * - * @param string $url * @return $this */ public function redirectTo(string $url) diff --git a/src/validation/src/ValidationRuleParser.php b/src/validation/src/ValidationRuleParser.php index 1961a503e..8218a5a96 100755 --- a/src/validation/src/ValidationRuleParser.php +++ b/src/validation/src/ValidationRuleParser.php @@ -37,8 +37,6 @@ class ValidationRuleParser /** * Create a new validation rule parser. - * - * @param array $data */ public function __construct(array $data) { @@ -48,7 +46,6 @@ class ValidationRuleParser /** * Parse the human-friendly rules into a full rules array for the validator. * - * @param array $rules * @return \stdClass */ public function explode(array $rules) @@ -66,10 +63,8 @@ class ValidationRuleParser /** * Merge additional rules into a given attribute(s). * - * @param array $results * @param array|string $attribute * @param array|string $rules - * @return array */ public function mergeRules(array $results, $attribute, $rules = []): array { @@ -92,7 +87,6 @@ class ValidationRuleParser * Extract the rule name and parameters from a rule. * * @param array|string $rules - * @return array */ public static function parse($rules): array { @@ -113,9 +107,6 @@ class ValidationRuleParser /** * Explode the rules into an array of explicit rules. - * - * @param array $rules - * @return array */ protected function explodeRules(array $rules): array { @@ -136,7 +127,6 @@ class ValidationRuleParser * Explode the explicit rule into an array if necessary. * * @param mixed $rule - * @return array */ protected function explodeExplicitRule($rule): array { @@ -175,10 +165,7 @@ class ValidationRuleParser /** * Define a set of rules that apply to each element in an array attribute. * - * @param array $results - * @param string $attribute * @param array|string $rules - * @return array */ protected function explodeWildcardRules(array $results, string $attribute, $rules): array { @@ -202,10 +189,7 @@ class ValidationRuleParser /** * Merge additional rules into a given attribute. * - * @param array $results - * @param string $attribute * @param array|string $rules - * @return array */ protected function mergeRulesForAttribute(array $results, string $attribute, $rules): array { @@ -221,9 +205,6 @@ class ValidationRuleParser /** * Parse an array based rule. - * - * @param array $rules - * @return array */ protected static function parseArrayRule(array $rules): array { @@ -232,9 +213,6 @@ class ValidationRuleParser /** * Parse a string based rule. - * - * @param string $rules - * @return array */ protected static function parseStringRule(string $rules): array { @@ -254,10 +232,6 @@ class ValidationRuleParser /** * Parse a parameter list. - * - * @param string $rule - * @param string $parameter - * @return array */ protected static function parseParameters(string $rule, string $parameter): array { @@ -272,9 +246,6 @@ class ValidationRuleParser /** * Normalizes a rule so that we can accept short types. - * - * @param string $rule - * @return string */ protected static function normalizeRule(string $rule): string { diff --git a/src/validation/src/Validator.php b/src/validation/src/Validator.php index 1f52d4b72..9a9433481 100755 --- a/src/validation/src/Validator.php +++ b/src/validation/src/Validator.php @@ -204,12 +204,6 @@ class Validator implements ValidatorContract /** * Create a new Validator instance. - * - * @param TranslatorInterface $translator - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes */ public function __construct( TranslatorInterface $translator, @@ -252,9 +246,6 @@ class Validator implements ValidatorContract /** * Parse the data array, converting dots to ->. - * - * @param array $data - * @return array */ public function parseData(array $data): array { @@ -295,8 +286,6 @@ class Validator implements ValidatorContract /** * Determine if the data passes the validation rules. - * - * @return bool */ public function passes(): bool { @@ -331,8 +320,6 @@ class Validator implements ValidatorContract /** * Determine if the data fails the validation rules. - * - * @return bool */ public function fails(): bool { @@ -343,7 +330,6 @@ class Validator implements ValidatorContract * Run the validator's rules against its data. * * @throws \Hyperf\Validation\ValidationException - * @return array */ public function validate(): array { @@ -358,7 +344,6 @@ class Validator implements ValidatorContract * Get the attributes and values that were validated. * * @throws \Hyperf\Validation\ValidationException - * @return array */ public function validated(): array { @@ -383,10 +368,6 @@ class Validator implements ValidatorContract /** * Add a failed rule and error message to the collection. - * - * @param string $attribute - * @param string $rule - * @param array $parameters */ public function addFailure(string $attribute, string $rule, array $parameters = []) { @@ -406,8 +387,6 @@ class Validator implements ValidatorContract /** * Returns the data which was valid. - * - * @return array */ public function valid(): array { @@ -423,8 +402,6 @@ class Validator implements ValidatorContract /** * Returns the data which was invalid. - * - * @return array */ public function invalid(): array { @@ -440,8 +417,6 @@ class Validator implements ValidatorContract /** * Get the failed validation rules. - * - * @return array */ public function failed(): array { @@ -485,9 +460,7 @@ class Validator implements ValidatorContract /** * Determine if the given attribute has a rule in the given set. * - * @param string $attribute * @param array|string $rules - * @return bool */ public function hasRule(string $attribute, $rules): bool { @@ -496,8 +469,6 @@ class Validator implements ValidatorContract /** * Get the data under validation. - * - * @return array */ public function attributes(): array { @@ -506,8 +477,6 @@ class Validator implements ValidatorContract /** * Get the data under validation. - * - * @return array */ public function getData(): array { @@ -517,7 +486,6 @@ class Validator implements ValidatorContract /** * Set the data under validation. * - * @param array $data * @return $this */ public function setData(array $data) @@ -531,8 +499,6 @@ class Validator implements ValidatorContract /** * Get the validation rules. - * - * @return array */ public function getRules(): array { @@ -542,7 +508,6 @@ class Validator implements ValidatorContract /** * Set the validation rules. * - * @param array $rules * @return $this */ public function setRules(array $rules) @@ -558,8 +523,6 @@ class Validator implements ValidatorContract /** * Parse the given rules and merge them into current rules. - * - * @param array $rules */ public function addRules(array $rules) { @@ -585,7 +548,6 @@ class Validator implements ValidatorContract * * @param array|string $attribute * @param array|string $rules - * @param callable $callback * @return $this */ public function sometimes($attribute, $rules, callable $callback) @@ -603,8 +565,6 @@ class Validator implements ValidatorContract /** * Register an array of custom validator extensions. - * - * @param array $extensions */ public function addExtensions(array $extensions) { @@ -619,8 +579,6 @@ class Validator implements ValidatorContract /** * Register an array of custom implicit validator extensions. - * - * @param array $extensions */ public function addImplicitExtensions(array $extensions) { @@ -633,8 +591,6 @@ class Validator implements ValidatorContract /** * Register an array of custom implicit validator extensions. - * - * @param array $extensions */ public function addDependentExtensions(array $extensions) { @@ -648,7 +604,6 @@ class Validator implements ValidatorContract /** * Register a custom validator extension. * - * @param string $rule * @param \Closure|string $extension */ public function addExtension(string $rule, $extension) @@ -659,7 +614,6 @@ class Validator implements ValidatorContract /** * Register a custom implicit validator extension. * - * @param string $rule * @param \Closure|string $extension */ public function addImplicitExtension(string $rule, $extension) @@ -672,7 +626,6 @@ class Validator implements ValidatorContract /** * Register a custom dependent validator extension. * - * @param string $rule * @param \Closure|string $extension */ public function addDependentExtension(string $rule, $extension) @@ -684,8 +637,6 @@ class Validator implements ValidatorContract /** * Register an array of custom validator message replacers. - * - * @param array $replacers */ public function addReplacers(array $replacers) { @@ -701,7 +652,6 @@ class Validator implements ValidatorContract /** * Register a custom validator message replacer. * - * @param string $rule * @param \Closure|string $replacer */ public function addReplacer(string $rule, $replacer) @@ -712,7 +662,6 @@ class Validator implements ValidatorContract /** * Set the custom messages for the validator. * - * @param array $messages * @return $this */ public function setCustomMessages(array $messages) @@ -725,7 +674,6 @@ class Validator implements ValidatorContract /** * Set the custom attributes on the validator. * - * @param array $attributes * @return $this */ public function setAttributeNames(array $attributes) @@ -738,7 +686,6 @@ class Validator implements ValidatorContract /** * Add custom attributes to the validator. * - * @param array $customAttributes * @return $this */ public function addCustomAttributes(array $customAttributes) @@ -751,7 +698,6 @@ class Validator implements ValidatorContract /** * Set the custom values on the validator. * - * @param array $values * @return $this */ public function setValueNames(array $values) @@ -764,7 +710,6 @@ class Validator implements ValidatorContract /** * Add the custom values for the validator. * - * @param array $customValues * @return $this */ public function addCustomValues(array $customValues) @@ -776,8 +721,6 @@ class Validator implements ValidatorContract /** * Set the fallback messages for the validator. - * - * @param array $messages */ public function setFallbackMessages(array $messages) { @@ -815,8 +758,6 @@ class Validator implements ValidatorContract /** * Set the Presence Verifier implementation. - * - * @param \Hyperf\Validation\PresenceVerifierInterface $presenceVerifier */ public function setPresenceVerifier(PresenceVerifierInterface $presenceVerifier) { @@ -835,8 +776,6 @@ class Validator implements ValidatorContract /** * Set the Translator implementation. - * - * @param TranslatorInterface $translator */ public function setTranslator(TranslatorInterface $translator) { @@ -845,8 +784,6 @@ class Validator implements ValidatorContract /** * Set the IoC container instance. - * - * @param Container $container */ public function setContainer(ContainerInterface $container) { @@ -910,7 +847,6 @@ class Validator implements ValidatorContract * Determine if the given rule depends on other fields. * * @param string $rule - * @return bool */ protected function dependsOnOtherFields($rule): bool { @@ -921,9 +857,6 @@ class Validator implements ValidatorContract * Get the explicit keys from an attribute flattened with dot notation. * * E.g. 'foo.1.bar.spark.baz' -> [1, 'spark'] for 'foo.*.bar.*.baz' - * - * @param string $attribute - * @return array */ protected function getExplicitKeys(string $attribute): array { @@ -942,9 +875,6 @@ class Validator implements ValidatorContract * Get the primary attribute name. * * For example, if "name.0" is given, "name.*" will be returned. - * - * @param string $attribute - * @return string */ protected function getPrimaryAttribute(string $attribute): string { @@ -959,10 +889,6 @@ class Validator implements ValidatorContract /** * Replace each field parameter which has asterisks with the given keys. - * - * @param array $parameters - * @param array $keys - * @return array */ protected function replaceAsterisksInParameters(array $parameters, array $keys): array { @@ -975,9 +901,7 @@ class Validator implements ValidatorContract * Determine if the attribute is validatable. * * @param object|string $rule - * @param string $attribute * @param mixed $value - * @return bool */ protected function isValidatable($rule, string $attribute, $value): bool { @@ -991,9 +915,7 @@ class Validator implements ValidatorContract * Determine if the field is present, or the rule implies required. * * @param object|string $rule - * @param string $attribute * @param mixed $value - * @return bool */ protected function presentOrRuleIsImplicit($rule, string $attribute, $value): bool { @@ -1009,7 +931,6 @@ class Validator implements ValidatorContract * Determine if a given rule implies the attribute is required. * * @param object|string $rule - * @return bool */ protected function isImplicit($rule): bool { @@ -1019,9 +940,6 @@ class Validator implements ValidatorContract /** * Determine if the attribute passes any optional check. - * - * @param string $attribute - * @return bool */ protected function passesOptionalCheck(string $attribute): bool { @@ -1039,8 +957,6 @@ class Validator implements ValidatorContract * Determine if the attribute fails the nullable check. * * @param string $rule - * @param string $attribute - * @return bool */ protected function isNotNullIfMarkedAsNullable($rule, string $attribute): bool { @@ -1057,8 +973,6 @@ class Validator implements ValidatorContract * This is to avoid possible database type comparison errors. * * @param string $rule - * @param string $attribute - * @return bool */ protected function hasNotFailedPreviousRuleIfPresenceRule($rule, string $attribute): bool { @@ -1068,7 +982,6 @@ class Validator implements ValidatorContract /** * Validate an attribute using a custom rule object. * - * @param string $attribute * @param mixed $value * @param \Hyperf\Validation\Contracts\Validation\Rule $rule */ @@ -1092,9 +1005,6 @@ class Validator implements ValidatorContract /** * Check if we should stop further validations on a given attribute. - * - * @param string $attribute - * @return bool */ protected function shouldStopValidating(string $attribute): bool { @@ -1117,8 +1027,6 @@ class Validator implements ValidatorContract /** * Generate an array of all attributes that have messages. - * - * @return array */ protected function attributesThatHaveMessages(): array { @@ -1130,7 +1038,6 @@ class Validator implements ValidatorContract /** * Get a rule and its parameters for a given attribute. * - * @param string $attribute * @param array|string $rules * @return null|array */ @@ -1154,7 +1061,6 @@ class Validator implements ValidatorContract /** * Get the value of a given attribute. * - * @param string $attribute * @return mixed */ protected function getValue(string $attribute) @@ -1165,8 +1071,6 @@ class Validator implements ValidatorContract /** * Call a custom validator extension. * - * @param string $rule - * @param array $parameters * @return null|bool */ protected function callExtension(string $rule, array $parameters) @@ -1184,8 +1088,6 @@ class Validator implements ValidatorContract /** * Call a class based validator extension. * - * @param string $callback - * @param array $parameters * @return bool */ protected function callClassBasedExtension(string $callback, array $parameters) From b81a48aef608ec908fec290e7d81c59f250bfca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Sun, 1 Sep 2019 22:35:45 +0800 Subject: [PATCH 62/79] Update DispatcherFactory.php --- src/http-server/src/Router/DispatcherFactory.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index 4b5332a8e..22edb7163 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -180,7 +180,9 @@ class DispatcherFactory } $path = $mapping->path; - if ($path[0] !== '/') { + if ($path === '') { + $path = $prefix; + } elseif ($path[0] !== '/') { $path = $prefix . '/' . $path; } $router->addRoute($mapping->methods, $path, [ From 593b4cc5b94daac4b4bd937d9b48e6f9fd5772f7 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 1 Sep 2019 22:39:53 +0800 Subject: [PATCH 63/79] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 073898333..93f07d545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Changed - [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Re-generate the `fillable` argument of Model when use `refresh-fillable` option, at the same time, the command will keep the `fillable` argument as default behaviours. +- [#501](https://github.com/hyperf-cloud/hyperf/pull/501) When the path argument of Mapping annotation is an empty string, then the path is equal to prefix of Controller annotation. ## Fixed From 48410609f533d47df7c4b4088091257112305016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 2 Sep 2019 13:38:05 +0800 Subject: [PATCH 64/79] Optimized code. --- src/devtool/src/Generator/RequestCommand.php | 1 - src/validation/src/Rules/Unique.php | 6 ++---- src/validation/src/ValidationRuleParser.php | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/devtool/src/Generator/RequestCommand.php b/src/devtool/src/Generator/RequestCommand.php index 12119e048..a5d306311 100644 --- a/src/devtool/src/Generator/RequestCommand.php +++ b/src/devtool/src/Generator/RequestCommand.php @@ -15,7 +15,6 @@ namespace Hyperf\Devtool\Generator; use Hyperf\Command\Annotation\Command; /** - * Class RequestCommand. * @Command */ class RequestCommand extends GeneratorCommand diff --git a/src/validation/src/Rules/Unique.php b/src/validation/src/Rules/Unique.php index 2e750ffe1..5ccd4151c 100755 --- a/src/validation/src/Rules/Unique.php +++ b/src/validation/src/Rules/Unique.php @@ -51,10 +51,9 @@ class Unique * Ignore the given ID during the unique check. * * @param mixed $id - * @param null|string $idColumn * @return $this */ - public function ignore($id, $idColumn = null) + public function ignore($id, ?string $idColumn = null) { if ($id instanceof Model) { return $this->ignoreModel($id, $idColumn); @@ -70,10 +69,9 @@ class Unique * Ignore the given model during the unique check. * * @param \Hyperf\Database\Model\Model $model - * @param null|string $idColumn * @return $this */ - public function ignoreModel($model, $idColumn = null) + public function ignoreModel($model, ?string $idColumn = null) { $this->idColumn = $idColumn ?? $model->getKeyName(); $this->ignore = $model->{$this->idColumn}; diff --git a/src/validation/src/ValidationRuleParser.php b/src/validation/src/ValidationRuleParser.php index 8218a5a96..0c1228cd1 100755 --- a/src/validation/src/ValidationRuleParser.php +++ b/src/validation/src/ValidationRuleParser.php @@ -69,7 +69,7 @@ class ValidationRuleParser public function mergeRules(array $results, $attribute, $rules = []): array { if (is_array($attribute)) { - foreach ((array) $attribute as $innerAttribute => $innerRules) { + foreach ($attribute as $innerAttribute => $innerRules) { $results = $this->mergeRulesForAttribute($results, $innerAttribute, $innerRules); } @@ -126,7 +126,7 @@ class ValidationRuleParser /** * Explode the explicit rule into an array if necessary. * - * @param mixed $rule + * @param array|object|string $rule */ protected function explodeExplicitRule($rule): array { @@ -208,7 +208,7 @@ class ValidationRuleParser */ protected static function parseArrayRule(array $rules): array { - return [Str::studly(trim((string) Arr::get($rules, (string) 0))), array_slice($rules, 1)]; + return [Str::studly(trim((string) Arr::get($rules, 0))), array_slice($rules, 1)]; } /** From 80b541edaba7dd58a0c9ac989f4f2f75234f3a72 Mon Sep 17 00:00:00 2001 From: hooklife Date: Mon, 2 Sep 2019 17:11:11 +0800 Subject: [PATCH 65/79] Fix namespace --- src/db-connection/src/Db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db-connection/src/Db.php b/src/db-connection/src/Db.php index 23e03b68a..ed9987be2 100644 --- a/src/db-connection/src/Db.php +++ b/src/db-connection/src/Db.php @@ -33,12 +33,12 @@ use Psr\Container\ContainerInterface; * @method static int affectingStatement(string $query, array $bindings = []) * @method static bool unprepared(string $query) * @method static array prepareBindings(array $bindings) - * @method static transaction(Closure $callback, int $attempts = 1) + * @method static transaction(\Closure $callback, int $attempts = 1) * @method static beginTransaction() * @method static rollBack() * @method static commit() * @method static int transactionLevel() - * @method static array pretend(Closure $callback) + * @method static array pretend(\Closure $callback) * @method static ConnectionInterface connection(string $pool) */ class Db From 3ccf438b72129f100e5e658b06f06f0eed5af557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=B8=E6=B0=94=E5=8D=83=E7=A7=8B?= Date: Mon, 2 Sep 2019 21:57:30 +0800 Subject: [PATCH 66/79] ensure returns -1 when running in non-coroutine context --- src/utils/src/Coroutine.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/utils/src/Coroutine.php b/src/utils/src/Coroutine.php index 1d6c185b8..c9b779733 100644 --- a/src/utils/src/Coroutine.php +++ b/src/utils/src/Coroutine.php @@ -43,10 +43,17 @@ class Coroutine /** * Returns the parent coroutine ID. * Returns -1 when running in non-coroutine context. + * + * @see https://github.com/swoole/swoole-src/pull/2669/files#diff-3bdf726b0ac53be7e274b60d59e6ec80R940 */ public static function parentId(): int { - return SwooleCoroutine::getPcid(); + $result = SwooleCoroutine::getPcid(); + if ($result === false) { + return -1; + } + + return $result; } /** From 70ce4fe2a3791ef9c9676ab78d279bf75f32493c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 3 Sep 2019 01:24:02 +0800 Subject: [PATCH 67/79] Update Coroutine.php --- src/utils/src/Coroutine.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/src/Coroutine.php b/src/utils/src/Coroutine.php index c9b779733..76c33a57b 100644 --- a/src/utils/src/Coroutine.php +++ b/src/utils/src/Coroutine.php @@ -48,12 +48,12 @@ class Coroutine */ public static function parentId(): int { - $result = SwooleCoroutine::getPcid(); - if ($result === false) { + $cid = SwooleCoroutine::getPcid(); + if ($cid === false) { return -1; } - return $result; + return $cid; } /** From 3158c3c7d9b044a52d192340a14af78051955316 Mon Sep 17 00:00:00 2001 From: "minbaby.zhang" Date: Tue, 3 Sep 2019 11:22:09 +0800 Subject: [PATCH 68/79] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 073898333..2cf8acde3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ## Fixed - [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. +- [#508](https://github.com/hyperf-cloud/hyperf/pull/508) ensure returns -1 when running in non-coroutine context # v1.0.13 - 2019-08-28 From b8bafad63fe198af480fdbaf456c2ebabebe08e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 3 Sep 2019 11:27:08 +0800 Subject: [PATCH 69/79] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cf8acde3..b5c55011d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,13 @@ ## Fixed - [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. -- [#508](https://github.com/hyperf-cloud/hyperf/pull/508) ensure returns -1 when running in non-coroutine context +- [#508](https://github.com/hyperf-cloud/hyperf/pull/508) Fixed typehint error for `Coroutine::parentId` when running in non-coroutine environment. # v1.0.13 - 2019-08-28 ## Added -- [#449](https://github.com/hyperf-cloud/hyperf/pull/428) Added an independent component [hyperf/translation](https://github.com/hyperf-cloud/translation), forked by illuminate/translation. +- [#428](https://github.com/hyperf-cloud/hyperf/pull/428) Added an independent component [hyperf/translation](https://github.com/hyperf-cloud/translation), forked by illuminate/translation. - [#449](https://github.com/hyperf-cloud/hyperf/pull/449) Added standard error code for grpc-server. - [#450](https://github.com/hyperf-cloud/hyperf/pull/450) Added comments of static methods for `Hyperf\Database\Schema\Schema`. From 8b8815149f0265d00d75db0ff5f7ca19765c0e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 3 Sep 2019 11:33:59 +0800 Subject: [PATCH 70/79] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5c55011d..cbe4385a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ## Fixed - [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. -- [#508](https://github.com/hyperf-cloud/hyperf/pull/508) Fixed typehint error for `Coroutine::parentId` when running in non-coroutine environment. +- [#508](https://github.com/hyperf-cloud/hyperf/pull/508) Fixed return type error of `Hyperf\Utils\Coroutine::parentId()` when running in non-coroutine environment. # v1.0.13 - 2019-08-28 From 3234bfba8ae09fee129686809370713e0a7e7158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 3 Sep 2019 12:05:29 +0800 Subject: [PATCH 71/79] Rewrite process name with app_name. --- src/server/.gitattributes | 1 + .../src/Listener/InitProcessTitleListener.php | 35 ++++++++++++++--- .../Listener/InitProcessTitleListenerTest.php | 39 ++++++++++++++++++- src/server/tests/Stub/DemoProcess.php | 24 ++++++++++++ .../Stub/InitProcessTitleListenerStub.php | 24 ++++++++++++ 5 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 src/server/.gitattributes create mode 100644 src/server/tests/Stub/DemoProcess.php create mode 100644 src/server/tests/Stub/InitProcessTitleListenerStub.php diff --git a/src/server/.gitattributes b/src/server/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/server/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/server/src/Listener/InitProcessTitleListener.php b/src/server/src/Listener/InitProcessTitleListener.php index d88a13020..ea91d5916 100644 --- a/src/server/src/Listener/InitProcessTitleListener.php +++ b/src/server/src/Listener/InitProcessTitleListener.php @@ -12,14 +12,26 @@ declare(strict_types=1); namespace Hyperf\Server\Listener; +use Hyperf\Contract\ConfigInterface; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\Framework\Event\AfterWorkerStart; use Hyperf\Framework\Event\OnManagerStart; use Hyperf\Framework\Event\OnStart; use Hyperf\Process\Event\BeforeProcessHandle; +use Psr\Container\ContainerInterface; class InitProcessTitleListener implements ListenerInterface { + /** + * @var ContainerInterface + */ + protected $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + public function listen(): array { return [ @@ -32,18 +44,31 @@ class InitProcessTitleListener implements ListenerInterface public function process(object $event) { + $prefix = 'Hyperf.'; + if ($this->container->has(ConfigInterface::class)) { + $name = $this->container->get(ConfigInterface::class)->get('app_name'); + if ($name) { + $prefix = $name . '.'; + } + } + if ($event instanceof OnStart) { - @cli_set_process_title('Master'); + $this->setTitle($prefix . 'Master'); } elseif ($event instanceof OnManagerStart) { - @cli_set_process_title('Manager'); + $this->setTitle($prefix . 'Manager'); } elseif ($event instanceof AfterWorkerStart) { if ($event->server->taskworker) { - @cli_set_process_title('TaskWorker.' . $event->workerId); + $this->setTitle($prefix . 'TaskWorker.' . $event->workerId); } else { - @cli_set_process_title('Worker.' . $event->workerId); + $this->setTitle($prefix . 'Worker.' . $event->workerId); } } elseif ($event instanceof BeforeProcessHandle) { - @cli_set_process_title($event->process->name . '.' . $event->index); + $this->setTitle($prefix . $event->process->name . '.' . $event->index); } } + + protected function setTitle($title) + { + @cli_set_process_title($title); + } } diff --git a/src/server/tests/Listener/InitProcessTitleListenerTest.php b/src/server/tests/Listener/InitProcessTitleListenerTest.php index 7dd4c4a42..dd8f6b341 100644 --- a/src/server/tests/Listener/InitProcessTitleListenerTest.php +++ b/src/server/tests/Listener/InitProcessTitleListenerTest.php @@ -17,7 +17,12 @@ use Hyperf\Framework\Event\OnManagerStart; use Hyperf\Framework\Event\OnStart; use Hyperf\Process\Event\BeforeProcessHandle; use Hyperf\Server\Listener\InitProcessTitleListener; +use Hyperf\Utils\Context; +use HyperfTest\Server\Stub\DemoProcess; +use HyperfTest\Server\Stub\InitProcessTitleListenerStub; +use Mockery; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; /** * @internal @@ -25,9 +30,15 @@ use PHPUnit\Framework\TestCase; */ class InitProcessTitleListenerTest extends TestCase { + protected function tearDown() + { + Mockery::close(); + } + public function testInitProcessTitleListenerListen() { - $listener = new InitProcessTitleListener(); + $container = Mockery::mock(ContainerInterface::class); + $listener = new InitProcessTitleListener($container); $this->assertSame([ OnStart::class, @@ -36,4 +47,30 @@ class InitProcessTitleListenerTest extends TestCase BeforeProcessHandle::class, ], $listener->listen()); } + + public function testProcessDefaultName() + { + $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('has')->with(Mockery::any())->andReturn(false); + + $listener = new InitProcessTitleListenerStub($container); + $process = new DemoProcess($container); + + $listener->process(new BeforeProcessHandle($process, 1)); + + $this->assertSame('Hyperf.test.demo.1', Context::get('test.server.process.title')); + } + + public function testProcessName() + { + $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('has')->with(Mockery::any())->andReturn(false); + + $listener = new InitProcessTitleListenerStub($container); + $process = new DemoProcess($container); + + $listener->process(new BeforeProcessHandle($process, 1)); + + $this->assertSame('Hyperf.test.demo.1', Context::get('test.server.process.title')); + } } diff --git a/src/server/tests/Stub/DemoProcess.php b/src/server/tests/Stub/DemoProcess.php new file mode 100644 index 000000000..04462c509 --- /dev/null +++ b/src/server/tests/Stub/DemoProcess.php @@ -0,0 +1,24 @@ + Date: Tue, 3 Sep 2019 13:30:14 +0800 Subject: [PATCH 72/79] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dauth=E6=9C=AA=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E9=87=8D=E8=BF=9E=E6=97=B6=E5=80=99=E6=B0=B8?= =?UTF-8?q?=E8=BF=9C=E8=B0=83=E7=94=A8$redis->auth=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/redis/src/RedisConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redis/src/RedisConnection.php b/src/redis/src/RedisConnection.php index 7cb3b3ef6..968c699f4 100644 --- a/src/redis/src/RedisConnection.php +++ b/src/redis/src/RedisConnection.php @@ -81,7 +81,7 @@ class RedisConnection extends BaseConnection implements ConnectionInterface throw new ConnectionException('Connection reconnect failed.'); } - if (isset($auth)) { + if (isset($auth) && $auth !== '') { $redis->auth($auth); } From 3d33b7ccc05340b96af68c55e20165ff3643ee00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 3 Sep 2019 13:33:50 +0800 Subject: [PATCH 73/79] Optimized code. --- .../src/Listener/InitProcessTitleListener.php | 30 ++++++++----------- .../Listener/InitProcessTitleListenerTest.php | 18 ++++++++--- .../Stub/InitProcessTitleListenerStub.php | 2 +- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/server/src/Listener/InitProcessTitleListener.php b/src/server/src/Listener/InitProcessTitleListener.php index ea91d5916..9da4a83bb 100644 --- a/src/server/src/Listener/InitProcessTitleListener.php +++ b/src/server/src/Listener/InitProcessTitleListener.php @@ -23,13 +23,17 @@ use Psr\Container\ContainerInterface; class InitProcessTitleListener implements ListenerInterface { /** - * @var ContainerInterface + * @var string */ - protected $container; + protected $prefix = ''; public function __construct(ContainerInterface $container) { - $this->container = $container; + if ($container->has(ConfigInterface::class)) { + if ($name = $container->get(ConfigInterface::class)->get('app_name')) { + $this->prefix = $name . '.'; + } + } } public function listen(): array @@ -44,31 +48,23 @@ class InitProcessTitleListener implements ListenerInterface public function process(object $event) { - $prefix = 'Hyperf.'; - if ($this->container->has(ConfigInterface::class)) { - $name = $this->container->get(ConfigInterface::class)->get('app_name'); - if ($name) { - $prefix = $name . '.'; - } - } - if ($event instanceof OnStart) { - $this->setTitle($prefix . 'Master'); + $this->setTitle('Master'); } elseif ($event instanceof OnManagerStart) { - $this->setTitle($prefix . 'Manager'); + $this->setTitle('Manager'); } elseif ($event instanceof AfterWorkerStart) { if ($event->server->taskworker) { - $this->setTitle($prefix . 'TaskWorker.' . $event->workerId); + $this->setTitle('TaskWorker.' . $event->workerId); } else { - $this->setTitle($prefix . 'Worker.' . $event->workerId); + $this->setTitle('Worker.' . $event->workerId); } } elseif ($event instanceof BeforeProcessHandle) { - $this->setTitle($prefix . $event->process->name . '.' . $event->index); + $this->setTitle($event->process->name . '.' . $event->index); } } protected function setTitle($title) { - @cli_set_process_title($title); + @cli_set_process_title($this->prefix . $title); } } diff --git a/src/server/tests/Listener/InitProcessTitleListenerTest.php b/src/server/tests/Listener/InitProcessTitleListenerTest.php index dd8f6b341..32d2bfa3a 100644 --- a/src/server/tests/Listener/InitProcessTitleListenerTest.php +++ b/src/server/tests/Listener/InitProcessTitleListenerTest.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace HyperfTest\Server\Listener; +use Hyperf\Config\Config; +use Hyperf\Contract\ConfigInterface; use Hyperf\Framework\Event\AfterWorkerStart; use Hyperf\Framework\Event\OnManagerStart; use Hyperf\Framework\Event\OnStart; @@ -23,6 +25,7 @@ use HyperfTest\Server\Stub\InitProcessTitleListenerStub; use Mockery; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use Psr\EventDispatcher\EventDispatcherInterface; /** * @internal @@ -38,6 +41,8 @@ class InitProcessTitleListenerTest extends TestCase public function testInitProcessTitleListenerListen() { $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('has')->with(Mockery::any())->andReturn(false); + $listener = new InitProcessTitleListener($container); $this->assertSame([ @@ -58,19 +63,24 @@ class InitProcessTitleListenerTest extends TestCase $listener->process(new BeforeProcessHandle($process, 1)); - $this->assertSame('Hyperf.test.demo.1', Context::get('test.server.process.title')); + $this->assertSame('test.demo.1', Context::get('test.server.process.title')); } public function testProcessName() { + $name = 'hyperf-skeleton.' . uniqid(); $container = Mockery::mock(ContainerInterface::class); - $container->shouldReceive('has')->with(Mockery::any())->andReturn(false); + $container->shouldReceive('has')->with(ConfigInterface::class)->andReturn(true); + $container->shouldReceive('has')->with(EventDispatcherInterface::class)->andReturn(false); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ + 'app_name' => $name, + ])); $listener = new InitProcessTitleListenerStub($container); $process = new DemoProcess($container); - $listener->process(new BeforeProcessHandle($process, 1)); + $listener->process(new BeforeProcessHandle($process, 0)); - $this->assertSame('Hyperf.test.demo.1', Context::get('test.server.process.title')); + $this->assertSame($name . '.test.demo.0', Context::get('test.server.process.title')); } } diff --git a/src/server/tests/Stub/InitProcessTitleListenerStub.php b/src/server/tests/Stub/InitProcessTitleListenerStub.php index 69fcd122e..79c21e0bd 100644 --- a/src/server/tests/Stub/InitProcessTitleListenerStub.php +++ b/src/server/tests/Stub/InitProcessTitleListenerStub.php @@ -19,6 +19,6 @@ class InitProcessTitleListenerStub extends InitProcessTitleListener { public function setTitle($title) { - Context::set('test.server.process.title', $title); + Context::set('test.server.process.title', $this->prefix . $title); } } From 007e4bb2b7194a1e70fc82f54f431b4f59dce41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 3 Sep 2019 14:55:22 +0800 Subject: [PATCH 74/79] Update changelog.md --- CHANGELOG.md | 1 + src/server/src/Listener/InitProcessTitleListener.php | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5b198d51..4a399a8be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#482](https://github.com/hyperf-cloud/hyperf/pull/482) Re-generate the `fillable` argument of Model when use `refresh-fillable` option, at the same time, the command will keep the `fillable` argument as default behaviours. - [#501](https://github.com/hyperf-cloud/hyperf/pull/501) When the path argument of Mapping annotation is an empty string, then the path is equal to prefix of Controller annotation. +- [#513](https://github.com/hyperf-cloud/hyperf/pull/513) Rewrite process name with `app_name`. ## Fixed diff --git a/src/server/src/Listener/InitProcessTitleListener.php b/src/server/src/Listener/InitProcessTitleListener.php index 9da4a83bb..d2b4666f0 100644 --- a/src/server/src/Listener/InitProcessTitleListener.php +++ b/src/server/src/Listener/InitProcessTitleListener.php @@ -27,11 +27,16 @@ class InitProcessTitleListener implements ListenerInterface */ protected $prefix = ''; + /** + * @var string + */ + protected $dot = '.'; + public function __construct(ContainerInterface $container) { if ($container->has(ConfigInterface::class)) { if ($name = $container->get(ConfigInterface::class)->get('app_name')) { - $this->prefix = $name . '.'; + $this->prefix = $name . $this->dot; } } } From dfadc27e322b3bf1cfb0ece43d9df90a1cb6f17b Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Tue, 3 Sep 2019 15:46:20 +0800 Subject: [PATCH 75/79] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93f07d545..ab2896f6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ## Fixed - [#479](https://github.com/hyperf-cloud/hyperf/pull/479) Fixed typehint error when host of Elasticsearch client does not reached. +- [#514](https://github.com/hyperf-cloud/hyperf/pull/514) Fixed redis auth failed when the password is an empty string. # v1.0.13 - 2019-08-28 From 72eaea71312031843b5b0e37edc384e282c83891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 3 Sep 2019 16:17:37 +0800 Subject: [PATCH 76/79] Added dot user can defined. --- .../src/Listener/InitProcessTitleListener.php | 30 +++++++++++++------ .../Listener/InitProcessTitleListenerTest.php | 19 ++++++++++++ .../Stub/InitProcessTitleListenerStub.php | 4 +-- .../Stub/InitProcessTitleListenerStub2.php | 26 ++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 src/server/tests/Stub/InitProcessTitleListenerStub2.php diff --git a/src/server/src/Listener/InitProcessTitleListener.php b/src/server/src/Listener/InitProcessTitleListener.php index d2b4666f0..09d9f9c6d 100644 --- a/src/server/src/Listener/InitProcessTitleListener.php +++ b/src/server/src/Listener/InitProcessTitleListener.php @@ -25,7 +25,7 @@ class InitProcessTitleListener implements ListenerInterface /** * @var string */ - protected $prefix = ''; + protected $name = ''; /** * @var string @@ -36,7 +36,7 @@ class InitProcessTitleListener implements ListenerInterface { if ($container->has(ConfigInterface::class)) { if ($name = $container->get(ConfigInterface::class)->get('app_name')) { - $this->prefix = $name . $this->dot; + $this->name = $name; } } } @@ -53,23 +53,35 @@ class InitProcessTitleListener implements ListenerInterface public function process(object $event) { + $array = []; + if ($this->name !== '') { + $array[] = $this->name; + } + if ($event instanceof OnStart) { - $this->setTitle('Master'); + $array[] = 'Master'; } elseif ($event instanceof OnManagerStart) { - $this->setTitle('Manager'); + $array[] = 'Manager'; } elseif ($event instanceof AfterWorkerStart) { if ($event->server->taskworker) { - $this->setTitle('TaskWorker.' . $event->workerId); + $array[] = 'TaskWorker'; + $array[] = $event->workerId; } else { - $this->setTitle('Worker.' . $event->workerId); + $array[] = 'Worker'; + $array[] = $event->workerId; } } elseif ($event instanceof BeforeProcessHandle) { - $this->setTitle($event->process->name . '.' . $event->index); + $array[] = $event->process->name; + $array[] = $event->index; + } + + if ($title = implode($this->dot, $array)) { + $this->setTitle($title); } } - protected function setTitle($title) + protected function setTitle(string $title) { - @cli_set_process_title($this->prefix . $title); + @cli_set_process_title($title); } } diff --git a/src/server/tests/Listener/InitProcessTitleListenerTest.php b/src/server/tests/Listener/InitProcessTitleListenerTest.php index 32d2bfa3a..5631319f3 100644 --- a/src/server/tests/Listener/InitProcessTitleListenerTest.php +++ b/src/server/tests/Listener/InitProcessTitleListenerTest.php @@ -22,6 +22,7 @@ use Hyperf\Server\Listener\InitProcessTitleListener; use Hyperf\Utils\Context; use HyperfTest\Server\Stub\DemoProcess; use HyperfTest\Server\Stub\InitProcessTitleListenerStub; +use HyperfTest\Server\Stub\InitProcessTitleListenerStub2; use Mockery; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; @@ -83,4 +84,22 @@ class InitProcessTitleListenerTest extends TestCase $this->assertSame($name . '.test.demo.0', Context::get('test.server.process.title')); } + + public function testUserDefinedDot() + { + $name = 'hyperf-skeleton.' . uniqid(); + $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('has')->with(ConfigInterface::class)->andReturn(true); + $container->shouldReceive('has')->with(EventDispatcherInterface::class)->andReturn(false); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ + 'app_name' => $name, + ])); + + $listener = new InitProcessTitleListenerStub2($container); + $process = new DemoProcess($container); + + $listener->process(new BeforeProcessHandle($process, 0)); + + $this->assertSame($name . '#test.demo#0', Context::get('test.server.process.title')); + } } diff --git a/src/server/tests/Stub/InitProcessTitleListenerStub.php b/src/server/tests/Stub/InitProcessTitleListenerStub.php index 79c21e0bd..5309202c2 100644 --- a/src/server/tests/Stub/InitProcessTitleListenerStub.php +++ b/src/server/tests/Stub/InitProcessTitleListenerStub.php @@ -17,8 +17,8 @@ use Hyperf\Utils\Context; class InitProcessTitleListenerStub extends InitProcessTitleListener { - public function setTitle($title) + public function setTitle(string $title) { - Context::set('test.server.process.title', $this->prefix . $title); + Context::set('test.server.process.title', $title); } } diff --git a/src/server/tests/Stub/InitProcessTitleListenerStub2.php b/src/server/tests/Stub/InitProcessTitleListenerStub2.php new file mode 100644 index 000000000..ae5bc68b7 --- /dev/null +++ b/src/server/tests/Stub/InitProcessTitleListenerStub2.php @@ -0,0 +1,26 @@ + Date: Wed, 4 Sep 2019 16:19:23 +0800 Subject: [PATCH 77/79] Optimized --- composer.json | 3 +- .../src/ValidatorInterface.php} | 26 +- .../src/Contracts}/MessageBag.php | 20 +- .../src/Contracts}/MessageProvider.php | 6 +- src/utils/src/MessageBag.php | 352 ++++++++++++++++++ src/validation/README.md | 4 +- .../src/Concerns/FormatsMessages.php | 6 +- src/validation/src/ConfigProvider.php | 4 +- .../src/Contracts/Validation/Factory.php | 2 +- src/validation/src/Request/FormRequest.php | 10 +- .../src/ValidatesWhenResolvedTrait.php | 6 +- src/validation/src/ValidationException.php | 7 +- src/validation/src/Validator.php | 81 ++-- .../tests/Cases/ValidationExistsRuleTest.php | 30 +- .../tests/Cases/ValidationInRuleTest.php | 4 +- .../tests/Cases/ValidationNotInRuleTest.php | 4 +- .../tests/Cases/ValidationUniqueRuleTest.php | 4 +- 17 files changed, 437 insertions(+), 132 deletions(-) rename src/{validation/src/Contracts/Validation/Validator.php => contract/src/ValidatorInterface.php} (64%) mode change 100755 => 100644 rename src/{validation/src/Contracts/Support => utils/src/Contracts}/MessageBag.php (78%) mode change 100755 => 100644 rename src/{validation/src/Contracts/Support => utils/src/Contracts}/MessageProvider.php (74%) mode change 100755 => 100644 create mode 100644 src/utils/src/MessageBag.php diff --git a/composer.json b/composer.json index 9b9a9c0dd..85ac2c463 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "squizlabs/php_codesniffer": "^3.4", "symfony/console": "^4.2", "symfony/finder": "^4.1", - "vlucas/phpdotenv": "^3.1" + "vlucas/phpdotenv": "^3.1", + "egulias/email-validator": "^2.1" }, "require-dev": { "doctrine/common": "@stable", diff --git a/src/validation/src/Contracts/Validation/Validator.php b/src/contract/src/ValidatorInterface.php old mode 100755 new mode 100644 similarity index 64% rename from src/validation/src/Contracts/Validation/Validator.php rename to src/contract/src/ValidatorInterface.php index 13624d1f8..9171ad80f --- a/src/validation/src/Contracts/Validation/Validator.php +++ b/src/contract/src/ValidatorInterface.php @@ -1,22 +1,13 @@ $value) { + $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; + + $this->messages[$key] = array_unique($value); + } + } + + /** + * Convert the message bag to its string representation. + */ + public function __toString(): string + { + return $this->toJson(); + } + + /** + * Get the keys present in the message bag. + */ + public function keys(): array + { + return array_keys($this->messages); + } + + /** + * Add a message to the message bag. + */ + public function add(string $key, string $message): MessageBagContract + { + if ($this->isUnique($key, $message)) { + $this->messages[$key][] = $message; + } + + return $this; + } + + /** + * Merge a new array of messages into the message bag. + * + * @param array|MessageProvider $messages + * @return $this + */ + public function merge($messages) + { + if ($messages instanceof MessageProvider) { + $messages = $messages->getMessageBag()->getMessages(); + } + + $this->messages = array_merge_recursive($this->messages, $messages); + + return $this; + } + + /** + * Determine if messages exist for all of the given keys. + * + * @param array|string $key + */ + public function has($key): bool + { + if ($this->isEmpty()) { + return false; + } + + if (is_null($key)) { + return $this->any(); + } + + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $key) { + if ($this->first($key) === '') { + return false; + } + } + + return true; + } + + /** + * Determine if messages exist for any of the given keys. + * + * @param array|string $keys + */ + public function hasAny($keys = []): bool + { + if ($this->isEmpty()) { + return false; + } + + $keys = is_array($keys) ? $keys : func_get_args(); + + foreach ($keys as $key) { + if ($this->has($key)) { + return true; + } + } + + return false; + } + + /** + * Get the first message from the message bag for a given key. + * + * @param string $key + * @param string $format + */ + public function first($key = null, $format = null): string + { + $messages = is_null($key) ? $this->all($format) : $this->get($key, $format); + + $firstMessage = Arr::first($messages, null, ''); + + return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage; + } + + /** + * Get all of the messages from the message bag for a given key. + */ + public function get(string $key, ?string $format = null): array + { + // If the message exists in the message bag, we will transform it and return + // the message. Otherwise, we will check if the key is implicit & collect + // all the messages that match the given key and output it as an array. + if (array_key_exists($key, $this->messages)) { + return $this->transform( + $this->messages[$key], + $this->checkFormat($format), + $key + ); + } + + if (Str::contains($key, '*')) { + return $this->getMessagesForWildcardKey($key, $format); + } + + return []; + } + + /** + * Get all of the messages for every key in the message bag. + */ + public function all(?string $format = null): array + { + $format = $this->checkFormat($format); + + $all = []; + + foreach ($this->messages as $key => $messages) { + $all = array_merge($all, $this->transform($messages, $format, $key)); + } + + return $all; + } + + /** + * Get all of the unique messages for every key in the message bag. + */ + public function unique(?string $format = null): array + { + return array_unique($this->all($format)); + } + + /** + * Get the raw messages in the message bag. + */ + public function messages(): array + { + return $this->messages; + } + + /** + * Get the raw messages in the message bag. + */ + public function getMessages(): array + { + return $this->messages(); + } + + /** + * Get the messages for the instance. + */ + public function getMessageBag(): MessageBagContract + { + return $this; + } + + /** + * Get the default message format. + */ + public function getFormat(): string + { + return $this->format; + } + + /** + * Set the default message format. + */ + public function setFormat(string $format = ':message'): self + { + $this->format = $format; + + return $this; + } + + /** + * Determine if the message bag has any messages. + */ + public function isEmpty(): bool + { + return ! $this->any(); + } + + /** + * Determine if the message bag has any messages. + */ + public function isNotEmpty(): bool + { + return $this->any(); + } + + /** + * Determine if the message bag has any messages. + */ + public function any(): bool + { + return $this->count() > 0; + } + + /** + * Get the number of messages in the message bag. + */ + public function count(): int + { + return count($this->messages, COUNT_RECURSIVE) - count($this->messages); + } + + /** + * Get the instance as an array. + */ + public function toArray(): array + { + return $this->getMessages(); + } + + /** + * Convert the object into something JSON serializable. + */ + public function jsonSerialize(): array + { + return $this->toArray(); + } + + /** + * Convert the object to its JSON representation. + */ + public function toJson(int $options = 0): string + { + return json_encode($this->jsonSerialize(), $options); + } + + /** + * Determine if a key and message combination already exists. + */ + protected function isUnique(string $key, string $message): bool + { + $messages = (array) $this->messages; + + return ! isset($messages[$key]) || ! in_array($message, $messages[$key]); + } + + /** + * Get the messages for a wildcard key. + */ + protected function getMessagesForWildcardKey(string $key, ?string $format): array + { + return collect($this->messages) + ->filter(function ($messages, $messageKey) use ($key) { + return Str::is($key, $messageKey); + }) + ->map(function ($messages, $messageKey) use ($format) { + return $this->transform( + $messages, + $this->checkFormat($format), + $messageKey + ); + })->all(); + } + + /** + * Format an array of messages. + */ + protected function transform(array $messages, string $format, string $messageKey): array + { + return collect($messages) + ->map(function ($message) use ($format, $messageKey) { + // We will simply spin through the given messages and transform each one + // replacing the :message place holder with the real message allowing + // the messages to be easily formatted to each developer's desires. + return str_replace([':message', ':key'], [$message, $messageKey], $format); + })->all(); + } + + /** + * Get the appropriate format based on the given format. + */ + protected function checkFormat(?string $format): string + { + return $format ?: $this->format; + } +} diff --git a/src/validation/README.md b/src/validation/README.md index f723771c6..b083d7a10 100644 --- a/src/validation/README.md +++ b/src/validation/README.md @@ -3,7 +3,7 @@ ## About -hyperf/validation 是对Laravel Validation的移植(不包含门面部分),具体使用方法可以参考Laravel Validation 的使用。 +[hyperf/validation](https://github.com/hyperf-cloud/validation) 组件衍生于 `Laravel Validation` 组件的,我们对它进行了一些改造,大部分功能保持了相同。在这里感谢一下 Laravel 开发组,实现了如此强大好用的 Validation 组件。 ## Install @@ -17,7 +17,7 @@ composer require hyperf/validation ### publish config ``` -php bin/hyperf.php vendor:publish hyperf/translation +php bin/hyperf.php vendor:publish hyperf/validation ``` diff --git a/src/validation/src/Concerns/FormatsMessages.php b/src/validation/src/Concerns/FormatsMessages.php index 6e1017a1b..b150b49e0 100755 --- a/src/validation/src/Concerns/FormatsMessages.php +++ b/src/validation/src/Concerns/FormatsMessages.php @@ -16,6 +16,7 @@ use Closure; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Utils\Arr; use Hyperf\Utils\Str; +use Hyperf\Validation\Validator; trait FormatsMessages { @@ -317,11 +318,8 @@ trait FormatsMessages /** * Call a custom validator message replacer. - * - * @param \Hyperf\Validation\Validator $validator - * @return null|string */ - protected function callReplacer(string $message, string $attribute, string $rule, array $parameters, $validator) + protected function callReplacer(string $message, string $attribute, string $rule, array $parameters, Validator $validator): ?string { $callback = $this->replacers[$rule]; diff --git a/src/validation/src/ConfigProvider.php b/src/validation/src/ConfigProvider.php index 0df7c4300..739db2075 100644 --- a/src/validation/src/ConfigProvider.php +++ b/src/validation/src/ConfigProvider.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Hyperf\Validation; use Hyperf\Validation\Contracts\Validation\Factory as FactoryInterface; -use Hyperf\Validation\Contracts\Validation\Validator as ValidatorInterface; +use Hyperf\Contract\ValidatorInterface; class ConfigProvider { @@ -23,7 +23,7 @@ class ConfigProvider 'dependencies' => [ ValidatorInterface::class => ValidatorFactory::class, PresenceVerifierInterface::class => DatabasePresenceVerifierFactory::class, - FactoryInterface::class => ValidatorFactory::class, + FactoryInterface::class => Factory::class, ], 'scan' => [ 'paths' => [ diff --git a/src/validation/src/Contracts/Validation/Factory.php b/src/validation/src/Contracts/Validation/Factory.php index 197d22e82..2b7d33423 100755 --- a/src/validation/src/Contracts/Validation/Factory.php +++ b/src/validation/src/Contracts/Validation/Factory.php @@ -17,7 +17,7 @@ interface Factory /** * Create a new Validator instance. * - * @return \Hyperf\Validation\Contracts\Validation\Validator + * @return \Hyperf\Contract\ValidatorInterface */ public function make(array $data, array $rules, array $messages = [], array $customAttributes = []); diff --git a/src/validation/src/Request/FormRequest.php b/src/validation/src/Request/FormRequest.php index 54b24dc4f..f3e956bc5 100755 --- a/src/validation/src/Request/FormRequest.php +++ b/src/validation/src/Request/FormRequest.php @@ -16,7 +16,7 @@ use Hyperf\HttpServer\Request; use Hyperf\Utils\Context; use Hyperf\Validation\Contracts\Validation\Factory as ValidationFactory; use Hyperf\Validation\Contracts\Validation\ValidatesWhenResolved; -use Hyperf\Validation\Contracts\Validation\Validator; +use Hyperf\Contract\ValidatorInterface; use Hyperf\Validation\ValidatesWhenResolvedTrait; use Hyperf\Validation\ValidationException; use Psr\Container\ContainerInterface; @@ -96,7 +96,7 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Get the validator instance for the request. * - * @return \Hyperf\Validation\Contracts\Validation\Validator + * @return ValidatorInterface */ protected function getValidatorInstance() { @@ -118,7 +118,7 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Create the default validator instance. * - * @return \Hyperf\Validation\Contracts\Validation\Validator + * @return ValidatorInterface */ protected function createDefaultValidator(ValidationFactory $factory) { @@ -145,7 +145,7 @@ class FormRequest extends Request implements ValidatesWhenResolved * * @throws ValidationException */ - protected function failedValidation(Validator $validator) + protected function failedValidation(ValidatorInterface $validator) { throw new ValidationException($validator, $this->response()); } @@ -153,7 +153,7 @@ class FormRequest extends Request implements ValidatesWhenResolved /** * Format the errors from the given Validator instance. */ - protected function formatErrors(Validator $validator): array + protected function formatErrors(ValidatorInterface $validator): array { return $validator->getMessageBag()->toArray(); } diff --git a/src/validation/src/ValidatesWhenResolvedTrait.php b/src/validation/src/ValidatesWhenResolvedTrait.php index 79aa93186..2785d886b 100755 --- a/src/validation/src/ValidatesWhenResolvedTrait.php +++ b/src/validation/src/ValidatesWhenResolvedTrait.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Hyperf\Validation; +use Hyperf\Contract\ValidatorInterface; + /** * Provides default implementation of ValidatesWhenResolved contract. */ @@ -46,7 +48,7 @@ trait ValidatesWhenResolvedTrait /** * Get the validator instance for the request. * - * @return \Hyperf\Validation\Contracts\Validation\Validator + * @return ValidatorInterface */ protected function getValidatorInstance() { @@ -58,7 +60,7 @@ trait ValidatesWhenResolvedTrait * * @throws \Hyperf\Validation\ValidationException */ - protected function failedValidation(Validator $validator) + protected function failedValidation(ValidatorInterface $validator) { throw new ValidationException($validator); } diff --git a/src/validation/src/ValidationException.php b/src/validation/src/ValidationException.php index d0c1dfd21..399f68353 100755 --- a/src/validation/src/ValidationException.php +++ b/src/validation/src/ValidationException.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\Validation; +use Hyperf\Contract\ValidatorInterface; use Hyperf\Server\Exception\ServerException; use Hyperf\Utils\Arr; use Psr\Http\Message\ResponseInterface; @@ -21,7 +22,7 @@ class ValidationException extends ServerException /** * The validator instance. * - * @var \Hyperf\Validation\Contracts\Validation\Validator + * @var ValidatorInterface */ public $validator; @@ -56,10 +57,10 @@ class ValidationException extends ServerException /** * Create a new exception instance. * - * @param \Hyperf\Validation\Contracts\Validation\Validator $validator + * @param ValidatorInterface $validator * @param null|ResponseInterface $response */ - public function __construct($validator, $response = null, string $errorBag = 'default') + public function __construct(ValidatorInterface $validator, $response = null, string $errorBag = 'default') { parent::__construct('The given data was invalid.'); diff --git a/src/validation/src/Validator.php b/src/validation/src/Validator.php index 9a9433481..873c1b101 100755 --- a/src/validation/src/Validator.php +++ b/src/validation/src/Validator.php @@ -14,15 +14,17 @@ namespace Hyperf\Validation; use BadMethodCallException; use Hyperf\Contract\TranslatorInterface; +use Hyperf\Contract\ValidatorInterface; use Hyperf\Di\Container; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\Utils\Arr; +use Hyperf\Utils\Contracts\MessageBag as MessageBagContract; use Hyperf\Utils\Fluent; use Hyperf\Utils\Str; use Hyperf\Validation\Contracts\Validation\ImplicitRule; use Hyperf\Validation\Contracts\Validation\Rule as RuleContract; -use Hyperf\Validation\Contracts\Validation\Validator as ValidatorContract; -use Hyperf\Validation\Support\MessageBag; +use Hyperf\Contract\ValidatorInterface as ValidatorContract; +use Hyperf\Utils\MessageBag; use Psr\Container\ContainerInterface; use RuntimeException; @@ -104,7 +106,7 @@ class Validator implements ValidatorContract /** * The message bag instance. * - * @var \Hyperf\Validation\Support\MessageBag + * @var MessageBag */ protected $messages; @@ -202,9 +204,6 @@ class Validator implements ValidatorContract */ protected $numericRules = ['Numeric', 'Integer']; - /** - * Create a new Validator instance. - */ public function __construct( TranslatorInterface $translator, array $data, @@ -224,10 +223,7 @@ class Validator implements ValidatorContract /** * Handle dynamic calls to class methods. * - * @param string $method - * @param array $parameters * @throws \BadMethodCallException - * @return mixed */ public function __call($method, $parameters) { @@ -273,9 +269,8 @@ class Validator implements ValidatorContract * Add an after validation callback. * * @param callable|string $callback - * @return $this */ - public function after($callback) + public function after($callback): self { $this->after[] = function () use ($callback) { return call_user_func_array($callback, [$this]); @@ -329,7 +324,7 @@ class Validator implements ValidatorContract /** * Run the validator's rules against its data. * - * @throws \Hyperf\Validation\ValidationException + * @throws \Hyperf\Validation\ValidationException If validate fails. */ public function validate(): array { @@ -343,7 +338,7 @@ class Validator implements ValidatorContract /** * Get the attributes and values that were validated. * - * @throws \Hyperf\Validation\ValidationException + * @throws \Hyperf\Validation\ValidationException If invalid. */ public function validated(): array { @@ -439,20 +434,16 @@ class Validator implements ValidatorContract /** * An alternative more semantic shortcut to the message container. - * - * @return MessageBag */ - public function errors() + public function errors(): MessageBagContract { return $this->messages(); } /** * Get the messages for the instance. - * - * @return MessageBag */ - public function getMessageBag() + public function getMessageBag(): MessageBagContract { return $this->messages(); } @@ -485,10 +476,8 @@ class Validator implements ValidatorContract /** * Set the data under validation. - * - * @return $this */ - public function setData(array $data) + public function setData(array $data): self { $this->data = $this->parseData($data); @@ -507,10 +496,8 @@ class Validator implements ValidatorContract /** * Set the validation rules. - * - * @return $this */ - public function setRules(array $rules) + public function setRules(array $rules): self { $this->initialRules = $rules; @@ -548,9 +535,8 @@ class Validator implements ValidatorContract * * @param array|string $attribute * @param array|string $rules - * @return $this */ - public function sometimes($attribute, $rules, callable $callback) + public function sometimes($attribute, $rules, callable $callback): self { $payload = new Fluent($this->getData()); @@ -661,10 +647,8 @@ class Validator implements ValidatorContract /** * Set the custom messages for the validator. - * - * @return $this */ - public function setCustomMessages(array $messages) + public function setCustomMessages(array $messages): self { $this->customMessages = array_merge($this->customMessages, $messages); @@ -673,10 +657,8 @@ class Validator implements ValidatorContract /** * Set the custom attributes on the validator. - * - * @return $this */ - public function setAttributeNames(array $attributes) + public function setAttributeNames(array $attributes): self { $this->customAttributes = $attributes; @@ -685,10 +667,8 @@ class Validator implements ValidatorContract /** * Add custom attributes to the validator. - * - * @return $this */ - public function addCustomAttributes(array $customAttributes) + public function addCustomAttributes(array $customAttributes): self { $this->customAttributes = array_merge($this->customAttributes, $customAttributes); @@ -697,10 +677,8 @@ class Validator implements ValidatorContract /** * Set the custom values on the validator. - * - * @return $this */ - public function setValueNames(array $values) + public function setValueNames(array $values): self { $this->customValues = $values; @@ -709,10 +687,8 @@ class Validator implements ValidatorContract /** * Add the custom values for the validator. - * - * @return $this */ - public function addCustomValues(array $customValues) + public function addCustomValues(array $customValues): self { $this->customValues = array_merge($this->customValues, $customValues); @@ -745,11 +721,10 @@ class Validator implements ValidatorContract /** * Get the Presence Verifier implementation. * - * @param string $connection * @throws \RuntimeException * @return \Hyperf\Validation\PresenceVerifierInterface */ - public function getPresenceVerifierFor($connection) + public function getPresenceVerifierFor(?string $connection) { return tap($this->getPresenceVerifier(), function ($verifier) use ($connection) { $verifier->setConnection($connection); @@ -766,10 +741,8 @@ class Validator implements ValidatorContract /** * Get the Translator implementation. - * - * @return TranslatorInterface */ - public function getTranslator() + public function getTranslator(): TranslatorInterface { return $this->translator; } @@ -793,10 +766,9 @@ class Validator implements ValidatorContract /** * Validate a given attribute against a rule. * - * @param string $attribute - * @param string $rule + * @param string|object $rule */ - protected function validateAttribute($attribute, $rule) + protected function validateAttribute(string $attribute, $rule) { $this->currentRule = $rule; @@ -846,7 +818,7 @@ class Validator implements ValidatorContract /** * Determine if the given rule depends on other fields. * - * @param string $rule + * @param string|object $rule */ protected function dependsOnOtherFields($rule): bool { @@ -901,7 +873,6 @@ class Validator implements ValidatorContract * Determine if the attribute is validatable. * * @param object|string $rule - * @param mixed $value */ protected function isValidatable($rule, string $attribute, $value): bool { @@ -915,7 +886,6 @@ class Validator implements ValidatorContract * Determine if the field is present, or the rule implies required. * * @param object|string $rule - * @param mixed $value */ protected function presentOrRuleIsImplicit($rule, string $attribute, $value): bool { @@ -956,7 +926,7 @@ class Validator implements ValidatorContract /** * Determine if the attribute fails the nullable check. * - * @param string $rule + * @param string|object $rule */ protected function isNotNullIfMarkedAsNullable($rule, string $attribute): bool { @@ -972,7 +942,7 @@ class Validator implements ValidatorContract * * This is to avoid possible database type comparison errors. * - * @param string $rule + * @param string|object $rule */ protected function hasNotFailedPreviousRuleIfPresenceRule($rule, string $attribute): bool { @@ -982,7 +952,6 @@ class Validator implements ValidatorContract /** * Validate an attribute using a custom rule object. * - * @param mixed $value * @param \Hyperf\Validation\Contracts\Validation\Rule $rule */ protected function validateUsingCustomRule(string $attribute, $value, $rule) diff --git a/src/validation/tests/Cases/ValidationExistsRuleTest.php b/src/validation/tests/Cases/ValidationExistsRuleTest.php index d767034cb..23c918259 100644 --- a/src/validation/tests/Cases/ValidationExistsRuleTest.php +++ b/src/validation/tests/Cases/ValidationExistsRuleTest.php @@ -20,7 +20,7 @@ use Hyperf\Database\Connectors\MySqlConnector; use Hyperf\Database\Model\Register; use Hyperf\Database\Schema\Builder; use Hyperf\DbConnection\ConnectionResolver as DBConnectionResolver; -use Hyperf\DbConnection\Model\Model as Eloquent; +use Hyperf\DbConnection\Model\Model; use Hyperf\Server\Entry\EventDispatcher; use Hyperf\Translation\ArrayLoader; use Hyperf\Translation\Translator; @@ -94,10 +94,10 @@ class ValidationExistsRuleTest extends TestCase $rule = new Exists('users', 'id'); $rule->whereIn('type', ['foo', 'bar']); - EloquentTestUser::create(['id' => '1', 'type' => 'foo']); - EloquentTestUser::create(['id' => '2', 'type' => 'bar']); - EloquentTestUser::create(['id' => '3', 'type' => 'baz']); - EloquentTestUser::create(['id' => '4', 'type' => 'other']); + DatabaseTestUser::create(['id' => '1', 'type' => 'foo']); + DatabaseTestUser::create(['id' => '2', 'type' => 'bar']); + DatabaseTestUser::create(['id' => '3', 'type' => 'baz']); + DatabaseTestUser::create(['id' => '4', 'type' => 'other']); $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, [], ['id' => $rule]); @@ -118,10 +118,10 @@ class ValidationExistsRuleTest extends TestCase $rule = new Exists('users', 'id'); $rule->whereNotIn('type', ['foo', 'bar']); - EloquentTestUser::create(['id' => '1', 'type' => 'foo']); - EloquentTestUser::create(['id' => '2', 'type' => 'bar']); - EloquentTestUser::create(['id' => '3', 'type' => 'baz']); - EloquentTestUser::create(['id' => '4', 'type' => 'other']); + DatabaseTestUser::create(['id' => '1', 'type' => 'foo']); + DatabaseTestUser::create(['id' => '2', 'type' => 'bar']); + DatabaseTestUser::create(['id' => '3', 'type' => 'baz']); + DatabaseTestUser::create(['id' => '4', 'type' => 'other']); $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, [], ['id' => $rule]); @@ -142,10 +142,10 @@ class ValidationExistsRuleTest extends TestCase $rule = new Exists('users', 'id'); $rule->whereIn('type', ['foo', 'bar', 'baz'])->whereNotIn('type', ['foo', 'bar']); - EloquentTestUser::create(['id' => '1', 'type' => 'foo']); - EloquentTestUser::create(['id' => '2', 'type' => 'bar']); - EloquentTestUser::create(['id' => '3', 'type' => 'baz']); - EloquentTestUser::create(['id' => '4', 'type' => 'other']); + DatabaseTestUser::create(['id' => '1', 'type' => 'foo']); + DatabaseTestUser::create(['id' => '2', 'type' => 'bar']); + DatabaseTestUser::create(['id' => '3', 'type' => 'baz']); + DatabaseTestUser::create(['id' => '4', 'type' => 'other']); $trans = $this->getIlluminateArrayTranslator(); $v = new Validator($trans, [], ['id' => $rule]); @@ -211,9 +211,9 @@ class ValidationExistsRuleTest extends TestCase } /** - * Eloquent Models. + * Database Models. */ -class EloquentTestUser extends Eloquent +class DatabaseTestUser extends Model { public $timestamps = false; diff --git a/src/validation/tests/Cases/ValidationInRuleTest.php b/src/validation/tests/Cases/ValidationInRuleTest.php index 6610316e9..e31a23fe6 100644 --- a/src/validation/tests/Cases/ValidationInRuleTest.php +++ b/src/validation/tests/Cases/ValidationInRuleTest.php @@ -25,9 +25,9 @@ class ValidationInRuleTest extends TestCase { public function testItCorrectlyFormatsAStringVersionOfTheRule() { - $rule = new In(['Laravel', 'Framework', 'PHP']); + $rule = new In(['Hyperf', 'Framework', 'PHP']); - $this->assertEquals('in:"Laravel","Framework","PHP"', (string) $rule); + $this->assertEquals('in:"Hyperf","Framework","PHP"', (string) $rule); $rule = new In(['Life, the Universe and Everything', 'this is a "quote"']); diff --git a/src/validation/tests/Cases/ValidationNotInRuleTest.php b/src/validation/tests/Cases/ValidationNotInRuleTest.php index 04070a14c..166809c51 100644 --- a/src/validation/tests/Cases/ValidationNotInRuleTest.php +++ b/src/validation/tests/Cases/ValidationNotInRuleTest.php @@ -24,9 +24,9 @@ class ValidationNotInRuleTest extends TestCase { public function testItCorrectlyFormatsAStringVersionOfTheRule() { - $rule = new NotIn(['Laravel', 'Framework', 'PHP']); + $rule = new NotIn(['Hyperf', 'Framework', 'PHP']); - $this->assertEquals('not_in:"Laravel","Framework","PHP"', (string) $rule); + $this->assertEquals('not_in:"Hyperf","Framework","PHP"', (string) $rule); $rule = Rule::notIn([1, 2, 3, 4]); diff --git a/src/validation/tests/Cases/ValidationUniqueRuleTest.php b/src/validation/tests/Cases/ValidationUniqueRuleTest.php index 4d925a7cf..04dfc9f3e 100644 --- a/src/validation/tests/Cases/ValidationUniqueRuleTest.php +++ b/src/validation/tests/Cases/ValidationUniqueRuleTest.php @@ -45,7 +45,7 @@ class ValidationUniqueRuleTest extends TestCase $rule->where('foo', 'bar'); $this->assertEquals('unique:table,column,NULL,id_column,foo,"bar"', (string) $rule); - $model = new EloquentModelStub(['id_column' => 1]); + $model = new DatabaseModelStub(['id_column' => 1]); $rule = new Unique('table', 'column'); $rule->ignore($model); @@ -63,7 +63,7 @@ class ValidationUniqueRuleTest extends TestCase } } -class EloquentModelStub extends Model +class DatabaseModelStub extends Model { protected $primaryKey = 'id_column'; From 8b929c24e5007192c32c18d5ccd426da85c613af Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 4 Sep 2019 17:55:00 +0800 Subject: [PATCH 78/79] Delete MessageBag.php --- src/validation/src/Support/MessageBag.php | 371 ---------------------- 1 file changed, 371 deletions(-) delete mode 100755 src/validation/src/Support/MessageBag.php diff --git a/src/validation/src/Support/MessageBag.php b/src/validation/src/Support/MessageBag.php deleted file mode 100755 index 686acb4d7..000000000 --- a/src/validation/src/Support/MessageBag.php +++ /dev/null @@ -1,371 +0,0 @@ - $value) { - $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; - - $this->messages[$key] = array_unique($value); - } - } - - /** - * Convert the message bag to its string representation. - */ - public function __toString(): string - { - return $this->toJson(); - } - - /** - * Get the keys present in the message bag. - */ - public function keys(): array - { - return array_keys($this->messages); - } - - /** - * Add a message to the message bag. - * - * @return $this - */ - public function add(string $key, string $message) - { - if ($this->isUnique($key, $message)) { - $this->messages[$key][] = $message; - } - - return $this; - } - - /** - * Merge a new array of messages into the message bag. - * - * @param array|MessageProvider $messages - * @return $this - */ - public function merge($messages) - { - if ($messages instanceof MessageProvider) { - $messages = $messages->getMessageBag()->getMessages(); - } - - $this->messages = array_merge_recursive($this->messages, $messages); - - return $this; - } - - /** - * Determine if messages exist for all of the given keys. - * - * @param array|string $key - */ - public function has($key): bool - { - if ($this->isEmpty()) { - return false; - } - - if (is_null($key)) { - return $this->any(); - } - - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $key) { - if ($this->first($key) === '') { - return false; - } - } - - return true; - } - - /** - * Determine if messages exist for any of the given keys. - * - * @param array|string $keys - */ - public function hasAny($keys = []): bool - { - if ($this->isEmpty()) { - return false; - } - - $keys = is_array($keys) ? $keys : func_get_args(); - - foreach ($keys as $key) { - if ($this->has($key)) { - return true; - } - } - - return false; - } - - /** - * Get the first message from the message bag for a given key. - * - * @param string $key - * @param string $format - */ - public function first($key = null, $format = null): string - { - $messages = is_null($key) ? $this->all($format) : $this->get($key, $format); - - $firstMessage = Arr::first($messages, null, ''); - - return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage; - } - - /** - * Get all of the messages from the message bag for a given key. - * - * @param string $format - */ - public function get(string $key, $format = null): array - { - // If the message exists in the message bag, we will transform it and return - // the message. Otherwise, we will check if the key is implicit & collect - // all the messages that match the given key and output it as an array. - if (array_key_exists($key, $this->messages)) { - return $this->transform( - $this->messages[$key], - $this->checkFormat($format), - $key - ); - } - - if (Str::contains($key, '*')) { - return $this->getMessagesForWildcardKey($key, $format); - } - - return []; - } - - /** - * Get all of the messages for every key in the message bag. - * - * @param string $format - */ - public function all($format = null): array - { - $format = $this->checkFormat($format); - - $all = []; - - foreach ($this->messages as $key => $messages) { - $all = array_merge($all, $this->transform($messages, $format, $key)); - } - - return $all; - } - - /** - * Get all of the unique messages for every key in the message bag. - * - * @param string $format - */ - public function unique($format = null): array - { - return array_unique($this->all($format)); - } - - /** - * Get the raw messages in the message bag. - */ - public function messages(): array - { - return $this->messages; - } - - /** - * Get the raw messages in the message bag. - */ - public function getMessages(): array - { - return $this->messages(); - } - - /** - * Get the messages for the instance. - * - * @return MessageBag - */ - public function getMessageBag() - { - return $this; - } - - /** - * Get the default message format. - */ - public function getFormat(): string - { - return $this->format; - } - - /** - * Set the default message format. - * - * @return MessageBag - */ - public function setFormat(string $format = ':message') - { - $this->format = $format; - - return $this; - } - - /** - * Determine if the message bag has any messages. - */ - public function isEmpty(): bool - { - return ! $this->any(); - } - - /** - * Determine if the message bag has any messages. - */ - public function isNotEmpty(): bool - { - return $this->any(); - } - - /** - * Determine if the message bag has any messages. - */ - public function any(): bool - { - return $this->count() > 0; - } - - /** - * Get the number of messages in the message bag. - */ - public function count(): int - { - return count($this->messages, COUNT_RECURSIVE) - count($this->messages); - } - - /** - * Get the instance as an array. - */ - public function toArray(): array - { - return $this->getMessages(); - } - - /** - * Convert the object into something JSON serializable. - */ - public function jsonSerialize(): array - { - return $this->toArray(); - } - - /** - * Convert the object to its JSON representation. - */ - public function toJson(int $options = 0): string - { - return json_encode($this->jsonSerialize(), $options); - } - - /** - * Determine if a key and message combination already exists. - */ - protected function isUnique(string $key, string $message): bool - { - $messages = (array) $this->messages; - - return ! isset($messages[$key]) || ! in_array($message, $messages[$key]); - } - - /** - * Get the messages for a wildcard key. - * - * @param null|string $format - */ - protected function getMessagesForWildcardKey(string $key, $format): array - { - return collect($this->messages) - ->filter(function ($messages, $messageKey) use ($key) { - return Str::is($key, $messageKey); - }) - ->map(function ($messages, $messageKey) use ($format) { - return $this->transform( - $messages, - $this->checkFormat($format), - $messageKey - ); - })->all(); - } - - /** - * Format an array of messages. - */ - protected function transform(array $messages, string $format, string $messageKey): array - { - return collect($messages) - ->map(function ($message) use ($format, $messageKey) { - // We will simply spin through the given messages and transform each one - // replacing the :message place holder with the real message allowing - // the messages to be easily formatted to each developer's desires. - return str_replace([':message', ':key'], [$message, $messageKey], $format); - })->all(); - } - - /** - * Get the appropriate format based on the given format. - * - * @param string $format - * @return string - */ - protected function checkFormat($format) - { - return $format ?: $this->format; - } -} From 757180c70b8a79e174038ceee717d71c1a21163a Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Wed, 4 Sep 2019 17:55:05 +0800 Subject: [PATCH 79/79] Update ValidatorFactory.php --- src/validation/src/ValidatorFactory.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/validation/src/ValidatorFactory.php b/src/validation/src/ValidatorFactory.php index 9a5ba7ef3..d1061353e 100755 --- a/src/validation/src/ValidatorFactory.php +++ b/src/validation/src/ValidatorFactory.php @@ -22,13 +22,24 @@ class ValidatorFactory { $translator = $container->get(TranslatorInterface::class); - $validator = make(Factory::class, compact('translator', 'container')); + /** @var \Hyperf\Validation\Factory $validatorFactory */ + $validatorFactory = make(Factory::class, compact('translator', 'container')); if ($container->has(ConnectionResolverInterface::class) && $container->has(PresenceVerifierInterface::class)) { $presenceVerifier = $container->get(PresenceVerifierInterface::class); - $validator->setPresenceVerifier($presenceVerifier); + $validatorFactory->setPresenceVerifier($presenceVerifier); } - return $validator; + $validatorFactory->resolver(function ( + TranslatorInterface $translator, + array $data, + array $rules, + array $messages = [], + array $customAttributes = [] + ) { + return make(Validator::class, [$translator, $data, $rules, $messages, $customAttributes]); + }); + + return $validatorFactory; } }