Skip to content

Smart Relations (Умные связи)

Концепция

Технологии и интеграции связаны с категориями услуг и отраслями через pivot-таблицы. Контроллеры ВСЕГДА используют pivot-связи модели, а не прямые запросы ко всем записям.

Pivot-таблицы

ТаблицаСвязьСтрок
technology_service_categoryTechnology ↔ ServiceCategory~414
industry_technologyTechnology ↔ Industry~372
integration_service_categoryIntegration ↔ ServiceCategory~113
integration_industryIntegration ↔ Industry~242
integration_technologyIntegration ↔ Technology~144
service_technologyService ↔ Technologyvaries
article_technologyArticle ↔ Technology~18
article_service_categoryArticle ↔ ServiceCategory~89
case_study_technologyCaseStudy ↔ Technology~24
package_technologyPackage ↔ Technology~45

Покрытие: 123/123 технологий и 50/50 интеграций имеют связи с категориями И отраслями.

Модели — pivot relations

Technology

php
$technology->serviceCategories()  // belongsToMany via technology_service_category
$technology->industries()          // belongsToMany via industry_technology (with is_primary, sort_order)
$technology->integrations()        // belongsToMany via integration_technology
$technology->services()            // belongsToMany via service_technology

Integration

php
$integration->serviceCategories()  // belongsToMany via integration_service_category
$integration->industries()          // belongsToMany via integration_industry
$integration->technologies()        // belongsToMany via integration_technology

Контроллеры — правила

show() методы

php
// ПРАВИЛЬНО — из pivot
$categories = $technology->serviceCategories()->has('services')->orderBy('sort_order')->get();
$industries = $technology->industries()->whereNotNull('seo_slug')->orderBy('name')->get();

// НЕПРАВИЛЬНО — все подряд
$categories = ServiceCategory::all();
$industries = Industry::all();

withCategory() / withIndustry() методы

php
// ПРАВИЛЬНО — другие категории/отрасли этой же сущности из pivot
$otherCategories = $technology->serviceCategories()
    ->where('service_categories.id', '!=', $category->id)
    ->has('services')
    ->orderBy('sort_order')
    ->get();

$otherIndustries = $integration->industries()
    ->where('industries.id', '!=', $industry->id)
    ->whereNotNull('seo_slug')
    ->orderBy('name')
    ->get();

Blade-шаблоны

На страницах show рендерится плоский список из pivot (не иерархия root→children):

blade
@foreach($industries as $industry)
    @if($industry->seo_slug)
        <a href="{{ route('technologies.with-industry', [$brand, $industry]) }}">
            {{ $industry->name }}
        </a>
    @endif
@endforeach

Не использовать $rootIndustry->children — это вызовет lazy loading ВСЕХ дочерних из БД.

Сидеры

Порядок в DatabaseSeeder важен:

  1. GranularRelationsSeeder — основные связи (integration_technology, article_, case_study_, package_*, integration_industry)
  2. SmartRelationsSeeder — дополнения tech↔category, tech↔industry, int↔category

Оба используют insertOrIgnore() — идемпотентны, безопасно запускать повторно.

Добавление новой технологии/интеграции

  1. Создать запись в соответствующей таблице (migration/seeder/admin)
  2. Добавить маппинг в SmartRelationsSeeder:
    • seedTechCategories() — slug технологии → массив slug'ов категорий
    • seedTechIndustries() — slug технологии → массив slug'ов отраслей
    • seedMissingIntegrationCategories() — slug интеграции → массив slug'ов категорий
  3. Запустить: docker exec gulaev-app php artisan db:seed --class=SmartRelationsSeeder

Anti-patterns

ПаттернПроблемаРешение
ServiceCategory::all() в контроллереПоказывает ВСЕ категории, не связанные$model->serviceCategories()
Industry::all() в контроллереПоказывает ВСЕ отрасли$model->industries()
Хардкод type→industry в контроллереСвязи не в БД, невозможно управлятьPivot-таблица + Filament
$rootIndustry->children в BladeN+1, грузит ВСЕ дочерниеПлоский список из pivot
Новая сущность без маппингаПустые секции на страницеДобавить в SmartRelationsSeeder

Внутренняя база знаний студии