Installation:
composer require connectholland/tulip-api-bundle
Ensure your project uses Symfony 3.3, 3.4, or 4.x.
Enable the Bundle:
Add to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
ConnectHolland\TulipAPIBundle\TulipAPIBundle::class => ['all' => true],
Configure API Credentials:
Add to .env (recommended) or config/packages/tulip_api.yaml:
tulip_api:
url: "%env(TULIP_API_URL)%"
client_id: "%env(TULIP_API_CLIENT_ID)%"
shared_secret: "%env(TULIP_API_SHARED_SECRET)%"
First Use Case:
Sync a Doctrine entity (e.g., User) to Tulip’s contact service:
use ConnectHolland\TulipAPIBundle\Manager\TulipManager;
class UserSyncCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$tulipManager = $this->getContainer()->get('tulip.manager');
$user = $this->getDoctrine()->getRepository(User::class)->find(1);
$tulipManager->create('contact', $user);
}
}
CRUD Operations:
Use the TulipManager service to interact with Tulip’s API:
$manager = $this->container->get('tulip.manager');
// Create
$tulipManager->create('contact', $userEntity);
// Read
$contact = $tulipManager->find('contact', $tulipId);
// Update
$tulipManager->update('contact', $tulipId, $updatedUser);
// Delete
$tulipManager->delete('contact', $tulipId);
Entity Mapping:
User → user service).config/packages/tulip_api.yaml:
tulip_api:
objects:
- { name: App\Entity\User, service: custom_contact }
Event-Driven Sync:
Listen to Doctrine lifecycle events (e.g., postPersist, postUpdate) to auto-sync:
// src/EventListener/TulipSyncListener.php
class TulipSyncListener
{
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$this->tulipManager->create(get_class($entity), $entity);
}
}
Bulk Operations:
Use batchCreate() for efficiency:
$users = $this->getDoctrine()->getRepository(User::class)->findAll();
$tulipManager->batchCreate('contact', $users);
try {
$tulipManager->create('contact', $user);
} catch (\Exception $e) {
$this->logger->error('Tulip sync failed', ['error' => $e->getMessage()]);
}
find() results) to reduce calls:
# config/packages/cache.yaml
services:
tulip.manager:
arguments:
$cache: '@cache.app'
Deprecated Bundle:
Entity Serialization:
getX()/setX() are synced.ExclusionPolicy:
use JMS\Serializer\Annotation as Serializer;
class User
{
#[Serializer\ExclusionPolicy('all')]
private $password;
}
Rate Limiting:
$attempts = 0;
while ($attempts < 3) {
try {
$tulipManager->create('contact', $user);
break;
} catch (RateLimitException $e) {
sleep(2 ** $attempts);
$attempts++;
}
}
Service Name Conflicts:
User and Customer → contact), explicitly define unique service names in config.Enable API Debugging:
Set debug: true in config to log raw API requests/responses:
tulip_api:
debug: true
Check logs in var/log/dev.log.
Common Errors:
client_id/shared_secret in .env.Custom Serializers: Override the default serializer for complex entities:
# config/packages/tulip_api.yaml
tulip_api:
serializers:
App\Entity\Order: App\Serializer\OrderTulipSerializer
Pre/Post Sync Hooks:
Extend TulipManager to add logic before/after sync:
class CustomTulipManager extends TulipManager
{
protected function preCreate($service, $entity)
{
// Add logic (e.g., sanitize data)
}
}
Register as a service:
services:
tulip.manager:
class: App\Service\CustomTulipManager
Webhook Listeners: Use Tulip’s webhooks to trigger Symfony events:
// src/EventListener/TulipWebhookListener.php
class TulipWebhookListener
{
public function onWebhook(Request $request)
{
$data = json_decode($request->getContent(), true);
// Dispatch event or update local DB
}
}
Route webhooks to a controller:
# config/routes.yaml
tulip_webhook:
path: /tulip/webhook
controller: App\Controller\TulipWebhookController::handle
How can I help you explore Laravel packages today?