diff --git a/.github/workflows/php.yml b/.github/workflows/codecov.yml similarity index 91% rename from .github/workflows/php.yml rename to .github/workflows/codecov.yml index 147cf17..4d1d440 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/codecov.yml @@ -1,10 +1,8 @@ -name: Build +name: Codecov on: - push: - branches: [ master ] - pull_request: - branches: [ master ] + push: ~ + pull_request: ~ jobs: build: diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml new file mode 100644 index 0000000..d59a5d3 --- /dev/null +++ b/.github/workflows/psalm.yml @@ -0,0 +1,36 @@ +name: Psalm + +on: + push: ~ + pull_request: ~ + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Psalm + run: | + ./vendor/bin/psalm --no-progress || ./vendor/bin/psalm --output-format=github --no-progress diff --git a/README.md b/README.md index 651c7c8..03d9701 100755 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ use Dzhdmitry\TinkoffInvestApi\Streaming\WebsocketConnectionFactory; while ($message = yield $connection->receive()) { /** @var \Amp\Websocket\Message $message полученное из WebSocket сообщение */ - /** @var AbstractResponse $response десериализованное тело сообщения */ + /** @var AbstractResponse $response десериализованное тело сообщения */ $response = $deserializer->deserialize(yield $message->buffer()); echo $response->getEvent() . ' at ' . $response->getTime()->format(DATE_RFC3339) . "\n"; diff --git a/composer.json b/composer.json index e5622ae..1dd955a 100755 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ } }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "^4.9" } } diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..c23e3ca --- /dev/null +++ b/psalm.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/src/Rest/Schema/Payload/MoneyAmount.php b/src/Rest/Schema/Payload/MoneyAmount.php index bafd647..e6a4083 100644 --- a/src/Rest/Schema/Payload/MoneyAmount.php +++ b/src/Rest/Schema/Payload/MoneyAmount.php @@ -16,12 +16,12 @@ class MoneyAmount /** * @param string $currency - * @param float $value + * @param $value */ public function __construct(string $currency, $value) { $this->currency = $currency; - $this->value = $value; + $this->value = (float) $value; } /** @@ -45,10 +45,6 @@ public function getValue(): float */ public function __toString(): string { - return sprintf( - is_float($this->value) ? '%.2f %s' : '%d %s', - $this->value, - $this->currency - ); + return sprintf('%.2f %s', $this->value, $this->currency); } } diff --git a/src/Streaming/Connection.php b/src/Streaming/Connection.php index 937b198..c630578 100644 --- a/src/Streaming/Connection.php +++ b/src/Streaming/Connection.php @@ -11,6 +11,7 @@ use Amp\Websocket\ClientMetadata; use Amp\Websocket\ClosedException; use Amp\Websocket\Code; +use Amp\Websocket\Message; use Amp\Websocket\Options; use Dzhdmitry\TinkoffInvestApi\Streaming\Schema\Request\RequestInterface; @@ -54,7 +55,7 @@ public function unsubscribe(RequestInterface $request): Promise } /** - * @return Promise + * @return Promise * * @throws ClosedException */ @@ -67,7 +68,7 @@ public function receive(): Promise * @param int $code * @param string $reason * - * @return Promise + * @return Promise */ public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Promise { diff --git a/src/Streaming/Denormalizer/ResponseDenormalizer.php b/src/Streaming/Denormalizer/ResponseDenormalizer.php index 4e68fb3..b19ab7e 100644 --- a/src/Streaming/Denormalizer/ResponseDenormalizer.php +++ b/src/Streaming/Denormalizer/ResponseDenormalizer.php @@ -6,11 +6,12 @@ use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerAwareTrait; /** - * Десериализует ассоциативныймассив в один из объектов, унаследованных от AbstractResponse. + * Десериализует ассоциативный массив в один из объектов, унаследованных от AbstractResponse. * Класс обекта определяет по полю "event" массива */ class ResponseDenormalizer implements ContextAwareDenormalizerInterface, SerializerAwareInterface @@ -25,7 +26,7 @@ class ResponseDenormalizer implements ContextAwareDenormalizerInterface, Seriali /** * @param string[] $responseTypes */ - public function __construct($responseTypes) + public function __construct(array $responseTypes) { $this->responseTypes = $responseTypes; } @@ -53,6 +54,10 @@ public function denormalize($data, string $type, string $format = null, array $c throw new UnexpectedValueException('Data has unknown event type ' . $data['event']); } + if (!($this->serializer instanceof Serializer)) { + throw new \LogicException('Serializer must be instance of ' . Serializer::class); + } + return $this->serializer->denormalize($data, $this->responseTypes[$data['event']], $format, $context); } }