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

v0.03 2026-02-13 13:51 UTC

This package is auto-updated.

Last update: 2026-02-13 13:55:24 UTC


README

Latest Version on Packagist Total Downloads PHP from Packagist

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).

Ö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

  1. Clone the repo into your project (e.g. packages/cdn-laravel-adapter).
  2. Add PSR-4 autoload: "CdnServices\\": "packages/cdn-laravel-adapter/src/".
  3. Register CdnServices\CdnServicesServiceProvider in config/app.php or bootstrap/providers.php.
  4. 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