Conversation
WalkthroughA new Contacts API feature was added, including a client class, DTOs for creating and updating contacts, and tests. The Mailtrap general client was updated to include the new endpoint. An example script and changelog entry were also introduced to document the functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant UserScript
participant MailtrapGeneralClient
participant ContactAPI
participant MailtrapAPI
UserScript->>MailtrapGeneralClient: contacts(accountId)
MailtrapGeneralClient->>ContactAPI: new Contact(config, accountId)
UserScript->>ContactAPI: createContact(CreateContactDTO)
ContactAPI->>MailtrapAPI: POST /accounts/{accountId}/contacts
MailtrapAPI-->>ContactAPI: Response (created contact)
ContactAPI-->>UserScript: Response
UserScript->>ContactAPI: updateContactById(contactId, UpdateContactDTO)
ContactAPI->>MailtrapAPI: PUT /accounts/{accountId}/contacts/{contactId}
MailtrapAPI-->>ContactAPI: Response (updated contact)
ContactAPI-->>UserScript: Response
UserScript->>ContactAPI: deleteContactByEmail(email)
ContactAPI->>MailtrapAPI: DELETE /accounts/{accountId}/contacts/email/{email}
MailtrapAPI-->>ContactAPI: Response (deletion status)
ContactAPI-->>UserScript: Response
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (3)
🔇 Additional comments (6)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
examples/general/contacts.php (2)
58-79: Consider demonstrating different update scenarios.Both
updateContactByIdandupdateContactByEmailuse identical contact data, which doesn't clearly demonstrate the difference between the two methods. Consider using different data or adding comments to highlight when each method would be preferred.// Update contact by ID $response = $contacts->updateContactById( '019706a8-0000-0000-0000-4f26816b467a', UpdateContact::init( - 'john.smith@example.com', - ['first_name' => 'John', 'last_name' => 'Smith'], // Fields + 'john.doe@example.com', // Update email + ['first_name' => 'John', 'last_name' => 'Doe'], // Update name [3], // List IDs to which the contact will be added [1, 2], // List IDs from which the contact will be removed true // Unsubscribe the contact ) ); // OR update contact by email $response = $contacts->updateContactByEmail( 'john.smith@example.com', UpdateContact::init( 'john.smith@example.com', - ['first_name' => 'John', 'last_name' => 'Smith'], // Fields + ['first_name' => 'Jane', 'last_name' => 'Smith'], // Update first name only [3], // List IDs to which the contact will be added [1, 2], // List IDs from which the contact will be removed - true // Unsubscribe the contact + false // Keep subscribed ) );
95-98: Variable reuse masks the first delete operation result.Both delete operations assign to the same
$responsevariable, which means the result ofdeleteContactByIdis immediately overwritten. This could confuse users about which operation's result is being displayed.// Delete contact by ID -$response = $contacts->deleteContactById('019706a8-0000-0000-0000-4f26816b467a'); +$responseById = $contacts->deleteContactById('019706a8-0000-0000-0000-4f26816b467a'); // OR delete contact by email -$response = $contacts->deleteContactByEmail('john.smith@example.com'); +$responseByEmail = $contacts->deleteContactByEmail('john.smith@example.com'); // print the response body (array) -var_dump(ResponseHelper::toArray($response)); +var_dump(ResponseHelper::toArray($responseByEmail));tests/Api/General/ContactTest.php (1)
60-61: Minor inconsistency with variable usage.The
$fakeEmailvariable is defined but the email value is hardcoded in theCreateContactconstructor. Consider using the variable for consistency.$fakeEmail = 'test@example.com'; -$contactDTO = new CreateContact('test@example.com', ['first_name' => 'John'], [1, 2]); +$contactDTO = new CreateContact($fakeEmail, ['first_name' => 'John'], [1, 2]);src/Api/General/Contact.php (1)
55-58: Consider adding input validation for better error handling.The public methods don't validate their string parameters. Consider adding validation to provide better error messages for empty or invalid inputs before making HTTP requests.
Example validation for contact ID/email parameters:
public function updateContactById(string $contactId, UpdateContact $contact): ResponseInterface { + if (empty(trim($contactId))) { + throw new \InvalidArgumentException('Contact ID cannot be empty'); + } return $this->updateContact($contactId, $contact); } public function updateContactByEmail(string $email, UpdateContact $contact): ResponseInterface { + if (empty(trim($email))) { + throw new \InvalidArgumentException('Email cannot be empty'); + } + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new \InvalidArgumentException('Invalid email format'); + } return $this->updateContact($email, $contact); }Also applies to: 67-70, 78-81, 89-92
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
CHANGELOG.md(1 hunks)examples/general/contacts.php(1 hunks)src/Api/General/Contact.php(1 hunks)src/DTO/Request/Contact/ContactInterface.php(1 hunks)src/DTO/Request/Contact/CreateContact.php(1 hunks)src/DTO/Request/Contact/UpdateContact.php(1 hunks)src/MailtrapGeneralClient.php(2 hunks)tests/Api/General/ContactTest.php(1 hunks)tests/MailtrapGeneralClientTest.php(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/DTO/Request/Contact/ContactInterface.php (3)
src/Api/General/Contact.php (1)
Contact(16-133)src/DTO/Request/Contact/CreateContact.php (2)
getEmail(24-27)getFields(29-32)src/DTO/Request/Contact/UpdateContact.php (2)
getEmail(31-34)getFields(36-39)
src/MailtrapGeneralClient.php (2)
src/Api/General/Permission.php (1)
Permission(16-72)src/Api/General/Contact.php (1)
Contact(16-133)
src/DTO/Request/Contact/UpdateContact.php (3)
src/Api/General/Contact.php (2)
Contact(16-133)__construct(18-21)src/DTO/Request/Contact/CreateContact.php (5)
__construct(12-17)init(19-22)getEmail(24-27)getFields(29-32)toArray(39-46)src/DTO/Request/Contact/ContactInterface.php (2)
getEmail(14-14)getFields(21-21)
tests/MailtrapGeneralClientTest.php (1)
tests/MailtrapTestCase.php (1)
getConfigMock(38-57)
🔇 Additional comments (14)
CHANGELOG.md (1)
1-2: LGTM! Well-formatted changelog entry.The changelog entry properly documents the new Contacts API functionality and follows the established format and versioning pattern.
src/DTO/Request/Contact/ContactInterface.php (1)
7-22: LGTM! Well-designed interface following best practices.The
ContactInterfaceprovides a clean contract for contact DTOs with:
- Appropriate extension of
RequestInterface- Clear method signatures with specific return types
- Comprehensive PHPDoc documentation
- Follows SOLID interface segregation principle
src/MailtrapGeneralClient.php (2)
11-11: LGTM! Method annotation follows established pattern.The
contacts(int $accountId)method annotation correctly specifies the parameter type and return type, consistent with other General API endpoints likepermissionsandusers.
21-21: LGTM! API mapping correctly integrates the Contact class.The contacts mapping entry follows the established pattern and properly maps to the
Api\General\Contactclass, maintaining consistency with the existing API structure.tests/MailtrapGeneralClientTest.php (1)
31-31: LGTM! Test correctly handles Contact class instantiation.Adding
'contacts'to the match expression ensures the Contact class is instantiated with both the config mock and account ID, which aligns with its constructor signature requirement (similar topermissionsandusersclasses).src/DTO/Request/Contact/CreateContact.php (1)
10-47: LGTM! Well-structured DTO with clean implementation.The class follows excellent practices:
- Immutable design with private promoted properties
- Static factory method for convenient instantiation
- Consistent getter methods
- Proper array serialization with snake_case keys matching API expectations
The implementation aligns well with the ContactInterface and integrates cleanly with the Contact API client.
tests/Api/General/ContactTest.php (1)
19-232: Excellent test coverage with comprehensive scenarios.The test class provides thorough coverage of the Contact API functionality:
- All CRUD operations are tested
- Both ID and email-based operations are covered
- Error scenarios are properly tested with exception expectations
- Mock setup correctly isolates the HTTP layer
- Response assertions validate both structure and content
The test structure follows PHPUnit best practices and will provide good confidence in the Contact API implementation.
src/Api/General/Contact.php (7)
1-11: LGTM! Clean imports and namespace declaration.The file header follows PHP best practices with strict types declaration and appropriate namespace organization. All imports are necessary and well-organized.
16-21: LGTM! Modern constructor with proper dependency injection.The class properly extends the abstract base class and uses PHP 8 constructor property promotion for the account ID parameter. The dependency injection pattern is correctly implemented.
28-33: LGTM! Simple and clean implementation.The method correctly implements the API call pattern using the inherited HTTP methods and response handling.
41-46: LGTM! Proper DTO usage and consistent API pattern.The method correctly uses the CreateContact DTO and follows the established API request pattern with proper body structure.
55-58: LGTM! Good use of delegation pattern.Both methods properly delegate to the private helper method, following the DRY principle while providing clear public APIs for different identifier types.
Also applies to: 67-70
78-81: LGTM! Consistent delegation pattern.Both delete methods follow the same clean delegation pattern as the update methods.
Also applies to: 89-92
129-132: LGTM! Clean path construction.The base path construction properly uses sprintf for string formatting and correctly incorporates the host and account ID.
Motivation
Support new functionality (Contacts API)
https://help.mailtrap.io/article/147-contacts
Changes
layerContact intoMailtrapGeneralClientHow to test
composer testOR run PHP code from the example
Summary by CodeRabbit