composer require baconmanager/packagist-bundle
AppKernel.php:
new Bacon\Bundle\PackagistBundle\BaconPackagistBundle(),
config/packages/bacon_packagist.yaml (Symfony 4+) or app/config/config.yml (Symfony 2/3):
bacon_packagist:
api:
base_url: https://packagist.org
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).
Search Packages:
$api->api('search.json', 'GET')
->setParameters(['q' => 'laravel', 'type' => 'package'])
->getResponse();
q (query), type (package/author), and pagination (page).Fetch Package Details:
$api->api('packages/laravel/framework.json', 'GET')
->getResponse();
Download Package Metadata:
$api->api('p/laravel/framework.json', 'GET')
->getResponse();
Handle Errors Gracefully:
try {
$response = $api->api('invalid-endpoint.json')->getResponse();
} catch (\RuntimeException $e) {
// Log or handle API errors
}
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) {}
Deprecated Symfony 2/3:
AppKernel.php, config.yml). For Symfony 4+, use config/packages/ and autowiring.config/services.yaml if needed:
services:
Bacon\Bundle\PackagistBundle\Service\PackagistApi:
arguments:
$baseUrl: '%env(PACKAGIST_API_URL)%'
Guzzle Version Mismatch:
composer.json:
"require": {
"guzzlehttp/guzzle": "6.3.3"
}
No Built-in Pagination Handling:
search.json endpoint supports pagination (page parameter), but the bundle doesn’t abstract this.// 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);
}
}
No Type Safety:
$response = $api->api('packages/laravel/framework.json')->getResponse();
$data = json_decode($response, true);
if (!isset($data['package']['name'])) {
throw new \RuntimeException('Invalid package data');
}
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
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.
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,
],
]);
}
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');
How can I help you explore Laravel packages today?