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

Nmm Portal Bundle Laravel Package

canaltp/nmm-portal-bundle

Laravel bundle for building an NMM portal: provides prebuilt portal features, configuration, and integration helpers to accelerate development of a portal-style web app, including common modules, routing, and service setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle via Composer:

    composer require canaltp/nmm-portal-bundle
    

    Enable it in config/bundles.php (Symfony):

    CanalTP\NmmPortalBundle\NmmPortalBundle::class => ['all' => true],
    
  2. Configuration Publish the default config:

    php bin/console nmm-portal:install
    

    Update config/packages/nmm_portal.yaml with your API credentials (e.g., canal_tp_api_key).

  3. First Use Case Fetch a basic portal resource (e.g., a user profile or transaction):

    use CanalTP\NmmPortalBundle\Service\PortalClient;
    
    class MyController extends AbstractController
    {
        public function __construct(private PortalClient $portalClient) {}
    
        public function showProfile()
        {
            $response = $this->portalClient->get('/users/me');
            return $this->json($response->getData());
        }
    }
    

Implementation Patterns

Common Workflows

  1. API Integration Use the PortalClient service for all API calls. Wrap requests in a service layer:

    // src/Service/UserService.php
    class UserService
    {
        public function __construct(private PortalClient $client) {}
    
        public function fetchUser($id)
        {
            return $this->client->get("/users/{$id}");
        }
    }
    
  2. Webhook Handling Register a controller to handle incoming webhooks (e.g., payment events):

    # config/routes.yaml
    nmm_portal_webhook:
        path: /webhook/nmm-portal
        controller: App\Controller\NmmWebhookController::handle
    
    // src/Controller/NmmWebhookController.php
    class NmmWebhookController extends AbstractController
    {
        public function handle(Request $request, PortalClient $client)
        {
            $payload = json_decode($request->getContent(), true);
            $client->verifyWebhook($payload); // Built-in verification
            // Process logic...
        }
    }
    
  3. Entity Mapping Use Symfony’s Serializer to map API responses to entities:

    // src/Entity/User.php
    #[ORM\Entity]
    class User
    {
        #[ORM\Id, ORM\GeneratedValue]
        private ?int $id = null;
    
        #[ORM\Column]
        private string $canalId;
    }
    
    // src/Service/UserMapper.php
    class UserMapper
    {
        public function map(array $data): User
        {
            $user = new User();
            $user->setCanalId($data['id']);
            return $user;
        }
    }
    
  4. Error Handling Centralize API error responses in a decorator:

    class PortalClientDecorator implements PortalClientInterface
    {
        public function __construct(private PortalClient $client) {}
    
        public function get(string $endpoint)
        {
            try {
                return $this->client->get($endpoint);
            } catch (ApiException $e) {
                // Log, retry, or throw custom exception
                throw new PortalException($e->getMessage());
            }
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Rate Limiting The bundle doesn’t auto-retry on rate limits. Implement exponential backoff in your service layer:

    use Symfony\Component\HttpClient\RetryableHttpClient;
    
    $client = new RetryableHttpClient(
        $httpClient,
        [
            'max_retries' => 3,
            'delay' => 1000,
            'multiplier' => 2,
            'statuses' => [429],
        ]
    );
    
  2. Webhook Verification Always verify webhook payloads using the verifyWebhook() method. Skipping this risks security vulnerabilities:

    $client->verifyWebhook($payload, $request->getSignature());
    
  3. Deprecated Endpoints The bundle may not document deprecated API routes. Check the CanalTP API docs for breaking changes.

  4. Configuration Overrides Avoid hardcoding API keys in services. Use Symfony’s ParameterBag:

    # config/services.yaml
    services:
        CanalTP\NmmPortalBundle\Service\PortalClient:
            arguments:
                $apiKey: '%env(NMM_PORTAL_API_KEY)%'
    

Debugging Tips

  • Enable Debug Mode Set debug: true in nmm_portal.yaml to log raw API responses:
    nmm_portal:
        debug: true
    
  • Mock the Client Use PHPUnit’s createMock() to test services without hitting the API:
    $mockClient = $this->createMock(PortalClient::class);
    $mockClient->method('get')->willReturn(new Response(json_encode(['id' => 123])));
    
  • Check Headers Ensure Accept: application/json and Authorization: Bearer {key} headers are included in requests.

Extension Points

  1. Custom Responses Extend the Response class to add domain-specific methods:

    class CustomResponse extends Response
    {
        public function getUserId(): int
        {
            return $this->getData()['id'];
        }
    }
    

    Override the bundle’s ResponseFactory to return your class.

  2. Middleware Add request/response middleware via Symfony’s kernel.request event:

    // src/EventListener/NmmMiddleware.php
    class NmmMiddleware implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [KernelEvents::REQUEST => 'onKernelRequest'];
        }
    
        public function onKernelRequest(RequestEvent $event)
        {
            $request = $event->getRequest();
            $request->headers->set('X-Custom-Header', 'value');
        }
    }
    
  3. Event Dispatching Trigger events for API responses (e.g., user.fetched):

    use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
    
    class PortalClientDecorator
    {
        public function __construct(
            private PortalClient $client,
            private EventDispatcherInterface $dispatcher
        ) {}
    
        public function get(string $endpoint)
        {
            $response = $this->client->get($endpoint);
            $this->dispatcher->dispatch(new UserFetchedEvent($response));
            return $response;
        }
    }
    
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.
alesima/laravel-azure-service-bus
tomshaw/shopcart
likyly/laravel
darthsoup/shoppingcart
tdt/core
labyrinthe/connect-php
encore2/laravel-admin2
cboxdk/laravel-console-kit
shapecode/doctrine-dbal-datetimeutc
gilads-otiannoh254/inertia-protocol
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel