diff --git a/README.md b/README.md index 0ff9cad..16fff83 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Example `.env` variables (or export in shell): ``` MAILTRAP_API_KEY=your_api_token # https://mailtrap.io/api-tokens MAILTRAP_USE_SANDBOX=true # true/false toggle -MAILTRAP_INBOX_ID=123456 # Only needed for sandbox +MAILTRAP_SANDBOX_ID=123456 # Only needed for sandbox ``` Bootstrap logic: @@ -93,12 +93,12 @@ require __DIR__ . '/vendor/autoload.php'; $apiKey = getenv('MAILTRAP_API_KEY'); $isSandbox = filter_var(getenv('MAILTRAP_USE_SANDBOX'), FILTER_VALIDATE_BOOL); -$inboxId = $isSandbox ? getenv('MAILTRAP_INBOX_ID') : null; // required only for sandbox +$sandboxId = $isSandbox ? getenv('MAILTRAP_SANDBOX_ID') : null; // required only for sandbox $client = MailtrapClient::initSendingEmails( apiKey: $apiKey, isSandbox: $isSandbox, - inboxId: $inboxId // null is ignored for production + sandboxId: $sandboxId // null is ignored for production ); $email = (new MailtrapEmail()) @@ -142,7 +142,7 @@ $mailtrap = MailtrapClient::initSendingEmails( apiKey: getenv('MAILTRAP_API_KEY'), # your API token isBulk: false, # set to true for bulk email sending (false by default) isSandbox: false, # set to true for sandbox mode (false by default) - inboxId: null # optional, only for sandbox mode (false by default) + sandboxId: null # required only for sandbox mode (null by default) ); $email = (new MailtrapEmail()) @@ -239,21 +239,21 @@ Email API: - Batch send (Bulk) – [`batch/bulk.php`](examples/batch/bulk.php) - Batch send with Template (Transactional) – [`batch/transactional_template.php`](examples/batch/transactional_template.php) - Batch send with Template (Bulk) – [`batch/bulk_template.php`](examples/batch/bulk_template.php) -- Sending domain management CRUD – [`sending-domains/all.php`](examples/sending-domains/all.php) -- Sending domain company info – [`sending-domains/company-info.php`](examples/sending-domains/company-info.php) +- Domain management CRUD – [`domains/all.php`](examples/domains/all.php) +- Domain company info – [`domains/company-info.php`](examples/domains/company-info.php) - Suppressions (create, find & delete) – [`sending/suppressions.php`](examples/sending/suppressions.php) - Tracking Opt-outs (list, create & delete) – [`sending/tracking-opt-outs.php`](examples/sending/tracking-opt-outs.php) - Email Logs (list & get by message ID) – [`sending/email-logs.php`](examples/sending/email-logs.php) -Email Sandbox (Testing): -- Send an email (Sandbox) – [`testing/send-mail.php`](examples/testing/send-mail.php) -- Send an email with a Template (Sandbox) – [`testing/template.php`](examples/testing/template.php) +Email Sandbox: +- Send an email (Sandbox) – [`sandbox/send-mail.php`](examples/sandbox/send-mail.php) +- Send an email with a Template (Sandbox) – [`sandbox/template.php`](examples/sandbox/template.php) - Batch send (Sandbox) – [`batch/sandbox.php`](examples/batch/sandbox.php) - Batch send with Template (Sandbox) – [`batch/sandbox_template.php`](examples/batch/sandbox_template.php) -- Message management CRUD – [`testing/messages.php`](examples/testing/messages.php) -- Inbox management CRUD – [`testing/inboxes.php`](examples/testing/inboxes.php) -- Project management CRUD – [`testing/projects.php`](examples/testing/projects.php) -- Attachments operations – [`testing/attachments.php`](examples/testing/attachments.php) +- Message management CRUD – [`sandbox/messages.php`](examples/sandbox/messages.php) +- Sandbox management CRUD – [`sandbox/sandboxes.php`](examples/sandbox/sandboxes.php) +- Project management CRUD – [`sandbox/projects.php`](examples/sandbox/projects.php) +- Attachments operations – [`sandbox/attachments.php`](examples/sandbox/attachments.php) Inbound Email API: - Folder management CRUD – [`inbound/folders.php`](examples/inbound/folders.php) @@ -297,6 +297,31 @@ See the full indexed list at [`examples/README.md`](examples/README.md). Webhooks: - Verifying webhook signatures – [`webhooks/verify_signature.php`](examples/webhooks/verify_signature.php) +## Renamed APIs + +The Email Sandbox's testing inboxes are now called **sandboxes**, and sending domains are now called **domains**. +The SDK follows these names. The old ones still work: they call the same API endpoints, and each emits an +`E_USER_DEPRECATED` notice the first time it is used. Symfony and Laravel log these notices; plain PHP ignores them. +The old names will be removed in a future major release. + +| Old name (deprecated) | New name | +|---|---| +| `MailtrapSandboxClient::inboxes($accountId)` | `MailtrapSandboxClient::sandboxes($accountId)` | +| `Mailtrap\Api\Sandbox\Inbox` | `Mailtrap\Api\Sandbox\Sandbox` | +| `Inbox::getInboxAttributes($inboxId)` | `Sandbox::getSandboxAttributes($sandboxId)` | +| `Mailtrap\DTO\Request\Inbox` | `Mailtrap\DTO\Request\Sandbox` | +| `inboxId:` argument of `MailtrapClient::initSendingEmails()` and of the sandbox `emails()`, `messages()` and `attachments()` | `sandboxId:` | +| `getInboxId()` of the sandbox `Emails`, `Message` and `Attachment` APIs | `getSandboxId()` | +| Symfony DSN option `?inboxId=` | `?sandboxId=` | +| Laravel `services.mailtrap-sdk.inboxId` config key | `services.mailtrap-sdk.sandboxId` (`MAILTRAP_SANDBOX_ID`) | +| `Domain::getSendingDomains()` | `Domain::getDomains()` | +| `Domain::createSendingDomain($domainName)` | `Domain::createDomain($domainName)` | +| `Domain::updateSendingDomain($domainId, $domain)` | `Domain::updateDomain($domainId, $domain)` | +| `Domain::deleteSendingDomain($domainId)` | `Domain::deleteDomain($domainId)` | + +Names that mirror an API field keep the old term, for example `inbox_id` in message responses, +`User::getList($inboxIds)`, `PermissionInterface::TYPE_INBOX` and the `sendingDomainIds` stats filters. + ## Contributing Bug reports and pull requests are welcome on [GitHub](https://github.com/railsware/mailtrap-php). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md). diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index 8483f9d..9f7ba16 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -68,7 +68,7 @@ UPGRADE FROM 1.x to 2.0 ``` ### Sandbox API -* **BC BREAK**: Rebuild `Projects` & `Messages` & `Attachments` & `Inboxes` layers ([examples](examples/testing)) +* **BC BREAK**: Rebuild `Projects` & `Messages` & `Attachments` & `Inboxes` layers ([examples](examples/sandbox)) __Before__: ```php diff --git a/examples/README.md b/examples/README.md index 084516e..1633c50 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,8 +3,8 @@ Central index of runnable example scripts demonstrating Mailtrap PHP SDK features. Each script is intentionally minimal; open the file to inspect parameters. Run examples from project root (adjust env vars first). ## Prerequisites -* Export or place inside the file your ENV variables (MAILTRAP_API_KEY, MAILTRAP_INBOX_ID, etc) -* Some examples require a verified sending domain (production / bulk / templates). +* Export or place inside the file your ENV variables (MAILTRAP_API_KEY, MAILTRAP_SANDBOX_ID, etc) +* Some examples require a verified domain (production / bulk / templates). ## Contents @@ -31,16 +31,16 @@ Central index of runnable example scripts demonstrating Mailtrap PHP SDK feature | Sandbox batch send | [`batch/sandbox.php`](batch/sandbox.php) | | Sandbox batch send (template) | [`batch/sandbox_template.php`](batch/sandbox_template.php) | -### Sandbox (Email Testing) +### Email Sandbox | Purpose | File | |---------|------| -| Sandbox transactional send | [`testing/send-mail.php`](testing/send-mail.php) | -| Sandbox send with template | [`testing/template.php`](testing/template.php) | -| Manage attachments of a message | [`testing/attachments.php`](testing/attachments.php) | -| Inbox CRUD / listing | [`testing/inboxes.php`](testing/inboxes.php) | -| Message CRUD / listing | [`testing/messages.php`](testing/messages.php) | -| Project CRUD / listing | [`testing/projects.php`](testing/projects.php) | +| Sandbox transactional send | [`sandbox/send-mail.php`](sandbox/send-mail.php) | +| Sandbox send with template | [`sandbox/template.php`](sandbox/template.php) | +| Manage attachments of a message | [`sandbox/attachments.php`](sandbox/attachments.php) | +| Sandbox CRUD / listing | [`sandbox/sandboxes.php`](sandbox/sandboxes.php) | +| Message CRUD / listing | [`sandbox/messages.php`](sandbox/messages.php) | +| Project CRUD / listing | [`sandbox/projects.php`](sandbox/projects.php) | ### Inbound Email @@ -68,8 +68,8 @@ Central index of runnable example scripts demonstrating Mailtrap PHP SDK feature |---------|------| | Templates CRUD + paginated list (experimental) | [`templates/templates.php`](templates/templates.php) | | Email templates CRUD | [`templates/all.php`](templates/all.php) | -| Sending domains CRUD | [`sending-domains/all.php`](sending-domains/all.php) | -| Sending domain company info | [`sending-domains/company-info.php`](sending-domains/company-info.php) | +| Domains CRUD | [`domains/all.php`](domains/all.php) | +| Domain company info | [`domains/company-info.php`](domains/company-info.php) | ### General API @@ -104,6 +104,6 @@ For batch examples, ensure the stream (bulk vs transactional vs sandbox) matches ## Tips - Keep secrets out of committed files; rely on environment variables. - Template examples require existing template UUIDs in your Mailtrap account. -- Sandbox examples need `MAILTRAP_INBOX_ID`. +- Sandbox examples need `MAILTRAP_SANDBOX_ID`. --- diff --git a/examples/batch/bulk.php b/examples/batch/bulk.php index 188479b..dc92303 100644 --- a/examples/batch/bulk.php +++ b/examples/batch/bulk.php @@ -16,7 +16,7 @@ * Users of this endpoint should check the success and errors for each message in the response (the results are ordered the same as the original messages - requests). * Please note that the endpoint accepts up to 500 messages per API call, and up to 50 MB payload size, including attachments. * - * For this example, you need to have ready-to-use sending domain or, a Demo domain that allows sending emails to your own account email. + * For this example, you need to have ready-to-use domain or, a Demo domain that allows sending emails to your own account email. * @see https://help.mailtrap.io/article/69-sending-domain-setup */ try { diff --git a/examples/batch/bulk_template.php b/examples/batch/bulk_template.php index ff851de..4cf74c9 100644 --- a/examples/batch/bulk_template.php +++ b/examples/batch/bulk_template.php @@ -15,7 +15,7 @@ * UUID of email template. Subject, text and html will be generated from template using optional template_variables. * Optional template variables that will be used to generate actual subject, text and html from email template * - * For this example, you need to have ready-to-use sending domain or, a Demo domain that allows sending emails to your own account email. + * For this example, you need to have ready-to-use domain or, a Demo domain that allows sending emails to your own account email. * @see https://help.mailtrap.io/article/69-sending-domain-setup */ try { diff --git a/examples/batch/sandbox.php b/examples/batch/sandbox.php index 133a0e9..c1e5c6b 100644 --- a/examples/batch/sandbox.php +++ b/examples/batch/sandbox.php @@ -19,7 +19,7 @@ $mailtrap = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], #your API token from here https://mailtrap.io/api-tokens isSandbox: true, # Sandbox sending (@see https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing) - inboxId: $_ENV['MAILTRAP_INBOX_ID'] # required param for sandbox sending + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'] # required param for sandbox sending ); $baseEmail = (new MailtrapEmail()) diff --git a/examples/batch/sandbox_template.php b/examples/batch/sandbox_template.php index 329629b..5e462e3 100644 --- a/examples/batch/sandbox_template.php +++ b/examples/batch/sandbox_template.php @@ -19,7 +19,7 @@ $mailtrap = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], #your API token from here https://mailtrap.io/api-tokens isSandbox: true, # Sandbox sending (@see https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing) - inboxId: $_ENV['MAILTRAP_INBOX_ID'] # required param for sandbox sending + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'] # required param for sandbox sending ); $baseEmail = (new MailtrapEmail()) diff --git a/examples/batch/transactional.php b/examples/batch/transactional.php index 028448f..39d470c 100644 --- a/examples/batch/transactional.php +++ b/examples/batch/transactional.php @@ -16,7 +16,7 @@ * Users of this endpoint should check the success and errors for each message in the response (the results are ordered the same as the original messages - requests). * Please note that the endpoint accepts up to 500 messages per API call, and up to 50 MB payload size, including attachments. * - * For this example, you need to have ready-to-use sending domain or, a Demo domain that allows sending emails to your own account email. + * For this example, you need to have ready-to-use domain or, a Demo domain that allows sending emails to your own account email. * @see https://help.mailtrap.io/article/69-sending-domain-setup */ try { diff --git a/examples/batch/transactional_template.php b/examples/batch/transactional_template.php index 83c646e..629cfaa 100644 --- a/examples/batch/transactional_template.php +++ b/examples/batch/transactional_template.php @@ -15,7 +15,7 @@ * UUID of email template. Subject, text and html will be generated from template using optional template_variables. * Optional template variables that will be used to generate actual subject, text and html from email template * - * For this example, you need to have ready-to-use sending domain or, a Demo domain that allows sending emails to your own account email. + * For this example, you need to have ready-to-use domain or, a Demo domain that allows sending emails to your own account email. * @see https://help.mailtrap.io/article/69-sending-domain-setup */ try { diff --git a/examples/sending-domains/all.php b/examples/domains/all.php similarity index 80% rename from examples/sending-domains/all.php rename to examples/domains/all.php index 415a1e7..47ed3bf 100644 --- a/examples/sending-domains/all.php +++ b/examples/domains/all.php @@ -12,15 +12,15 @@ $accountId = (int) $_ENV['MAILTRAP_ACCOUNT_ID']; $config = new Config($_ENV['MAILTRAP_API_KEY']); #your API token from here https://mailtrap.io/api-tokens -$sendingDomains = (new MailtrapSendingClient($config))->domains($accountId); #required parameter is accountId +$domains = (new MailtrapSendingClient($config))->domains($accountId); #required parameter is accountId /** - * Get a list of sending domains. + * Get a list of domains. * * GET https://mailtrap.io/api/accounts/{account_id}/domains */ try { - $response = $sendingDomains->getSendingDomains(); + $response = $domains->getDomains(); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -30,14 +30,14 @@ /** - * Create a new sending domain + * Create a new domain * * POST https://mailtrap.io/api/accounts/{account_id}/domains */ try { $domainName = 'example.com'; - $response = $sendingDomains->createSendingDomain($domainName); + $response = $domains->createDomain($domainName); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -47,14 +47,14 @@ /** - * Get a sending domain by ID + * Get a domain by ID * * GET https://mailtrap.io/api/accounts/{account_id}/domains/{domain_id} */ try { $domainId = (int) $_ENV['MAILTRAP_DOMAIN_ID']; // Set this environment variable with a valid domain ID - $response = $sendingDomains->getDomainById($domainId); + $response = $domains->getDomainById($domainId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -72,7 +72,7 @@ $domainId = (int) $_ENV['MAILTRAP_DOMAIN_ID']; // Set this environment variable with a valid domain ID $email = 'devops@example.com'; // Email address to send setup instructions to - $response = $sendingDomains->sendDomainSetupInstructions($domainId, $email); + $response = $domains->sendDomainSetupInstructions($domainId, $email); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -82,14 +82,14 @@ /** - * Update sending domain configuration settings + * Update domain configuration settings * * PATCH https://mailtrap.io/api/accounts/{account_id}/domains/{domain_id} */ try { $domainId = (int) $_ENV['MAILTRAP_DOMAIN_ID']; // Set this environment variable with a valid domain ID - $response = $sendingDomains->updateSendingDomain( + $response = $domains->updateDomain( $domainId, new UpdateDomain( openTrackingEnabled: true, @@ -108,14 +108,14 @@ /** - * Delete a sending domain + * Delete a domain * * DELETE https://mailtrap.io/api/accounts/{account_id}/domains/{domain_id} */ try { $domainId = (int) $_ENV['MAILTRAP_DOMAIN_ID']; // Set this environment variable with a valid domain ID - $response = $sendingDomains->deleteSendingDomain($domainId); + $response = $domains->deleteDomain($domainId); // Print the response status code var_dump($response->getStatusCode()); diff --git a/examples/sending-domains/company-info.php b/examples/domains/company-info.php similarity index 94% rename from examples/sending-domains/company-info.php rename to examples/domains/company-info.php index 045310b..818d68f 100644 --- a/examples/sending-domains/company-info.php +++ b/examples/domains/company-info.php @@ -17,7 +17,7 @@ $companyInfo = (new MailtrapSendingClient($config))->companyInfo($domainId); #required parameter is domainId /** - * Create company info for a sending domain + * Create company info for a domain * * POST https://mailtrap.io/api/domains/{domain_id}/company_info */ @@ -45,7 +45,7 @@ /** - * Get company info for a sending domain + * Get company info for a domain * * GET https://mailtrap.io/api/domains/{domain_id}/company_info */ @@ -60,7 +60,7 @@ /** - * Update company info for a sending domain + * Update company info for a domain * * PATCH https://mailtrap.io/api/domains/{domain_id}/company_info * diff --git a/examples/email-campaigns/all.php b/examples/email-campaigns/all.php index 9aa94f6..f89178d 100644 --- a/examples/email-campaigns/all.php +++ b/examples/email-campaigns/all.php @@ -42,7 +42,7 @@ try { $response = $emailCampaigns->createEmailCampaign(new CreateEmailCampaign( name: 'Spring Sale', - domainId: (int) $_ENV['MAILTRAP_DOMAIN_ID'], // set this environment variable with your sending domain ID + domainId: (int) $_ENV['MAILTRAP_DOMAIN_ID'], // set this environment variable with your domain ID fromLocalPart: 'news', templateAttributes: new TemplateAttributes(subject: 'Spring is here — 30% off'), fromDisplayName: 'Acme Marketing', diff --git a/examples/general/billing.php b/examples/general/billing.php index 4180ac6..8e73134 100644 --- a/examples/general/billing.php +++ b/examples/general/billing.php @@ -12,7 +12,7 @@ /** - * Get current billing cycle usage for Email Testing and Email Sending. + * Get current billing cycle usage for Email Sandbox and Email Sending. * * GET https://mailtrap.io/api/accounts/{account_id}/billing/usage */ diff --git a/examples/laravel/sandbox.php b/examples/laravel/sandbox.php index 2465dd2..5b8ade2 100644 --- a/examples/laravel/sandbox.php +++ b/examples/laravel/sandbox.php @@ -19,7 +19,7 @@ $response = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], // your API token from here https://mailtrap.io/api-tokens isSandbox: true, - inboxId: $_ENV['MAILTRAP_INBOX_ID'], // your Inbox ID from here https://mailtrap.io/inboxes + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'], // your Sandbox ID from here https://mailtrap.io/inboxes )->send($email); var_dump(ResponseHelper::toArray($response)); diff --git a/examples/marketing-stats/all.php b/examples/marketing-stats/all.php index 588d6a3..aed2945 100644 --- a/examples/marketing-stats/all.php +++ b/examples/marketing-stats/all.php @@ -38,7 +38,7 @@ /** * Get Email Marketing stats with filters: campaigns only, sent to Google and Yahoo. - * Pass `sendingDomainIds` as well to narrow the stats to specific sending domains. + * Pass `sendingDomainIds` as well to narrow the stats to specific domains. * * GET https://mailtrap.io/api/marketing/stats */ diff --git a/examples/testing/attachments.php b/examples/sandbox/attachments.php similarity index 91% rename from examples/testing/attachments.php rename to examples/sandbox/attachments.php index 1a10c74..d3b6d54 100644 --- a/examples/testing/attachments.php +++ b/examples/sandbox/attachments.php @@ -7,10 +7,10 @@ require __DIR__ . '/../../vendor/autoload.php'; $accountId = $_ENV['MAILTRAP_ACCOUNT_ID']; -$inboxId = $_ENV['MAILTRAP_INBOX_ID']; +$sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; $config = new Config($_ENV['MAILTRAP_API_KEY']); #your API token from here https://mailtrap.io/api-tokens -$sandboxAttachments = (new MailtrapSandboxClient($config))->attachments($accountId, $inboxId); #required parameters are accountId amd inboxId +$sandboxAttachments = (new MailtrapSandboxClient($config))->attachments($accountId, $sandboxId); #required parameters are accountId and sandboxId /** diff --git a/examples/testing/messages.php b/examples/sandbox/messages.php similarity index 87% rename from examples/testing/messages.php rename to examples/sandbox/messages.php index b9301e5..a6d6355 100644 --- a/examples/testing/messages.php +++ b/examples/sandbox/messages.php @@ -8,10 +8,10 @@ // your API token from here https://mailtrap.io/api-tokens $accountId = $_ENV['MAILTRAP_ACCOUNT_ID']; -$inboxId = $_ENV['MAILTRAP_INBOX_ID']; +$sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; $config = new Config($_ENV['MAILTRAP_API_KEY']); #your API token from here https://mailtrap.io/api-tokens -$sandboxMessages = (new MailtrapSandboxClient($config))->messages($accountId, $inboxId); #required parameters are accountId and inboxId +$sandboxMessages = (new MailtrapSandboxClient($config))->messages($accountId, $sandboxId); #required parameters are accountId and sandboxId /** * Get messages @@ -40,7 +40,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id} */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getById($messageId); @@ -57,7 +57,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/body.htmlsource */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getSource($messageId); @@ -74,7 +74,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/body.eml */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getEml($messageId); @@ -91,7 +91,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/body.html */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getHtml($messageId); @@ -108,7 +108,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/body.raw */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getRaw($messageId); @@ -125,7 +125,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/body.txt */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getText($messageId); @@ -142,7 +142,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/analyze */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getHtmlAnalysis($messageId); @@ -159,7 +159,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/spam_report */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getSpamScore($messageId); @@ -176,7 +176,7 @@ * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id} */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->markAsRead($messageId); @@ -193,7 +193,7 @@ * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/mail_headers */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->getMailHeaders($messageId); @@ -209,7 +209,7 @@ * POST https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id}/forward */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->forward($messageId, 'recipient@example.com'); @@ -225,7 +225,7 @@ * DELETE https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/messages/{message_id} */ try { - $messageId = $_ENV['MAILTRAP_INBOX_MESSAGE_ID']; + $messageId = $_ENV['MAILTRAP_SANDBOX_MESSAGE_ID']; $response = $sandboxMessages->delete($messageId); diff --git a/examples/testing/projects.php b/examples/sandbox/projects.php similarity index 94% rename from examples/testing/projects.php rename to examples/sandbox/projects.php index e0dea6a..f6da308 100644 --- a/examples/testing/projects.php +++ b/examples/sandbox/projects.php @@ -12,7 +12,7 @@ $sandboxProjects = (new MailtrapSandboxClient($config))->projects($accountId); #required parameter is accountId /** - * List projects and their inboxes to which the API token has access. + * List projects and their sandboxes to which the API token has access. * * GET https://mailtrap.io/api/accounts/{account_id}/projects */ @@ -27,7 +27,7 @@ /** - * Get the project and its inboxes. + * Get the project and its sandboxes. * * GET https://mailtrap.io/api/accounts/{account_id}/projects/{project_id} */ @@ -80,7 +80,7 @@ /** - * Delete project and its inboxes. + * Delete project and its sandboxes. * * DELETE https://mailtrap.io/api/accounts/{account_id}/projects/{project_id} */ diff --git a/examples/testing/inboxes.php b/examples/sandbox/sandboxes.php similarity index 70% rename from examples/testing/inboxes.php rename to examples/sandbox/sandboxes.php index a9cff8d..9d24695 100644 --- a/examples/testing/inboxes.php +++ b/examples/sandbox/sandboxes.php @@ -1,7 +1,7 @@ inboxes($accountId); #required parameter is accountId +$sandboxes = (new MailtrapSandboxClient($config))->sandboxes($accountId); #required parameter is accountId /** - * Get a list of inboxes. + * Get a list of sandboxes. * * GET https://mailtrap.io/api/accounts/{account_id}/inboxes */ try { - $response = $sandboxInboxes->getList(); + $response = $sandboxes->getList(); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -28,15 +28,15 @@ /** - * Create an inbox + * Create a sandbox * * POST https://mailtrap.io/api/accounts/{account_id}/projects/{project_id}/inboxes */ try { $projectId = $_ENV['MAILTRAP_PROJECT_ID']; - $inboxName = 'First inbox'; + $sandboxName = 'First sandbox'; - $response = $sandboxInboxes->create($projectId, $inboxName); + $response = $sandboxes->create($projectId, $sandboxName); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -46,14 +46,14 @@ /** - * Get inbox attributes + * Get sandbox attributes * * GET https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id} */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->getInboxAttributes($inboxId); + $response = $sandboxes->getSandboxAttributes($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -63,14 +63,14 @@ /** - * Delete an inbox + * Delete a sandbox * * DELETE https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id} */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->delete($inboxId); + $response = $sandboxes->delete($sandboxId); // Print the response status code var_dump($response->getStatusCode()); @@ -85,9 +85,9 @@ * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/reset_email_username */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->resetEmailAddress($inboxId); + $response = $sandboxes->resetEmailAddress($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -102,9 +102,9 @@ * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/toggle_email_username */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->toggleEmailAddress($inboxId); + $response = $sandboxes->toggleEmailAddress($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -119,9 +119,9 @@ * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/reset_credentials */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->resetSmtpCredentials($inboxId); + $response = $sandboxes->resetSmtpCredentials($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -136,9 +136,9 @@ * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/all_read */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->markAsRead($inboxId); + $response = $sandboxes->markAsRead($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -148,14 +148,14 @@ /** - * Clean inbox + * Clean sandbox * * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id}/clean */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; - $response = $sandboxInboxes->clean($inboxId); + $response = $sandboxes->clean($sandboxId); // print the response body (array) var_dump(ResponseHelper::toArray($response)); @@ -165,18 +165,18 @@ /** - * Update an inbox + * Update a sandbox * * PATCH https://mailtrap.io/api/accounts/{account_id}/inboxes/{inbox_id} */ try { - $inboxId = $_ENV['MAILTRAP_INBOX_ID']; - $newInboxName = 'New inbox name'; + $sandboxId = $_ENV['MAILTRAP_SANDBOX_ID']; + $newSandboxName = 'New sandbox name'; $newEmailUsername = 'new-email-username'; - $response = $sandboxInboxes->update( - $inboxId, - new Inbox($newInboxName, $newEmailUsername) + $response = $sandboxes->update( + $sandboxId, + new Sandbox($newSandboxName, $newEmailUsername) ); // print the response body (array) diff --git a/examples/testing/send-mail.php b/examples/sandbox/send-mail.php similarity index 91% rename from examples/testing/send-mail.php rename to examples/sandbox/send-mail.php index 5e0c1da..72a1a2f 100644 --- a/examples/testing/send-mail.php +++ b/examples/sandbox/send-mail.php @@ -10,7 +10,7 @@ /** - * Email Testing API + * Email Sandbox API * * POST https://sandbox.api.mailtrap.io/api/send/{inbox_id} */ @@ -18,7 +18,7 @@ $mailtrap = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], #your API token from here https://mailtrap.io/api-tokens isSandbox: true, # Sandbox sending (@see https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing) - inboxId: $_ENV['MAILTRAP_INBOX_ID'] # required param for sandbox sending + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'] # required param for sandbox sending ); $email = (new MailtrapEmail()) diff --git a/examples/testing/template.php b/examples/sandbox/template.php similarity index 94% rename from examples/testing/template.php rename to examples/sandbox/template.php index 24a4638..edf916d 100644 --- a/examples/testing/template.php +++ b/examples/sandbox/template.php @@ -21,7 +21,7 @@ $mailtrap = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], #your API token from here https://mailtrap.io/api-tokens isSandbox: true, # Sandbox sending (@see https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing) - inboxId: $_ENV['MAILTRAP_INBOX_ID'] # required param for sandbox sending + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'] # required param for sandbox sending ); $email = (new MailtrapEmail()) diff --git a/examples/symfony/sandbox.php b/examples/symfony/sandbox.php index 01c0b6a..be686d5 100644 --- a/examples/symfony/sandbox.php +++ b/examples/symfony/sandbox.php @@ -25,7 +25,7 @@ public function __invoke(): int { // Available since Symfony 7.0. For earlier ve $response = MailtrapClient::initSendingEmails( apiKey: $_ENV['MAILTRAP_API_KEY'], // your API token from here https://mailtrap.io/api-tokens isSandbox: true, - inboxId: $_ENV['MAILTRAP_INBOX_ID'], // your Inbox ID from here https://mailtrap.io/inboxes + sandboxId: $_ENV['MAILTRAP_SANDBOX_ID'], // your Sandbox ID from here https://mailtrap.io/inboxes )->send($email); var_dump(ResponseHelper::toArray($response)); diff --git a/src/AbstractMailtrapClient.php b/src/AbstractMailtrapClient.php index 84bc046..6037dd3 100644 --- a/src/AbstractMailtrapClient.php +++ b/src/AbstractMailtrapClient.php @@ -5,7 +5,6 @@ namespace Mailtrap; use Mailtrap\Exception\BadMethodCallException; -use Mailtrap\Exception\InvalidArgumentException; /** * Class AbstractMailtrapClient @@ -18,11 +17,13 @@ public function __construct(protected ConfigInterface $config) public function __call(string $name, array $arguments) { - try { - return $this->initByName($name, $arguments); - } catch (InvalidArgumentException) { + $className = $this->getClassByName($name); + if (null === $className) { throw new BadMethodCallException(sprintf('%s -> undefined method called: "%s"', static::class, $name)); } + + /** @psalm-suppress LessSpecificReturnStatement */ + return new $className($this->getConfig(), ...$arguments); } public function getConfig(): ConfigInterface @@ -35,15 +36,4 @@ private function getClassByName(string $name): ?string /** @psalm-suppress UndefinedConstant */ return !empty(static::API_MAPPING[$name]) ? static::API_MAPPING[$name] : null; } - - private function initByName(string $name, $arguments) - { - $className = $this->getClassByName($name); - if (null === $className) { - throw new InvalidArgumentException(sprintf('%s -> undefined api instance called: "%s"', static::class, $name)); - } - - /** @psalm-suppress LessSpecificReturnStatement */ - return new $className($this->getConfig(), ...$arguments); - } } diff --git a/src/Api/Sandbox/Attachment.php b/src/Api/Sandbox/Attachment.php index 574dcf7..0e88ddc 100644 --- a/src/Api/Sandbox/Attachment.php +++ b/src/Api/Sandbox/Attachment.php @@ -13,16 +13,23 @@ */ class Attachment extends AbstractApi implements SandboxInterface { + use SandboxIdTrait; + + /** + * @param int|null $inboxId deprecated, use $sandboxId instead + */ public function __construct( ConfigInterface $config, private int $accountId, - private int $inboxId, + ?int $sandboxId = null, + ?int $inboxId = null, ) { parent::__construct($config); + $this->setSandboxId($sandboxId, $inboxId); } /** - * Get message attachments by inboxId and messageId. + * Get message attachments by sandboxId and messageId. * * @param int $messageId * @param string|null $attachmentType @@ -45,7 +52,7 @@ public function getMessageAttachments( '%s/api/accounts/%s/inboxes/%s/messages/%s/attachments', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ), $parameters @@ -66,7 +73,7 @@ public function getMessageAttachment(int $messageId, int $attachmentId): Respons '%s/api/accounts/%s/inboxes/%s/messages/%s/attachments/%s', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId, $attachmentId ))); @@ -76,9 +83,4 @@ public function getAccountId(): int { return $this->accountId; } - - public function getInboxId(): int - { - return $this->inboxId; - } } diff --git a/src/Api/Sandbox/Emails.php b/src/Api/Sandbox/Emails.php index d0dc42c..1e48731 100644 --- a/src/Api/Sandbox/Emails.php +++ b/src/Api/Sandbox/Emails.php @@ -14,15 +14,21 @@ */ class Emails extends AbstractEmails implements SandboxInterface { - public function __construct(ConfigInterface $config, private int $inboxId) + use SandboxIdTrait; + + /** + * @param int|null $inboxId deprecated, use $sandboxId instead + */ + public function __construct(ConfigInterface $config, ?int $sandboxId = null, ?int $inboxId = null) { parent::__construct($config); + $this->setSandboxId($sandboxId, $inboxId); } public function send(Email $email): ResponseInterface { return $this->handleResponse( - $this->httpPost(sprintf('%s/api/send/%s', $this->getHost(), $this->getInboxId()), [], $this->getPayload($email)) + $this->httpPost(sprintf('%s/api/send/%s', $this->getHost(), $this->getSandboxId()), [], $this->getPayload($email)) ); } @@ -30,7 +36,7 @@ public function batchSend(array $recipientEmails, ?Email $baseEmail = null): Res { return $this->handleResponse( $this->httpPost( - sprintf('%s/api/batch/%s', $this->getHost(), $this->getInboxId()), + sprintf('%s/api/batch/%s', $this->getHost(), $this->getSandboxId()), [], $this->getBatchBody($recipientEmails, $baseEmail), ) @@ -41,9 +47,4 @@ protected function getHost(): string { return $this->config->getHost() ?: self::SENDMAIL_SANDBOX_HOST; } - - public function getInboxId(): int - { - return $this->inboxId; - } } diff --git a/src/Api/Sandbox/Inbox.php b/src/Api/Sandbox/Inbox.php index d649bd8..271776a 100644 --- a/src/Api/Sandbox/Inbox.php +++ b/src/Api/Sandbox/Inbox.php @@ -4,180 +4,78 @@ namespace Mailtrap\Api\Sandbox; -use Mailtrap\Api\AbstractApi; use Mailtrap\ConfigInterface; -use Mailtrap\DTO\Request\Inbox as InboxRequest; -use Mailtrap\Exception\RuntimeException; +use Mailtrap\DTO\Request\Sandbox as SandboxRequest; +use Mailtrap\Helper\Deprecation; use Psr\Http\Message\ResponseInterface; /** + * The overrides below only keep the old parameter names, so calls with named arguments keep working. + * + * @deprecated Use {@see Sandbox} (MailtrapSandboxClient::sandboxes()) instead. + * @psalm-suppress ParamNameMismatch + * * Class Inbox */ -class Inbox extends AbstractApi implements SandboxInterface +class Inbox extends Sandbox { - public function __construct(ConfigInterface $config, private int $accountId) + public function __construct(ConfigInterface $config, int $accountId) { - parent::__construct($config); - } + Deprecation::trigger( + self::class . ' (MailtrapSandboxClient::inboxes())', + Sandbox::class . ' (MailtrapSandboxClient::sandboxes())' + ); - /** - * Get a list of inboxes. - * - * @return ResponseInterface - */ - public function getList(): ResponseInterface - { - return $this->handleResponse($this->httpGet( - sprintf('%s/api/accounts/%s/inboxes', $this->getHost(), $this->getAccountId()) - )); + parent::__construct($config, $accountId); } /** - * Get inbox attributes by inbox id. See the list of attributes in the example - * - * @param int $inboxId - * - * @return ResponseInterface + * @deprecated Use {@see Sandbox::getSandboxAttributes()} instead. */ public function getInboxAttributes(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpGet( - sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $inboxId) - )); + Deprecation::trigger(__METHOD__ . '()', Sandbox::class . '::getSandboxAttributes()'); + + return $this->getSandboxAttributes($inboxId); } - /** - * Create an inbox in a project. - * - * @param int $projectId - * @param string $inboxName - * - * @return ResponseInterface - */ public function create(int $projectId, string $inboxName): ResponseInterface { - return $this->handleResponse( - $this->httpPost( - sprintf('%s/api/accounts/%s/projects/%s/inboxes', $this->getHost(), $this->getAccountId(), $projectId), - [], - ['inbox' => ['name' => $inboxName]] - ) - ); + return parent::create($projectId, $inboxName); } - /** - * Delete an inbox with all its emails. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function delete(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpDelete( - sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $inboxId) - )); + return parent::delete($inboxId); } - /** - * Update inbox name and/or inbox email username. - * - * @param int $inboxId - * @param InboxRequest $updateInbox - * - * @return ResponseInterface - */ - public function update(int $inboxId, InboxRequest $updateInbox): ResponseInterface + public function update(int $inboxId, SandboxRequest $updateInbox): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $inboxId), - [], - ['inbox' => $this->getUpdatePayload($updateInbox)] - )); + return parent::update($inboxId, $updateInbox); } - /** - * Delete all messages (emails) from inbox. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function clean(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/clean', $this->getHost(), $this->getAccountId(), $inboxId) - )); + return parent::clean($inboxId); } - /** - * Mark all messages in the inbox as read. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function markAsRead(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/all_read', $this->getHost(), $this->getAccountId(), $inboxId) - )); + return parent::markAsRead($inboxId); } - /** - * Reset SMTP credentials of the inbox. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function resetSmtpCredentials(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/reset_credentials', $this->getHost(), $this->getAccountId(), $inboxId) - )); + return parent::resetSmtpCredentials($inboxId); } - /** - * Turn the email address of the inbox on/off. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function toggleEmailAddress(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/toggle_email_username', $this->getHost(), $this->getAccountId(), $inboxId) - )); + return parent::toggleEmailAddress($inboxId); } - /** - * Reset username of email address per inbox. - * - * @param int $inboxId - * - * @return ResponseInterface - */ public function resetEmailAddress(int $inboxId): ResponseInterface { - return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/reset_email_username', $this->getHost(), $this->getAccountId(), $inboxId) - )); - } - - private function getUpdatePayload(InboxRequest $updateInbox): array - { - $result = $updateInbox->toArray(); - if (empty($result)) { - throw new RuntimeException('At least one inbox parameter should be populated ("name" or "email_username")'); - } - - return $result; - } - - public function getAccountId(): int - { - return $this->accountId; + return parent::resetEmailAddress($inboxId); } } diff --git a/src/Api/Sandbox/Message.php b/src/Api/Sandbox/Message.php index 85d3e56..47c5c75 100644 --- a/src/Api/Sandbox/Message.php +++ b/src/Api/Sandbox/Message.php @@ -14,16 +14,23 @@ */ class Message extends AbstractApi implements SandboxInterface { + use SandboxIdTrait; + + /** + * @param int|null $inboxId deprecated, use $sandboxId instead + */ public function __construct( ConfigInterface $config, private int $accountId, - private int $inboxId, + ?int $sandboxId = null, + ?int $inboxId = null, ) { parent::__construct($config); + $this->setSandboxId($sandboxId, $inboxId); } /** - * Get all messages in the inbox + * Get all messages in the sandbox * Note: if you want to get all messages you need to use "page" param (by default will return only 30 messages per * page) * @@ -56,7 +63,7 @@ public function getList( } return $this->handleResponse($this->httpGet( - sprintf('%s/api/accounts/%s/inboxes/%s/messages', $this->getHost(), $this->getAccountId(), $this->getInboxId()), + sprintf('%s/api/accounts/%s/inboxes/%s/messages', $this->getHost(), $this->getAccountId(), $this->getSandboxId()), $parameters )); } @@ -71,7 +78,7 @@ public function getList( public function getById(int $messageId): ResponseInterface { return $this->handleResponse($this->httpGet( - sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getInboxId(), $messageId) + sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getSandboxId(), $messageId) )); } @@ -88,7 +95,7 @@ public function getSpamScore(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/spam_report', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -106,7 +113,7 @@ public function getHtmlAnalysis(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/analyze', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -124,7 +131,7 @@ public function getMailHeaders(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/mail_headers', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -142,7 +149,7 @@ public function getText(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/body.txt', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -160,7 +167,7 @@ public function getRaw(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/body.raw', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -178,7 +185,7 @@ public function getHtml(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/body.html', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -196,7 +203,7 @@ public function getEml( int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/body.eml', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -214,7 +221,7 @@ public function getSource(int $messageId): ResponseInterface '%s/api/accounts/%s/inboxes/%s/messages/%s/body.htmlsource', $this->getHost(), $this->getAccountId(), - $this->getInboxId(), + $this->getSandboxId(), $messageId ))); } @@ -230,7 +237,7 @@ public function getSource(int $messageId): ResponseInterface public function markAsRead(int $messageId, bool $isRead = true): ResponseInterface { return $this->handleResponse($this->httpPatch( - sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getInboxId(), $messageId), + sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getSandboxId(), $messageId), [], [ 'message' => [ @@ -241,7 +248,7 @@ public function markAsRead(int $messageId, bool $isRead = true): ResponseInterfa } /** - * Delete message from inbox. + * Delete message from sandbox. * * @param int $messageId * @@ -250,7 +257,7 @@ public function markAsRead(int $messageId, bool $isRead = true): ResponseInterfa public function delete(int $messageId): ResponseInterface { return $this->handleResponse($this->httpDelete( - sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getInboxId(), $messageId) + sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s', $this->getHost(), $this->getAccountId(), $this->getSandboxId(), $messageId) )); } @@ -269,7 +276,7 @@ public function forward(int $messageId, string $email): ResponseInterface } return $this->handleResponse($this->httpPost( - sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s/forward', $this->getHost(), $this->getAccountId(), $this->getInboxId(), $messageId), + sprintf('%s/api/accounts/%s/inboxes/%s/messages/%s/forward', $this->getHost(), $this->getAccountId(), $this->getSandboxId(), $messageId), [], ['email' => $email] )); @@ -279,9 +286,4 @@ public function getAccountId(): int { return $this->accountId; } - - public function getInboxId(): int - { - return $this->inboxId; - } } diff --git a/src/Api/Sandbox/Project.php b/src/Api/Sandbox/Project.php index e4dced0..90fa340 100644 --- a/src/Api/Sandbox/Project.php +++ b/src/Api/Sandbox/Project.php @@ -19,7 +19,7 @@ public function __construct(ConfigInterface $config, private int $accountId) } /** - * List projects and their inboxes to which the API token has access. + * List projects and their sandboxes to which the API token has access. * * @return ResponseInterface */ @@ -31,7 +31,7 @@ public function getList(): ResponseInterface } /** - * Get the project and its inboxes. + * Get the project and its sandboxes. * * @param int $projectId * @@ -61,7 +61,7 @@ public function create(string $projectName): ResponseInterface } /** - * Delete project and its inboxes. + * Delete project and its sandboxes. * * @param int $projectId * diff --git a/src/Api/Sandbox/Sandbox.php b/src/Api/Sandbox/Sandbox.php new file mode 100644 index 0000000..3e6b951 --- /dev/null +++ b/src/Api/Sandbox/Sandbox.php @@ -0,0 +1,183 @@ +handleResponse($this->httpGet( + sprintf('%s/api/accounts/%s/inboxes', $this->getHost(), $this->getAccountId()) + )); + } + + /** + * Get sandbox attributes by sandbox id. See the list of attributes in the example + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function getSandboxAttributes(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpGet( + sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Create a sandbox in a project. + * + * @param int $projectId + * @param string $sandboxName + * + * @return ResponseInterface + */ + public function create(int $projectId, string $sandboxName): ResponseInterface + { + return $this->handleResponse( + $this->httpPost( + sprintf('%s/api/accounts/%s/projects/%s/inboxes', $this->getHost(), $this->getAccountId(), $projectId), + [], + ['inbox' => ['name' => $sandboxName]] + ) + ); + } + + /** + * Delete a sandbox with all its emails. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function delete(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpDelete( + sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Update sandbox name and/or sandbox email username. + * + * @param int $sandboxId + * @param SandboxRequest $sandbox + * + * @return ResponseInterface + */ + public function update(int $sandboxId, SandboxRequest $sandbox): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s', $this->getHost(), $this->getAccountId(), $sandboxId), + [], + ['inbox' => $this->getUpdatePayload($sandbox)] + )); + } + + /** + * Delete all messages (emails) from sandbox. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function clean(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s/clean', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Mark all messages in the sandbox as read. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function markAsRead(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s/all_read', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Reset SMTP credentials of the sandbox. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function resetSmtpCredentials(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s/reset_credentials', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Turn the email address of the sandbox on/off. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function toggleEmailAddress(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s/toggle_email_username', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + /** + * Reset username of email address per sandbox. + * + * @param int $sandboxId + * + * @return ResponseInterface + */ + public function resetEmailAddress(int $sandboxId): ResponseInterface + { + return $this->handleResponse($this->httpPatch( + sprintf('%s/api/accounts/%s/inboxes/%s/reset_email_username', $this->getHost(), $this->getAccountId(), $sandboxId) + )); + } + + private function getUpdatePayload(SandboxRequest $sandbox): array + { + $result = $sandbox->toArray(); + if (empty($result)) { + throw new RuntimeException('At least one sandbox parameter should be populated ("name" or "email_username")'); + } + + return $result; + } + + public function getAccountId(): int + { + return $this->accountId; + } +} diff --git a/src/Api/Sandbox/SandboxIdTrait.php b/src/Api/Sandbox/SandboxIdTrait.php new file mode 100644 index 0000000..7300021 --- /dev/null +++ b/src/Api/Sandbox/SandboxIdTrait.php @@ -0,0 +1,50 @@ +sandboxId; + } + + /** + * @deprecated Use getSandboxId() instead. + */ + public function getInboxId(): int + { + Deprecation::trigger(self::class . '::getInboxId()', self::class . '::getSandboxId()'); + + return $this->sandboxId; + } + + private function setSandboxId(?int $sandboxId, ?int $inboxId): void + { + $sandboxId = Deprecation::renamedArgument( + self::class . '::__construct()', + 'inboxId', + 'sandboxId', + $inboxId, + $sandboxId + ); + + if (null === $sandboxId) { + throw new InvalidArgumentException(sprintf('%s::__construct() requires the $sandboxId argument.', self::class)); + } + + $this->sandboxId = $sandboxId; + } +} diff --git a/src/Api/Sending/CompanyInfo.php b/src/Api/Sending/CompanyInfo.php index 2160fae..2da416f 100644 --- a/src/Api/Sending/CompanyInfo.php +++ b/src/Api/Sending/CompanyInfo.php @@ -21,7 +21,7 @@ public function __construct(ConfigInterface $config, private int $domainId) } /** - * Get the company info associated with the sending domain. + * Get the company info associated with the domain. * * @return ResponseInterface */ @@ -33,7 +33,7 @@ public function getCompanyInfo(): ResponseInterface } /** - * Create the company info for the sending domain. Company info is required + * Create the company info for the domain. Company info is required * for domain compliance verification. * * @param CreateCompanyInfo $companyInfo @@ -52,7 +52,7 @@ public function createCompanyInfo(CreateCompanyInfo $companyInfo): ResponseInter } /** - * Update the company info for the sending domain. + * Update the company info for the domain. * * @param UpdateCompanyInfo $companyInfo * @return ResponseInterface diff --git a/src/Api/Sending/Domain.php b/src/Api/Sending/Domain.php index 5496749..70fad4a 100644 --- a/src/Api/Sending/Domain.php +++ b/src/Api/Sending/Domain.php @@ -7,6 +7,7 @@ use Mailtrap\Api\AbstractApi; use Mailtrap\ConfigInterface; use Mailtrap\DTO\Request\Domain\UpdateDomain; +use Mailtrap\Helper\Deprecation; use Psr\Http\Message\ResponseInterface; /** @@ -20,11 +21,11 @@ public function __construct(ConfigInterface $config, private int $accountId) } /** - * Get a list of sending domains. + * Get a list of domains. * * @return ResponseInterface */ - public function getSendingDomains(): ResponseInterface + public function getDomains(): ResponseInterface { return $this->handleResponse( $this->httpGet($this->getBasePath()) @@ -32,12 +33,12 @@ public function getSendingDomains(): ResponseInterface } /** - * Create a new sending domain. + * Create a new domain. * * @param string $domainName * @return ResponseInterface */ - public function createSendingDomain(string $domainName): ResponseInterface + public function createDomain(string $domainName): ResponseInterface { return $this->handleResponse( $this->httpPost( @@ -52,7 +53,7 @@ public function createSendingDomain(string $domainName): ResponseInterface } /** - * Get a sending domain by ID. + * Get a domain by ID. * * @param int $domainId * @return ResponseInterface @@ -67,13 +68,13 @@ public function getDomainById(int $domainId): ResponseInterface } /** - * Update configuration settings for a sending domain. + * Update configuration settings for a domain. * * @param int $domainId * @param UpdateDomain $domain * @return ResponseInterface */ - public function updateSendingDomain(int $domainId, UpdateDomain $domain): ResponseInterface + public function updateDomain(int $domainId, UpdateDomain $domain): ResponseInterface { return $this->handleResponse( $this->httpPatch( @@ -86,12 +87,12 @@ public function updateSendingDomain(int $domainId, UpdateDomain $domain): Respon } /** - * Delete a sending domain by ID. + * Delete a domain by ID. * * @param int $domainId * @return ResponseInterface */ - public function deleteSendingDomain(int $domainId): ResponseInterface + public function deleteDomain(int $domainId): ResponseInterface { return $this->handleResponse( $this->httpDelete( @@ -101,7 +102,7 @@ public function deleteSendingDomain(int $domainId): ResponseInterface } /** - * Send sending domain setup instructions. + * Send domain setup instructions. * * @param int $domainId * @param string $email @@ -119,6 +120,46 @@ public function sendDomainSetupInstructions(int $domainId, string $email): Respo ); } + /** + * @deprecated Use getDomains() instead. + */ + public function getSendingDomains(): ResponseInterface + { + Deprecation::trigger(__METHOD__ . '()', self::class . '::getDomains()'); + + return $this->getDomains(); + } + + /** + * @deprecated Use createDomain() instead. + */ + public function createSendingDomain(string $domainName): ResponseInterface + { + Deprecation::trigger(__METHOD__ . '()', self::class . '::createDomain()'); + + return $this->createDomain($domainName); + } + + /** + * @deprecated Use updateDomain() instead. + */ + public function updateSendingDomain(int $domainId, UpdateDomain $domain): ResponseInterface + { + Deprecation::trigger(__METHOD__ . '()', self::class . '::updateDomain()'); + + return $this->updateDomain($domainId, $domain); + } + + /** + * @deprecated Use deleteDomain() instead. + */ + public function deleteSendingDomain(int $domainId): ResponseInterface + { + Deprecation::trigger(__METHOD__ . '()', self::class . '::deleteDomain()'); + + return $this->deleteDomain($domainId); + } + private function getBasePath(): string { return sprintf('%s/api/accounts/%s/sending_domains', $this->getHost(), $this->accountId); diff --git a/src/Api/Sending/EmailLogs.php b/src/Api/Sending/EmailLogs.php index 5a6da29..b323e36 100644 --- a/src/Api/Sending/EmailLogs.php +++ b/src/Api/Sending/EmailLogs.php @@ -26,7 +26,7 @@ public function __construct(ConfigInterface $config, private int $accountId) /** * List email logs (paginated). * - * Returns a paginated list of email logs for the account. Results are restricted to sending domains + * Returns a paginated list of email logs for the account. Results are restricted to domains * the authenticated token has access to. Invalid or unknown filters are ignored. * Results are ordered by sent_at descending. * @@ -58,7 +58,7 @@ public function getList(array|EmailLogsListFilters $filters = [], ?string $searc /** * Get a single email log message by ID. * - * Returns message details including events. Message must belong to the account and a sending domain + * Returns message details including events. Message must belong to the account and a domain * the token can access. * * @param string $sendingMessageId Message UUID (sending_message_id). diff --git a/src/Api/Sending/TrackingOptOut.php b/src/Api/Sending/TrackingOptOut.php index ab6b839..bd0debb 100644 --- a/src/Api/Sending/TrackingOptOut.php +++ b/src/Api/Sending/TrackingOptOut.php @@ -33,7 +33,7 @@ public function getTrackingOptOuts(?TrackingOptOutsFilter $filter = null): Respo } /** - * Add an email address to the tracking opt-out list for a sending domain. + * Add an email address to the tracking opt-out list for a domain. * * @param CreateTrackingOptOut $trackingOptOut * @return ResponseInterface diff --git a/src/Bridge/Laravel/README.md b/src/Bridge/Laravel/README.md index 41315c6..e8566dc 100644 --- a/src/Bridge/Laravel/README.md +++ b/src/Bridge/Laravel/README.md @@ -59,7 +59,7 @@ MAILTRAP_HOST="bulk.api.mailtrap.io" MAILTRAP_API_KEY="YOUR_API_KEY_HERE" ``` ### Sandbox -You need to set the API key to the `MAILTRAP_API_KEY` variable and set your inboxId to the `MAILTRAP_INBOX_ID`. +You need to set the API key to the `MAILTRAP_API_KEY` variable and set your sandbox ID to the `MAILTRAP_SANDBOX_ID`. More info sandbox -> https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing ```bash @@ -67,8 +67,9 @@ MAIL_MAILER="mailtrap-sdk" MAILTRAP_HOST="sandbox.api.mailtrap.io" MAILTRAP_API_KEY="YOUR_API_KEY_HERE" -MAILTRAP_INBOX_ID=1000001 +MAILTRAP_SANDBOX_ID=1000001 ``` +The deprecated `MAILTRAP_INBOX_ID` variable and `inboxId` key still work. If your `config/services.php` defines its own `mailtrap-sdk` entry, it replaces the package's default one as a whole, so change its `inboxId` key to `'sandboxId' => env('MAILTRAP_SANDBOX_ID')` when you rename the variable. Before starting, run the clear configuration cache command to set up new variables. ```bash @@ -358,7 +359,7 @@ Please add them manually to the `config/services.php` file and after that run th 'mailtrap-sdk' => [ 'host' => env('MAILTRAP_HOST', 'send.api.mailtrap.io'), 'apiKey' => env('MAILTRAP_API_KEY'), - 'inboxId' => env('MAILTRAP_INBOX_ID'), + 'sandboxId' => env('MAILTRAP_SANDBOX_ID'), ], ``` diff --git a/src/Bridge/Laravel/config/mailtrap-sdk.php b/src/Bridge/Laravel/config/mailtrap-sdk.php index ca3e5e4..3ae4b02 100644 --- a/src/Bridge/Laravel/config/mailtrap-sdk.php +++ b/src/Bridge/Laravel/config/mailtrap-sdk.php @@ -4,6 +4,7 @@ 'mailtrap-sdk' => [ 'host' => env('MAILTRAP_HOST', 'send.api.mailtrap.io'), 'apiKey' => env('MAILTRAP_API_KEY'), - 'inboxId' => env('MAILTRAP_INBOX_ID'), + 'sandboxId' => env('MAILTRAP_SANDBOX_ID'), + 'inboxId' => env('MAILTRAP_INBOX_ID'), // deprecated, use MAILTRAP_SANDBOX_ID ], ]; diff --git a/src/Bridge/Symfony/README.md b/src/Bridge/Symfony/README.md index 94293b5..6322568 100644 --- a/src/Bridge/Symfony/README.md +++ b/src/Bridge/Symfony/README.md @@ -39,12 +39,13 @@ MAILER_DSN=mailtrap+sdk://YOUR_API_KEY_HERE@bulk.api.mailtrap.io ``` ### Sandbox -Add or change MAILER_DSN variable inside your `.env` file. Also, you need to change the `YOUR_API_KEY_HERE` placeholder and put correct `inboxId`. +Add or change MAILER_DSN variable inside your `.env` file. Also, you need to change the `YOUR_API_KEY_HERE` placeholder and put correct `sandboxId`. More info sandbox -> https://help.mailtrap.io/article/109-getting-started-with-mailtrap-email-testing ```bash -MAILER_DSN=mailtrap+sdk://YOUR_API_KEY_HERE@sandbox.api.mailtrap.io?inboxId=1000001 +MAILER_DSN=mailtrap+sdk://YOUR_API_KEY_HERE@sandbox.api.mailtrap.io?sandboxId=1000001 ``` +The deprecated `inboxId` option still works. ### Send you first email diff --git a/src/Bridge/Transport/MailtrapSdkTransport.php b/src/Bridge/Transport/MailtrapSdkTransport.php index 9174811..31ac366 100644 --- a/src/Bridge/Transport/MailtrapSdkTransport.php +++ b/src/Bridge/Transport/MailtrapSdkTransport.php @@ -65,12 +65,12 @@ protected function doSend(SentMessage $message): void private function getEndpoint(): string { - $inboxId = null; + $sandboxId = null; if ($this->emailsSendApiLayer instanceof SandboxEmails) { - $inboxId = $this->emailsSendApiLayer->getInboxId(); + $sandboxId = $this->emailsSendApiLayer->getSandboxId(); } - return $this->config->getHost() . (null === $inboxId ? '' : '?inboxId=' . $inboxId); + return $this->config->getHost() . (null === $sandboxId ? '' : '?sandboxId=' . $sandboxId); } private function getEnvelopeRecipients(Email $email, Envelope $envelope): array diff --git a/src/Bridge/Transport/MailtrapSdkTransportFactory.php b/src/Bridge/Transport/MailtrapSdkTransportFactory.php index b6d08f1..d5d5b65 100644 --- a/src/Bridge/Transport/MailtrapSdkTransportFactory.php +++ b/src/Bridge/Transport/MailtrapSdkTransportFactory.php @@ -7,8 +7,10 @@ use Mailtrap\Api\AbstractApi; use Mailtrap\Config; use Mailtrap\EmailsSendMailtrapClientInterface; +use Mailtrap\Exception\InvalidArgumentException; use Mailtrap\Exception\RuntimeException; use Mailtrap\Exception\Transport\UnsupportedHostException; +use Mailtrap\Helper\Deprecation; use Mailtrap\MailtrapClient; use Mailtrap\MailtrapSandboxClient; use Symfony\Component\HttpClient\Psr18Client; @@ -28,7 +30,7 @@ public function create(Dsn $dsn): TransportInterface throw new UnsupportedSchemeException($dsn, 'mailtrap+sdk', $this->getSupportedSchemes()); } - $inboxId = !empty($dsn->getOption('inboxId')) ? (int) $dsn->getOption('inboxId') : null; + $sandboxId = $this->getSandboxId($dsn); $config = (new Config($this->getUser($dsn))) ->setHost('default' === $dsn->getHost() ? AbstractApi::SENDMAIL_TRANSACTIONAL_HOST : $dsn->getHost()) ->setHttpClient(null === $this->client ? null : new Psr18Client($this->client)) @@ -36,13 +38,13 @@ public function create(Dsn $dsn): TransportInterface $emailsSendMailtrapClient = $this->getEmailsSendMailTrapClient($config); if ($emailsSendMailtrapClient instanceof MailtrapSandboxClient) { - if (null === $inboxId) { + if (!$sandboxId) { throw new RuntimeException( - 'You cannot send an email to a sandbox with an empty "inboxId" parameter. Example -> "MAILER_DSN=mailtrap+sdk://APIKEY@sandbox.api.mailtrap.io?inboxId=1234"' + 'You cannot send an email to a sandbox with an empty "sandboxId" parameter. Example -> "MAILER_DSN=mailtrap+sdk://APIKEY@sandbox.api.mailtrap.io?sandboxId=1234"' ); } - $emailsSendApiLayer = $emailsSendMailtrapClient->emails($inboxId); + $emailsSendApiLayer = $emailsSendMailtrapClient->emails($sandboxId); } else { $emailsSendApiLayer = $emailsSendMailtrapClient->emails(); } @@ -55,6 +57,44 @@ protected function getSupportedSchemes(): array return ['mailtrap+sdk']; } + /** + * Reads the "sandboxId" option, falling back to the deprecated "inboxId" one. In Laravel these are the + * services.mailtrap-sdk config keys, set from MAILTRAP_SANDBOX_ID and MAILTRAP_INBOX_ID. Setting both to + * different values, a zero included, is an error, as passing both arguments to + * MailtrapClient::initSendingEmails() is. + */ + private function getSandboxId(Dsn $dsn): ?int + { + $sandboxId = $this->getIdOption($dsn, 'sandboxId'); + $inboxId = $this->getIdOption($dsn, 'inboxId'); + if (null === $inboxId) { + return $sandboxId; + } + + Deprecation::trigger( + 'The "inboxId" option of the mailtrap+sdk transport (MAILTRAP_INBOX_ID in Laravel)', + 'the "sandboxId" option (MAILTRAP_SANDBOX_ID)' + ); + + if (null !== $sandboxId && $sandboxId !== $inboxId) { + throw new InvalidArgumentException( + 'The mailtrap+sdk transport received different values for the "sandboxId" and "inboxId" options (MAILTRAP_SANDBOX_ID and MAILTRAP_INBOX_ID in Laravel); set only "sandboxId".' + ); + } + + return $inboxId; + } + + /** + * An option left empty, such as an empty MAILTRAP_SANDBOX_ID in Laravel, is unset. + */ + private function getIdOption(Dsn $dsn, string $option): ?int + { + $value = $dsn->getOption($option); + + return null === $value || '' === $value ? null : (int) $value; + } + private function getEmailsSendMailTrapClient(Config $config): EmailsSendMailtrapClientInterface { $layer = $this->determineLayerNameByHost($config->getHost()); diff --git a/src/DTO/Request/Domain/CreateCompanyInfo.php b/src/DTO/Request/Domain/CreateCompanyInfo.php index d3b91a4..53ed5cd 100644 --- a/src/DTO/Request/Domain/CreateCompanyInfo.php +++ b/src/DTO/Request/Domain/CreateCompanyInfo.php @@ -7,7 +7,7 @@ /** * Class CreateCompanyInfo * - * Company information for a sending domain. Required for domain compliance + * Company information for a domain. Required for domain compliance * verification. */ final class CreateCompanyInfo implements DomainInterface diff --git a/src/DTO/Request/Domain/UpdateDomain.php b/src/DTO/Request/Domain/UpdateDomain.php index f6c8c2b..3d17c53 100644 --- a/src/DTO/Request/Domain/UpdateDomain.php +++ b/src/DTO/Request/Domain/UpdateDomain.php @@ -9,7 +9,7 @@ /** * Class UpdateDomain * - * Configuration settings for a sending domain. Only the fields provided are + * Configuration settings for a domain. Only the fields provided are * updated. */ final class UpdateDomain implements DomainInterface @@ -58,7 +58,7 @@ public function toArray(): array if ($payload === []) { throw new InvalidArgumentException( - 'At least one updatable field must be provided to update a sending domain' + 'At least one updatable field must be provided to update a domain' ); } diff --git a/src/DTO/Request/EmailCampaign/CreateEmailCampaign.php b/src/DTO/Request/EmailCampaign/CreateEmailCampaign.php index 98723bd..fabe192 100644 --- a/src/DTO/Request/EmailCampaign/CreateEmailCampaign.php +++ b/src/DTO/Request/EmailCampaign/CreateEmailCampaign.php @@ -15,7 +15,7 @@ final class CreateEmailCampaign implements EmailCampaignInterface { /** * @param string $name Campaign name (required) - * @param int $domainId ID of the verified sending domain, as returned by the Sending Domains endpoints (required) + * @param int $domainId ID of the verified domain, as returned by the Domains endpoints (required) * @param string $fromLocalPart Local part (before the @) of the From address (required) * @param TemplateAttributes $templateAttributes Template attributes; `subject` is required on create * @param string|null $fromDisplayName Display name shown in the From header diff --git a/src/DTO/Request/EmailCampaign/UpdateEmailCampaign.php b/src/DTO/Request/EmailCampaign/UpdateEmailCampaign.php index 13f8b75..5d42f3c 100644 --- a/src/DTO/Request/EmailCampaign/UpdateEmailCampaign.php +++ b/src/DTO/Request/EmailCampaign/UpdateEmailCampaign.php @@ -16,7 +16,7 @@ final class UpdateEmailCampaign implements EmailCampaignInterface { /** * @param string|null $name Campaign name - * @param int|null $domainId ID of the verified sending domain, as returned by the Sending Domains endpoints + * @param int|null $domainId ID of the verified domain, as returned by the Domains endpoints * @param string|null $fromDisplayName Display name shown in the From header * @param string|null $fromLocalPart Local part (before the @) of the From address * @param string|null $deliveryMode One of EmailCampaignInterface::DELIVERY_MODE_* diff --git a/src/DTO/Request/Inbox.php b/src/DTO/Request/Inbox.php index 8f487e3..15b6546 100644 --- a/src/DTO/Request/Inbox.php +++ b/src/DTO/Request/Inbox.php @@ -4,43 +4,19 @@ namespace Mailtrap\DTO\Request; +use Mailtrap\Helper\Deprecation; + /** - * Class UpdateInbox + * @deprecated Use {@see Sandbox} instead. + * + * Class Inbox */ -class Inbox implements RequestInterface +class Inbox extends Sandbox { - public function __construct(private ?string $name = null, private ?string $emailUsername = null) - { - } - - /** - * @return string|null - */ - public function getName(): ?string - { - return $this->name; - } - - /** - * @return string|null - */ - public function getEmailUsername(): ?string - { - return $this->emailUsername; - } - - public function toArray(): array + public function __construct(?string $name = null, ?string $emailUsername = null) { - $array = []; - - if (!empty($this->getName())) { - $array['name'] = $this->getName(); - } - - if (!empty($this->getEmailUsername())) { - $array['email_username'] = $this->getEmailUsername(); - } + Deprecation::trigger(self::class, Sandbox::class); - return $array; + parent::__construct($name, $emailUsername); } } diff --git a/src/DTO/Request/MarketingStats/MarketingStatsFilter.php b/src/DTO/Request/MarketingStats/MarketingStatsFilter.php index 8ec2823..3f08cba 100644 --- a/src/DTO/Request/MarketingStats/MarketingStatsFilter.php +++ b/src/DTO/Request/MarketingStats/MarketingStatsFilter.php @@ -17,7 +17,7 @@ final class MarketingStatsFilter implements MarketingStatsInterface /** * @param string $startDate Start of the date range (inclusive), `YYYY-MM-DD` * @param string $endDate End of the date range (inclusive), `YYYY-MM-DD` - * @param int[] $sendingDomainIds Only traffic sent from these sending domains + * @param int[] $sendingDomainIds Only traffic sent from these domains * @param string[] $sources Subset of MarketingStatsInterface::SOURCES; one value narrows * to that source, none or both mean all Email Marketing traffic * @param string[] $emailServiceProviders Only traffic to these email service providers (e.g. "Google") diff --git a/src/DTO/Request/Sandbox.php b/src/DTO/Request/Sandbox.php new file mode 100644 index 0000000..73d92db --- /dev/null +++ b/src/DTO/Request/Sandbox.php @@ -0,0 +1,46 @@ +name; + } + + /** + * @return string|null + */ + public function getEmailUsername(): ?string + { + return $this->emailUsername; + } + + public function toArray(): array + { + $array = []; + + if (!empty($this->getName())) { + $array['name'] = $this->getName(); + } + + if (!empty($this->getEmailUsername())) { + $array['email_username'] = $this->getEmailUsername(); + } + + return $array; + } +} diff --git a/src/DTO/Request/TrackingOptOut/CreateTrackingOptOut.php b/src/DTO/Request/TrackingOptOut/CreateTrackingOptOut.php index 4b4ea9b..eef886d 100644 --- a/src/DTO/Request/TrackingOptOut/CreateTrackingOptOut.php +++ b/src/DTO/Request/TrackingOptOut/CreateTrackingOptOut.php @@ -7,13 +7,13 @@ /** * Class CreateTrackingOptOut * - * Adds an email address to the tracking opt-out list for a sending domain. + * Adds an email address to the tracking opt-out list for a domain. */ final class CreateTrackingOptOut implements TrackingOptOutInterface { /** * @param string $email Email address to opt out of tracking - * @param int $domainId ID of the sending domain the opt-out applies to + * @param int $domainId ID of the domain the opt-out applies to */ public function __construct( private string $email, diff --git a/src/Helper/Deprecation.php b/src/Helper/Deprecation.php new file mode 100644 index 0000000..5ebca66 --- /dev/null +++ b/src/Helper/Deprecation.php @@ -0,0 +1,68 @@ + + */ + private static array $triggered = []; + + public static function trigger(string $old, string $new): void + { + if (isset(self::$triggered[$old])) { + return; + } + self::$triggered[$old] = true; + + @trigger_error( + sprintf('%s is deprecated and will be removed in a future major release; use %s instead.', $old, $new), + E_USER_DEPRECATED + ); + } + + /** + * Resolves an argument renamed from $oldName to $newName, which callers may still pass by its old name. + * Passing both names with different values is an error. + */ + public static function renamedArgument( + string $function, + string $oldName, + string $newName, + mixed $oldValue, + mixed $newValue, + ): mixed { + if (null === $oldValue) { + return $newValue; + } + + self::trigger(sprintf('The $%s argument of %s', $oldName, $function), sprintf('$%s', $newName)); + + if (null !== $newValue && $newValue !== $oldValue) { + throw new InvalidArgumentException( + sprintf('%s received different values for $%s and $%s; pass only $%s.', $function, $newName, $oldName, $newName) + ); + } + + return $oldValue; + } + + /** + * Forgets which notices were triggered, so tests can assert each one. + */ + public static function reset(): void + { + self::$triggered = []; + } +} diff --git a/src/MailtrapClient.php b/src/MailtrapClient.php index 3e56d13..2ea6407 100644 --- a/src/MailtrapClient.php +++ b/src/MailtrapClient.php @@ -6,6 +6,7 @@ use Mailtrap\Api\EmailsSendApiInterface; use Mailtrap\Exception\InvalidArgumentException; +use Mailtrap\Helper\Deprecation; /** * The main entry point to use all possible API layers @@ -34,12 +35,24 @@ class MailtrapClient extends AbstractMailtrapClient self::LAYER_INBOUND => MailtrapInboundClient::class, ]; + /** + * @param int|null $sandboxId required for the sandbox API + * @param int|null $inboxId deprecated, use $sandboxId instead + */ public static function initSendingEmails( string $apiKey, bool $isBulk = false, bool $isSandbox = false, + ?int $sandboxId = null, ?int $inboxId = null, ): EmailsSendApiInterface { + $sandboxId = Deprecation::renamedArgument( + self::class . '::initSendingEmails()', + 'inboxId', + 'sandboxId', + $inboxId, + $sandboxId + ); $client = new self(new Config($apiKey)); if ($isBulk && $isSandbox) { @@ -47,7 +60,7 @@ public static function initSendingEmails( } if ($isSandbox) { - return $client->sandbox()->emails($inboxId); + return $client->sandbox()->emails($sandboxId); } if ($isBulk) { diff --git a/src/MailtrapSandboxClient.php b/src/MailtrapSandboxClient.php index 7194bc6..287cced 100644 --- a/src/MailtrapSandboxClient.php +++ b/src/MailtrapSandboxClient.php @@ -5,11 +5,12 @@ namespace Mailtrap; /** - * @method Api\Sandbox\Emails emails(int $inboxId) + * @method Api\Sandbox\Emails emails(int|null $sandboxId = null, int|null $inboxId = null) inboxId is deprecated, use sandboxId. * @method Api\Sandbox\Project projects(int $accountId) - * @method Api\Sandbox\Inbox inboxes(int $accountId) - * @method Api\Sandbox\Attachment attachments(int $accountId, int $inboxId) - * @method Api\Sandbox\Message messages(int $accountId, int $inboxId) + * @method Api\Sandbox\Sandbox sandboxes(int $accountId) + * @method Api\Sandbox\Attachment attachments(int $accountId, int|null $sandboxId = null, int|null $inboxId = null) inboxId is deprecated, use sandboxId. + * @method Api\Sandbox\Message messages(int $accountId, int|null $sandboxId = null, int|null $inboxId = null) inboxId is deprecated, use sandboxId. + * @method Api\Sandbox\Inbox inboxes(int $accountId) Deprecated: use sandboxes() instead. * * Class MailtrapSandboxClient */ @@ -18,6 +19,7 @@ final class MailtrapSandboxClient extends AbstractMailtrapClient implements Emai public const API_MAPPING = [ 'emails' => Api\Sandbox\Emails::class, 'projects' => Api\Sandbox\Project::class, + 'sandboxes' => Api\Sandbox\Sandbox::class, 'inboxes' => Api\Sandbox\Inbox::class, 'attachments' => Api\Sandbox\Attachment::class, 'messages' => Api\Sandbox\Message::class, diff --git a/tests/Api/Sandbox/AttachmentTest.php b/tests/Api/Sandbox/AttachmentTest.php index 92a3a38..6e763b9 100644 --- a/tests/Api/Sandbox/AttachmentTest.php +++ b/tests/Api/Sandbox/AttachmentTest.php @@ -27,7 +27,7 @@ protected function setUp(): void $this->attachment = $this->getMockBuilder(Attachment::class) ->onlyMethods(['httpGet']) - ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_INBOX_ID]) + ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_SANDBOX_ID]) ->getMock() ; } @@ -49,7 +49,7 @@ public function testGetMessageAttachments(): void '%s/api/accounts/%s/inboxes/%s/messages/%s/attachments', AbstractApi::DEFAULT_HOST, self::FAKE_ACCOUNT_ID, - self::FAKE_INBOX_ID, + self::FAKE_SANDBOX_ID, self::FAKE_MESSAGE_ID, ), [ @@ -77,7 +77,7 @@ public function testGetMessageAttachment(): void '%s/api/accounts/%s/inboxes/%s/messages/%s/attachments/%s', AbstractApi::DEFAULT_HOST, self::FAKE_ACCOUNT_ID, - self::FAKE_INBOX_ID, + self::FAKE_SANDBOX_ID, self::FAKE_MESSAGE_ID, self::FAKE_MESSAGE_ATTACHMENT_ID )) diff --git a/tests/Api/Sandbox/EmailsTest.php b/tests/Api/Sandbox/EmailsTest.php index c57eab5..47c069f 100644 --- a/tests/Api/Sandbox/EmailsTest.php +++ b/tests/Api/Sandbox/EmailsTest.php @@ -33,7 +33,7 @@ protected function setUp(): void $this->email = $this->getMockBuilder(Emails::class) ->onlyMethods(['httpPost']) - ->setConstructorArgs([$this->getConfigMock(), self::FAKE_INBOX_ID]) + ->setConstructorArgs([$this->getConfigMock(), self::FAKE_SANDBOX_ID]) ->getMock() ; } @@ -70,7 +70,7 @@ public function testValidSendToSandBox(): void $this->email ->expects($this->once()) ->method('httpPost') - ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_INBOX_ID, [], [ + ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_SANDBOX_ID, [], [ 'from' => [ 'email' => 'foo@example.com', 'name' => 'Ms. Foo Bar', @@ -144,7 +144,7 @@ public function testValidSendTemplateToSandbox(): void $this->email ->expects($this->once()) ->method('httpPost') - ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_INBOX_ID, [], [ + ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_SANDBOX_ID, [], [ 'from' => [ 'email' => 'foo@example.com', 'name' => 'Ms. Foo Bar', @@ -230,7 +230,7 @@ public function testValidSendTemplateToSandboxNewEmailWrapper(): void $this->email ->expects($this->once()) ->method('httpPost') - ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_INBOX_ID, [], [ + ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/send/' . self::FAKE_SANDBOX_ID, [], [ 'from' => [ 'email' => 'foo@example.com', 'name' => 'Ms. Foo Bar', @@ -335,7 +335,7 @@ public function testBatchSend(): void $this->email ->expects($this->once()) ->method('httpPost') - ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/batch/' . self::FAKE_INBOX_ID, [], $expectedPayload) + ->with(AbstractApi::SENDMAIL_SANDBOX_HOST . '/api/batch/' . self::FAKE_SANDBOX_ID, [], $expectedPayload) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedResponse))); $response = $this->email->batchSend($recipientEmails, $baseEmail); diff --git a/tests/Api/Sandbox/InboxTest.php b/tests/Api/Sandbox/InboxTest.php index 5cbbb0e..a5997c6 100644 --- a/tests/Api/Sandbox/InboxTest.php +++ b/tests/Api/Sandbox/InboxTest.php @@ -1,33 +1,37 @@ inbox = $this->getMockBuilder(Inbox::class) - ->onlyMethods(['httpGet', 'httpPost', 'httpPatch', 'httpDelete']) + ->onlyMethods(['httpGet', 'httpPost', 'httpPatch', 'httpDelete']) ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID]) ->getMock() ; @@ -40,377 +44,92 @@ protected function tearDown(): void parent::tearDown(); } - public function testGetList(): void + public function testConstructorIsDeprecated(): void { - $this->inbox->expects($this->once()) - ->method('httpGet') - ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes') - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedInboxData()))); - - $response = $this->inbox->getList(); - $responseData = ResponseHelper::toArray($response); + $inbox = $this->assertDeprecationTriggered( + 'Mailtrap\Api\Sandbox\Inbox (MailtrapSandboxClient::inboxes()) is deprecated and will be removed in a future major release; use Mailtrap\Api\Sandbox\Sandbox (MailtrapSandboxClient::sandboxes()) instead.', + fn () => new Inbox($this->getConfigMock(), self::FAKE_ACCOUNT_ID) + ); - $this->assertInstanceOf(Response::class, $response); - $this->assertCount(2, $responseData); - $this->assertArrayHasKey('id', array_shift($responseData)); + $this->assertInstanceOf(Sandbox::class, $inbox); + $this->assertSame(self::FAKE_ACCOUNT_ID, $inbox->getAccountId()); } public function testGetInboxAttributes(): void { $this->inbox->expects($this->once()) ->method('httpGet') - ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedInboxData()[0]))); + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode(['id' => self::FAKE_SANDBOX_ID]))); - $response = $this->inbox->getInboxAttributes(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); + $response = $this->assertDeprecationTriggered( + 'Inbox::getInboxAttributes() is deprecated and will be removed in a future major release; use Mailtrap\Api\Sandbox\Sandbox::getSandboxAttributes() instead.', + fn () => $this->inbox->getInboxAttributes(self::FAKE_SANDBOX_ID) + ); - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - $this->assertEquals('Admin Inbox', $responseData['name']); - $this->assertCount(4, $responseData['permissions']); + $this->assertSame(200, $response->getStatusCode()); } - public function testValidCreate(): void + public function testCreateKeepsOldNamedArguments(): void { - $expectedData = [ - "id" => self::FAKE_INBOX_ID, - "name" => "My new inbox", - "username" => "24a5f9a9947fc7", - "password" => "a41e3846e78543", - "max_size" => 600, - "status" => "active", - "email_username" => "d008137b46-4d932f", - "email_username_enabled" => false, - "sent_messages_count" => 0, - "forwarded_messages_count" => 0, - "used" => false, - "forward_from_email_address" => "a3336-i3866@forward.mailtrap.info", - "project_id" => 2424, - "domain" => "localhost", - "pop3_domain" => "localhost", - "email_domain" => "localhost", - "emails_count" => 0, - "emails_unread_count" => 0, - "last_message_sent_at" => null, - "smtp_ports" => [ - 25, - 465, - 587, - 2525 - ], - "pop3_ports" => [ - 1100, - 9950 - ], - "max_message_size" => 15728640, - "permissions" => [ - "can_read" => true, - "can_update" => true, - "can_destroy" => true, - "can_leave" => false - ] - ]; - $this->inbox->expects($this->once()) ->method('httpPost') ->with( AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/projects/' . self::FAKE_PROJECT_ID . '/inboxes', [], - ['inbox' => ['name' => $expectedData['name']]] + ['inbox' => ['name' => 'My new inbox']] ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode(['id' => self::FAKE_SANDBOX_ID]))); - $response = $this->inbox->create(self::FAKE_PROJECT_ID, $expectedData['name']); - $responseData = ResponseHelper::toArray($response); + $response = $this->inbox->create(projectId: self::FAKE_PROJECT_ID, inboxName: 'My new inbox'); - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); + $this->assertSame(200, $response->getStatusCode()); } - public function testInvalidCreate(): void + public function testUpdateKeepsOldNamedArgumentsAndAcceptsInboxRequest(): void { - $errorMsg = [ - "error" => [ - "name" => [ - "can't be blank", - ] - ] - ]; - $this->inbox->expects($this->once()) - ->method('httpPost') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/projects/' . self::FAKE_PROJECT_ID . '/inboxes', - ) - ->willReturn(new Response(422, ['Content-Type' => 'application/json'], json_encode($errorMsg))); - - $this->expectException(HttpClientException::class); - $this->expectExceptionMessage( - 'Errors: name -> can\'t be blank.' + $inboxRequest = $this->assertDeprecationTriggered( + 'Mailtrap\DTO\Request\Inbox is deprecated and will be removed in a future major release; use Mailtrap\DTO\Request\Sandbox instead.', + fn () => new InboxRequest('New inbox name', 'new-email-username') ); - - $this->inbox->create(self::FAKE_PROJECT_ID, 'a'); - } - - public function testValidDelete(): void - { - $this->inbox->expects($this->once()) - ->method('httpDelete') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedInboxData()[0]))); - - $response = $this->inbox->delete(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); - - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - } - - public function testUpdate(): void - { - $newName = 'New inbox name'; - $emailUsername = 'new-email-username'; - $inboxRequest = new InboxRequest($newName, $emailUsername); - $expectedData = [ - "id" => self::FAKE_INBOX_ID, - "name" => $newName, - "username" => "24a5f9a9947fc7", - "password" => "a41e3846e78543", - "max_size" => 600, - "status" => "active", - "email_username" => $emailUsername, - "email_username_enabled" => false, - "sent_messages_count" => 0, - "forwarded_messages_count" => 0, - "used" => false, - "forward_from_email_address" => "a3336-i3866@forward.mailtrap.info", - "project_id" => 2424, - "domain" => "localhost", - "pop3_domain" => "localhost", - "email_domain" => "localhost", - "emails_count" => 0, - "emails_unread_count" => 0, - "last_message_sent_at" => null, - "smtp_ports" => [ - 25, - 465, - 587, - 2525 - ], - "pop3_ports" => [ - 1100, - 9950 - ], - "max_message_size" => 15728640, - "permissions" => [ - "can_read" => true, - "can_update" => true, - "can_destroy" => true, - "can_leave" => false - ] - ]; + $this->assertInstanceOf(SandboxRequest::class, $inboxRequest); $this->inbox->expects($this->once()) ->method('httpPatch') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID, + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID, [], - ['inbox' => $inboxRequest->toArray()] - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); - - $response = $this->inbox->update(self::FAKE_INBOX_ID, $inboxRequest); - $responseData = ResponseHelper::toArray($response); - - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - $this->assertEquals($newName, $responseData['name']); - $this->assertEquals($emailUsername, $responseData['email_username']); - } - - public function testClean(): void - { - $this->inbox->expects($this->once()) - ->method('httpPatch') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/clean', - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedInboxData()[0]))); - - $response = $this->inbox->clean(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); - - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - } - - public function testMarkAsRead(): void - { - $this->inbox->expects($this->once()) - ->method('httpPatch') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/all_read', - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedInboxData()[0]))); - - $response = $this->inbox->markAsRead(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); - - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - } - - public function testResetSmtpCredentials(): void - { - $expectedData = $this->getExpectedInboxData()[0]; - $expectedData['username'] = 'new_username'; - $expectedData['password'] = 'new_password'; - $this->inbox->expects($this->once()) - ->method('httpPatch') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/reset_credentials', - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); - - $response = $this->inbox->resetSmtpCredentials(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); - - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - $this->assertEquals($expectedData['username'], $responseData['username']); - $this->assertEquals($expectedData['password'], $responseData['password']); - } - - public function testToggleEmailAddress(): void - { - $expectedData = $this->getExpectedInboxData()[0]; - $expectedData['email_username_enabled'] = true; - - $this->inbox->expects($this->once()) - ->method('httpPatch') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/toggle_email_username', + ['inbox' => ['name' => 'New inbox name', 'email_username' => 'new-email-username']] ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode(['id' => self::FAKE_SANDBOX_ID]))); - $response = $this->inbox->toggleEmailAddress(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); + $response = $this->inbox->update(inboxId: self::FAKE_SANDBOX_ID, updateInbox: $inboxRequest); - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - $this->assertEquals($expectedData['email_username_enabled'], $responseData['email_username_enabled']); + $this->assertSame(200, $response->getStatusCode()); } - public function testResetEmailAddress(): void + /** + * @dataProvider inboxIdMethodsProvider + */ + public function testMethodsKeepOldInboxIdNamedArgument(string $method, string $httpMethod, string $pathSuffix): void { - $expectedData = $this->getExpectedInboxData()[0]; - $expectedData['email_username'] = 'new_email_username'; - $this->inbox->expects($this->once()) - ->method('httpPatch') - ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/reset_email_username', - ) - ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + ->method($httpMethod) + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . $pathSuffix) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode(['id' => self::FAKE_SANDBOX_ID]))); - $response = $this->inbox->resetEmailAddress(self::FAKE_INBOX_ID); - $responseData = ResponseHelper::toArray($response); + $response = $this->inbox->{$method}(inboxId: self::FAKE_SANDBOX_ID); - $this->assertInstanceOf(Response::class, $response); - $this->assertArrayHasKey('id', $responseData); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['id']); - $this->assertEquals($expectedData['email_username'], $responseData['email_username']); + $this->assertSame(200, $response->getStatusCode()); } - private function getExpectedInboxData(): array + public function inboxIdMethodsProvider(): iterable { - return [ - [ - "id" => self::FAKE_INBOX_ID, - "name" => "Admin Inbox", - "username" => "b3a87978452ae1", - "password" => "6be9fcfc613a7c", - "max_size" => 0, - "status" => "active", - "email_username" => "b7eae548c3-54c542", - "email_username_enabled" => false, - "sent_messages_count" => 52, - "forwarded_messages_count" => 0, - "used" => false, - "forward_from_email_address" => "a3538-i4088@forward.mailtrap.info", - "project_id" => 2293, - "domain" => "localhost", - "pop3_domain" => "localhost", - "email_domain" => "localhost", - "emails_count" => 0, - "emails_unread_count" => 0, - "last_message_sent_at" => null, - "smtp_ports" => [ - 25, - 465, - 587, - 2525 - ], - "pop3_ports" => [ - 1100, - 9950 - ], - "max_message_size" => 5242880, - "permissions" => [ - "can_read" => true, - "can_update" => true, - "can_destroy" => true, - "can_leave" => true - ] - ], - [ - "id" => 4089, - "name" => "Viewer Inbox", - "username" => "1d0aa0282f7712", - "password" => "5667a20f611ae7", - "max_size" => 0, - "status" => "active", - "email_username" => "f25402f8df-b77899", - "email_username_enabled" => false, - "sent_messages_count" => 527, - "forwarded_messages_count" => 0, - "used" => false, - "forward_from_email_address" => "a3538-i4089@forward.mailtrap.info", - "project_id" => 2293, - "domain" => "localhost", - "pop3_domain" => "localhost", - "email_domain" => "localhost", - "emails_count" => 0, - "emails_unread_count" => 0, - "last_message_sent_at" => null, - "smtp_ports" => [ - 25, - 465, - 587, - 2525 - ], - "pop3_ports" => [ - 1100, - 9950 - ], - "max_message_size" => 5242880, - "permissions" => [ - "can_read" => true, - "can_update" => false, - "can_destroy" => false, - "can_leave" => true - ] - ] - ]; + yield ['delete', 'httpDelete', '']; + yield ['clean', 'httpPatch', '/clean']; + yield ['markAsRead', 'httpPatch', '/all_read']; + yield ['resetSmtpCredentials', 'httpPatch', '/reset_credentials']; + yield ['toggleEmailAddress', 'httpPatch', '/toggle_email_username']; + yield ['resetEmailAddress', 'httpPatch', '/reset_email_username']; } } diff --git a/tests/Api/Sandbox/MessageTest.php b/tests/Api/Sandbox/MessageTest.php index 4787834..9a4c890 100644 --- a/tests/Api/Sandbox/MessageTest.php +++ b/tests/Api/Sandbox/MessageTest.php @@ -28,7 +28,7 @@ protected function setUp(): void $this->message = $this->getMockBuilder(Message::class) ->onlyMethods(['httpGet', 'httpPost', 'httpPatch', 'httpDelete']) - ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_INBOX_ID]) + ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_SANDBOX_ID]) ->getMock() ; } @@ -45,7 +45,7 @@ public function testValidGetList(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages', ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getMessagesData()))); @@ -66,7 +66,7 @@ public function testValidGetListWithFilters(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages', [ 'page' => $page, 'search' => $search, @@ -86,7 +86,7 @@ public function testValidGetListWithFilters(): void $responseData = array_shift($responseData); $this->assertArrayHasKey('id', $responseData); $this->assertEquals(self::FAKE_MESSAGE_ID, $responseData['id']); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['inbox_id']); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['inbox_id']); } public function testGetById(): void @@ -94,7 +94,7 @@ public function testGetById(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getMessagesData()[0]))); @@ -104,7 +104,7 @@ public function testGetById(): void $this->assertInstanceOf(Response::class, $response); $this->assertArrayHasKey('id', $responseData); $this->assertEquals(self::FAKE_MESSAGE_ID, $responseData['id']); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['inbox_id']); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['inbox_id']); } /** @@ -115,7 +115,7 @@ public function testGetSpamScore($expectedData): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/spam_report', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/spam_report', ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); @@ -134,7 +134,7 @@ public function testGetHtmlAnalysis($expectedData): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/analyze', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/analyze', ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); @@ -158,7 +158,7 @@ public function testGetMailHeaders(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/mail_headers', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/mail_headers', ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedHeaders))); @@ -176,7 +176,7 @@ public function testForward(): void $this->message->expects($this->once()) ->method('httpPost') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/forward', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/forward', [], ['email' => $email] ) @@ -195,7 +195,7 @@ public function testForwardFailsWithUnverifiedRecipient(): void $this->message->expects($this->once()) ->method('httpPost') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/forward', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/forward', [], ['email' => $email] ) @@ -225,7 +225,7 @@ public function testGetText(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.txt', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.txt', ) ->willReturn(new Response(200, ['Content-Type' => 'text/plain'], $expectedData)); @@ -242,7 +242,7 @@ public function testGetRaw(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.raw', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.raw', ) ->willReturn(new Response(200, ['Content-Type' => 'text/plain'], $expectedData)); @@ -259,7 +259,7 @@ public function testGetHtml(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.html', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.html', ) ->willReturn(new Response(200, ['Content-Type' => 'text/html'], $expectedData)); @@ -276,7 +276,7 @@ public function testGetEml(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.eml', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.eml', ) ->willReturn(new Response(200, ['Content-Type' => 'message/rfc822'], $expectedData)); @@ -293,7 +293,7 @@ public function testGeSource(): void $this->message->expects($this->once()) ->method('httpGet') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.htmlsource', + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID . '/body.htmlsource', ) ->willReturn(new Response(200, ['Content-Type' => 'text/html'], $expectedData)); @@ -312,7 +312,7 @@ public function testMarkAsRead($expectedData, $isRead): void $this->message->expects($this->once()) ->method('httpPatch') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, [], [ 'message' => [ @@ -335,7 +335,7 @@ public function testDelete(): void $this->message->expects($this->once()) ->method('httpDelete') ->with( - AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_INBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/messages/' . self::FAKE_MESSAGE_ID, ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getMessagesData()[0]))); @@ -345,7 +345,7 @@ public function testDelete(): void $this->assertInstanceOf(Response::class, $response); $this->assertArrayHasKey('id', $responseData); $this->assertEquals(self::FAKE_MESSAGE_ID, $responseData['id']); - $this->assertEquals(self::FAKE_INBOX_ID, $responseData['inbox_id']); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['inbox_id']); } public function spamScoreProvider(): array @@ -443,7 +443,7 @@ private function getMessagesData(): array return [ [ "id" => self::FAKE_MESSAGE_ID, - "inbox_id" => self::FAKE_INBOX_ID, + "inbox_id" => self::FAKE_SANDBOX_ID, "subject" => "Test email", "sent_at" => "2022-08-19T11:34:33.839Z", "from_email" => "per667son25@feeney.biz", diff --git a/tests/Api/Sandbox/SandboxTest.php b/tests/Api/Sandbox/SandboxTest.php new file mode 100644 index 0000000..41abb45 --- /dev/null +++ b/tests/Api/Sandbox/SandboxTest.php @@ -0,0 +1,416 @@ +sandbox = $this->getMockBuilder(Sandbox::class) + ->onlyMethods(['httpGet', 'httpPost', 'httpPatch', 'httpDelete']) + ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID]) + ->getMock() + ; + } + + protected function tearDown(): void + { + $this->sandbox = null; + + parent::tearDown(); + } + + public function testGetList(): void + { + $this->sandbox->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes') + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedSandboxData()))); + + $response = $this->sandbox->getList(); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertCount(2, $responseData); + $this->assertArrayHasKey('id', array_shift($responseData)); + } + + public function testGetSandboxAttributes(): void + { + $this->sandbox->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedSandboxData()[0]))); + + $response = $this->sandbox->getSandboxAttributes(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + $this->assertEquals('Admin Inbox', $responseData['name']); + $this->assertCount(4, $responseData['permissions']); + } + + public function testValidCreate(): void + { + $expectedData = [ + "id" => self::FAKE_SANDBOX_ID, + "name" => "My new sandbox", + "username" => "24a5f9a9947fc7", + "password" => "a41e3846e78543", + "max_size" => 600, + "status" => "active", + "email_username" => "d008137b46-4d932f", + "email_username_enabled" => false, + "sent_messages_count" => 0, + "forwarded_messages_count" => 0, + "used" => false, + "forward_from_email_address" => "a3336-i3866@forward.mailtrap.info", + "project_id" => 2424, + "domain" => "localhost", + "pop3_domain" => "localhost", + "email_domain" => "localhost", + "emails_count" => 0, + "emails_unread_count" => 0, + "last_message_sent_at" => null, + "smtp_ports" => [ + 25, + 465, + 587, + 2525 + ], + "pop3_ports" => [ + 1100, + 9950 + ], + "max_message_size" => 15728640, + "permissions" => [ + "can_read" => true, + "can_update" => true, + "can_destroy" => true, + "can_leave" => false + ] + ]; + + $this->sandbox->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/projects/' . self::FAKE_PROJECT_ID . '/inboxes', + [], + ['inbox' => ['name' => $expectedData['name']]] + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + + $response = $this->sandbox->create(self::FAKE_PROJECT_ID, $expectedData['name']); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + } + + public function testInvalidCreate(): void + { + $errorMsg = [ + "error" => [ + "name" => [ + "can't be blank", + ] + ] + ]; + $this->sandbox->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/projects/' . self::FAKE_PROJECT_ID . '/inboxes', + ) + ->willReturn(new Response(422, ['Content-Type' => 'application/json'], json_encode($errorMsg))); + + $this->expectException(HttpClientException::class); + $this->expectExceptionMessage( + 'Errors: name -> can\'t be blank.' + ); + + $this->sandbox->create(self::FAKE_PROJECT_ID, 'a'); + } + + public function testValidDelete(): void + { + $this->sandbox->expects($this->once()) + ->method('httpDelete') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedSandboxData()[0]))); + + $response = $this->sandbox->delete(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + } + + public function testUpdate(): void + { + $newName = 'New sandbox name'; + $emailUsername = 'new-email-username'; + $sandboxRequest = new SandboxRequest($newName, $emailUsername); + $expectedData = [ + "id" => self::FAKE_SANDBOX_ID, + "name" => $newName, + "username" => "24a5f9a9947fc7", + "password" => "a41e3846e78543", + "max_size" => 600, + "status" => "active", + "email_username" => $emailUsername, + "email_username_enabled" => false, + "sent_messages_count" => 0, + "forwarded_messages_count" => 0, + "used" => false, + "forward_from_email_address" => "a3336-i3866@forward.mailtrap.info", + "project_id" => 2424, + "domain" => "localhost", + "pop3_domain" => "localhost", + "email_domain" => "localhost", + "emails_count" => 0, + "emails_unread_count" => 0, + "last_message_sent_at" => null, + "smtp_ports" => [ + 25, + 465, + 587, + 2525 + ], + "pop3_ports" => [ + 1100, + 9950 + ], + "max_message_size" => 15728640, + "permissions" => [ + "can_read" => true, + "can_update" => true, + "can_destroy" => true, + "can_leave" => false + ] + ]; + + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID, + [], + ['inbox' => $sandboxRequest->toArray()] + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + + $response = $this->sandbox->update(self::FAKE_SANDBOX_ID, $sandboxRequest); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + $this->assertEquals($newName, $responseData['name']); + $this->assertEquals($emailUsername, $responseData['email_username']); + } + + public function testClean(): void + { + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/clean', + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedSandboxData()[0]))); + + $response = $this->sandbox->clean(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + } + + public function testMarkAsRead(): void + { + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/all_read', + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedSandboxData()[0]))); + + $response = $this->sandbox->markAsRead(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + } + + public function testResetSmtpCredentials(): void + { + $expectedData = $this->getExpectedSandboxData()[0]; + $expectedData['username'] = 'new_username'; + $expectedData['password'] = 'new_password'; + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/reset_credentials', + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + + $response = $this->sandbox->resetSmtpCredentials(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + $this->assertEquals($expectedData['username'], $responseData['username']); + $this->assertEquals($expectedData['password'], $responseData['password']); + } + + public function testToggleEmailAddress(): void + { + $expectedData = $this->getExpectedSandboxData()[0]; + $expectedData['email_username_enabled'] = true; + + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/toggle_email_username', + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + + $response = $this->sandbox->toggleEmailAddress(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + $this->assertEquals($expectedData['email_username_enabled'], $responseData['email_username_enabled']); + } + + public function testResetEmailAddress(): void + { + $expectedData = $this->getExpectedSandboxData()[0]; + $expectedData['email_username'] = 'new_email_username'; + + $this->sandbox->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/inboxes/' . self::FAKE_SANDBOX_ID . '/reset_email_username', + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($expectedData))); + + $response = $this->sandbox->resetEmailAddress(self::FAKE_SANDBOX_ID); + $responseData = ResponseHelper::toArray($response); + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals(self::FAKE_SANDBOX_ID, $responseData['id']); + $this->assertEquals($expectedData['email_username'], $responseData['email_username']); + } + + private function getExpectedSandboxData(): array + { + return [ + [ + "id" => self::FAKE_SANDBOX_ID, + "name" => "Admin Inbox", + "username" => "b3a87978452ae1", + "password" => "6be9fcfc613a7c", + "max_size" => 0, + "status" => "active", + "email_username" => "b7eae548c3-54c542", + "email_username_enabled" => false, + "sent_messages_count" => 52, + "forwarded_messages_count" => 0, + "used" => false, + "forward_from_email_address" => "a3538-i4088@forward.mailtrap.info", + "project_id" => 2293, + "domain" => "localhost", + "pop3_domain" => "localhost", + "email_domain" => "localhost", + "emails_count" => 0, + "emails_unread_count" => 0, + "last_message_sent_at" => null, + "smtp_ports" => [ + 25, + 465, + 587, + 2525 + ], + "pop3_ports" => [ + 1100, + 9950 + ], + "max_message_size" => 5242880, + "permissions" => [ + "can_read" => true, + "can_update" => true, + "can_destroy" => true, + "can_leave" => true + ] + ], + [ + "id" => 4089, + "name" => "Viewer Inbox", + "username" => "1d0aa0282f7712", + "password" => "5667a20f611ae7", + "max_size" => 0, + "status" => "active", + "email_username" => "f25402f8df-b77899", + "email_username_enabled" => false, + "sent_messages_count" => 527, + "forwarded_messages_count" => 0, + "used" => false, + "forward_from_email_address" => "a3538-i4089@forward.mailtrap.info", + "project_id" => 2293, + "domain" => "localhost", + "pop3_domain" => "localhost", + "email_domain" => "localhost", + "emails_count" => 0, + "emails_unread_count" => 0, + "last_message_sent_at" => null, + "smtp_ports" => [ + 25, + 465, + 587, + 2525 + ], + "pop3_ports" => [ + 1100, + 9950 + ], + "max_message_size" => 5242880, + "permissions" => [ + "can_read" => true, + "can_update" => false, + "can_destroy" => false, + "can_leave" => true + ] + ] + ]; + } +} diff --git a/tests/Api/Sending/DomainTest.php b/tests/Api/Sending/DomainTest.php index 8f7d2ec..c4c0f26 100644 --- a/tests/Api/Sending/DomainTest.php +++ b/tests/Api/Sending/DomainTest.php @@ -10,6 +10,7 @@ use Mailtrap\Exception\HttpClientException; use Mailtrap\Exception\InvalidArgumentException; use Mailtrap\Helper\ResponseHelper; +use Mailtrap\Tests\AssertsDeprecationsTrait; use Mailtrap\Tests\MailtrapTestCase; use Nyholm\Psr7\Response; @@ -20,6 +21,8 @@ */ class DomainTest extends MailtrapTestCase { + use AssertsDeprecationsTrait; + private ?Domain $domain; protected function setUp(): void @@ -37,7 +40,7 @@ protected function tearDown(): void parent::tearDown(); } - public function testGetSendingDomains(): void + public function testGetDomains(): void { $expectedResponseBody = $this->getExpectedDomainsResponse(); @@ -46,7 +49,7 @@ public function testGetSendingDomains(): void ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/sending_domains') ->willReturn(new Response(200, ['Content-Type' => 'application/json'], $expectedResponseBody)); - $response = $this->domain->getSendingDomains(); + $response = $this->domain->getDomains(); $responseData = ResponseHelper::toArray($response); $this->assertSame(200, $response->getStatusCode()); @@ -58,7 +61,7 @@ public function testGetSendingDomains(): void $this->assertArrayHasKey('permissions', $responseData['data'][0]); } - public function testCreateSendingDomain(): void + public function testCreateDomain(): void { $domainName = 'example.com'; $expectedResponseBody = $this->getExpectedDomainResponse($domainName); @@ -76,7 +79,7 @@ public function testCreateSendingDomain(): void ) ->willReturn(new Response(201, ['Content-Type' => 'application/json'], $expectedResponseBody)); - $response = $this->domain->createSendingDomain($domainName); + $response = $this->domain->createDomain($domainName); $responseData = ResponseHelper::toArray($response); $this->assertSame(201, $response->getStatusCode()); @@ -88,7 +91,7 @@ public function testCreateSendingDomain(): void $this->assertSame($domainName, $responseData['domain_name']); } - public function testCreateSendingDomainInvalid(): void + public function testCreateDomainInvalid(): void { $domainName = ''; $errorResponse = [ @@ -115,7 +118,7 @@ public function testCreateSendingDomainInvalid(): void $this->expectException(HttpClientException::class); $this->expectExceptionMessage('Errors: sending_domain -> domain_name -> can\'t be blank.'); - $this->domain->createSendingDomain($domainName); + $this->domain->createDomain($domainName); } public function testGetDomainById(): void @@ -158,7 +161,7 @@ public function testGetDomainByIdNotFound(): void $this->domain->getDomainById($domainId); } - public function testDeleteSendingDomain(): void + public function testDeleteDomain(): void { $domainId = 12345; @@ -167,11 +170,11 @@ public function testDeleteSendingDomain(): void ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/sending_domains/' . $domainId) ->willReturn(new Response(204)); - $response = $this->domain->deleteSendingDomain($domainId); + $response = $this->domain->deleteDomain($domainId); $this->assertSame(204, $response->getStatusCode()); } - public function testDeleteSendingDomainNotFound(): void + public function testDeleteDomainNotFound(): void { $domainId = 99999; $errorResponse = [ @@ -186,7 +189,7 @@ public function testDeleteSendingDomainNotFound(): void $this->expectException(HttpClientException::class); $this->expectExceptionMessage('The requested entity has not been found. Errors: Domain not found.'); - $this->domain->deleteSendingDomain($domainId); + $this->domain->deleteDomain($domainId); } public function testSendDomainSetupInstructions(): void @@ -277,7 +280,7 @@ private function getExpectedDomainsResponse(): string ]); } - public function testUpdateSendingDomain(): void + public function testUpdateDomain(): void { $domainId = 12345; $expectedResponseBody = $this->getExpectedDomainResponse('example.com', $domainId); @@ -299,7 +302,7 @@ public function testUpdateSendingDomain(): void ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], $expectedResponseBody)); - $response = $this->domain->updateSendingDomain( + $response = $this->domain->updateDomain( $domainId, new UpdateDomain( openTrackingEnabled: true, @@ -315,7 +318,7 @@ public function testUpdateSendingDomain(): void $this->assertSame($domainId, $responseData['id']); } - public function testUpdateSendingDomainSendsOnlyProvidedFields(): void + public function testUpdateDomainSendsOnlyProvidedFields(): void { $domainId = 12345; $expectedResponseBody = $this->getExpectedDomainResponse('example.com', $domainId); @@ -333,7 +336,7 @@ public function testUpdateSendingDomainSendsOnlyProvidedFields(): void ) ->willReturn(new Response(200, ['Content-Type' => 'application/json'], $expectedResponseBody)); - $response = $this->domain->updateSendingDomain( + $response = $this->domain->updateDomain( $domainId, new UpdateDomain(trackingOptOutEnabled: false) ); @@ -341,16 +344,45 @@ public function testUpdateSendingDomainSendsOnlyProvidedFields(): void $this->assertSame(200, $response->getStatusCode()); } - public function testUpdateSendingDomainWithEmptyPayload(): void + public function testUpdateDomainWithEmptyPayload(): void { $this->domain->expects($this->never())->method('httpPatch'); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( - 'At least one updatable field must be provided to update a sending domain' + 'At least one updatable field must be provided to update a domain' ); - $this->domain->updateSendingDomain(12345, new UpdateDomain()); + $this->domain->updateDomain(12345, new UpdateDomain()); + } + + /** + * @dataProvider deprecatedMethodsProvider + */ + public function testDeprecatedMethods(string $method, array $arguments, string $httpMethod, string $newMethod): void + { + $this->domain->expects($this->once()) + ->method($httpMethod) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], $this->getExpectedDomainResponse('example.com'))); + + $response = $this->assertDeprecationTriggered( + sprintf( + 'Mailtrap\Api\Sending\Domain::%s() is deprecated and will be removed in a future major release; use Mailtrap\Api\Sending\Domain::%s() instead.', + $method, + $newMethod + ), + fn () => $this->domain->{$method}(...$arguments) + ); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function deprecatedMethodsProvider(): iterable + { + yield ['getSendingDomains', [], 'httpGet', 'getDomains']; + yield ['createSendingDomain', ['example.com'], 'httpPost', 'createDomain']; + yield ['updateSendingDomain', [12345, new UpdateDomain(openTrackingEnabled: false)], 'httpPatch', 'updateDomain']; + yield ['deleteSendingDomain', [12345], 'httpDelete', 'deleteDomain']; } private function getExpectedDomainResponse(string $domainName, ?int $domainId = null): string diff --git a/tests/AssertsDeprecationsTrait.php b/tests/AssertsDeprecationsTrait.php new file mode 100644 index 0000000..47a5e09 --- /dev/null +++ b/tests/AssertsDeprecationsTrait.php @@ -0,0 +1,64 @@ +captureDeprecations($call); + + self::assertNotEmpty( + array_filter($messages, static fn (string $message): bool => str_contains($message, $needle)), + sprintf('No deprecation notice containing "%s" was triggered. Triggered: %s', $needle, json_encode($messages)) + ); + + return $result; + } + + /** + * Runs $call, asserts it triggered no deprecation notice and returns what $call returned. + */ + protected function assertNoDeprecationTriggered(callable $call): mixed + { + [$result, $messages] = $this->captureDeprecations($call); + + self::assertSame([], $messages, 'Unexpected deprecation notices were triggered.'); + + return $result; + } + + /** + * Runs $call and returns what it returned and the deprecation notices it triggered. + * + * @return array{0: mixed, 1: string[]} + */ + protected function captureDeprecations(callable $call): array + { + Deprecation::reset(); + $messages = []; + set_error_handler(static function (int $level, string $message) use (&$messages): bool { + $messages[] = $message; + + return true; + }, E_USER_DEPRECATED); + + try { + $result = $call(); + } finally { + restore_error_handler(); + } + + return [$result, $messages]; + } +} diff --git a/tests/Bridge/Transport/MailtrapSdkTransportFactoryTest.php b/tests/Bridge/Transport/MailtrapSdkTransportFactoryTest.php index ca07695..95bdc58 100644 --- a/tests/Bridge/Transport/MailtrapSdkTransportFactoryTest.php +++ b/tests/Bridge/Transport/MailtrapSdkTransportFactoryTest.php @@ -8,7 +8,10 @@ use Mailtrap\Bridge\Transport\MailtrapSdkTransport; use Mailtrap\Bridge\Transport\MailtrapSdkTransportFactory; use Mailtrap\Config; +use Mailtrap\Exception\InvalidArgumentException; +use Mailtrap\Exception\RuntimeException; use Mailtrap\MailtrapClient; +use Mailtrap\Tests\AssertsDeprecationsTrait; use Symfony\Component\HttpClient\Psr18Client; use Symfony\Component\Mailer\Transport\Dsn; use Symfony\Component\Mailer\Transport\TransportFactoryInterface; @@ -20,6 +23,8 @@ */ class MailtrapSdkTransportFactoryTest extends TransportFactoryTestCase { + use AssertsDeprecationsTrait; + protected function setUp(): void { if (!class_exists(Dsn::class)) { @@ -58,7 +63,7 @@ public function createProvider(): iterable $bulkConfig = (new Config(self::USER)) ->setHttpClient($psrClient) ->setHost(AbstractApi::SENDMAIL_BULK_HOST); - $inboxId = 1234; + $sandboxId = 1234; yield [ new Dsn('mailtrap+sdk', 'default', self::USER), @@ -82,9 +87,9 @@ public function createProvider(): iterable // sandbox yield [ - new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, ['inboxId' => 1234]), + new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, ['sandboxId' => 1234]), new MailtrapSdkTransport( - (new MailtrapClient($sandboxConfig))->sandbox()->emails($inboxId), + (new MailtrapClient($sandboxConfig))->sandbox()->emails($sandboxId), $sandboxConfig, $dispatcher, $logger @@ -103,6 +108,90 @@ public function createProvider(): iterable ]; } + public function testSandboxIdOptionTriggersNoDeprecation(): void + { + $transport = $this->assertNoDeprecationTriggered( + fn () => $this->getFactory()->create( + new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, ['sandboxId' => '1234']) + ) + ); + + $this->assertSame(sprintf('mailtrap+sdk://%s?sandboxId=1234', AbstractApi::SENDMAIL_SANDBOX_HOST), (string) $transport); + } + + /** + * @dataProvider deprecatedInboxIdOptionsProvider + */ + public function testInboxIdOptionIsDeprecated(array $options): void + { + $transport = $this->assertDeprecationTriggered( + 'The "inboxId" option of the mailtrap+sdk transport (MAILTRAP_INBOX_ID in Laravel) is deprecated and will be removed in a future major release; use the "sandboxId" option (MAILTRAP_SANDBOX_ID) instead.', + fn () => $this->getFactory()->create( + new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, $options) + ) + ); + + $this->assertSame(sprintf('mailtrap+sdk://%s?sandboxId=1234', AbstractApi::SENDMAIL_SANDBOX_HOST), (string) $transport); + } + + public function deprecatedInboxIdOptionsProvider(): iterable + { + // MAILER_DSN=mailtrap+sdk://APIKEY@sandbox.api.mailtrap.io?inboxId=1234 + yield 'Symfony DSN query' => [['inboxId' => '1234']]; + + // Laravel passes its "services.mailtrap-sdk" config as the options: here only MAILTRAP_INBOX_ID is set + yield 'Laravel config' => [[ + 'host' => AbstractApi::SENDMAIL_SANDBOX_HOST, + 'apiKey' => self::USER, + 'sandboxId' => null, + 'inboxId' => '1234', + ]]; + + yield 'empty sandboxId' => [['sandboxId' => '', 'inboxId' => '1234']]; + + yield 'sandboxId and inboxId with the same value' => [['sandboxId' => '1234', 'inboxId' => '1234']]; + } + + /** + * @dataProvider differentSandboxIdAndInboxIdOptionsProvider + */ + public function testDifferentSandboxIdAndInboxIdOptions(array $options): void + { + $this->expectExceptionObject(new InvalidArgumentException( + 'The mailtrap+sdk transport received different values for the "sandboxId" and "inboxId" options (MAILTRAP_SANDBOX_ID and MAILTRAP_INBOX_ID in Laravel); set only "sandboxId".' + )); + + $this->getFactory()->create( + new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, $options) + ); + } + + public function differentSandboxIdAndInboxIdOptionsProvider(): iterable + { + yield 'two IDs' => [['sandboxId' => '1234', 'inboxId' => '5678']]; + yield 'zero sandboxId' => [['sandboxId' => '0', 'inboxId' => '1234']]; + yield 'zero inboxId' => [['sandboxId' => '1234', 'inboxId' => '0']]; + } + + /** + * @dataProvider withoutSandboxIdOptionsProvider + */ + public function testSandboxWithoutSandboxIdOption(array $options): void + { + $this->expectExceptionObject(new RuntimeException( + 'You cannot send an email to a sandbox with an empty "sandboxId" parameter. Example -> "MAILER_DSN=mailtrap+sdk://APIKEY@sandbox.api.mailtrap.io?sandboxId=1234"' + )); + + $this->getFactory()->create(new Dsn('mailtrap+sdk', AbstractApi::SENDMAIL_SANDBOX_HOST, self::USER, null, null, $options)); + } + + public function withoutSandboxIdOptionsProvider(): iterable + { + yield 'no options' => [[]]; + yield 'zero sandboxId' => [['sandboxId' => '0']]; + yield 'zero inboxId' => [['inboxId' => '0']]; + } + public function unsupportedSchemeProvider(): iterable { yield [ diff --git a/tests/Bridge/Transport/MailtrapSdkTransportTest.php b/tests/Bridge/Transport/MailtrapSdkTransportTest.php index 4fcef75..028e6c4 100644 --- a/tests/Bridge/Transport/MailtrapSdkTransportTest.php +++ b/tests/Bridge/Transport/MailtrapSdkTransportTest.php @@ -42,7 +42,7 @@ public static function getTransportData(): array $sendConfig = (new Config('key'))->setHost(AbstractApi::SENDMAIL_TRANSACTIONAL_HOST); $sandboxConfig = (new Config('key'))->setHost(AbstractApi::SENDMAIL_SANDBOX_HOST); $bulkConfig = (new Config('key'))->setHost(AbstractApi::SENDMAIL_BULK_HOST); - $inboxId = 1234; + $sandboxId = 1234; return [ [ @@ -54,10 +54,10 @@ public static function getTransportData(): array ], [ new MailtrapSdkTransport( - (new MailtrapSandboxClient($sandboxConfig))->emails($inboxId), + (new MailtrapSandboxClient($sandboxConfig))->emails($sandboxId), $sandboxConfig ), - sprintf('mailtrap+sdk://%s?inboxId=%s', AbstractApi::SENDMAIL_SANDBOX_HOST, $inboxId), + sprintf('mailtrap+sdk://%s?sandboxId=%s', AbstractApi::SENDMAIL_SANDBOX_HOST, $sandboxId), ], [ new MailtrapSdkTransport( diff --git a/tests/Helper/DeprecationTest.php b/tests/Helper/DeprecationTest.php new file mode 100644 index 0000000..31ab258 --- /dev/null +++ b/tests/Helper/DeprecationTest.php @@ -0,0 +1,64 @@ +captureDeprecations(static function (): void { + Deprecation::trigger('Foo::old()', 'Foo::new()'); + Deprecation::trigger('Foo::old()', 'Foo::new()'); + Deprecation::trigger('Bar::old()', 'Bar::new()'); + }); + + $this->assertSame([ + 'Foo::old() is deprecated and will be removed in a future major release; use Foo::new() instead.', + 'Bar::old() is deprecated and will be removed in a future major release; use Bar::new() instead.', + ], $messages); + } + + public function testRenamedArgumentReturnsNewValueSilently(): void + { + $this->assertNoDeprecationTriggered(function (): void { + $this->assertSame(1, Deprecation::renamedArgument('foo()', 'old', 'new', null, 1)); + $this->assertNull(Deprecation::renamedArgument('foo()', 'old', 'new', null, null)); + }); + } + + public function testRenamedArgumentFallsBackToOldValue(): void + { + [, $messages] = $this->captureDeprecations(function (): void { + $this->assertSame(1, Deprecation::renamedArgument('foo()', 'old', 'new', 1, null)); + $this->assertSame(1, Deprecation::renamedArgument('foo()', 'old', 'new', 1, 1)); + }); + + $this->assertSame( + ['The $old argument of foo() is deprecated and will be removed in a future major release; use $new instead.'], + $messages + ); + } + + public function testRenamedArgumentRejectsDifferentValues(): void + { + $this->expectExceptionObject( + new InvalidArgumentException('foo() received different values for $new and $old; pass only $new.') + ); + + $this->captureDeprecations(static fn () => Deprecation::renamedArgument('foo()', 'old', 'new', 1, 2)); + } +} diff --git a/tests/MailtrapClientTestCase.php b/tests/MailtrapClientTestCase.php index 80153fa..7e985fb 100644 --- a/tests/MailtrapClientTestCase.php +++ b/tests/MailtrapClientTestCase.php @@ -13,7 +13,7 @@ */ abstract class MailtrapClientTestCase extends MailtrapTestCase { - private ?MailtrapClientInterface $mailtrapClientLayer; + protected ?MailtrapClientInterface $mailtrapClientLayer; abstract public function getMailtrapClientClassName(): string; diff --git a/tests/MailtrapSandboxClientTest.php b/tests/MailtrapSandboxClientTest.php index 0f72582..7adac48 100644 --- a/tests/MailtrapSandboxClientTest.php +++ b/tests/MailtrapSandboxClientTest.php @@ -5,7 +5,10 @@ namespace Mailtrap\Tests; use Mailtrap\Api\Sandbox\Emails as SandboxSendingEmails; +use Mailtrap\Api\Sandbox\Inbox; +use Mailtrap\Api\Sandbox\Sandbox; use Mailtrap\Api\Sandbox\SandboxInterface; +use Mailtrap\Exception\InvalidArgumentException; use Mailtrap\MailtrapClient; use Mailtrap\MailtrapSandboxClient; @@ -16,6 +19,8 @@ */ class MailtrapSandboxClientTest extends MailtrapClientTestCase { + use AssertsDeprecationsTrait; + public function getMailtrapClientClassName(): string { return MailtrapSandboxClient::class; @@ -30,19 +35,125 @@ public function mapInstancesProvider(): iterable { foreach (MailtrapSandboxClient::API_MAPPING as $key => $item) { yield match ($key) { - 'emails' => [new $item($this->getConfigMock(), self::FAKE_INBOX_ID)], - 'projects', 'inboxes' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID)], - 'messages', 'attachments' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_INBOX_ID)], + 'emails' => [new $item($this->getConfigMock(), self::FAKE_SANDBOX_ID)], + 'projects', 'sandboxes', 'inboxes' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID)], + 'messages', 'attachments' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID, self::FAKE_SANDBOX_ID)], default => [new $item($this->getConfigMock())], }; } } + public function testSandboxes(): void + { + $sandboxes = $this->assertNoDeprecationTriggered(fn () => $this->mailtrapClientLayer->sandboxes(self::FAKE_ACCOUNT_ID)); + + $this->assertInstanceOf(Sandbox::class, $sandboxes); + $this->assertNotInstanceOf(Inbox::class, $sandboxes); + $this->assertSame(self::FAKE_ACCOUNT_ID, $sandboxes->getAccountId()); + } + + public function testInboxesIsDeprecated(): void + { + $inboxes = $this->assertDeprecationTriggered( + 'Mailtrap\Api\Sandbox\Inbox (MailtrapSandboxClient::inboxes()) is deprecated and will be removed in a future major release; use Mailtrap\Api\Sandbox\Sandbox (MailtrapSandboxClient::sandboxes()) instead.', + fn () => $this->mailtrapClientLayer->inboxes(self::FAKE_ACCOUNT_ID) + ); + + $this->assertInstanceOf(Inbox::class, $inboxes); + $this->assertInstanceOf(Sandbox::class, $inboxes); + $this->assertSame(self::FAKE_ACCOUNT_ID, $inboxes->getAccountId()); + } + + /** + * @dataProvider sandboxIdApisProvider + */ + public function testSandboxIdArgument(string $method, array $arguments): void + { + $api = $this->assertNoDeprecationTriggered( + fn () => $this->mailtrapClientLayer->{$method}(...$arguments, ...['sandboxId' => self::FAKE_SANDBOX_ID]) + ); + + $this->assertSame(self::FAKE_SANDBOX_ID, $api->getSandboxId()); + } + + /** + * @dataProvider sandboxIdApisProvider + */ + public function testInboxIdArgumentIsDeprecated(string $method, array $arguments, string $className): void + { + $api = $this->assertDeprecationTriggered( + sprintf('The $inboxId argument of %s::__construct() is deprecated', $className), + fn () => $this->mailtrapClientLayer->{$method}(...$arguments, ...['inboxId' => self::FAKE_SANDBOX_ID]) + ); + + $this->assertSame(self::FAKE_SANDBOX_ID, $api->getSandboxId()); + } + + /** + * @dataProvider sandboxIdApisProvider + */ + public function testGetInboxIdIsDeprecated(string $method, array $arguments, string $className): void + { + $api = $this->mailtrapClientLayer->{$method}(...$arguments, ...[self::FAKE_SANDBOX_ID]); + + $inboxId = $this->assertDeprecationTriggered( + sprintf('%1$s::getInboxId() is deprecated and will be removed in a future major release; use %1$s::getSandboxId() instead.', $className), + fn () => $api->getInboxId() + ); + + $this->assertSame(self::FAKE_SANDBOX_ID, $inboxId); + } + + /** + * @dataProvider sandboxIdApisProvider + */ + public function testSandboxIdIsRequired(string $method, array $arguments, string $className): void + { + $this->expectExceptionObject( + new InvalidArgumentException(sprintf('%s::__construct() requires the $sandboxId argument.', $className)) + ); + + $this->mailtrapClientLayer->{$method}(...$arguments); + } + + /** + * @dataProvider sandboxIdApisProvider + */ + public function testDifferentSandboxIdAndInboxIdAreRejected(string $method, array $arguments, string $className): void + { + $this->expectExceptionObject(new InvalidArgumentException(sprintf( + '%s::__construct() received different values for $sandboxId and $inboxId; pass only $sandboxId.', + $className + ))); + + $this->mailtrapClientLayer->{$method}(...$arguments, ...['sandboxId' => self::FAKE_SANDBOX_ID, 'inboxId' => self::FAKE_SANDBOX_ID + 1]); + } + + public function sandboxIdApisProvider(): iterable + { + yield ['emails', [], SandboxSendingEmails::class]; + yield ['messages', [self::FAKE_ACCOUNT_ID], MailtrapSandboxClient::API_MAPPING['messages']]; + yield ['attachments', [self::FAKE_ACCOUNT_ID], MailtrapSandboxClient::API_MAPPING['attachments']]; + } + public function testValidInitSandboxSendingEmails(): void { - $this->assertInstanceOf( - SandboxSendingEmails::class, - MailtrapClient::initSendingEmails(apiKey: self::DEFAULT_API_KEY, isSandbox: true, inboxId: self::FAKE_INBOX_ID) + $emails = $this->assertNoDeprecationTriggered( + fn () => MailtrapClient::initSendingEmails(apiKey: self::DEFAULT_API_KEY, isSandbox: true, sandboxId: self::FAKE_SANDBOX_ID) ); + + $this->assertInstanceOf(SandboxSendingEmails::class, $emails); + $this->assertSame(self::FAKE_SANDBOX_ID, $emails->getSandboxId()); + } + + public function testInitSandboxSendingEmailsWithInboxIdIsDeprecated(): void + { + $emails = $this->assertDeprecationTriggered( + 'The $inboxId argument of Mailtrap\MailtrapClient::initSendingEmails() is deprecated and will be removed in a future major release; use $sandboxId instead.', + fn () => MailtrapClient::initSendingEmails(apiKey: self::DEFAULT_API_KEY, isSandbox: true, inboxId: self::FAKE_SANDBOX_ID) + ); + + $this->assertInstanceOf(SandboxSendingEmails::class, $emails); + $this->assertSame(self::FAKE_SANDBOX_ID, $emails->getSandboxId()); } } diff --git a/tests/MailtrapTestCase.php b/tests/MailtrapTestCase.php index 6c0440f..d958c6c 100644 --- a/tests/MailtrapTestCase.php +++ b/tests/MailtrapTestCase.php @@ -19,6 +19,7 @@ abstract class MailtrapTestCase extends TestCase public const FAKE_ORGANIZATION_ID = 7777; public const FAKE_ACCOUNT_ACCESS_ID = 1000001; public const FAKE_PROJECT_ID = 2436; + public const FAKE_SANDBOX_ID = 4015; public const FAKE_INBOX_ID = 4015; public const FAKE_MESSAGE_ID = 457; public const FAKE_MESSAGE_ATTACHMENT_ID = 67;