PHP code example of dancycodes / gale

1. Go to this page and download the library: Download dancycodes/gale library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

dancycodes / gale example snippets


Route::get('/counter', fn() => gale()->view('counter', ['count' => 0], web: true));

Route::post('/increment', function () {
    return gale()->state('count', request()->state('count', 0) + 1);
});

return [
    'mode' => env('GALE_MODE', 'http'),
    // ...
];

return gale()->stream(function ($gale) {
    // This always streams via SSE
    $gale->state('progress', 50);
});

return gale()
    ->state('count', 42)
    ->state('updated', now()->toISOString())
    ->messages(['_success' => 'Saved!']);

// Single key-value
gale()->state('count', 42);

// Multiple values
gale()->state([
    'count' => 42,
    'user' => ['name' => 'John', 'email' => '[email protected]'],
]);

// Nested update (merges with existing)
gale()->state('user.email', '[email protected]');

// Only set if key doesn't exist in component state
gale()->state('defaults', ['theme' => 'dark'], ['onlyIfMissing' => true]);

gale()->patchState(['count' => 1, 'updated' => true]);

gale()->forget('tempData');
gale()->forget(['tempData', 'cache', 'draft']);

gale()->messages([
    'email' => 'Invalid email address',
    'password' => 'Password too short',
]);

// Success pattern
gale()->messages(['_success' => 'Profile saved!']);

gale()->clearMessages();

gale()->flash('status', 'Your account has been updated.');
gale()->flash(['status' => 'ok', 'message' => 'Saved!']);

// Morph by matching element IDs
gale()->view('partials.user-card', ['user' => $user]);

// With selector and mode
gale()->view('partials.item', ['item' => $item], [
    'selector' => '#items-list',
    'mode' => 'append',
]);

// As web fallback for non-Gale requests
gale()->view('dashboard', $data, web: true);

gale()->html('<div id="content">New content</div>');

gale()->html('<li>New item</li>', [
    'selector' => '#list',
    'mode' => 'append',
]);

// Server-driven state (replacement via initTree)
gale()->outer('#element', '<div id="element">Replaced</div>');
gale()->inner('#container', '<p>Inner content</p>');

// Client-preserved state (smart morphing via Alpine.morph)
gale()->outerMorph('#element', '<div id="element">Updated</div>');
gale()->innerMorph('#container', '<p>Morphed content</p>');

// Insertion modes
gale()->append('#list', '<li>Last</li>');
gale()->prepend('#list', '<li>First</li>');
gale()->before('#target', '<div>Before</div>');
gale()->after('#target', '<div>After</div>');

// Removal
gale()->remove('.deprecated');

// Viewport modifiers (optional third parameter)
gale()->append('#chat', $html, ['scroll' => 'bottom']);
gale()->outer('#form', $html, ['show' => 'top']);

// Single fragment
gale()->fragment('todos', 'todo-items', ['todos' => $todos]);

// With options
gale()->fragment('todos', 'todo-items', ['todos' => $todos], [
    'selector' => '#todo-list',
    'mode' => 'morph',
]);

// Multiple fragments at once
gale()->fragments([
    ['view' => 'dashboard', 'fragment' => 'stats', 'data' => $statsData],
    ['view' => 'dashboard', 'fragment' => 'recent-orders', 'data' => $ordersData],
]);

return gale()->redirect('/dashboard');

return gale()->redirect('/dashboard')
    ->with('message', 'Welcome back!')
    ->with(['key' => 'value']);

return gale()->redirect('/register')
    ->withErrors($validator)
    ->withInput();

gale()->navigate('/users');
gale()->navigate('/users', 'main-content');

// Merge query params
gale()->navigateMerge(['page' => 2]);

// Replace history instead of push
gale()->navigateReplace('/users');

// Update query parameters in place
gale()->updateQueries(['sort' => 'name', 'order' => 'asc']);

// Clear specific query parameters
gale()->clearQueries(['filter', 'search']);

// Full page reload
gale()->reload();

gale()->dispatch('user-updated', ['id' => $user->id]);

// Targeted to a specific element
gale()->dispatch('refresh', ['section' => 'cart'], [
    'selector' => '.shopping-cart',
]);

gale()->js('console.log("Hello from server")');
gale()->js('myApp.showNotification("Saved!")');

gale()->debug('payload', $request->all());
gale()->debug(['user' => $user, 'state' => $state]);

// Update a component's state
gale()->componentState('cart', [
    'items' => $cartItems,
    'total' => $total,
]);

// Invoke a method on a named component
gale()->componentMethod('cart', 'recalculate');
gale()->componentMethod('calculator', 'setValues', [10, 20, 30]);

