Weave Code
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

S365 Content Bundle Laravel Package

bash/s365-content-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Install the Bundle

    composer require amitrev/bash-s365-content-bundle
    

    Ensure your composer.json meets PHP 8.2+ and Symfony 7.4 requirements.

  2. Configure Environment Variables Add the required .env variables (see README) and replace placeholders with your S365 API credentials.

  3. Generate Configuration Files Copy the template from vendor/amitrev/bash-s365-content-bundle/recipe/config/packages/s365_content.yaml to config/packages/s365_content.yaml in your project.

  4. Register the Bundle Ensure the bundle is enabled in config/bundles.php:

    return [
        // ...
        Amitrev\S365ContentBundle\S365ContentBundle::class => ['all' => true],
    ];
    
  5. First API Call Use the proxy controller to forward a request:

    use Symfony\Component\HttpFoundation\Request;
    
    $client = new \Symfony\Contracts\HttpClient\HttpClient();
    $response = $client->request('GET', '/api/s365-content/proxy', [
        'query' => [
            'endpoint' => '/api/v1/content',
            'method' => 'GET',
        ],
    ]);
    

Implementation Patterns

Core Workflows

  1. Direct API Integration Use the S365ContentClient service to interact with the API directly:

    $client = $this->container->get('s365_content.client');
    $response = $client->fetchContent($projectCode, $contentId);
    
    • Typed Responses: The bundle returns structured objects (e.g., ContentEntity) instead of raw arrays.
    • Correlation IDs: Automatically injected for traceability:
      $response = $client->fetchContent($projectCode, $contentId, ['correlation_id' => 'abc123']);
      
  2. Proxy Controller Forward requests via the dedicated controller for flexibility:

    # config/routes.yaml
    s365_content_proxy:
        path: /api/s365-content/proxy
        controller: Amitrev\S365ContentBundle\Controller\ProxyController::proxy
        methods: [GET, POST, PUT, DELETE]
    
    • Request Parameters:
      • endpoint: Target S365 API endpoint (e.g., /api/v1/content).
      • method: HTTP method (GET, POST, etc.).
      • data: JSON payload for POST/PUT requests.
  3. Caching Strategy Leverage built-in caching for OAuth tokens and API responses:

    # config/packages/s365_content.yaml
    s365_content:
        cache:
            enabled: true
            ttl_token: 2592000  # 30 days (default)
            ttl_response: 300   # 5 minutes (adjust as needed)
    
  4. Domain-Driven Design (DDD) Integration

    • Domain Layer: Use ContentEntity, ProjectEntity, etc., for business logic.
      $content = new ContentEntity($responseData);
      $content->publish(); // Example domain method
      
    • Infrastructure Layer: Inject S365ContentClient into services for API calls.

Integration Tips

  1. Dependency Injection Bind the client to your services via constructor injection:

    use Amitrev\S365ContentBundle\Client\S365ContentClientInterface;
    
    class MyService {
        public function __construct(
            private S365ContentClientInterface $s365Client
        ) {}
    }
    
  2. Event Listeners Extend functionality with events (e.g., log API calls):

    use Amitrev\S365ContentBundle\Event\S365ContentEvent;
    
    class MyListener {
        public function onContentFetched(S365ContentEvent $event) {
            // Custom logic (e.g., analytics, transformations)
        }
    }
    

    Register in config/services.yaml:

    services:
        App\EventListener\MyListener:
            tags:
                - { name: kernel.event_listener, event: s365_content.fetched, method: onContentFetched }
    
  3. Testing Use the S365ContentClientInterface for mocking in tests:

    $mockClient = $this->createMock(S365ContentClientInterface::class);
    $mockClient->method('fetchContent')->willReturn(new ContentEntity([]));
    
    $service = new MyService($mockClient);
    

Gotchas and Tips

Pitfalls

  1. Authentication Failures

    • Issue: OAuth2 token caching may cause stale tokens if S365_CONTENT_API_DISABLE_CACHE is false.
    • Fix: Manually invalidate the cache or adjust S365_CONTENT_API_TTL_CACHED_TOKEN (e.g., to 3600 for 1 hour).
    • Debug: Check Symfony’s profiler for S365ContentBundle events under the "Events" tab.
  2. Proxy Controller Misuse

    • Issue: Forgetting to include required parameters (endpoint, method) in proxy requests.
    • Fix: Validate input in a custom controller or use a DTO:
      use Symfony\Component\Validator\Constraints as Assert;
      
      class ProxyRequestDto {
          #[Assert\NotBlank]
          public string $endpoint;
      
          #[Assert\NotBlank]
          public string $method;
      }
      
  3. Typed Response Mismatches

    • Issue: API responses may not match expected Entity structures (e.g., S365 schema changes).
    • Fix: Extend entities or use a mapper:
      class CustomContentEntity extends ContentEntity {
          public function __construct(array $data) {
              $data['custom_field'] = $data['raw_data']['custom_field'] ?? null;
              parent::__construct($data);
          }
      }
      
  4. Correlation ID Propagation

    • Issue: Correlation IDs may not propagate across nested API calls.
    • Fix: Manually pass the ID in recursive calls or use middleware:
      $client->fetchContent($projectCode, $contentId, [
          'correlation_id' => $this->correlationIdService->getId()
      ]);
      

Debugging Tips

  1. Enable Verbose Logging Add to config/packages/s365_content.yaml:

    s365_content:
        debug: true
    

    Logs will appear in var/log/dev.log with detailed API request/response payloads.

  2. HTTP Client Debugging Use Symfony’s HTTP client debug factory:

    $client = $this->container->get('http_client');
    $client->withOptions([
        'debug' => function ($message, $level) {
            error_log(sprintf('[S365] %s', $message));
        },
    ]);
    
  3. Token Cache Inspection Check cached tokens via Symfony’s cache pool:

    $cache = $this->container->get('s365_content.cache.token');
    $token = $cache->get('oauth_token');
    

Extension Points

  1. Custom Authentication Override the OAuth2 flow by implementing Amitrev\S365ContentBundle\Client\Auth\AuthenticatorInterface:

    class CustomAuthenticator implements AuthenticatorInterface {
        public function authenticate(): string {
            // Custom logic (e.g., JWT, API key)
            return 'custom_token';
        }
    }
    

    Register in config/services.yaml:

    services:
        App\Auth\CustomAuthenticator:
            tags:
                - { name: s365_content.authenticator }
    
  2. Response Transformers Modify how API responses are converted to entities:

    use Amitrev\S365ContentBundle\Client\ResponseTransformerInterface;
    
    class CustomTransformer implements ResponseTransformerInterface {
        public function transform(array $data, string $endpoint): array {
            return array_merge($data, ['processed' => true]);
        }
    }
    

    Bind in config/services.yaml:

    services:
        App\Client\CustomTransformer:
            tags:
                - { name: s365_content.response_transformer }
    
  3. Event Subscribers Extend the bundle’s event system for pre/post-processing:

    use Amitrev\S365ContentBundle\Event\S365ContentEvents;
    
    class MySubscriber implements EventSubscriberInterface {
        public static function getSubscribedEvents(): array {
            return [
                S365ContentEvents::PRE_FETCH => 'onPreFetch',
                S365ContentEvents::POST_FETCH => 'onPostFetch',
            ];
        }
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle