sushidev/fairu-sdk
最新稳定版本:v1.1.0
Composer 安装命令:
composer require sushidev/fairu-sdk
包简介
Laravel SDK for Fairu GraphQL API
README 文档
README
A comprehensive Laravel SDK for the Fairu GraphQL API with dynamic fragments, caching, and full type support.
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
Installation
composer require sushidev/fairu-sdk
The package will auto-register its service provider and facade.
Publish Configuration
php artisan vendor:publish --tag=fairu-config
Configuration
Add the following to your .env file:
FAIRU_URL=https://fairu.app FAIRU_TOKEN=your-api-token
Full Configuration Options
// config/fairu.php return [ 'base_url' => env('FAIRU_URL', 'https://fairu.app'), 'token' => env('FAIRU_TOKEN'), 'timeout' => 30, 'retry' => [ 'times' => 3, 'sleep' => 100, ], 'cache' => [ 'enabled' => true, 'store' => null, // null = default cache store 'prefix' => 'fairu_', 'ttl' => [ 'tenant' => 3600, 'roles' => 3600, 'assets' => 300, 'default' => 600, ], ], ];
Important: UUIDs
All IDs in the Fairu API are UUIDs (Universally Unique Identifiers). This applies to all resources:
- Assets
- Folders
- Galleries
- Copyrights
- Licenses
- Users
- Roles
- Disks
- Tenants
Example:
$assetId = '550e8400-e29b-41d4-a716-446655440000'; $asset = Fairu::assets()->find($assetId);
Basic Usage
Queries
use SushiDev\Fairu\Facades\Fairu; // Health Check $status = Fairu::health()->check(); // Get single asset $asset = Fairu::assets()->find('uuid'); $asset = Fairu::assets()->findByPath('/images/logo.png'); // Get multiple assets $assets = Fairu::assets()->findMany(['uuid-1', 'uuid-2']); // Search assets $results = Fairu::assets()->search('logo', page: 1, perPage: 20); // List assets in folder $assets = Fairu::assets()->all(folderId: 'folder-uuid', page: 1, perPage: 20); // Get folder content (folders + assets) $content = Fairu::folders()->content('folder-uuid'); $content->folders; // Array of Folder objects $content->assets; // Array of Asset objects // Get tenant info $tenant = Fairu::tenant()->get(); // List galleries $galleries = Fairu::galleries()->all(['tenant-uuid'], from: '2024-01-01'); // Other queries $copyrights = Fairu::copyrights()->all(); $licenses = Fairu::licenses()->all(); $workflows = Fairu::workflows()->all(); $users = Fairu::users()->all(); $roles = Fairu::roles()->all(); $disks = Fairu::disks()->all();
Mutations
use SushiDev\Fairu\Facades\Fairu; use SushiDev\Fairu\DTOs\FileDTO; use SushiDev\Fairu\DTOs\FolderDTO; use SushiDev\Fairu\DTOs\GalleryDTO; use SushiDev\Fairu\Enums\UploadType; // Upload a file $uploadLink = Fairu::uploads()->createLink( filename: 'photo.jpg', type: UploadType::STANDARD, folderId: 'folder-uuid', alt: 'Photo description' ); // Use $uploadLink->getUrl() to upload your file via PUT request // Update asset metadata $asset = Fairu::assetMutations()->update( FileDTO::make() ->id('asset-uuid') ->alt('New alt text') ->description('Updated description') ->copyrightIds(['copyright-uuid']) ); // Delete asset Fairu::assetMutations()->delete('asset-uuid'); // Move asset to another folder Fairu::assetMutations()->move('asset-uuid', 'new-folder-uuid'); // Create folder $folder = Fairu::folderMutations()->create( FolderDTO::make() ->name('New Folder') ->parent('parent-uuid') ); // Create gallery $gallery = Fairu::galleryMutations()->create( GalleryDTO::make() ->name('Event 2024') ->folderId('folder-uuid') ->date(now()) ->location('Berlin') );
Fragments
Fragments allow you to customize which fields are returned from the API.
Predefined Fragments
Each resource type has three predefined variants: minimal, default, and full.
use SushiDev\Fairu\Facades\Fairu; // Use predefined fragments $asset = Fairu::assets()->find('uuid', Fairu::fragments()->asset('minimal')); $asset = Fairu::assets()->find('uuid', Fairu::fragments()->asset('full'));
Custom Fragments with FragmentBuilder
use SushiDev\Fairu\Fragments\FragmentBuilder; // Build custom fragment $fragment = FragmentBuilder::for('FairuAsset') ->select(['id', 'name', 'mime', 'url', 'width', 'height', 'blurhash']) ->with('copyrights', fn($f) => $f->select(['id', 'name', 'email'])) ->with('licenses', fn($f) => $f->select(['id', 'name', 'type', 'start', 'end'])) ->build(); $asset = Fairu::assets()->find('uuid', $fragment); // With arguments (e.g., for URL parameters) $fragment = FragmentBuilder::for('FairuAsset') ->select(['id', 'name']) ->withArguments('url', ['width' => 800, 'height' => 600, 'quality' => 80], []) ->build();
Register Custom Fragments
// In a service provider Fairu::fragments()->register('my_asset_card', FragmentBuilder::for('FairuAsset') ->select(['id', 'name', 'url', 'blurhash', 'width', 'height']) ->build() ); // Use it later $asset = Fairu::assets()->find('uuid', Fairu::fragments()->get('my_asset_card'));
Caching
The SDK supports Laravel's cache system for API responses.
// Enable caching for a query (uses config TTL) $tenant = Fairu::tenant()->cached()->get(); // Custom TTL (in seconds) $roles = Fairu::roles()->cached(ttl: 3600)->all(); // Force fresh data (bypass cache) $tenant = Fairu::tenant()->fresh()->get(); // Clear cached data Fairu::tenant()->forget('cache-key');
DTOs (Data Transfer Objects)
All input types have fluent DTOs for type-safe data handling.
use SushiDev\Fairu\DTOs\FileDTO; use SushiDev\Fairu\DTOs\FolderDTO; use SushiDev\Fairu\DTOs\CopyrightDTO; use SushiDev\Fairu\DTOs\LicenseDTO; use SushiDev\Fairu\DTOs\GalleryDTO; use SushiDev\Fairu\DTOs\DiskDTO; use SushiDev\Fairu\DTOs\DiskCredentialsDTO; use SushiDev\Fairu\Enums\DiskType; use SushiDev\Fairu\Enums\LicenseType; // File DTO $file = FileDTO::make() ->id('uuid') ->name('photo.jpg') ->alt('Description') ->caption('Caption text') ->description('Full description') ->focalPoint('50-50') ->copyrightIds(['cr-1', 'cr-2']) ->licenseIds(['lic-1']); // Copyright DTO $copyright = CopyrightDTO::make() ->name('John Doe Photography') ->email('john@example.com') ->phone('+1234567890') ->website('https://johndoe.com') ->active(true); // License DTO $license = LicenseDTO::make() ->name('Annual License') ->type(LicenseType::PERIOD) ->copyrightId('copyright-uuid') ->start(now()) ->end(now()->addYear()) ->days(365); // Disk DTO with credentials $credentials = DiskCredentialsDTO::make() ->key('aws-access-key') ->secret('aws-secret') ->bucket('my-bucket') ->region('eu-west-1'); $disk = DiskDTO::make() ->name('S3 Backup') ->type(DiskType::S3) ->folderId('folder-uuid') ->credentials($credentials) ->active(true);
Response Objects
All API responses are wrapped in typed response objects.
$asset = Fairu::assets()->find('uuid'); // Access properties $asset->id; $asset->name; $asset->mime; $asset->url; $asset->width; $asset->height; $asset->blurhash; // Helper methods $asset->isImage(); // true for image/* mime types $asset->isVideo(); // true for video/* mime types $asset->isPdf(); // true for application/pdf $asset->getAspectRatio(); // width/height ratio // Nested relations $asset->getCopyrights(); // Array of Copyright objects $asset->getLicenses(); // Array of License objects // Array access $asset['name']; $asset['url']; // JSON serialization json_encode($asset);
Paginated Lists
$results = Fairu::assets()->search('logo'); // Access items $results->items(); // Array of Asset objects $results->first(); // First item $results->last(); // Last item $results->isEmpty(); // Check if empty $results->count(); // Items on current page // Pagination info $results->total(); // Total items across all pages $results->currentPage(); // Current page number $results->lastPage(); // Last page number $results->perPage(); // Items per page $results->hasMorePages(); // Has more pages? // Iteration foreach ($results as $asset) { echo $asset->name; } // Collection-like methods $ids = $results->pluck('id'); $filtered = $results->filter(fn($a) => $a->isImage()); $mapped = $results->map(fn($a) => $a->name);
Enums
All GraphQL enums are available as PHP 8.1 backed enums.
use SushiDev\Fairu\Enums\UploadType; use SushiDev\Fairu\Enums\SortingDirection; use SushiDev\Fairu\Enums\LicenseType; use SushiDev\Fairu\Enums\WorkflowStatus; use SushiDev\Fairu\Enums\WorkflowType; use SushiDev\Fairu\Enums\UserStatus; use SushiDev\Fairu\Enums\DiskType; use SushiDev\Fairu\Enums\WebhookType; use SushiDev\Fairu\Enums\CustomDomainStatus; use SushiDev\Fairu\Enums\GallerySortingField; use SushiDev\Fairu\Enums\VideoVersions; use SushiDev\Fairu\Enums\DmcaStatus; use SushiDev\Fairu\Enums\UploadShareLinkExpiration; use SushiDev\Fairu\Enums\PdfSignatureRequestStatus; // Usage $type = UploadType::STANDARD; $direction = SortingDirection::DESC; // From string $status = WorkflowStatus::from('PROCESSING'); $status = WorkflowStatus::tryFrom('INVALID'); // null
Error Handling
use SushiDev\Fairu\Exceptions\FairuException; use SushiDev\Fairu\Exceptions\AuthenticationException; use SushiDev\Fairu\Exceptions\GraphQLException; try { $asset = Fairu::assets()->find('uuid'); } catch (AuthenticationException $e) { // Invalid or missing token (401) } catch (GraphQLException $e) { // GraphQL errors $errors = $e->getGraphQLErrors(); $first = $e->getFirstError(); if ($e->hasValidationErrors()) { $validation = $e->getValidationErrors(); } } catch (FairuException $e) { // General API errors }
Events
The SDK dispatches events for debugging and logging.
use SushiDev\Fairu\Events\QueryExecuted; use SushiDev\Fairu\Events\MutationExecuted; // In EventServiceProvider protected $listen = [ QueryExecuted::class => [ LogQueryListener::class, ], MutationExecuted::class => [ LogMutationListener::class, ], ]; // Listener class LogQueryListener { public function handle(QueryExecuted $event) { Log::debug('Fairu Query', [ 'query' => $event->query, 'variables' => $event->variables, 'response' => $event->response, ]); } }
Multipart Uploads
For large files, use multipart uploads.
// Initialize multipart upload $init = Fairu::uploads()->initMultipart( filename: 'large-video.mp4', folderId: 'folder-uuid', fileSize: 104857600, // 100MB contentType: 'video/mp4' ); $fileId = $init->getId(); $uploadId = $init->getUploadId(); // Get upload URL for each part $parts = []; for ($i = 1; $i <= $totalParts; $i++) { $partInfo = Fairu::uploads()->getMultipartPartUrl($fileId, $uploadId, $i); // Upload part to $partInfo['url'] via PUT // Collect ETag from response $parts[] = [ 'partNumber' => $i, 'etag' => $etag, ]; } // Complete upload $result = Fairu::uploads()->completeMultipart($fileId, $uploadId, $parts); // Or abort if needed Fairu::uploads()->abortMultipart($fileId, $uploadId);
File Proxy
The File Proxy provides image transformation and optimized file delivery.
Configuration
FAIRU_FILE_PROXY_URL=https://files.fairu.app
Basic Usage
use SushiDev\Fairu\Facades\Fairu; // Generate a URL for an asset $url = Fairu::fileProxy()->url('asset-uuid', 'image.jpg')->toUrl(); // From an Asset object $asset = Fairu::assets()->find('asset-uuid'); $url = Fairu::fileProxy()->fromAsset($asset)->toUrl();
Image Transformations
use SushiDev\Fairu\Facades\Fairu; use SushiDev\Fairu\Enums\FileProxyFit; use SushiDev\Fairu\Enums\FileProxyFormat; // Resize image $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->width(800) ->height(600) ->toUrl(); // Set dimensions with aspect ratio $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->dimensions(1200, 800) ->toUrl(); // Change format and quality $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->format(FileProxyFormat::WEBP) ->quality(85) ->toUrl(); // Shorthand format methods $url = Fairu::fileProxy()->url('asset-uuid', 'photo.jpg')->webp()->toUrl(); $url = Fairu::fileProxy()->url('asset-uuid', 'photo.jpg')->jpg()->toUrl(); $url = Fairu::fileProxy()->url('asset-uuid', 'photo.jpg')->png()->toUrl(); // Fit modes $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->dimensions(400, 400) ->cover() // Scale and crop to fill (default) ->toUrl(); $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->dimensions(400, 400) ->contain() // Maintain aspect ratio within dimensions ->toUrl(); // Focal point for smart cropping $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->dimensions(400, 400) ->focal(50, 30) // x=50%, y=30% ->toUrl(); // With zoom level $url = Fairu::fileProxy() ->url('asset-uuid', 'photo.jpg') ->focal(50, 50, 2.0) // x, y, zoom ->toUrl();
Video Features
use SushiDev\Fairu\Enums\VideoVersions; // Extract video frame at timestamp $url = Fairu::fileProxy() ->url('asset-uuid', 'video.mp4') ->timestamp('00:00:05.000') ->toUrl(); // Video quality version $url = Fairu::fileProxy() ->url('asset-uuid', 'video.mp4') ->videoVersion(VideoVersions::HIGH) ->toUrl(); // HLS streaming URL $hlsUrl = Fairu::fileProxy()->hlsUrl('tenant-uuid', 'asset-uuid');
Other Options
// Raw file download (no processing) $url = Fairu::fileProxy() ->url('asset-uuid', 'document.eps') ->raw() ->toUrl(); // Process SVG to raster $url = Fairu::fileProxy() ->url('asset-uuid', 'logo.svg') ->processSvg() ->width(200) ->toUrl(); // Signed URLs for restricted content $url = Fairu::fileProxy() ->url('asset-uuid', 'file.jpg') ->signature($hmacSignature, $signatureDate) ->toUrl();
Utility Methods
// Check if file exists $exists = Fairu::fileProxy()->exists('asset-uuid'); // Get image dimensions $meta = Fairu::fileProxy()->meta('asset-uuid'); // Returns: ['width' => 1920, 'height' => 1080] // Health check $healthy = Fairu::fileProxy()->health();
Available Parameters
| Parameter | Range | Description |
|---|---|---|
width |
1-6000 | Output width in pixels |
height |
1-6000 | Output height in pixels |
quality |
1-100 | JPEG/WebP quality (default: 95) |
format |
jpg, png, webp | Output format (default: webp) |
fit |
cover, contain | Resize mode (default: cover) |
focal |
x-y-zoom | Smart crop focal point |
Testing
composer test
License
MIT License. See LICENSE for details.
统计信息
- 总下载量: 3
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-30