PHP code example of tinymvc / orbit

1. Go to this page and download the library: Download tinymvc/orbit 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/ */

    

tinymvc / orbit example snippets




namespace App\Http\Resources;

use App\Models\Product;
use App\Modules\Bread\Form;
use App\Modules\Bread\Resource;
use App\Modules\Bread\Table;

class ProductsResource extends Resource
{
    // ─── Core ───────────────────────────────────────────────────────────

    /** The Eloquent model this resource manages */
    protected static string $model = Product::class;

    /** Singular display name (shown in forms, flash messages) */
    protected static string $name = 'Product';

    /** URL slug — the resource will be accessible at /admin/products */
    protected static string $slug = 'products';

    /** Page title (defaults to pluralized $name if omitted) */
    protected static null|string $title = 'Products';

    /** Description shown below the page title */
    protected static null|string $description = 'Manage your product catalog.';

    /** Relationships to eager-load on the index query */
    protected static array $with = ['category:id,name'];

    /** Columns searchable via the search input */
    protected static array $searchable = ['name', 'sku', 'description'];

    /** Default sort column and direction */
    protected static string $orderBy = 'id';
    protected static string $orderDirection = 'desc';

    // ─── Drawer / Sheet ─────────────────────────────────────────────────

    /** Create/edit drawer width: sm | md | lg | xl | 2xl */
    protected static string $drawerWidth = 'lg';

    // ─── Disabled Features ──────────────────────────────────────────────

    /** Disable specific features: "search", "columns", "add_record" */
    protected static array $disabled = [];

    // ... fields(), columns(), etc.
}

Form\TextInput::make('name')
    ->label('Display Name')           // Field label
    ->placeholder('Enter name...')    // Placeholder text
    ->umnSpan(2)                   // Span 2 columns (full-width in 2-col grid)
    ->fullWidth()                     // Alias for columnSpan(2)
    ->disabled()                      // Render as read-only
    ->createOnly()                    // Only show on create form
    ->editOnly()                      // Only show on edit form
    ->hidden()                        // Don't render (but 

// Simple text
Form\TextInput::make('name')->il()->sword()->c()->min(0)->max(99999)->step(0.01)

// With uniqueness validation
Form\TextInput::make('email')->email()->unique('users,email')

Form\SlugInput::make('slug')
    ->from('title')                    // Source field to generate slug from
    ->unique('posts,slug')             // Uniqueness validation (table,column)
    ->maxLength(255)

// Static options
Form\Select::make('status')
    ->lue' => 'draft',     'label' => 'Draft'],
        ['value' => 'published', 'label' => 'Published'],
        ['value' => 'archived',  'label' => 'Archived'],
    ])
    ->in('draft,published,archived')  // Validation: allowed values

// Dynamic options from server (via dynamicProps)
Form\Select::make('category_id')
    ->dynamicOptions('categories')

// Static searchable select
Form\Combobox::make('country')
    ->options([
        ['value' => 'us', 'label' => 'United States'],
        ['value' => 'uk', 'label' => 'United Kingdom'],
    ])

// BelongsTo relationship (single select, stores FK on the model)
Form\Combobox::make('user_id')
    ->belongsTo('user', 'id', 'display_name')
    ->searchRoute(self::getUrl())         // Enable AJAX search
    ->selectKeys(['id', 'first_name', 'last_name', 'username'])
    ->searchKeys(['first_name', 'last_name', 'username'])
    ->placeholder('Select author...')

// BelongsToMany relationship (multiple select, syncs pivot table)
Form\Combobox::make('categories')
    ->belongsToMany('categories', 'id', 'name')
    ->dynamicOptions('categories')        // Pre-loaded options
    ->placeholder('Select categories...')

// Taggable mode — create new options on the fly
Form\Combobox::make('tags')
    ->multiple()
    ->taggable()
    ->dynamicOptions('tags')

// Date only
Form\DatePicker::make('published_at')

// Date + Time
Form\DatePicker::make('scheduled_at')
    ->withTime()
    ->disablePastDates()

// Disable future dates
Form\DatePicker::make('birth_date')
    ->disableFutureDates()

Form\FileUpload::make('thumbnail')
    ->uploadTo('posts')                    // Upload directory (relative to storage/uploads/)
    ->acceptedTypes(['jpg', 'png', 'webp']) // Allowed extensions
    ->maxFileSize(4096)                    // Max size in KB (4MB)
    ->compress(80)                         // JPEG/WebP quality (1-100)
    ->resize(1200, 800)                    // Max width × height
    ->multiple()                           // Allow multiple files

Form\RichEditor::make('content')
    ->rows(12)                             // Editor height
    ->

Form\Toggle::make('is_active')->label('Active')->default(true)
Form\Checkbox::make('is_featured')

public static function columns(): array
{
    return [
        // Basic text with click-to-edit and truncation
        Table\Column::make('title')
            ->clickToEdit()
            ->truncate(45),

        // Thumbnail image
        Table\Column::make('thumbnail')
            ->header('Image')
            ->thumbnail(),

        // Avatar column (circular image + name)
        Table\Column::make('user')
            ->header('Author')
            ->avatar('avatar_url')
            ->display(['display_name']),

        // Badge with color mapping
        Table\Column::make('status')
            ->badge()
            ->badgeMap([
                'draft'     => ['label' => 'Draft',     'variant' => 'secondary'],
                'published' => ['label' => 'Published', 'variant' => 'default'],
                'archived'  => ['label' => 'Archived',  'variant' => 'outline'],
            ]),

        // Tags (array of related items)
        Table\Column::make('categories')
            ->tags()
            ->display(['name'])
            ->limit(3),

        // Date formatting
        Table\Column::make('created_at')
            ->header('Created')
            ->date(),

        // Boolean column
        Table\Column::make('is_active')
            ->boolean(),

        // HTML content
        Table\Column::make('content')
            ->html()
            ->truncate(100),

        // Initially hidden (user can toggle via column visibility)
        Table\Column::make('excerpt')
            ->truncate(60)
            ->hidden(),
    ];
}

public static function filters(): array
{
    return [
        // Simple column filter (WHERE status = ?)
        Table\Filter::make('status')
            ->label('Status')
            ->options([
                ['value' => 'draft',     'label' => 'Draft'],
                ['value' => 'published', 'label' => 'Published'],
            ]),

        // Dynamic options from server
        Table\Filter::make('category_id')
            ->label('Category')
            ->options('dynamic:categories'),

        // Custom filter callback (for complex queries)
        Table\Filter::make('category_id')
            ->label('Category')
            ->callback(function ($query, $value) {
                $query->whereHas('categories', fn($q) => $q->where('categories.id', (int) $value));
            })
            ->options('dynamic:categories'),
    ];
}

public static function bulkActions(): array
{
    return [
        // Status change actions (auto-updates the 'status' column)
        Table\BulkAction::make('published')->label('Publish Selected'),
        Table\BulkAction::make('draft')->label('Move to Draft'),
        Table\BulkAction::make('archived')->label('Archive Selected'),

        // Delete action (built-in, handles file cleanup)
        Table\BulkAction::make('delete')->label('Delete Selected')->destructive(),

        // Custom callback action
        Table\BulkAction::make('export')
            ->label('Export Selected')
            ->callback(function (array $ids) {
                // Custom logic here
            }),

        // Custom status column
        Table\BulkAction::make('inactive')
            ->label('Deactivate')
            ->statusColumn('is_active'),
    ];
}

public static function handleBulkAction(string $action, array $ids)
{
    if ($action === 'export') {
        // ... custom logic
        return inertia()->back()->with('success', 'Exported!');
    }

    return null; // Fall through to default handling
}

protected static null|string $browsePerm = 'products.browse';
protected static null|string $createPerm = 'products.create';
protected static null|string $editPerm   = 'products.edit';
protected static null|string $deletePerm = 'products.delete';

> return [
>     'products' => [
>         'browse' => 'View Products Table',
>         'create' => 'Create Products',
>         'edit'   => 'Edit Products',
>         'delete' => 'Delete Products',
>     ],
> ];
> 

public static function dynamicProps(): array
{
    return [
        'categories' => Category::select(['id', 'name'])
            ->map(fn($c) => [
                'value' => (string) $c->id,
                'label' => $c->name,
            ])->all(...),
    ];
}

// Mutate data before creating a new record
public static function mutateBeforeCreate(array $data): array
{
    $data['user_id'] = auth()->id();
    return $data;
}

// Called after a record is created
public static function afterCreate($record, array $data): void
{
    // Send notification, dispatch job, etc.
}

// Mutate data before updating
public static function mutateBeforeUpdate(array $data, $record): array
{
    if (empty($data['published_at'])) {
        unset($data['published_at']);
    }
    return $data;
}

// Called after a record is updated
public static function afterUpdate($record, array $data): void {}

// Called before a record is deleted
public static function beforeDelete($record): void {}