return gale()->stream(function ($gale) {
    $users = User::cursor();
    $total = User::count();
    $processed = 0;

    foreach ($users as $user) {
        $user->processExpensiveOperation();
        $processed++;

        // Sent immediately to the browser
        $gale->state('progress', [
            'current' => $processed,
            'total' => $total,
            'percent' => round(($processed / $total) * 100),
        ]);
    }

    $gale->state('complete', true);
    $gale->messages(['_success' => "Processed {$total} users"]);
});

// Check if the request is a Gale request
if (request()->isGale()) {
    return gale()->state('data', $data);
}
return view('page', compact('data'));

// Access state sent from the Alpine component
$count = request()->state('count', 0);
$email = request()->state('user.email');

// Check if it's a navigation request
if (request()->isGaleNavigate()) {
    return gale()->fragment('page', 'content', $data);
}

// Validate state with automatic error response
$validated = request()->validateState([
    'email' => '

// Standard validate() -- auto-converts for Gale requests
public function store(Request $request)
{
    $request->validate([
        'state.name' => 'y
public function store(Request $request)
{
    $validated = $request->validateState([
        'name' => '

// app/Http/Requests/StoreUserRequest.php
class StoreUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'state.name' => ')
{
    User::create($request->validated());
    return gale()->messages(['_success' => 'Created!']);
}

gale()->when($condition, function ($gale) {
    $gale->state('visible', true);
});

gale()->whenGale(
    fn($g) => $g->state('partial', true),
    fn($g) => $g->web(view('full'))
);

gale()->whenGaleNavigate('sidebar', function ($gale) {
    $gale->fragment('layout', 'sidebar', $data);
});

// Web fallback for non-Gale requests
return gale()
    ->state('data', $data)
    ->web(view('page', compact('data')));

// config/gale.php
'route_discovery' => [
    'enabled' => true,
    'discover_controllers_in_directory' => [
        app_path('Http/Controllers'),
    ],
],

use Dancycodes\Gale\Routing\Attributes\Route;
use Dancycodes\Gale\Routing\Attributes\Prefix;
use Dancycodes\Gale\Routing\Attributes\Group;
use Dancycodes\Gale\Routing\Attributes\Middleware;

#[Prefix('/admin')]
class UserController extends Controller
{
    #[Route('GET', '/users', name: 'admin.users.index')]
    public function index() { }

    #[Route('GET', '/users/{id}', name: 'admin.users.show')]
    public function show($id) { }
}

// Group attribute (prefix + middleware + route name prefix in one)
#[Group(prefix: '/api', middleware: ['auth'], as: 'api.')]
class ApiController extends Controller
{
    #[Route('GET', '/data')]
    public function data() { }
}

return [
    // Default response mode: 'http' (JSON) or 'sse' (Server-Sent Events)
    'mode' => env('GALE_MODE', 'http'),

    // Intercept dd() and dump() during Gale requests, render in debug panel
    'debug' => env('GALE_DEBUG', false),

    // Sanitize HTML in gale-patch-elements events (XSS protection)
    'sanitize_html' => env('GALE_SANITIZE_HTML', true),

    // Allow <script> tags in patched HTML (false = strip scripts)
    'allow_scripts' => env('GALE_ALLOW_SCRIPTS', false),

    // Inject HTML comment markers for conditional/loop Blade blocks
    // Improves morph accuracy; disable in production to reduce payload
    'morph_markers' => env('GALE_MORPH_MARKERS', true),

    // Content Security Policy nonce: null | 'auto' | '<nonce-string>'
    'csp_nonce' => env('GALE_CSP_NONCE', null),

    // Security headers added to all Gale responses
    'headers' => [
        'x_content_type_options' => 'nosniff',
        'x_frame_options' => 'SAMEORIGIN',
        'cache_control' => 'no-store, no-cache, must-revalidate',
        'custom' => [],
    ],

    // Open-redirect prevention
    'redirect' => [
        'allowed_domains' => [],  // e.g. ['payment.stripe.com', '*.myapp.com']
        'allow_external' => false,
        'log_blocked' => true,
    ],

    // Attribute-based route discovery (opt-in)
    'route_discovery' => [
        'enabled' => false,
        'conventions' => true,  // Auto-discover index/show/create/store/edit/update/destroy
        'discover_controllers_in_directory' => [
            // app_path('Http/Controllers'),
        ],
        'discover_views_in_directory' => [],
        'pending_route_transformers' => [
            ...Dancycodes\Gale\Routing\Config::defaultRouteTransformers(),
        ],
    ],
];

gale()->view('page', $data, ['useViewTransition' => true]);
bash
php artisan vendor:publish --tag=gale-config
bash
php artisan gale:routes
php artisan gale:routes --json
html
<div x-data="{ user: {...}, temp: null }" x-sync="['user']">
    <button @click="$action('/save')">Save User</button>
    <!-- Only { user: {...} } is sent -->
</div>