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

Guzzle Markus Client Laravel Package

devmachine/guzzle-markus-client

Guzzle-powered PHP client for Markus Cinema System (MCS) XML APIs used by Forum Cinemas/Finnkino and others. Normalizes inconsistent XML, renames/regroups fields, and returns cleaner structured data for areas, events (movies) and shows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require devmachine/guzzle-markus-client
    

    Add the package to your composer.json under require.

  2. Initialize Client:

    use Devmachine\Guzzle\Markus\MarkusClient;
    
    $client = MarkusClient::factory('http://forumcinemas.lv/XML');
    
  3. First Use Case: Fetch cinema areas (locations) to understand the structure:

    $areas = $client->areas();
    dd($areas['items']);
    

    This returns an array of cinema locations (e.g., cities or theaters) with id and name.


Implementation Patterns

Core Workflows

  1. Fetching Data Hierarchically:

    • Start with areas() to identify locations, then use their IDs to filter other endpoints.
    • Example: Fetch events for a specific area:
      $events = $client->events(['area' => '1002']); // '1002' is Tallinn's area ID
      
  2. Handling Dates and Shows:

    • Use schedule() to get available dates, then shows() to fetch showtimes for a specific date/event:
      $dates = $client->schedule(['area' => '1002']);
      $shows = $client->shows([
          'area' => '1002',
          'event' => '1234', // Movie ID
          'date' => '2023-10-15'
      ]);
      
  3. Media-Rich Data:

    • Enable optional media fields (videos, galleries, images) for richer responses:
      $event = $client->events([
          'id' => '1234',
          'include_videos' => true,
          'include_gallery' => true,
          'all_images' => true
      ]);
      
  4. Pagination (Implicit):

    • The API returns paginated results via items and total keys. Loop through pages by adjusting query parameters (e.g., offset/limit if supported by the underlying endpoint).

Integration Tips

  1. Caching Responses:

    • Cache frequent or static data (e.g., areas, languages) to reduce API calls:
      $areas = Cache::remember('markus_areas', now()->addHours(1), function () use ($client) {
          return $client->areas();
      });
      
  2. Error Handling:

    • Wrap API calls in try-catch blocks to handle XML parsing errors or HTTP issues:
      try {
          $data = $client->events(['area' => '1002']);
      } catch (\Exception $e) {
          Log::error("Markus API Error: " . $e->getMessage());
          return response()->json(['error' => 'Service unavailable'], 503);
      }
      
  3. Dynamic Endpoint Selection:

    • Store supported Markus API URLs in config and switch dynamically:
      config(['markus.endpoints' => [
          'latvia' => 'http://forumcinemas.lv/XML',
          'estonia' => 'http://forumcinemas.ee/XML',
      ]]);
      
      Then use:
      $client = MarkusClient::factory(config('markus.endpoints.latvia'));
      
  4. Data Transformation:

    • Use Laravel’s collect() to reshape data for your application:
      $shows = collect($client->shows(['area' => '1002']))
          ->map(function ($show) {
              return [
                  'theater' => $show['theater_name'],
                  'time' => Carbon::parse($show['start'])->format('H:i'),
                  'price' => $show['price'] ?? 'N/A'
              ];
          });
      

Gotchas and Tips

Pitfalls

  1. Inconsistent API Responses:

    • Some endpoints (e.g., articles, events) may return incomplete or malformed data for certain cinemas (e.g., edencinemas.com.mt). Validate responses:
      if (empty($result['items'])) {
          throw new \RuntimeException("No data returned for the given filters.");
      }
      
  2. Date Handling:

    • The date parameter in shows() expects YYYY-MM-DD format. Use Carbon for validation:
      $date = Carbon::parse($request->date)->format('Y-m-d');
      
  3. Missing IDs:

    • Some endpoints (e.g., articles) require an event ID to filter by movie. Ensure you fetch this first via events().
  4. Image URLs:

    • Image paths are relative to the base URL. Construct full URLs dynamically:
      $baseUrl = 'http://forumcinemas.lv';
      $imageUrl = $baseUrl . $event['images']['large']['portrait'];
      

Debugging

  1. Raw XML Inspection:

    • Access the raw XML response for debugging:
      $response = $client->getGuzzleClient()->get('http://forumcinemas.lv/XML');
      $xml = $response->getBody();
      file_put_contents('debug.xml', $xml);
      
  2. Logging API Calls:

    • Enable Guzzle middleware to log requests/responses:
      $client = MarkusClient::factory('http://forumcinemas.lv/XML');
      $client->getGuzzleClient()->getEmitter()->attach(
          Subscriber::create()->tap(function ($request, $response) {
              Log::debug('Markus API Request:', [
                  'url' => $request->getUri(),
                  'response' => $response->getBody()
              ]);
          })
      );
      

Extension Points

  1. Custom Endpoints:

    • Extend the client to support non-standard Markus APIs by subclassing MarkusClient:
      class CustomMarkusClient extends MarkusClient {
          public function customEndpoint() {
              return $this->request('GET', '/custom/path');
          }
      }
      
  2. Additional Methods:

    • Add helper methods for common queries (e.g., "upcoming shows for a city"):
      public function upcomingShows($areaId, $days = 7) {
          $today = now()->format('Y-m-d');
          $endDate = now()->addDays($days)->format('Y-m-d');
          return $this->shows([
              'area' => $areaId,
              'date' => $today,
              'days_from_date' => $days
          ]);
      }
      
  3. Rate Limiting:

    • Implement rate limiting using Guzzle’s DelayMiddleware:
      $client = MarkusClient::factory('http://forumcinemas.lv/XML');
      $client->getGuzzleClient()->getEmitter()->attach(
          new \GuzzleHttp\Middleware::delay(100) // 100ms delay between requests
      );
      
  4. Testing:

    • Mock the client in tests using Laravel’s Mockery:
      $mockClient = Mockery::mock(MarkusClient::class);
      $mockClient->shouldReceive('events')->once()->andReturn(['items' => []]);
      $this->app->instance(MarkusClient::class, $mockClient);
      
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity