Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Msg Repo Laravel Package

mmerlijn/msg-repo

A Laravel package that adds a clean repository layer for messages and related Eloquent models, wrapping common queries behind a simple, testable interface so data access is easier to swap, mock, and maintain in larger PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Where to look first

  1. composer require mmerlijn/msg-repo

  2. Check composer.json / package src/ for the service provider. Laravel auto-discovery should register it; if not, add the provider to bootstrap/providers.php (Laravel 11+) or config/app.php.

  3. Publish the config and inspect it before writing any code:

    php artisan vendor:publish --provider="Mmerlijn\MsgRepo\MsgRepoServiceProvider" --tag=config
    

    The published config/msg-repo.php is the source of truth for storage driver, table/connection names, and any parser settings. Read it alongside the repository contract in src/ — the README is intentionally minimal, so the interface and config are your real documentation.

  4. Identify the contract you should depend on (typically something like MsgRepositoryInterface) and the concrete implementation. Bind the interface if the package doesn't already do it:

    // AppServiceProvider::register()
    $this->app->bind(
        \Mmerlijn\MsgRepo\Contracts\MsgRepositoryInterface::class,
        \Mmerlijn\MsgRepo\Repositories\MsgRepository::class
    );
    

First use case: store and re-read one message

The fastest way to validate the integration is a round-trip in Tinker with a real HL7 or EDIFACT sample:

$repo = app(\Mmerlijn\MsgRepo\Contracts\MsgRepositoryInterface::class);

$msg = $repo->create([
    'type'    => 'HL7v2',
    'payload' => $rawHl7String,
]);

$fresh = $repo->find($msg->id);
dump($fresh->payload === $rawHl7String); // verify no delimiter/newline corruption

If that round-trip is byte-identical, the package is wired correctly. Only then move on to controllers and parsing. With zero stars and no dependents, treat the round-trip test as mandatory due diligence rather than a formality.

Implementation Patterns

Depend on the contract, never the concrete class. Inject the repository interface into controllers, jobs, and services. This is the entire point of the package and also what makes it mockable later.

Thin controller, repository as gateway:

class InboundMessageController extends Controller
{
    public function __construct(private MsgRepositoryInterface $messages) {}

    public function store(StoreMessageRequest $request)
    {
        $record = $this->messages->create([
            'type'    => $request->input('type'),
            'payload' => $request->input('payload'),
        ]);

        ProcessInboundMessage::dispatch($record->id);

        return response()->json(['id' => $record->id], 201);
    }
}

Pass IDs to queues, not models or raw payloads. Re-fetch inside the job via the repository. This keeps serialized jobs small (healthcare messages can be large) and guarantees the job reads the persisted, canonical copy.

Separate raw storage from parsed metadata. Store the original payload untouched and persist derived fields (message type, control ID, patient identifier, timestamp) alongside it. If the package only exposes payload storage, wrap it in your own service that writes metadata to a side table keyed by the repository record ID. Never let parsing overwrite the original — you will need it for reprocessing after parser upgrades.

Idempotency wrapper. Inbound interfaces retry. Decorate the repository:

class IdempotentMsgRepository implements MsgRepositoryInterface
{
    public function __construct(
        private MsgRepositoryInterface $inner,
        private MessageKeyExtractor $extractor,
    ) {}

    public function create(array $attributes)
    {
        $key = $this->extractor->controlId($attributes['payload']);
        return $this->inner->findByControlId($key)
            ?? $this->inner->create($attributes + ['control_id' => $key]);
    }
}

Bind the decorator to the interface in the container so callers are unaware.

Use the repository as a parser boundary. If the package handles EDIFACT/HL7, route all format detection and parsing through one service that consumes the repository record. Controllers and jobs should never touch raw segment delimiters directly.

Testing pattern. Because the repository is a contract, swap it for an in-memory fake in feature tests and use the real one only in integration tests against a test database/connection. Assert on the fake's recorded calls, not on persistence, for controller tests.

Config-driven multi-connection storage. If the config supports a connection or table name, use config() overrides per environment (e.g., a separate msg_repo connection) rather than hardcoding. This is also how you'll isolate high-volume message tables from your application tables.

Gotchas and Tips

Byte fidelity is the top risk. HL7 uses \r segment terminators and EDIFACT uses ' with a UNA header defining delimiters. Any layer that trims, normalizes newlines, or runs mb_convert_encoding will corrupt messages. Verify the round-trip from Getting Started with a message containing escaping (\F\, \S\, \R\ in HL7) and a UNA:+.? ' EDIFACT header. If the package stores via Eloquent TEXT, confirm your connection's charset is utf8mb4 but not doing implicit conversion.

PHI in logs and exceptions. Healthcare payloads in Log::info($message) or an exception trace that dumps attributes is a compliance incident. Add a redaction layer before anything reaches logs, and check whether the package's own exception messages include payload content.

Config caching. php artisan config:cache in deployment will ignore runtime config() mutation. If you switch storage connections per-tenant, use a service that resolves the connection explicitly or clear the cache path; don't rely on mutating config mid-request.

License is NOASSERTION. There is no declared license. Before production use, confirm with the maintainer or your legal team — for a healthcare data path this is a real blocker, not a formality. Pin the exact version in composer.json ("mmerlijn/msg-repo": "0.x.y") since a 2025-10-29 release with no downstream consumers means no ecosystem pressure against breaking changes.

Binding conflicts. If the package's provider already binds the interface, a second bind() in AppServiceProvider silently wins or loses depending on registration order. Run php artisan about and php artisan tinker → app()->getBindings() to confirm which implementation resolves. Use singleton only if the repository is stateless; a stateful repository reused across a request can leak filters between queries.

Migrations. If storage is DB-backed, check whether the package ships migrations or expects you to publish them. Publish and run them before the service provider touches the table, and verify indexes on any column you'll query by (control ID, patient ID, received-at). Message tables grow fast — plan archival from day one, not after the first million rows.

Large payloads. Some inbound messages (batch HL7, large ORUs) exceed default max_allowed_packet/TEXT limits. If the schema uses TEXT, a >64KB message truncates silently on MySQL. Use MEDIUMTEXT/LONGTEXT via a published migration override, and add an assertion on stored length vs. received length.

Date/time quirks. HL7 timestamps (YYYYMMDDHHMMSS[+/-ZZZZ]) and EDIFACT dates are not ISO-8601. Store them as received and normalize only in a separate column; do not let an ORM cast attempt to parse the raw payload.

Extension points. The most reliable customization seams are (in order): the repository contract (decorate it), the published config (storage), and a service provider binding override. Avoid subclassing the concrete repository — you'll inherit its internals and break on upgrade.

Debugging checklist when retrieval is wrong: (1) compare byte length and hex of stored vs. received, (2) log the resolved repository class, (3) confirm the config cache is current, (4) check the connection's charset and strict mode, (5) test with a message containing the format's escape sequences.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin