# Supabase Laravel Package This package provides a comprehensive Laravel integration for Supabase, the open-source Firebase alternative. It enables Laravel developers to seamlessly interact with Supabase's backend services including authentication, PostgreSQL database operations, file storage, and real-time subscriptions through WebSocket connections. The package wraps Supabase's REST API with Laravel-friendly interfaces, providing both facade-based and service-based access patterns. The package is designed for Laravel 11+ applications running PHP 8.0 or higher. It uses GuzzleHTTP for API communication and includes automatic retry logic with exponential backoff for improved reliability. All services are configurable through Laravel's standard configuration system, and the package supports both public and authenticated operations with built-in error handling and logging. ## Database Service - Select Records Query data from Supabase tables with filtering, ordering, and pagination support using PostgREST syntax. ```php use Saeedvir\Supabase\Facades\Supabase; // Simple select all records $users = Supabase::db()->select('users', '*'); // Select with filters $activeUsers = Supabase::db()->select( 'users', 'id,name,email,created_at', ['active' => true, 'role' => 'admin'], ['limit' => 10, 'order' => 'created_at.desc'] ); // Using operators for complex queries $posts = Supabase::db()->select( 'posts', 'id,title,content,author_id', ['views' => 100], [ 'operators' => ['views' => 'gte'], 'limit' => 50, 'offset' => 0, 'order' => 'views.desc' ] ); // Array filters for IN queries $specificUsers = Supabase::db()->select( 'users', '*', ['id' => [1, 2, 3, 5, 8]] ); // Error handling if (isset($users['error'])) { echo "Error: " . $users['message']; } else { foreach ($users as $user) { echo $user['name'] . "\n"; } } ``` ## Database Service - Insert Records Create new records in Supabase tables with optional upsert functionality. ```php use Saeedvir\Supabase\Facades\Supabase; // Insert single record $newUser = Supabase::db()->insert('users', [ 'name' => 'John Doe', 'email' => 'john@example.com', 'active' => true, 'role' => 'user', 'created_at' => date('c') ]); // Insert with upsert (update if exists) $product = Supabase::db()->insert('products', [ 'id' => 123, 'name' => 'Laptop', 'price' => 999.99, 'stock' => 50 ], true); // Insert multiple records $bulkInsert = Supabase::db()->insert('posts', [ [ 'title' => 'First Post', 'content' => 'Content here', 'author_id' => 1, 'published' => true ], [ 'title' => 'Second Post', 'content' => 'More content', 'author_id' => 1, 'published' => false ] ]); // Check for errors if (isset($newUser['error'])) { return response()->json(['error' => $newUser['message']], 500); } return response()->json($newUser, 201); ``` ## Database Service - Update Records Modify existing records with flexible filtering options. ```php use Saeedvir\Supabase\Facades\Supabase; // Update by ID $result = Supabase::db()->update( 'users', ['id' => 1], ['last_login' => date('c'), 'login_count' => 5] ); // Update multiple records $result = Supabase::db()->update( 'posts', ['published' => false], ['published' => true, 'published_at' => date('c')] ); // Update with IN filter $result = Supabase::db()->update( 'products', ['category_id' => [1, 2, 3]], ['discount' => 10, 'on_sale' => true] ); // Using service directly use Saeedvir\Supabase\Services\SupabaseService; $supabase = new SupabaseService(); $updated = $supabase->db->update( 'users', ['email' => 'old@example.com'], ['email' => 'new@example.com', 'updated_at' => date('c')] ); // Error handling if (isset($result['error'])) { throw new \Exception("Update failed: " . $result['message']); } ``` ## Database Service - Delete Records Remove records from tables with precise filtering. ```php use Saeedvir\Supabase\Facades\Supabase; // Delete by ID $result = Supabase::db()->delete('users', ['id' => 42]); // Delete with filter $result = Supabase::db()->delete('sessions', ['expired' => true]); // Delete multiple records by IDs $result = Supabase::db()->delete('temp_files', ['id' => [10, 20, 30, 40]]); // Delete old records $result = Supabase::db()->delete('logs', ['created_at' => '2024-01-01']); // In a controller public function deleteInactiveUsers() { try { $result = Supabase::db()->delete('users', [ 'active' => false, 'last_login' => '2023-01-01' ]); if (isset($result['error'])) { return response()->json(['error' => $result['message']], 500); } return response()->json(['message' => 'Inactive users deleted']); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } } ``` ## Database Service - RPC Functions Execute custom PostgreSQL functions with parameters. ```php use Saeedvir\Supabase\Facades\Supabase; // Call RPC function without parameters $stats = Supabase::db()->rpc('get_user_statistics'); // Call RPC function with parameters $searchResults = Supabase::db()->rpc('search_products', [ 'search_term' => 'laptop', 'min_price' => 500, 'max_price' => 2000, 'category' => 'electronics' ]); // Complex RPC call $result = Supabase::db()->rpc('calculate_user_score', [ 'user_id' => 123, 'start_date' => '2024-01-01', 'end_date' => '2024-12-31', 'include_bonus' => true ]); // RPC for aggregations $totals = Supabase::db()->rpc('get_monthly_totals', [ 'year' => 2024, 'month' => 11 ]); // Error handling if (isset($searchResults['error'])) { echo "RPC Error: " . $searchResults['message']; } else { foreach ($searchResults as $product) { echo $product['name'] . ": $" . $product['price'] . "\n"; } } ``` ## Authentication Service - Sign Up Register new users with email and password. ```php use Saeedvir\Supabase\Facades\Supabase; // Basic signup $result = Supabase::auth()->signUp( 'newuser@example.com', 'SecurePassword123!' ); // Signup with additional user data $result = Supabase::auth()->signUp( 'john@example.com', 'MyPassword456!', [ 'data' => [ 'first_name' => 'John', 'last_name' => 'Doe', 'age' => 30, 'preferences' => ['theme' => 'dark'] ] ] ); // In a controller public function register(Request $request) { $validated = $request->validate([ 'email' => 'required|email', 'password' => 'required|min:8', 'name' => 'required|string' ]); $result = Supabase::auth()->signUp( $validated['email'], $validated['password'], ['data' => ['name' => $validated['name']]] ); if (isset($result['error'])) { return response()->json([ 'error' => $result['message'] ], 400); } return response()->json([ 'message' => 'Registration successful', 'user' => $result['user'], 'session' => $result['session'] ], 201); } ``` ## Authentication Service - Sign In Authenticate users and obtain access tokens. ```php use Saeedvir\Supabase\Facades\Supabase; // Basic sign in $result = Supabase::auth()->signIn( 'user@example.com', 'password123' ); // Access token and user data if (!isset($result['error'])) { $accessToken = $result['access_token']; $refreshToken = $result['refresh_token']; $user = $result['user']; $expiresIn = $result['expires_in']; } // Login controller example public function login(Request $request) { $credentials = $request->validate([ 'email' => 'required|email', 'password' => 'required' ]); $result = Supabase::auth()->signIn( $credentials['email'], $credentials['password'] ); if (isset($result['error'])) { return response()->json([ 'error' => 'Invalid credentials' ], 401); } // Store tokens in session or return to client session([ 'supabase_token' => $result['access_token'], 'supabase_refresh' => $result['refresh_token'] ]); return response()->json([ 'message' => 'Login successful', 'user' => $result['user'], 'token' => $result['access_token'] ]); } ``` ## Authentication Service - User Management Retrieve, update, and manage user accounts. ```php use Saeedvir\Supabase\Facades\Supabase; // Get user details $accessToken = session('supabase_token'); $user = Supabase::auth()->getUser($accessToken); // Update user profile $updated = Supabase::auth()->updateUser($accessToken, [ 'data' => [ 'first_name' => 'Jane', 'last_name' => 'Smith', 'avatar_url' => 'https://example.com/avatar.jpg', 'preferences' => [ 'notifications' => true, 'theme' => 'light' ] ] ]); // Update password $result = Supabase::auth()->updateUser($accessToken, [ 'password' => 'NewSecurePassword789!' ]); // Update email $result = Supabase::auth()->updateUser($accessToken, [ 'email' => 'newemail@example.com' ]); // Profile controller public function updateProfile(Request $request) { $token = $request->bearerToken(); $validated = $request->validate([ 'name' => 'sometimes|string', 'bio' => 'sometimes|string|max:500', 'website' => 'sometimes|url' ]); $result = Supabase::auth()->updateUser($token, [ 'data' => $validated ]); if (isset($result['error'])) { return response()->json(['error' => $result['message']], 400); } return response()->json(['user' => $result]); } ``` ## Authentication Service - Session Management Handle user sessions, token refresh, and logout. ```php use Saeedvir\Supabase\Facades\Supabase; // Refresh access token $refreshToken = session('supabase_refresh'); $result = Supabase::auth()->refresh($refreshToken); if (!isset($result['error'])) { $newAccessToken = $result['access_token']; $newRefreshToken = $result['refresh_token']; session([ 'supabase_token' => $newAccessToken, 'supabase_refresh' => $newRefreshToken ]); } // Sign out $accessToken = session('supabase_token'); $result = Supabase::auth()->signOut($accessToken); // Password reset $result = Supabase::auth()->resetPassword('user@example.com'); // Invite user (requires admin token) $adminToken = config('supabase.secret'); $result = Supabase::auth()->inviteUser('newuser@example.com', $adminToken); // Middleware for token refresh public function handle($request, Closure $next) { $token = $request->bearerToken(); if (!$token) { return response()->json(['error' => 'Unauthorized'], 401); } // Verify token and refresh if needed $user = Supabase::auth()->getUser($token); if (isset($user['error'])) { // Try to refresh $refreshToken = session('supabase_refresh'); $result = Supabase::auth()->refresh($refreshToken); if (isset($result['error'])) { return response()->json(['error' => 'Session expired'], 401); } $request->headers->set('Authorization', 'Bearer ' . $result['access_token']); } return $next($request); } ``` ## Storage Service - File Upload Upload files to Supabase Storage buckets. ```php use Saeedvir\Supabase\Facades\Supabase; // Upload from file path $result = Supabase::storage()->upload( 'avatars', 'user-123.png', '/path/to/local/avatar.png' ); // Upload with options $result = Supabase::storage()->upload( 'documents', 'reports/2024/report.pdf', '/path/to/report.pdf', [ 'upsert' => true, 'cacheControl' => '3600' ] ); // Upload from content $imageData = file_get_contents('php://input'); $result = Supabase::storage()->uploadContent( 'images', 'photos/photo-' . time() . '.jpg', $imageData, 'image/jpeg', ['upsert' => false] ); // Laravel controller upload public function uploadAvatar(Request $request) { $request->validate([ 'avatar' => 'required|image|max:2048' ]); $file = $request->file('avatar'); $userId = auth()->id(); $extension = $file->getClientOriginalExtension(); $fileName = "avatar-{$userId}.{$extension}"; // Store temporarily $tempPath = $file->store('temp'); $fullPath = storage_path('app/' . $tempPath); try { $result = Supabase::storage()->upload( 'avatars', $fileName, $fullPath, ['upsert' => true] ); unlink($fullPath); if (isset($result['error'])) { return response()->json(['error' => $result['message']], 500); } $publicUrl = Supabase::storage()->publicUrl('avatars', $fileName); return response()->json([ 'message' => 'Upload successful', 'url' => $publicUrl ]); } catch (\Exception $e) { @unlink($fullPath); return response()->json(['error' => $e->getMessage()], 500); } } ``` ## Storage Service - File Management Move, copy, delete, and list files in storage buckets. ```php use Saeedvir\Supabase\Facades\Supabase; // Move file $result = Supabase::storage()->move( 'documents', 'old-folder/file.pdf', 'new-folder/file.pdf' ); // Copy file $result = Supabase::storage()->copy( 'images', 'original/photo.jpg', 'thumbnails/photo-thumb.jpg' ); // Delete single file $result = Supabase::storage()->delete('avatars', ['user-123.png']); // Delete multiple files $result = Supabase::storage()->delete('temp', [ 'file1.tmp', 'file2.tmp', 'uploads/file3.tmp' ]); // List files in bucket $files = Supabase::storage()->listObjects('documents', 'reports/2024/', [ 'limit' => 100, 'offset' => 0, 'sortBy' => ['column' => 'name', 'order' => 'asc'] ]); // File manager controller public function listUserFiles(Request $request) { $userId = auth()->id(); $files = Supabase::storage()->listObjects( 'user-files', "user-{$userId}/", ['limit' => 50] ); if (isset($files['error'])) { return response()->json(['error' => $files['message']], 500); } $filesWithUrls = array_map(function($file) use ($userId) { return [ 'name' => $file['name'], 'size' => $file['metadata']['size'], 'updated_at' => $file['updated_at'], 'url' => Supabase::storage()->publicUrl( 'user-files', "user-{$userId}/" . $file['name'] ) ]; }, $files); return response()->json(['files' => $filesWithUrls]); } ``` ## Storage Service - URL Generation Generate public, authenticated, and signed URLs for stored files. ```php use Saeedvir\Supabase\Facades\Supabase; // Public URL (for public buckets) $url = Supabase::storage()->publicUrl('avatars', 'user-123.png'); // Returns: https://project.supabase.co/storage/v1/object/public/avatars/user-123.png // Authenticated URL (requires auth) $url = Supabase::storage()->authenticatedUrl('private-docs', 'report.pdf'); // Returns: https://project.supabase.co/storage/v1/object/authenticated/private-docs/report.pdf // Signed URL (temporary access to private files) $result = Supabase::storage()->createSignedUrl( 'private-docs', 'confidential/report.pdf', 3600 // expires in 1 hour ); $signedUrl = $result['signedURL']; // Different expiry times $shortUrl = Supabase::storage()->createSignedUrl('temp-files', 'file.zip', 300); // 5 minutes $longUrl = Supabase::storage()->createSignedUrl('downloads', 'file.pdf', 86400); // 24 hours // Download controller public function downloadFile(Request $request, $fileId) { $file = File::findOrFail($fileId); // Check permissions if ($file->user_id !== auth()->id()) { abort(403); } $result = Supabase::storage()->createSignedUrl( 'private-files', $file->path, 300 // 5 minute expiry ); if (isset($result['error'])) { abort(500, 'Failed to generate download link'); } return response()->json([ 'download_url' => $result['signedURL'], 'expires_in' => 300 ]); } ``` ## Realtime Service - WebSocket Channels Subscribe to real-time database changes via WebSocket connections. ```php use Saeedvir\Supabase\Facades\Supabase; // Get WebSocket channel URL $channelUrl = Supabase::realtime()->channelUrl('public', 'users'); // Returns: wss://project.supabase.co/realtime/v1/public:users // Get headers for authentication $headers = Supabase::realtime()->headers(); // Returns: ['apikey' => '...', 'Authorization' => 'Bearer ...'] // Get subscription payload $payload = Supabase::realtime()->subscribePayload('INSERT', 'public', 'products'); // Returns: ['type' => 'subscribe', 'event' => 'INSERT', 'schema' => 'public', 'table' => 'products'] // Subscribe to all events $allEvents = Supabase::realtime()->subscribePayload('*', 'public', 'orders'); // Get full realtime URL $realtimeUrl = Supabase::realtime()->getRealtimeUrl(); // Controller for real-time data public function realtimeConfig(Request $request) { $table = $request->input('table', 'notifications'); return response()->json([ 'channel_url' => Supabase::realtime()->channelUrl('public', $table), 'headers' => Supabase::realtime()->headers(), 'subscribe_payload' => Supabase::realtime()->subscribePayload('*', 'public', $table) ]); } ``` ## Realtime Service - Frontend Integration Generate JavaScript snippets for client-side real-time subscriptions. ```php use Saeedvir\Supabase\Facades\Supabase; // Get JavaScript snippet for a table $jsCode = Supabase::realtime()->clientJsSnippet('products', 'public'); // Use in a Blade view public function dashboardView() { $realtimeScript = Supabase::realtime()->clientJsSnippet('notifications'); return view('dashboard', [ 'realtime_script' => $realtimeScript ]); } ``` **Blade template example:** ```blade Real-time Dashboard
{!! $realtime_script !!} ``` ## Configuration and Service Information Configure the package and retrieve connection information. ```php // .env configuration SUPABASE_URL=https://your-project.supabase.co SUPABASE_KEY=your-public-anon-key SUPABASE_SECRET=your-service-role-key // Get connection info use Saeedvir\Supabase\Facades\Supabase; $info = Supabase::info(); // Returns: // [ // 'url' => 'https://your-project.supabase.co', // 'connected' => true, // 'services' => [ // 'auth' => true, // 'database' => true, // 'storage' => true, // 'realtime' => true // ] // ] // Custom configuration in config/supabase.php return [ 'url' => env('SUPABASE_URL', ''), 'key' => env('SUPABASE_KEY', ''), 'secret' => env('SUPABASE_SECRET', ''), 'services' => [ 'auth' => true, 'database' => true, 'storage' => true, 'realtime' => false // Disable specific services ], 'http' => [ 'timeout' => 30, 'retries' => 3 // Auto-retry failed requests ] ]; // Using service directly use Saeedvir\Supabase\Services\SupabaseService; $supabase = new SupabaseService(); // Access services $users = $supabase->db->select('users'); $authResult = $supabase->auth->signIn('email@example.com', 'pass'); $upload = $supabase->storage->upload('bucket', 'path', '/file'); // Get raw client $client = $supabase->getClient(); $baseUrl = $client->getBaseUrl(); $apiKey = $client->getApiKey(); // Health check endpoint public function health() { $info = Supabase::info(); return response()->json([ 'status' => $info['connected'] ? 'healthy' : 'disconnected', 'supabase' => $info ]); } ``` ## Service Provider Registration Install and configure the package in your Laravel application. ```bash # Install via Composer composer require saeedvir/supabase # Publish configuration file php artisan vendor:publish --provider="Saeedvir\Supabase\SupabaseServiceProvider" --tag="supabase-config" ``` ```php // The package auto-registers via Laravel's package discovery // Service provider: Saeedvir\Supabase\SupabaseServiceProvider // Facade: Saeedvir\Supabase\Facades\Supabase // Manual registration (if auto-discovery disabled) // config/app.php 'providers' => [ // ... Saeedvir\Supabase\SupabaseServiceProvider::class, ], 'aliases' => [ // ... 'Supabase' => Saeedvir\Supabase\Facades\Supabase::class, ], // Dependency injection in controllers use Saeedvir\Supabase\Services\SupabaseService; class UserController extends Controller { protected $supabase; public function __construct(SupabaseService $supabase) { $this->supabase = $supabase; } public function index() { $users = $this->supabase->db->select('users', '*', ['active' => true]); return view('users.index', compact('users')); } } // Error handling and logging use Illuminate\Support\Facades\Log; try { $result = Supabase::db()->insert('users', $data); if (isset($result['error'])) { Log::error('Supabase insert failed', [ 'error' => $result['message'], 'data' => $data ]); throw new \Exception($result['message']); } } catch (\Exception $e) { Log::critical('Supabase exception', ['exception' => $e->getMessage()]); throw $e; } ``` ## Summary The Supabase Laravel Package provides a complete integration solution for Laravel applications that need to leverage Supabase's backend services. Primary use cases include building full-stack web applications with real-time features, mobile app backends, SaaS platforms requiring multi-tenant data isolation, and API services with built-in authentication. The package is particularly well-suited for rapid prototyping and MVP development where you need a robust backend without managing infrastructure. Common scenarios include user-generated content platforms with file uploads, collaborative tools with real-time synchronization, dashboard applications with live data updates, and e-commerce platforms with inventory management. Integration patterns follow Laravel conventions for seamless adoption. Use the Supabase facade for quick operations in controllers and Blade views, inject the SupabaseService for dependency injection and testing, or instantiate individual service classes for granular control. The package handles authentication tokens, retry logic, error formatting, and logging automatically. For production deployments, configure environment-specific settings in .env files, enable only required services to reduce overhead, implement proper error handling and logging strategies, and use signed URLs for secure file access. The package supports both synchronous operations for immediate responses and asynchronous patterns for background processing, making it adaptable to various architectural requirements.