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

Packagist Bundle Laravel Package

baconmanager/packagist-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require baconmanager/packagist-bundle
    
  2. Register Bundle: Add to AppKernel.php:
    new Bacon\Bundle\PackagistBundle\BaconPackagistBundle(),
    
  3. Configure: Add to config/packages/bacon_packagist.yaml (Symfony 4+) or app/config/config.yml (Symfony 2/3):
    bacon_packagist:
        api:
            base_url: https://packagist.org
    

First Use Case

Fetch search results for a package:

// src/Controller/PackageController.php
use Symfony\Component\HttpFoundation\Response;

class PackageController extends AbstractController
{
    public function search(PackageApi $api): Response
    {
        $response = $api
            ->api('search.json', 'GET')
            ->setParameters(['q' => 'symfony'])
            ->getResponse();

        return $this->json($response);
    }
}

Service Autowiring: Use PackageApi (Symfony 4+) or inject via get('bacon_packagist.api') (Symfony 2/3).


Implementation Patterns

Common Workflows

  1. Search Packages:

    $api->api('search.json', 'GET')
        ->setParameters(['q' => 'laravel', 'type' => 'package'])
        ->getResponse();
    
    • Supports q (query), type (package/author), and pagination (page).
  2. Fetch Package Details:

    $api->api('packages/laravel/framework.json', 'GET')
        ->getResponse();
    
  3. Download Package Metadata:

    $api->api('p/laravel/framework.json', 'GET')
        ->getResponse();
    
  4. Handle Errors Gracefully:

    try {
        $response = $api->api('invalid-endpoint.json')->getResponse();
    } catch (\RuntimeException $e) {
        // Log or handle API errors
    }
    

Integration Tips

  • Caching Responses: Use Symfony’s cache system to store API responses:

    # config/packages/cache.yaml
    framework:
        cache:
            app: cache.adapter.redis
    

    Then wrap API calls in a cache layer (e.g., CacheInterface).

  • Rate Limiting: Packagist’s API has rate limits. Implement retries with exponential backoff:

    use GuzzleHttp\Exception\RequestException;
    
    try {
        $response = $api->api('search.json')->getResponse();
    } catch (RequestException $e) {
        if ($e->hasResponse() && $e->getResponse()->getStatusCode() === 429) {
            sleep(2); // Retry after delay
            return $this->search($api); // Recursive retry
        }
        throw $e;
    }
    
  • Dependency Injection: Prefer autowiring (Symfony 4+) for cleaner code:

    use Bacon\Bundle\PackagistBundle\Service\PackagistApi;
    
    public function __construct(private PackagistApi $api) {}
    

Gotchas and Tips

Pitfalls

  1. Deprecated Symfony 2/3:

    • The bundle assumes Symfony 2/3 conventions (e.g., AppKernel.php, config.yml). For Symfony 4+, use config/packages/ and autowiring.
    • Fix: Override the service definition in config/services.yaml if needed:
      services:
          Bacon\Bundle\PackagistBundle\Service\PackagistApi:
              arguments:
                  $baseUrl: '%env(PACKAGIST_API_URL)%'
      
  2. Guzzle Version Mismatch:

    • The bundle requires Guzzle 6.x. If your project uses Guzzle 7+, conflicts may arise.
    • Fix: Pin Guzzle 6.x in composer.json:
      "require": {
          "guzzlehttp/guzzle": "6.3.3"
      }
      
  3. No Built-in Pagination Handling:

    • The search.json endpoint supports pagination (page parameter), but the bundle doesn’t abstract this.
    • Tip: Create a helper service:
      // src/Service/PackagistSearchService.php
      class PackagistSearchService
      {
          public function search(string $query, int $page = 1): array
          {
              $api = $this->container->get('bacon_packagist.api');
              $response = $api->api('search.json')
                  ->setParameters(['q' => $query, 'page' => $page])
                  ->getResponse();
      
              return json_decode($response, true);
          }
      }
      
  4. No Type Safety:

    • Responses are raw strings or JSON arrays. Validate data manually:
      $response = $api->api('packages/laravel/framework.json')->getResponse();
      $data = json_decode($response, true);
      
      if (!isset($data['package']['name'])) {
          throw new \RuntimeException('Invalid package data');
      }
      

Debugging

  • Enable Guzzle Debugging: Add to config/packages/bacon_packagist.yaml:

    bacon_packagist:
        api:
            debug: true
    

    This logs requests/responses to var/log/dev.log.

  • Check API Status: Packagist’s API may be down. Test with:

    $response = $api->api('', 'GET')->getResponse(); // Empty endpoint
    

Extension Points

  1. Custom Endpoints: Extend the PackagistApi service to support non-Packagist APIs:

    // src/Service/CustomPackagistApi.php
    class CustomPackagistApi extends PackagistApi
    {
        public function customEndpoint(string $endpoint, string $method = 'GET')
        {
            return $this->client->request($method, $this->baseUrl . '/custom/' . $endpoint);
        }
    }
    

    Register as a replacement service in config/services.yaml.

  2. Add Headers: Override the getClient() method to include headers (e.g., API keys):

    // src/Service/PackagistApi.php (override)
    protected function getClient()
    {
        return new Client([
            'headers' => [
                'User-Agent' => 'MyApp/1.0',
                'Authorization' => 'Bearer ' . $this->apiKey,
            ],
        ]);
    }
    
  3. Mocking for Tests: Use Symfony’s HttpClient or Guzzle’s mocking:

    // tests/Service/PackagistApiTest.php
    use GuzzleHttp\Handler\MockHandler;
    use GuzzleHttp\HandlerStack;
    use GuzzleHttp\Psr7\Response;
    
    $mock = new MockHandler([
        new Response(200, [], '{"total": 1}'),
    ]);
    $handler = HandlerStack::create($mock);
    
    $client = new Client(['handler' => $handler]);
    $api = new PackagistApi($client, 'https://packagist.org');
    
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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge