Installation:
composer require cedricziel/canva-bundle
For non-Flex projects, also enable the bundle in config/bundles.php:
CedricZiel\CanvaBundle\CanvaBundle::class => ['all' => true],
Configuration:
Add your Canva API credentials to .env:
CANVA_CLIENT_ID=your_client_id
CANVA_CLIENT_SECRET=your_client_secret
CANVA_REDIRECT_URI=http://your-app.dev/login/canva/callback
First Use Case: Trigger the OAuth flow in a controller:
use CedricZiel\CanvaBundle\Controller\CanvaAuthController;
// Redirect to Canva for authentication
return $this->redirect($this->generateUrl('canva_auth_login'));
// Handle callback (auto-configured via routing)
config/packages/canva.yaml (default config)src/Controller/CanvaAuthController.php (auth flow)src/Service/CanvaService.php (core API interactions)// In your controller
use CedricZiel\CanvaBundle\Service\CanvaService;
class MyController extends AbstractController {
public function __construct(private CanvaService $canva) {}
public function connectCanva() {
// Redirect to Canva OAuth
return $this->redirect($this->canva->getAuthUrl());
// After callback, the bundle auto-exchanges code for token
}
}
// Fetch user's Canva assets
$userAssets = $this->canva->get('/me/designs', [
'fields' => 'items.id,items.url',
'limit' => 10
]);
// Upload a design
$response = $this->canva->post('/designs', [
'data' => [
'name' => 'My Design',
'background_color' => '#FFFFFF',
],
'upload_preset' => 'your_preset_id'
]);
Listen for auth events to persist tokens:
// config/services.yaml
services:
App\EventListener\CanvaAuthListener:
tags:
- { name: kernel.event_listener, event: canva.auth.success, method: onAuthSuccess }
CanvaService to refresh tokens automatically:
$this->canva->refreshToken(); // If expired
$this->canva->setWebhook('https://your-app.dev/canva/webhook', 'design.created');
batch() method for bulk requests:
$this->canva->batch([
['method' => 'GET', 'endpoint' => '/me/designs'],
['method' => 'POST', 'endpoint' => '/designs', 'data' => [...]]
]);
Token Expiry Handling:
CANVA_AUTO_REFRESH=true (default: false).refreshToken() before critical operations.Redirect URI Mismatch:
.env and your Canva Developer App settings.CANVA_REDIRECT_URI in .env and verify it matches the callback route in routing.yaml.Rate Limiting:
$this->canva->get('/me/designs', [], 3600); // Cache for 1 hour
Webhook Verification:
CanvaWebhookEvent but requires manual validation:
public function onWebhook(CanvaWebhookEvent $event) {
$signature = $event->getSignature();
$payload = $event->getPayload();
// Validate $signature === hash_hmac('sha256', $payload, $event->getSecret())
}
Enable Logging:
# config/packages/canva.yaml
canva:
debug: true
Logs will appear in var/log/dev.log.
HTTP Client Debug:
Use Symfony’s HttpClient debug mode:
$this->canva->getClient()->getConfig()->setDebug(true);
Custom Responses: Override the default response handler:
$this->canva->setResponseTransformer(function ($response) {
return json_decode($response->getContent(), true);
});
Middleware: Add custom middleware to the HTTP client:
$this->canva->getClient()->setDefaultOptions([
'auth_bearer' => 'custom_token',
'headers' => ['X-Custom-Header' => 'value']
]);
Event Dispatching:
Extend the bundle’s events (e.g., canva.request, canva.response) in your EventSubscriber:
public static function getSubscribedEvents() {
return [
CanvaEvents::REQUEST => 'onCanvaRequest',
CanvaEvents::RESPONSE => 'onCanvaResponse',
];
}
CANVA_API_URL for staging/prod).CanvaService in tests:
$this->canva = $this->createMock(CanvaService::class);
$this->canva->method('get')->willReturn(['data' => 'mocked']);
query() method:
$this->canva->query('
query {
me { designs(first: 10) { edges { node { id } } } }
}
');
How can I help you explore Laravel packages today?