snowsoft / cdn-laravel-adapter
Laravel Storage adapter for CDN Services Node.js backend
Installs: 3
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/snowsoft/cdn-laravel-adapter
Requires
- php: ^8.0
- illuminate/filesystem: ^9.0|^10.0|^11.0|^12.0
- illuminate/http: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Suggests
- rebing/graphql-laravel: GraphQL ve resim yükleme eklentisi için
README
Laravel Storage adapter for CDN Services Node.js backend. Use CDN Services as a Laravel filesystem disk (Laravel 9, 10, 11, 12). Domain Driven Design (DDD) uyumlu yapı: Domain (value objects, port interfaces), Application (use case services), Infrastructure (HTTP gateway).
- Packagist: packagist.org/packages/snowsoft/cdn-laravel-adapter
- Source: github.com/snowsoft/cdn-laravel-adapter
Özellikler
| Özellik | Açıklama |
|---|---|
| Storage disk | Storage::disk('cdn-services') ile put/get/delete/url, caption, tags, folder, visibility |
| CdnServicesAuth | Kayıt (registration token), giriş, tokenForUser ile JWT |
| Depolama kotası | QuotaExceededException, getQuotaRemaining(), usage() ile quotaBytes/quotaMB |
| CdnServicesPdf | PDF yükleme, session ile süreli erişim, DDD (PdfDocument, PdfSession) |
| CdnServicesApi | Meta, list, usage, import, placeholder, signed URL, processedUrl, Cloudflare cloudflareProcessedUrl |
DDD yapısı
| Katman | Açıklama |
|---|---|
| Domain | Domain\Pdf\PdfDocument, PdfSession (value objects); PdfStorageGatewayInterface (port). |
| Application | Application\Pdf\PdfStorageService – PDF use case'leri (upload, list, session, delete). |
| Infrastructure | Infrastructure\Http\PdfStorageGateway – backend /api/pdf/* HTTP adapter. |
Bağımlılık Domain → Application → Infrastructure yönünde; uygulama PdfStorageGatewayInterface ile tip bağımlılığı kurar, implementasyon ServiceProvider'da bağlanır.
Requirements
- PHP 8.0+
- Laravel 9.x, 10.x, 11.x or 12.x
- CDN Services Node.js backend
Installation
Install via Composer (Packagist):
composer require snowsoft/cdn-laravel-adapter
Service provider and aliases are auto-discovered. Publish config:
php artisan vendor:publish --tag=cdn-services-config
Install from GitHub (development)
Add the VCS repository to composer.json, then require the package:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/snowsoft/cdn-laravel-adapter"
}
]
}
composer require snowsoft/cdn-laravel-adapter
Manual install
- Clone the repo into your project (e.g.
packages/cdn-laravel-adapter). - Add PSR-4 autoload:
"CdnServices\\": "packages/cdn-laravel-adapter/src/". - Register
CdnServices\CdnServicesServiceProviderinconfig/app.phporbootstrap/providers.php. - Run
php artisan vendor:publish --tag=cdn-services-config.
Configuration
Environment (.env)
CDN_SERVICES_BASE_URL=http://localhost:3012 CDN_SERVICES_TOKEN=your-jwt-token-here # Backend'de REGISTRATION_TOKEN zorunluysa; kayıt için (CdnServicesAuth::register) CDN_SERVICES_REGISTRATION_TOKEN= CDN_SERVICES_DISK=local CDN_SERVICES_DEFAULT_DISK=local CDN_SERVICES_TIMEOUT=30
Filesystem (config/filesystems.php)
'disks' => [ // ... 'cdn-services' => [ 'driver' => 'cdn-services', 'base_url' => env('CDN_SERVICES_BASE_URL', 'http://localhost:3012'), 'token' => env('CDN_SERVICES_TOKEN'), 'disk' => env('CDN_SERVICES_DISK', 'local'), ], ],
Usage
Storage facade
use Illuminate\Support\Facades\Storage; // Upload (optional: caption, tags, folder, visibility) Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, [ 'caption' => 'Açıklama', 'tags' => ['ürün', 'kampanya'], 'folder' => 'galeri', 'visibility' => 'public', // public|private|unlisted ]); // Read, exists, delete, url, copy, move $contents = Storage::disk('cdn-services')->get('images/photo.jpg'); $exists = Storage::disk('cdn-services')->exists('images/photo.jpg'); Storage::disk('cdn-services')->delete('images/photo.jpg'); $url = Storage::disk('cdn-services')->url('images/photo.jpg'); Storage::disk('cdn-services')->copy('images/photo.jpg', 'images/photo-copy.jpg'); Storage::disk('cdn-services')->move('images/photo.jpg', 'images/new-photo.jpg');
CdnServicesAuth – kayıt, giriş, token
Backend'de kullanıcı kaydı (registration token zorunlu olabilir), giriş ve CDN işlemleri için JWT almak:
use CdnServices\Facades\CdnServicesAuth; // Kayıt (registration token config'ten veya 2. parametre ile) $result = CdnServicesAuth::register([ 'email' => 'user@example.com', 'password' => 'secret123', 'name' => 'Ad Soyad', ]); // $result['token'] → JWT (CDN_SERVICES_TOKEN olarak kullanılabilir) // $result['user'] → id, email, name, role, createdAt // Giriş $result = CdnServicesAuth::login('user@example.com', 'secret123'); if ($result) { $jwt = $result['token']; } // Sunucu tarafında bir kullanıcı için JWT üret (CDN işlemleri için) $tokenPayload = CdnServicesAuth::tokenForUser($userId, 'user@example.com', 'user'); $jwt = $tokenPayload['token'] ?? null; // Kayıt için token zorunlu mu? if (CdnServicesAuth::requiresRegistrationToken()) { // Config'te CDN_SERVICES_REGISTRATION_TOKEN tanımlı }
CdnServices facade
use CdnServices\Facades\CdnServices; CdnServices::put('images/photo.jpg', $fileContents); $contents = CdnServices::get('images/photo.jpg'); $url = CdnServices::url('images/photo.jpg');
Upload with UploadedFile
use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; public function upload(Request $request) { $request->validate(['image' => 'required|image|max:51200']); // 50MB $path = Storage::disk('cdn-services')->put('images', $request->file('image')); return response()->json([ 'success' => true, 'path' => $path, 'url' => Storage::disk('cdn-services')->url($path), ]); }
CdnServicesApi – meta, list, usage (kota), import, placeholder, signed URL, processed URL
use CdnServices\Facades\CdnServicesApi; $info = CdnServicesApi::getInfo($imageId); $images = CdnServicesApi::listImages(['tag' => 'ürün', 'favorite' => true]); CdnServicesApi::updateMeta($imageId, ['caption' => 'Yeni başlık', 'visibility' => 'private']); CdnServicesApi::replace($imageId, $request->file('image')); $usage = CdnServicesApi::usage(); // fileCount, totalSize, totalSizeMB, viewCountTotal, quotaBytes?, quotaMB? $quotaRemaining = CdnServicesApi::getQuotaRemaining(); // null if no quota $file = CdnServicesApi::importFromUrl('https://example.com/photo.jpg'); $file = CdnServicesApi::createPlaceholder(['width' => 800, 'height' => 600, 'text' => 'Placeholder']); $result = CdnServicesApi::bulkDelete(['id1', 'id2']); $signed = CdnServicesApi::getSignedUrl($imageId, 3600); $url = CdnServicesApi::processedUrl($imageId, '800x600', 'webp', [ 'quality' => 80, 'fit' => 'cover', 'filter' => 'sepia', 'crop' => 'smart', 'watermark' => true, ]);
Different backend disks (S3, Azure, etc.)
Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, ['disk' => 's3']); Storage::disk('cdn-services')->put('images/photo.jpg', $fileContents, ['disk' => 'azure']);
Processed image URLs
$originalUrl = Storage::disk('cdn-services')->url($imageId); $thumb = CdnServicesApi::processedUrl($imageId, 'thumbnail', 'jpeg'); $custom = CdnServicesApi::processedUrl($imageId, '800x600', 'webp', ['quality' => 75, 'watermark' => true]);
Cloudflare Image Resizing
Backend’de Cloudflare Image Resizing açıksa, edge’de resize/format/quality için URL alınır:
$url = CdnServicesApi::cloudflareProcessedUrl($imageId, '800x600', 'webp', [ 'quality' => 80, 'fit' => 'cover', 'crop' => 'smart', ]); // Backend GET /api/image/{id}/cloudflare-url ile aynı parametreler
Detay: CDN Services docs/CLOUDFLARE_IMAGE_RESIZING.md.
CdnServicesPdf – PDF depolama (blockchain, süreli session)
Backend'de PDF_STORAGE_ENABLED=true ise kullanılır; resim alanından bağımsızdır.
use CdnServices\Facades\CdnServicesPdf; use CdnServices\Domain\Pdf\PdfDocument; use CdnServices\Domain\Pdf\PdfSession; if (!CdnServicesPdf::isEnabled()) { return; // PDF storage kapalı } // Yükle (value object döner) $doc = CdnServicesPdf::upload($request->file('pdf')); if ($doc instanceof PdfDocument) { $id = $doc->id; } // Listele $documents = CdnServicesPdf::list(); // list<PdfDocument> // Süreli erişim session'ı al $session = CdnServicesPdf::createSession($doc->id); if ($session instanceof PdfSession) { $url = CdnServicesPdf::sessionUrl($session); // GET ile PDF açılır // veya: $session->url(config('cdn-services.base_url')); } // Sil CdnServicesPdf::delete($doc->id);
Constructor injection (DDD): Uygulama sınıflarında port kullanmak için:
use CdnServices\Domain\Pdf\PdfStorageGatewayInterface; class MyController extends Controller { public function __construct( private PdfStorageGatewayInterface $pdfStorage ) {} }
Customization
Custom base URL: set base_url in config/filesystems.php for the cdn-services disk.
Dynamic token: in your service provider, when extending the disk, get config and call $adapter->setToken(auth()->user()->cdn_token) (or your logic) before returning the adapter.
Storage quota and exceptions
When the backend has USER_STORAGE_QUOTA_BYTES set, uploads (Storage put, API replace, importFromUrl, createPlaceholder) may return 413. The adapter throws CdnServices\Exceptions\QuotaExceededException so you can catch and show a friendly message:
use CdnServices\Exceptions\QuotaExceededException; try { Storage::disk('cdn-services')->put('images/photo.jpg', $contents); } catch (QuotaExceededException $e) { return back()->with('error', 'Depolama limitiniz doldu.'); }
CdnServicesApi::usage() includes quotaBytes and quotaMB when a quota is set; use getQuotaRemaining() to show remaining space.
Troubleshooting
| Problem | Check |
|---|---|
| Connection refused | Backend running: curl http://localhost:3012/health |
| Unauthorized | Valid JWT in CDN_SERVICES_TOKEN; create token via backend /api/auth/token |
| File not found | Use image ID (not path) when calling URL/meta APIs |
| QuotaExceededException | Backend USER_STORAGE_QUOTA_BYTES limit reached; free space or increase quota |
API quick reference
Storage put() options: disk, caption, tags, folder, visibility
CdnServicesAuth: register, login, tokenForUser, getRegistrationToken, requiresRegistrationToken
CdnServicesPdf (DDD): upload(UploadedFile), list(), createSession(documentId), sessionUrl(PdfSession), delete(documentId), isEnabled()
CdnServicesApi: getInfo, listImages, updateMeta, replace, usage, getQuotaBytes, getQuotaRemaining, importFromUrl, createPlaceholder, bulkDelete, getSignedUrl, processedUrl, cloudflareProcessedUrl
Disk methods: exists, get, put, delete, copy, move, size, lastModified, mimeType, url, temporaryUrl, readStream, writeStream, files
License
MIT