Install the Bundle Add the package via Composer:
composer require atoolo/citycall-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Atoolo\CityCallBundle\AtooloCityCallBundle::class => ['all' => true],
];
Configure the Bundle
Define your CityCall API credentials in config/packages/atoolo_citycall.yaml:
atoolo_citycall:
api:
endpoint: '%env(CITYCALL_API_ENDPOINT)%'
token: '%env(CITYCALL_API_TOKEN)%'
search:
enabled: true
First Use Case: Querying CityCall Data
Inject the CityCallClient service and fetch data:
use Atoolo\CityCallBundle\Service\CityCallClient;
class MyController extends AbstractController
{
public function __construct(private CityCallClient $cityCallClient) {}
public function search(Request $request)
{
$results = $this->cityCallClient->search('query');
return $this->json($results);
}
}
Verify Integration Check the official documentation for API endpoints and response structures.
Use the CityCallClient service to integrate search functionality into your application:
// Basic search
$results = $cityCallClient->search('school holidays 2024');
// Filtered search (if supported by API)
$filteredResults = $cityCallClient->search('query', [
'type' => 'news',
'language' => 'en',
]);
Leverage the bundle’s dependency on atoolo/search-bundle to index CityCall data:
# config/packages/atoolo_search.yaml
atoolo_search:
indexes:
citycall:
type: citycall
client: '@atoolo_citycall.client'
Trigger indexing via CLI:
php bin/console atoolo:search:index citycall
Subscribe to CityCall events (e.g., document updates) using Symfony’s event system:
// src/EventListener/CityCallUpdateListener.php
use Atoolo\CityCallBundle\Event\CityCallDocumentUpdatedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
class CityCallUpdateListener
{
#[AsEventListener(CityCallDocumentUpdatedEvent::class)]
public function onDocumentUpdated(CityCallDocumentUpdatedEvent $event)
{
// Sync with your database or trigger notifications
}
}
Extend the CityCallClient to add custom logic:
// src/Service/CustomCityCallClient.php
use Atoolo\CityCallBundle\Service\CityCallClient;
class CustomCityCallClient extends CityCallClient
{
public function getAdHocNews()
{
return $this->search('ad hoc news', ['isAdHoc' => true]);
}
}
Register the service in config/services.yaml:
services:
Atoolo\CityCallBundle\Service\CityCallClient: '@custom_citycall.client'
custom_citycall.client:
class: App\Service\CustomCityCallClient
arguments: ['@atoolo_citycall.client']
Use CityCall data to populate form choices:
use Atoolo\CityCallBundle\Service\CityCallClient;
class MyType extends AbstractType
{
public function __construct(private CityCallClient $cityCallClient) {}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$choices = $this->cityCallClient->getCategories();
$builder->add('category', ChoiceType::class, [
'choices' => $choices,
]);
}
}
Pass CityCall data to templates:
{% for result in citycall_results %}
<div class="citycall-result">
<h3>{{ result.title }}</h3>
<p>{{ result.summary }}</p>
</div>
{% endfor %}
In your controller:
return $this->render('template.html.twig', [
'citycall_results' => $cityCallClient->search('query'),
]);
Implement a decorator to handle rate limits:
use Atoolo\CityCallBundle\Service\CityCallClientInterface;
use Psr\Cache\CacheItemPoolInterface;
class RateLimitedCityCallClient implements CityCallClientInterface
{
public function __construct(
private CityCallClientInterface $decorated,
private CacheItemPoolInterface $cache
) {}
public function search(string $query, array $options = [])
{
$cacheKey = 'citycall_search_' . md5($query);
$item = $this->cache->getItem($cacheKey);
if (!$item->isMiss()) {
return $item->get();
}
$result = $this->decorated->search($query, $options);
$item->set($result)->expiresAfter(3600); // Cache for 1 hour
$this->cache->save($item);
return $result;
}
}
atoolo/search-bundle (^1.0). Ensure compatibility:
composer require atoolo/search-bundle:^1.0
atoolo/search-bundle, test CityCall functionality thoroughly.CityCallClient) requires proper aliasing in services.yaml:
services:
atoolo_citycall.client:
alias: custom_citycall.client
CityCallDocumentUpdatedEvent are not automatically dispatched unless triggered by the API. You may need to poll the API or use webhooks if supported.composer validate --strict
Configure Monolog to log API requests/responses:
# config/packages/monolog.yaml
monolog:
handlers:
citycall:
type: stream
path: "%kernel.logs_dir%/citycall.log"
level: debug
channels: ["citycall"]
Add a subscriber to log API calls:
use Atoolo\CityCallBundle\Service\CityCallClient;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Atoolo\CityCallBundle\Event\CityCallApiRequestEvent;
class CityCallLoggerSubscriber implements EventSubscriberInterface
{
public function __construct(private LoggerInterface $logger) {}
public static function getSubscribedEvents()
{
return [
CityCallApiRequestEvent::class => 'logRequest',
];
}
public function logRequest(CityCallApiRequestEvent $event)
{
$this->logger->debug('CityCall API Request', [
'query' => $event->getQuery(),
'options' => $event->getOptions(),
'response' => $event->getResponse(),
]);
}
}
The bundle assumes the API returns data in a specific format. If responses break:
CityCallClient to normalize responses:
public function search(string $query, array $options = []): array
{
$response = $this->httpClient->request('GET', '/search', [
'query' => $query,
'options' => $options,
]);
return $this->normalizeResponse($response);
}
private function normalizeResponse(array $response): array
{
// Handle missing fields, deprecated keys
How can I help you explore Laravel packages today?