Installation:
composer require bastsys/cdn-bundle
Add to config/app.php under providers:
Bastsys\CdnBundle\CdnServiceProvider::class,
Publish config (if needed):
php artisan vendor:publish --provider="Bastsys\CdnBundle\CdnServiceProvider"
Configuration:
Edit config/cdn.php to define CDN endpoints (e.g., AWS CloudFront, Akamai, or custom):
'endpoints' => [
'default' => [
'url' => 'https://cdn.example.com',
'bucket' => 'your-bucket-name',
],
],
First Use Case: Upload a file via the facade:
use Bastsys\CdnBundle\Facades\Cdn;
$path = Cdn::upload('path/to/local/file.jpg', 'remote/path/file.jpg');
Outputs the CDN URL (e.g., https://cdn.example.com/remote/path/file.jpg).
File Uploads:
Cdn::upload() for direct uploads with optional metadata:
$path = Cdn::upload('local.jpg', 'remote.jpg', [
'contentType' => 'image/jpeg',
'cacheControl' => 'public, max-age=31536000',
]);
Cdn::getUrl() to fetch the CDN path:
$cdnUrl = Cdn::getUrl('remote.jpg');
Asset Management:
$versionedPath = Cdn::version('remote.jpg', 'v1');
Cdn::delete('remote.jpg');
Integration with Laravel:
cdn disk in filesystem.php:
'disks' => [
'cdn' => [
'driver' => 'cdn',
'endpoint' => 'default',
],
],
Blade::directive('cdn', function ($path) {
return "<?php echo Bastsys\CdnBundle\Facades\Cdn::getUrl($path); ?>";
});
Usage:
<img src="{{ cdn('remote.jpg') }}">
Batch Operations:
$results = Cdn::uploadMultiple([
'local1.jpg' => 'remote1.jpg',
'local2.jpg' => 'remote2.jpg',
]);
Endpoint Configuration:
config/cdn.php has at least one defined endpoint. Throws InvalidArgumentException if not.File Path Handling:
remote/path/ vs. remote/path). The package trims them but may cause silent failures.Str::slug() if needed.Cache Invalidation:
cacheControl in metadata.Local Fallback:
Storage facade:
$localPath = Storage::disk('local')->put('file.jpg', $content);
Cdn::upload($localPath, 'remote.jpg');
Logs:
Enable debug mode in config/cdn.php:
'debug' => env('CDN_DEBUG', false),
Logs upload/deletion attempts to storage/logs/cdn.log.
Testing:
CdnManager in tests:
$this->app->instance(\Bastsys\CdnBundle\Contracts\CdnManager::class, Mockery::mock());
Artisan::call() to test commands:
$this->artisan('cdn:purge')->assertExitCode(0);
Custom Drivers:
Bastsys\CdnBundle\Contracts\CdnDriver for unsupported CDNs (e.g., Backblaze B2):
class BackblazeDriver implements CdnDriver {
public function upload($localPath, $remotePath, array $options) {
// Custom logic
}
}
CdnServiceProvider:
$this->app->bind(CdnDriver::class, function () {
return new BackblazeDriver();
});
Events:
CdnEvents:
event(new CdnUploading($localPath, $remotePath));
EventServiceProvider:
protected $listen = [
CdnUploading::class => [
YourListener::class,
],
];
Middleware:
Route::middleware(['cdn.verify'])->group(function () {
// Routes requiring CDN access
});
CdnMiddleware contract to validate CDN tokens/headers.Parallel Uploads:
parallel helper for batch uploads:
parallel([
fn() => Cdn::upload('file1.jpg', 'remote1.jpg'),
fn() => Cdn::upload('file2.jpg', 'remote2.jpg'),
]);
Lazy Loading:
// In a service class
public function getCdnUrl($path) {
return Cdn::getUrl($path);
}
<img src="{{ $service->getCdnUrl('remote.jpg') }}">
How can I help you explore Laravel packages today?