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

Opds Parser Bundle Laravel Package

bookeenweb/opds-parser-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require bookeenweb/opds-parser-bundle
    

    Ensure your project uses Symfony 2.3–3.4 (last release was 2018).

  2. Enable Bundle: Register in config/bundles.php (Symfony 4+) or app/AppKernel.php (Symfony 2/3):

    return [
        // ...
        bookeen\OpdsParserBundle\OpdsParserBundle::class => ['all' => true],
    ];
    
  3. First Use Case: Parse an OPDS feed (e.g., from a library API) into a structured array:

    use bookeen\OpdsParserBundle\Parser\OpdsParser;
    
    $parser = new OpdsParser();
    $opdsXml = file_get_contents('https://example.com/opds/feed');
    $feedData = $parser->parse($opdsXml);
    

    Key Output: Returns an associative array with parsed entries, navigation links, and metadata (e.g., title, author, links, id).


Implementation Patterns

Core Workflows

  1. Parsing Feeds:

    • Use OpdsParser to convert raw OPDS XML into PHP arrays.
    • Example: Extract book entries from a catalog:
      $entries = $feedData['entries'] ?? [];
      foreach ($entries as $entry) {
          echo $entry['title'] . " by " . $entry['author'][0] . "\n";
      }
      
  2. Handling Navigation:

    • OPDS feeds often link to sub-feeds (e.g., collections → items). Traverse recursively:
      function fetchAllBooks($url, OpdsParser $parser) {
          $data = $parser->parse(file_get_contents($url));
          $books = $data['entries'] ?? [];
          foreach ($data['links'] ?? [] as $link) {
              if ($link['rel'] === 'http://opds-spec.org/acquisition/collection') {
                  $books = array_merge($books, fetchAllBooks($link['href'], $parser));
              }
          }
          return $books;
      }
      
  3. Integration with Symfony:

    • Services: Register the parser as a service in config/services.yaml:
      services:
          bookeen.opds_parser:
              class: bookeen\OpdsParserBundle\Parser\OpdsParser
      
    • Controllers: Inject and reuse:
      use bookeen\OpdsParserBundle\Parser\OpdsParser;
      
      class BookController extends AbstractController {
          public function index(OpdsParser $parser) {
              $feed = $parser->parse(file_get_contents('https://library.opds'));
              return $this->render('books/index.html.twig', ['books' => $feed['entries']]);
          }
      }
      
  4. Caching:

    • Cache parsed feeds to avoid repeated HTTP/XML processing:
      $cacheKey = md5($url);
      $feedData = $cache->get($cacheKey, function() use ($parser, $url) {
          return $parser->parse(file_get_contents($url));
      });
      

Gotchas and Tips

Pitfalls

  1. Deprecated Symfony Version:

    • Last release predates Symfony Flex and modern dependency management. Manually handle autoloading if issues arise.
  2. XML Namespaces:

    • OPDS feeds may use custom namespaces (e.g., xmlns:dcterms). The parser may not handle all edge cases. Validate XML structure first:
      $dom = new DOMDocument();
      if (!$dom->loadXML($opdsXml)) {
          throw new \RuntimeException("Invalid OPDS XML");
      }
      
  3. Missing Error Handling:

    • The parser lacks built-in validation for malformed OPDS. Wrap calls in try-catch:
      try {
          $data = $parser->parse($xml);
      } catch (\Exception $e) {
          // Log or retry with fallback
      }
      
  4. Date Handling:

    • Dates in OPDS (e.g., published) may return as strings. Convert to DateTime:
      $entry['published'] = new \DateTime($entry['published']);
      

Tips

  1. Extend the Parser:

    • Override OpdsParser to add custom logic (e.g., normalize author names):
      class CustomOpdsParser extends OpdsParser {
          protected function parseAuthor($node) {
              $authors = parent::parseAuthor($node);
              return array_map('trim', $authors);
          }
      }
      
  2. Debugging:

    • Dump raw XML to verify structure:
      file_put_contents('debug.opds', $opdsXml);
      
    • Use SimpleXMLElement to inspect nodes:
      $xml = simplexml_load_string($opdsXml);
      print_r($xml->xpath('//entry'));
      
  3. Performance:

    • Stream large feeds with SimpleXMLIterator instead of loading full DOM:
      $iterator = new SimpleXMLIterator($opdsXml);
      foreach ($iterator as $entry) {
          // Process incrementally
      }
      
  4. Testing:

    • Mock HTTP responses and XML for unit tests:
      $this->mockHttpClient()
           ->with('https://library.opds')
           ->respondWith(file_get_contents('tests/fixtures/feed.opds'));
      
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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle