Skip to content

Add name prefix into custom EmailHeaders to avoid conflicts with reserved names#35

Merged
gaalferov merged 1 commit intomainfrom
fix/fix-custom-email-headers
Jan 22, 2025
Merged

Add name prefix into custom EmailHeaders to avoid conflicts with reserved names#35
gaalferov merged 1 commit intomainfrom
fix/fix-custom-email-headers

Conversation

@gaalferov
Copy link
Collaborator

@gaalferov gaalferov commented Jan 21, 2025

Motivation

Issue - #34

Conflict with reserved mime header names

Changes

  • Add name prefix into custom EmailHeaders to avoid conflicts with reserved names Symfony\Component\Mime\Header\Headers::HEADER_CLASS_MAP

p.s. prefix is added only at the time of request generation and is not passed to MailTrap

How to test

composer test

Summary by CodeRabbit

Release Notes for Version 2.0.4

  • New Features

    • Introduced a new CustomHeaderInterface to manage email header names
    • Added name prefix mechanism for custom email headers to prevent naming conflicts
  • Improvements

    • Enhanced email header processing to handle reserved names more effectively
    • Updated custom and template variable header implementations
  • Bug Fixes

    • Resolved potential naming conflicts with Symfony's reserved header names
  • Tests

    • Expanded test coverage for custom and template variable scenarios

@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2025

Walkthrough

This pull request introduces modifications to email header handling in the Mailtrap library. The changes focus on preventing naming conflicts with reserved Symfony header names by adding a prefix to custom and template variable headers. A new CustomHeaderInterface is introduced to standardize the header name retrieval process. The modifications affect the CustomVariableHeader and TemplateVariableHeader classes, adding a name prefix mechanism and a method to retrieve the original header name without the prefix.

Changes

File Change Summary
CHANGELOG.md Added version 2.0.4 entry documenting header name prefix addition
src/EmailHeader/CustomHeaderInterface.php New interface with getNameWithoutPrefix() method declaration
src/EmailHeader/CustomVariableHeader.php Implemented CustomHeaderInterface, added NAME_PREFIX constant, new getNameWithoutPrefix() method
src/EmailHeader/Template/TemplateVariableHeader.php Implemented CustomHeaderInterface, added NAME_PREFIX constant, new getNameWithoutPrefix() method
src/Api/AbstractEmails.php Modified getPayload() to use getNameWithoutPrefix() for header processing
tests/Api/AbstractEmailsTest.php Expanded test data providers with additional custom variable scenarios

Sequence Diagram

sequenceDiagram
    participant CH as CustomHeader
    participant API as AbstractEmails
    participant Payload as Payload Generation

    CH->>CH: Apply NAME_PREFIX
    CH->>CH: Implement getNameWithoutPrefix()
    API->>CH: Request header name
    CH-->>API: Return name without prefix
    API->>Payload: Use clean header name
Loading

Poem

🐰 A Rabbit's Ode to Header Harmony 🐰

Prefixes dance, no names collide,
Symfony's map now set aside
Custom headers, clean and bright
Hopping through with pure delight!
Code hops on, no conflicts in sight 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/EmailHeader/CustomVariableHeader.php (2)

23-24: Consider adding validation for empty name parameter.