// Custom validation rules (return null to auto-generate from fields)
public static function storeRules(): null|array
{
    return [
        'name' => '

Form\Combobox::make('user_id')
    ->belongsTo('user', 'id', 'display_name')
    ->searchRoute(self::getUrl())

Form\Combobox::make('categories')
    ->belongsToMany('categories', 'id', 'name')
    ->dynamicOptions('categories')

use App\Http\Resources\ProductsResource;
use App\Modules\Bread\ResourceController;

Route::group(function () {
    // ... existing routes ...

    // Register BREAD routes for Products
    ResourceController::routes(ProductsResource::class);

})->middleware('auth')->prefix('admin');



namespace App\Http\Resources;

use App\Models\Category;
use App\Models\Post;
use App\Modules\Bread\Form;
use App\Modules\Bread\Resource;
use App\Modules\Bread\Table;

class PostsResource extends Resource
{
    protected static string $model = Post::class;
    protected static string $name = 'Post';
    protected static string $slug = 'posts';
    protected static null|string $title = 'Posts';
    protected static null|string $description = 'Manage blog posts, drafts, and scheduled publications.';

    protected static array $with = [
        'user:id,first_name,last_name,username,email',
        'categories:id,name',
    ];
    protected static array $searchable = ['title', 'slug', 'excerpt'];

    protected static null|string $browsePerm = 'posts.browse';
    protected static null|string $createPerm = 'posts.create';
    protected static null|string $editPerm   = 'posts.edit';
    protected static null|string $deletePerm = 'posts.delete';

    protected static string $drawerWidth = 'xl';

    public static function fields(): array
    {
        return [
            Form\TextInput::make('title')
                ->label('Title')->         Form\DatePicker::make('published_at')
                ->withTime()->label('Published At')
                ->visibleWhen(['status' => 'published'])->fullWidth(),

            Form\FileUpload::make('thumbnail')
                ->label('Thumbnail')->uploadTo('posts')
                ->acceptedTypes(['jpg', 'jpeg', 'png', 'webp', 'gif'])
                ->maxFileSize(4096)->compress(80)->columnSpan(2),

            Form\Textarea::make('excerpt')
                ->label('Excerpt')->maxLength(500)->rows(3)->columnSpan(2),

            Form\RichEditor::make('content')
                ->label('Content')->rows(12)->columnSpan(2),
        ];
    }

    public static function columns(): array
    {
        return [
            Table\Column::make('title')->clickToEdit()->truncate(45),
            Table\Column::make('thumbnail')->header('Thumbnail')->thumbnail(),
            Table\Column::make('user')->header('Author')->avatar('avatar_url')->display(['display_name']),
            Table\Column::make('status')->badge()->badgeMap([
                'draft'     => ['label' => 'Draft',     'variant' => 'secondary'],
                'published' => ['label' => 'Published', 'variant' => 'default'],
                'archived'  => ['label' => 'Archived',  'variant' => 'outline'],
            ]),
            Table\Column::make('categories')->tags()->display(['name'])->limit(3),
            Table\Column::make('published_at')->header('Published')->date(),
            Table\Column::make('created_at')->header('Created')->hidden()->date(),
        ];
    }

    public static function filters(): array
    {
        return [
            Table\Filter::make('status')->label('Status')->options([
                ['value' => 'draft',     'label' => 'Draft'],
                ['value' => 'published', 'label' => 'Published'],
            ]),
            Table\Filter::make('category_id')->label('Category')
                ->callback(fn($query, $value) =>
                    $query->whereHas('categories', fn($q) => $q->where('categories.id', (int) $value))
                )->options('dynamic:categories'),
        ];
    }

    public static function bulkActions(): array
    {
        return [
            Table\BulkAction::make('published')->label('Publish Selected'),
            Table\BulkAction::make('draft')->label('Move to Draft'),
            Table\BulkAction::make('delete')->label('Delete Selected')->destructive(),
        ];
    }

    public static function dynamicProps(): array
    {
        return [
            'categories' => Category::select(['id', 'name'])
                ->map(fn($c) => ['value' => (string) $c->id, 'label' => $c->name])
                ->all(...),
        ];
    }

    public static function mutateBeforeCreate(array $data): array
    {
        if (empty($data['published_at'])) unset($data['published_at']);
        if (empty($data['scheduled_at'])) unset($data['scheduled_at']);
        return $data;
    }
}

use App\Modules\Dashboard\Stats;

Stats::make('Total Revenue')
    ->value('$1,250.00')       // Display value (formatted string)
    ->change(12.5)             // Percentage change
    ->trend('up')              // 'up' | 'down' | 'neutral'
    ->footer('Trending up this month')
    ->description('Revenue for the last 6 months');

use App\Modules\Dashboard\Charts\BarChart;

BarChart::make('Monthly Revenue')
    ->description('Revenue vs Expenses')     // Subtitle
    ->xAxisKey('month')                      // Category axis key
    ->dataKeys(['revenue', 'expenses'])      // Data series keys
    ->colors([                               // Colors per series
        'hsl(221, 83%, 53%)',
        'hsl(0, 84%, 60%)',
    ])
    ->colSpan(2)                             // Grid columns to span (1-3)
    ->height(350)                            // Chart height in pixels
    ->data([                                 // Data array
        ['month' => 'Jan', 'revenue' => 4000, 'expenses' => 2400],
        ['month' => 'Feb', 'revenue' => 3000, 'expenses' => 1398],
        ['month' => 'Mar', 'revenue' => 5000, 'expenses' => 3800],
    ]);

PieChart::make('Browser Share')
    ->dataKeys(['value'])
    ->colors(['hsl(221, 83%, 53%)', 'hsl(262, 83%, 58%)', 'hsl(173, 58%, 39%)'])
    ->colSpan(1)
    ->data([
        ['name' => 'Chrome',  'value' => 62],
        ['name' => 'Safari',  'value' => 19],
        ['name' => 'Firefox', 'value' => 10],
    ]);

RadialChart::make('Goal Completion')
    ->dataKeys(['value'])
    ->colors(['hsl(221, 83%, 53%)', 'hsl(173, 58%, 39%)'])
    ->colSpan(1)
    ->data([
        ['name' => 'Sales',     'value' => 78],
        ['name' => 'Support',   'value' => 92],
        ['name' => 'Marketing', 'value' => 65],
    ]);

$dashboard = Dashboard::make('Dashboard')
    ->dateRange('/admin', [
        ['label' => '7D',  'days' => 7],
        ['label' => '14D', 'days' => 14],
        ['label' => '30D', 'days' => 30],
        ['label' => '90D', 'days' => 90],
    ])
    ->activeDateRange($request->input('from'), $request->input('to'));



namespace App\Http\Controllers;

use App\Modules\Dashboard\Dashboard;
use App\Modules\Dashboard\Stats;
use App\Modules\Dashboard\Charts\AreaChart;
use App\Modules\Dashboard\Charts\BarChart;
use App\Modules\Dashboard\Charts\PieChart;
use Spark\Http\Request;

class DashboardController extends Controller
{
    public function overview(Request $request)
    {
        $from = $request->input('from');
        $to   = $request->input('to');

        // Fetch your real data based on $from / $to date range
        $dashboard = Dashboard::make('Dashboard', 'Your analytics overview at a glance.')
            ->dateRange('/admin', [
                ['label' => '7D', 'days' => 7],
                ['label' => '30D', 'days' => 30],
                ['label' => '90D', 'days' => 90],
            ])
            ->activeDateRange($from, $to)
            ->stats([
                Stats::make('Total Revenue')
                    ->value('$1,250.00')
                    ->change(12.5)
                    ->trend('up')
                    ->footer('Trending up this month'),

                Stats::make('New Customers')
                    ->value('1,234')
                    ->change(-20)
                    ->trend('down')
                    ->footer('Down 20% this period'),
            ])
            ->charts([
                BarChart::make('Monthly Revenue')
                    ->xAxisKey('month')
                    ->dataKeys(['revenue', 'expenses'])
                    ->colors(['hsl(221, 83%, 53%)', 'hsl(0, 84%, 60%)'])
                    ->colSpan(2)->height(350)
                    ->data([
                        ['month' => 'Jan', 'revenue' => 4000, 'expenses' => 2400],
                        ['month' => 'Feb', 'revenue' => 3000, 'expenses' => 1398],
                    ]),

                PieChart::make('Browser Share')
                    ->dataKeys(['value'])
                    ->colors(['hsl(221, 83%, 53%)', 'hsl(262, 83%, 58%)'])
                    ->colSpan(1)->height(350)
                    ->data([
                        ['name' => 'Chrome', 'value' => 62],
                        ['name' => 'Safari', 'value' => 19],
                    ]),
            ]);

        return inertia('admin/dashboard', [
            'dashboard' => $dashboard->toArray(),
        ]);
    }
}



return [
    'dashboard' => [
        'overview' => 'View Dashboard Overview',
    ],
    'roles' => [
        'browse' => 'View Roles Table',
        'create' => 'Create Roles',
        'edit'   => 'Edit Roles',
        'delete' => 'Delete Roles',
    ],
    'users' => [
        'browse' => 'View Users Table',
        'create' => 'Create Users',
        'edit'   => 'Edit Users',
        'delete' => 'Delete Users',
    ],
    'posts' => [
        'browse' => 'View Posts Table',
        'create' => 'Create Posts',
        'edit'   => 'Edit Posts',
        'delete' => 'Delete Posts',
    ],
    // Add your resource permissions here
    'products' => [
        'browse' => 'View Products Table',
        'create' => 'Create Products',
        'edit'   => 'Edit Products',
        'delete' => 'Delete Products',
    ],
];
bash
php spark key:generate
php spark storage:link
php spark migrate --seed
bash
# Terminal 1 — PHP server
php spark serve

# Terminal 2 — Vite dev server (hot reload)
npm run dev
bash
php spark make:bread Post
bash
php spark make:bread Blog/Post