# Orchid Platform — быстрый старт админки за 30 минут

URL: https://dmeshcheryakov.ru/blog/orchid-getting-started/
Раздел: Laravel
Теги: Laravel, Orchid, Admin Panel, PHP
Опубликовано: 2026-06-26
Обновлено: 2026-09-07
Автор: Дмитрий Мещеряков (https://dmeshcheryakov.ru)

> Orchid — современная платформа для создания админ-панелей на Laravel. Устанавливаем, настраиваем, создаём первый CRUD без лишнего кода.

Orchid — административная панель для Laravel, построенная на классах-экранах вместо генерации CRUD по модели. Подход отличается от привычного по другим панелям, и это стоит понять до начала: здесь вы описываете экран целиком — какие данные загрузить, какие блоки показать, какие действия доступны, — а не настраиваете готовый ресурс.

Разберём основы и, отдельно, для каких задач этот инструмент подходит, а для каких — нет.

## Что такое Orchid

Orchid Platform — это пакет для Laravel, который превращает создание админ-панелей из рутины в удовольствие. Вместо написания CRUD-контроллеров, views и форм вы описываете экраны декларативно.

**Преимущества:**
- Готовый UI на основе Bootstrap 5
- Декларативные экраны (Screens)
- Встроенные компоненты: таблицы, формы, фильтры
- Гибкая система прав
- Уведомления, виджеты, графики

**Orchid vs Nova/Filament:** Orchid бесплатный и open-source. Nova платная ($199). Filament тоже бесплатный, но Orchid более гибкий для кастомной логики.

## Установка

```bash
# Новый проект Laravel
composer create-project laravel/laravel admin-panel
cd admin-panel
# Установка Orchid
composer require orchid/platform
# Публикация ресурсов
php artisan orchid:install
# Создание админа
php artisan orchid:admin admin admin@example.com password
```

```bash
# .env
APP_URL=http://localhost:8000
```

```bash
php artisan serve
# Админка: http://localhost:8000/admin
```

## Структура проекта

После установки появляются:

```
app/
├── Orchid/
│   ├── Layouts/           # Компоненты таблиц и форм
│   ├── Screens/           # Экраны (страницы админки)
│   ├── Presenters/        # Форматирование данных
│   └── PlatformProvider.php  # Регистрация меню
```

## Первый Screen

Создадим экран списка статей:

```bash
php artisan orchid:screen PostListScreen
```

```php
// app/Orchid/Screens/PostListScreen.php
namespace App\Orchid\Screens;
use App\Models\Post;
use Orchid\Screen\Screen;
use Orchid\Screen\Actions\Link;
use Orchid\Support\Facades\Layout;
use Orchid\Screen\TD;
class PostListScreen extends Screen
{
    /**
     * Название экрана
     */
    public ?string $name = 'Статьи';
    /**
     * Описание
     */
    public ?string $description = 'Управление статьями блога';
    /**
     * Получение данных для экрана
     */
    public function query(): iterable
    {
        return [
            'posts' => Post::filters()->defaultSort('created_at', 'desc')->paginate(),
        ];
    }
    /**
     * Кнопки в header
     */
    public function commandBar(): iterable
    {
        return [
            Link::make('Создать статью')
                ->icon('plus')
                ->route('platform.post.edit'),
        ];
    }
    /**
     * Layouts — что отображаем
     */
    public function layout(): iterable
    {
        return [
            Layout::table('posts', [
                TD::make('id', 'ID')
                    ->sort()
                    ->width('80px'),
                TD::make('title', 'Заголовок')
                    ->sort()
                    ->filter()
                    ->render(fn(Post $post) => Link::make($post->title)
                        ->route('platform.post.edit', $post)),
                TD::make('status', 'Статус')
                    ->sort()
                    ->render(fn(Post $post) => $post->is_published 
                        ? '<span class="badge bg-success">Опубликована</span>'
                        : '<span class="badge bg-secondary">Черновик</span>'),
                TD::make('created_at', 'Создана')
                    ->sort()
                    ->render(fn(Post $post) => $post->created_at->format('d.m.Y H:i')),
            ]),
        ];
    }
}
```

## Экран редактирования

```bash
php artisan orchid:screen PostEditScreen
```

```php
// app/Orchid/Screens/PostEditScreen.php
namespace App\Orchid\Screens;
use App\Models\Post;
use Orchid\Screen\Screen;
use Orchid\Screen\Actions\Button;
use Orchid\Support\Facades\Layout;
use Orchid\Screen\Fields\Input;
use Orchid\Screen\Fields\TextArea;
use Orchid\Screen\Fields\Switcher;
use Orchid\Screen\Fields\Quill;
use Orchid\Screen\Fields\Upload;
use Orchid\Support\Facades\Toast;
use Illuminate\Http\Request;
class PostEditScreen extends Screen
{
    public ?Post $post = null;
    public function query(Post $post): iterable
    {
        return [
            'post' => $post,
        ];
    }
    public function name(): ?string
    {
        return $this->post->exists 
            ? 'Редактирование: ' . $this->post->title 
            : 'Создание статьи';
    }
    public function commandBar(): iterable
    {
        return [
            Button::make('Сохранить')
                ->icon('save')
                ->method('save'),
            Button::make('Удалить')
                ->icon('trash')
                ->method('remove')
                ->canSee($this->post->exists)
                ->confirm('Вы уверены, что хотите удалить статью?'),
        ];
    }
    public function layout(): iterable
    {
        return [
            Layout::rows([
                Input::make('post.title')
                    ->title('Заголовок')
                    ->required()
                    ->placeholder('Введите заголовок'),
                Input::make('post.slug')
                    ->title('URL (slug)')
                    ->placeholder('avtomaticheski-iz-zagolovka'),
                TextArea::make('post.excerpt')
                    ->title('Краткое описание')
                    ->rows(3),
                Quill::make('post.content')
                    ->title('Содержание'),
                Upload::make('post.image')
                    ->title('Изображение')
                    ->maxFiles(1)
                    ->acceptedFiles('image/*'),
                Switcher::make('post.is_published')
                    ->title('Опубликовать')
                    ->sendTrueOrFalse(),
            ]),
        ];
    }
    public function save(Post $post, Request $request): void
    {
        $data = $request->validate([
            'post.title' => 'required|string|max:255',
            'post.slug' => 'nullable|string|max:255',
            'post.excerpt' => 'nullable|string',
            'post.content' => 'nullable|string',
            'post.is_published' => 'boolean',
        ]);
        $post->fill($data['post']);
        if (empty($post->slug)) {
            $post->slug = \Str::slug($post->title);
        }
        $post->save();
        Toast::success('Статья сохранена');
    }
    public function remove(Post $post): void
    {
        $post->delete();
        Toast::info('Статья удалена');
    }
}
```

## Регистрация роутов

```php
// routes/platform.php
use App\Orchid\Screens\PostListScreen;
use App\Orchid\Screens\PostEditScreen;
Route::screen('posts', PostListScreen::class)
    ->name('platform.post.list');
Route::screen('posts/{post?}', PostEditScreen::class)
    ->name('platform.post.edit');
```

## Меню

```php
// app/Orchid/PlatformProvider.php
namespace App\Orchid;
use Orchid\Platform\Dashboard;
use Orchid\Platform\OrchidServiceProvider;
use Orchid\Screen\Actions\Menu;
class PlatformProvider extends OrchidServiceProvider
{
    public function menu(): array
    {
        return [
            Menu::make('Главная')
                ->icon('home')
                ->route('platform.main'),
            Menu::make('Статьи')
                ->icon('docs')
                ->route('platform.post.list')
                ->badge(fn() => Post::where('is_published', false)->count()),
            Menu::make('Пользователи')
                ->icon('people')
                ->route('platform.systems.users')
                ->permission('platform.systems.users'),
            Menu::make('Настройки')
                ->icon('settings')
                ->list([
                    Menu::make('Роли')
                        ->icon('shield')
                        ->route('platform.systems.roles'),
                ]),
        ];
    }
}
```

## Модель с Orchid traits

```php
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Orchid\Filters\Filterable;
use Orchid\Screen\AsSource;
use Orchid\Attachment\Attachable;
class Post extends Model
{
    use AsSource, Filterable, Attachable;
    protected $fillable = [
        'title',
        'slug', 
        'excerpt',
        'content',
        'is_published',
    ];
    protected $casts = [
        'is_published' => 'boolean',
    ];
    protected $allowedSorts = [
        'id',
        'title',
        'created_at',
    ];
    protected $allowedFilters = [
        'title',
    ];
}
```

**Не забудьте миграцию!**
```bash
php artisan make:migration create_posts_table
php artisan migrate
```

## Результат

За 30 минут мы получили:
- Список статей с сортировкой и пагинацией
- Форму создания и редактирования
- WYSIWYG-редактор
- Загрузку изображений
- Удаление с подтверждением
- Toast-уведомления
- Меню со счётчиком

## Итоги

| Компонент | Назначение |
|-----------|------------|
| Screen | Страница админки |
| Layout | Структура экрана |
| TD | Колонка таблицы |
| Fields | Поля форм |
| Actions | Кнопки и ссылки |
| Toast | Уведомления |

## Когда Orchid — правильный выбор

Стоит сказать прямо, потому что выбор админки определяет работу на годы вперёд.

**Подходит** для внутренних инструментов: панели управления контентом, административной части сервиса, интерфейсов для сотрудников. Экраны описываются кодом, значит живут в репозитории, проходят ревью и разворачиваются вместе с приложением — для командной работы это существенное преимущество перед настройкой через интерфейс.

**Не подходит** в качестве личного кабинета для клиентов. Админка — это админка: её внешний вид, поведение и логика прав рассчитаны на сотрудников. Попытка сделать из неё пользовательский интерфейс заканчивается борьбой с фреймворком.

**Подумайте дважды**, если проекту нужен сильно нестандартный интерфейс. Orchid хорош, пока вы работаете в его модели — экраны, слои, поля. Как только требуется что-то принципиально другое, объём кастомизации быстро превышает стоимость обычных контроллеров с Blade-шаблонами.

**И оцените связанность.** Экраны, поля, права и меню — всё это код, зависящий от конкретного пакета. Смена админки через два года будет означать переписывание всего этого слоя. Это нормальная плата за скорость разработки, но принимать её лучше осознанно.

## Следующие шаги

- Продвинутые layouts: вкладки, аккордеоны, модальные окна
- Фильтры и сортировка — вместе с индексами под них
- Собственные поля — когда встроенных действительно не хватает
- Права и роли — и понимание, что скрытая кнопка не равна закрытому действию