The constructor should validate that the name parameter is not empty before adding the prefix.

 public function __construct(string $name, string $value)
 {
+    if (empty($name)) {
+        throw new \InvalidArgumentException('Header name cannot be empty');
+    }
     // add prefix to avoid conflicts with reserved header names
     parent::__construct(self::NAME_PREFIX . $name);

61-64: Consider optimizing the getNameWithoutPrefix implementation.

The current implementation recalculates the prefix length on every call. Consider caching the prefix length as a constant.

+    private const NAME_PREFIX_LENGTH = 23; // length of 'custom_variables_prefix_'

     public function getNameWithoutPrefix(): string
     {
-        return substr($this->getName(), strlen(self::NAME_PREFIX));
+        return substr($this->getName(), self::NAME_PREFIX_LENGTH);
     }
src/EmailHeader/Template/TemplateVariableHeader.php (2)

25-26: Consider adding validation for empty name parameter.

The constructor should validate that the name parameter is not empty before adding the prefix.

 public function __construct(string $name, mixed $value)
 {
+    if (empty($name)) {
+        throw new \InvalidArgumentException('Header name cannot be empty');
+    }
     // add prefix to avoid conflicts with reserved header names
     parent::__construct(self::NAME_PREFIX . $name);

60-63: Consider optimizing the getNameWithoutPrefix implementation.

The current implementation recalculates the prefix length on every call. Consider caching the prefix length as a constant.

+    private const NAME_PREFIX_LENGTH = 25; // length of 'template_variables_prefix_'

     public function getNameWithoutPrefix(): string
     {
-        return substr($this->getName(), strlen(self::NAME_PREFIX));
+        return substr($this->getName(), self::NAME_PREFIX_LENGTH);
     }
src/Api/AbstractEmails.php (1)

64-64: Consider reducing duplication in header handling.

While the change correctly implements prefix stripping for template variables, there's similar logic between CustomVariableHeader and TemplateVariableHeader handling. Consider extracting this common behavior into a shared method.

Example refactor:

+ private function processVariableHeader($header, string $varName): void
+ {
+     $payload[$varName][$header->getNameWithoutPrefix()] = $header->getValue();
+ }

  switch(true) {
      case $header instanceof CustomVariableHeader:
-         $payload[CustomVariableHeader::VAR_NAME][$header->getNameWithoutPrefix()] = $header->getValue();
+         $this->processVariableHeader($header, CustomVariableHeader::VAR_NAME);
          break;
      case $header instanceof TemplateVariableHeader:
-         $payload[TemplateVariableHeader::VAR_NAME][$header->getNameWithoutPrefix()] = $header->getValue();
+         $this->processVariableHeader($header, TemplateVariableHeader::VAR_NAME);
          break;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8e6fe and 3817a9b.

📒 Files selected for processing (6)
  • CHANGELOG.md (1 hunks)
  • src/Api/AbstractEmails.php (1 hunks)
  • src/EmailHeader/CustomHeaderInterface.php (1 hunks)
  • src/EmailHeader/CustomVariableHeader.php (2 hunks)
  • src/EmailHeader/Template/TemplateVariableHeader.php (2 hunks)
  • tests/Api/AbstractEmailsTest.php (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🔇 Additional comments (6)
src/EmailHeader/CustomHeaderInterface.php (1)

7-10: LGTM! Well-designed interface.

The interface follows the Interface Segregation Principle with a single, focused method.

src/EmailHeader/CustomVariableHeader.php (1)

14-14: LGTM! Good implementation of the interface.

The class correctly implements the interface and defines an appropriate prefix constant.

Also applies to: 17-17

src/EmailHeader/Template/TemplateVariableHeader.php (1)

16-16: LGTM! Good implementation of the interface.

The class correctly implements the interface and defines an appropriate prefix constant.

Also applies to: 19-19

tests/Api/AbstractEmailsTest.php (1)

575-585: LGTM! Comprehensive test coverage for header name conflicts.

The added test cases thoroughly verify that the prefix mechanism prevents conflicts with reserved MIME header names.

Also applies to: 627-637

src/Api/AbstractEmails.php (2)

61-61: LGTM! Correctly implements prefix stripping for custom variables.

The change appropriately uses getNameWithoutPrefix() to ensure the payload contains the original header name without the prefix, maintaining compatibility while avoiding conflicts with reserved names.


61-64: Verify the CustomHeaderInterface implementation.

Let's ensure the header classes properly implement the new interface and prefix mechanism.

✅ Verification successful

Implementation verified and correct

The CustomHeaderInterface is properly implemented by both header classes with consistent prefix handling and method implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of CustomHeaderInterface and its usage

# Check for the interface definition
echo "Checking for CustomHeaderInterface definition..."
rg -l "interface CustomHeaderInterface"

# Check for implementation in both header classes
echo "Checking implementation in header classes..."
rg -l "implements.*CustomHeaderInterface"

# Check for prefix-related methods
echo "Checking prefix-related methods..."
rg "getNameWithoutPrefix|getName" --type php

Length of output: 1818


Script:

#!/bin/bash
# Check for NAME_PREFIX constant definitions in header classes
echo "Checking NAME_PREFIX constants..."
rg "const.*NAME_PREFIX" --type php

Length of output: 531

@gaalferov gaalferov merged commit 730b8f9 into main Jan 22, 2025
13 checks passed
@gaalferov gaalferov deleted the fix/fix-custom-email-headers branch January 22, 2025 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The "date" header must be an instance of "Symfony\...\DateHeader" (got "Mailtrap\...\TemplateVariableHeader").

4 participants