# 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