Skip to content

Commit 56041d8

Browse files
committed
Try to fix vies valdiation api
1 parent 6f52cd8 commit 56041d8

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

src/Resources/config/services.xml

+3
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,8 @@
2828
<tag name="sylius.taxation.calculation_strategy" type="italian_tax_calculation_strategy" label="Italian tax calculation" />
2929
</service>
3030

31+
<service id="app.validator.constraint.vat_number_validator" class="Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints\VatNumberValidator" decorates="sandwich_vies.validator.constraint.vat_number_validator">
32+
<argument type="service" id="sandwich_vies.vies_api"/>
33+
</service>
3134
</services>
3235
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints;
6+
7+
use DragonBe\Vies\Vies;
8+
use DragonBe\Vies\ViesException;
9+
use DragonBe\Vies\ViesServiceException;
10+
use Sandwich\ViesBundle\Validator\Constraint\VatNumber;
11+
use Symfony\Component\Validator\Constraint;
12+
use Symfony\Component\Validator\ConstraintValidator;
13+
use Webgriffe\SyliusItalianInvoiceableOrderPlugin\Vies\HeartBeat;
14+
15+
final class VatNumberValidator extends ConstraintValidator
16+
{
17+
public function __construct(private Vies $viesApi)
18+
{
19+
}
20+
21+
public function validate($value, Constraint $constraint): void
22+
{
23+
if (empty($value)) {
24+
return;
25+
}
26+
27+
if (!$constraint instanceof VatNumber) {
28+
return;
29+
}
30+
31+
$this->viesApi->setHeartBeat(new HeartBeat());
32+
33+
if (!$this->viesApi->getHeartBeat()->isAlive()) {
34+
//VIES service is not available
35+
return;
36+
}
37+
38+
$format = $constraint->getFormat();
39+
$isValid = false;
40+
41+
try {
42+
$isValid = $this->viesApi->validateVat($format, str_replace($format, '', $value))->isValid();
43+
} catch (ViesServiceException $exception) {
44+
//There is probably a temporary problem with back-end VIES service
45+
return;
46+
} catch (ViesException $exception) {
47+
}
48+
49+
if ($isValid) {
50+
return;
51+
}
52+
53+
$this->context->addViolation($constraint->message, ['%format%' => $format]);
54+
}
55+
}

src/Vies/HeartBeat.php

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Webgriffe\SyliusItalianInvoiceableOrderPlugin\Vies;
6+
7+
use DragonBe\Vies\HeartBeat as BaseHeartBeat;
8+
use DragonBe\Vies\Vies;
9+
use InvalidArgumentException;
10+
use RuntimeException;
11+
12+
final class HeartBeat extends BaseHeartBeat
13+
{
14+
private const DEFAULT_TIMEOUT = 10;
15+
16+
public function isAlive(): bool
17+
{
18+
if (false === self::$testingEnabled) {
19+
return $this->reachOut();
20+
}
21+
22+
return self::$testingServiceIsUp;
23+
}
24+
25+
/**
26+
* A private routine to send a request over a socket to
27+
* test if the remote service is responding with a status
28+
* code of 200 OK. Now supports also proxy connections.
29+
*
30+
* @return bool
31+
*/
32+
private function reachOut(): bool
33+
{
34+
try {
35+
$data = $this->getSecuredResponse();
36+
} catch (RuntimeException $runtimeException) {
37+
return false;
38+
}
39+
40+
return (
41+
(0 === strcmp('HTTP/1.1 200 OK', $data[0])) ||
42+
(0 === strcmp('HTTP/1.1 307 Temporary Redirect', $data[0]))
43+
);
44+
}
45+
46+
/**
47+
* This method will make a simple request inside a stream
48+
* resource to retrieve its contents. Useful inside secured
49+
* streams.
50+
*
51+
* @param resource $handle
52+
* @return array
53+
*/
54+
private function readContents($handle): array
55+
{
56+
if (! is_resource($handle)) {
57+
throw new InvalidArgumentException('Expecting a resource to be provided');
58+
}
59+
$response = '';
60+
$uri = sprintf('%s://%s/taxation_customs/vies', Vies::VIES_PROTO, $this->host);
61+
$stream = [
62+
'GET ' . $uri . ' HTTP/1.0',
63+
'Host: ' . $this->host,
64+
'Connection: close',
65+
];
66+
fwrite($handle, implode("\r\n", $stream) . "\r\n\r\n");
67+
while (! feof($handle)) {
68+
$response .= fgets($handle, 1024);
69+
}
70+
fclose($handle);
71+
$response = str_replace("\r\n", PHP_EOL, $response);
72+
73+
return explode(PHP_EOL, $response);
74+
}
75+
76+
/**
77+
* Will make a secured request over SSL/TLS where this
78+
* method will first create a secured stream before
79+
* making the request.
80+
*
81+
* @return array
82+
* @throws RuntimeException
83+
* @see https://bytephunk.wordpress.com/2017/11/27/ssl-tls-stream-sockets-in-php-7/
84+
*/
85+
private function getSecuredResponse(): array
86+
{
87+
$streamOptions = [
88+
'ssl' => [
89+
'verify_peer' => true,
90+
'verify_peer_name' => true,
91+
'allow_self_signed' => false,
92+
],
93+
];
94+
$streamContext = stream_context_create($streamOptions);
95+
$socketAddress = sprintf(
96+
'tls://%s:%d',
97+
$this->host,
98+
$this->port
99+
);
100+
$error = null;
101+
$errno = null;
102+
$stream = stream_socket_client(
103+
$socketAddress,
104+
$errno,
105+
$error,
106+
self::DEFAULT_TIMEOUT,
107+
STREAM_CLIENT_CONNECT,
108+
$streamContext
109+
);
110+
111+
if (! $stream) {
112+
throw new RuntimeException('Can not create socket stream: ' . $error);
113+
}
114+
115+
return $this->readContents($stream);
116+
}
117+
}

0 commit comments

Comments
 (0)