Ви запускаєте інтернет-магазин з каталогом у 10 000 товарів. Стандартний LAMP-стек справляється, але через місяць сторінки завантажуються по 3 секунди, а додавання нового розділу вимагає переписування чотирьох контролерів. Кожен запит до бази тягне десятки пов'язаних таблиць — N+1 проблема сповільнює роботу. Yii2 вирішує це за допомогою жадібного завантаження та кешування схеми. Ми пропонуємо розробку бекенду на Yii2 під ключ — рішення, яке прискорює розробку вдвічі та дозволяє легко масштабувати функціонал. Наші інженери мають 10+ років досвіду з Yii2 і гарантують стабільну роботу. Нижче — реальна історія переходу з моноліту на модульний REST API.
Які проблеми вирішує бекенд на Yii2?
Перша — N+1 запити. При вибірці списку товарів стандартний підхід робить запит для кожного пов'язаного елемента. Yii2 вирішує це через жадібне завантаження: Product::find()->with('category')->all(). Друга — відсутність прав доступу. Вбудований RBAC з ієрархією ролей та кастомними правилами позбавляє від саморобної реалізації. Третя — повільна робота без кешу. Yii2 підтримує кеш схеми БД, фрагментний кеш та HTTP-кеш, знижуючи навантаження на базу.
Нещодавно ми переносили монолітний додаток на Yii2 REST API. Клієнт мав 50+ таблиць, потрібно було створити модульну архітектуру. Ми використали Gii для генерації моделей та CRUD-контролерів, налаштували кеш схеми БД через Redis, RBAC з кастомними правилами та JWT. Строк розробки скоротився на 30%. Код вийшов одноманітним, що спростило підтримку. За словами клієнта: Перехід на Yii2 скоротив час виведення нових функцій на 40%.
Чому Yii2 швидший за Laravel?
Yii2 використовує кешування схеми БД, зменшуючи кількість запитів до бази. За нашими тестами, стандартний CRUD на Yii2 виконується на 40% швидше, ніж на Laravel. Gii генерує код без зайвих залежностей, знижуючи час виконання. У таблиці — наочне порівняння.
| Критерій | Yii2 | Laravel |
|---|---|---|
| Швидкість роботи | Висока (кеш схеми) | Середня |
| Генерація коду | Gii (вбудований) | Artisan + пакети |
| RBAC | З коробки | Через пакети |
| Крива навчання | Середня | Низька |
Як Yii2 допомагає уникнути N+1 запитів?
Yii2 надає жадібне завантаження через with() і зв'язки. Наприклад, Product::find()->with('category')->all() виконує 2 запити замість N+1. Ми завжди використовуємо це в проектах, що критично для швидкодії каталогів. Для складних сценаріїв застосовуємо joinWith().
Що таке Gii і як він прискорює розробку?
Gii — це генератор коду, вбудований у Yii2. Він створює моделі, CRUD-контролери та REST-ендпоінти за кілька команд. Для каталогу з 20 сутностями вся базова структура генерується за один день, економлячи 30–40% часу на рутинних операціях.
Як налаштувати кешування в Yii2?
Yii2 підтримує кілька типів кешу: кеш схеми БД, фрагментний кеш та HTTP-кеш. Для зберігання використовується Redis або Memcached. Налаштування компонента cache в конфігурації включає кеш схеми та фрагментів. Це знижує навантаження на базу і прискорює відповіді до 50%.
Ключові компоненти архітектури
Конфігурація додатку
// config/web.php
return [
'id' => 'my-app',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log', 'queue'],
'components' => [
'db' => [
'class' => yii\db\Connection::class,
'dsn' => 'pgsql:host=localhost;dbname=myapp',
'username' => getenv('DB_USER'),
'password' => getenv('DB_PASS'),
'charset' => 'utf8',
'enableSchemaCache' => true,
'schemaCacheDuration' => 3600,
],
'cache' => [
'class' => yii\redis\Cache::class,
'redis' => ['hostname' => 'localhost', 'port' => 6379],
],
'user' => [
'identityClass' => app\models\User::class,
'enableAutoLogin' => false,
'enableSession' => false,
],
'queue' => [
'class' => yii\queue\redis\Queue::class,
'redis' => 'redis',
'channel' => 'queue',
],
],
'modules' => [
'api' => [
'class' => app\modules\api\Module::class,
'version' => 'v1',
],
],
];
ActiveRecord
namespace app\models;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
use yii\behaviors\SluggableBehavior;
class Product extends ActiveRecord
{
public static function tableName(): string { return 'products'; }
public function behaviors(): array
{
return [
TimestampBehavior::class,
['class' => SluggableBehavior::class, 'attribute' => 'name', 'slugAttribute' => 'slug', 'ensureUnique' => true],
];
}
public function rules(): array
{
return [
[['name', 'price'], 'required'],
['name', 'string', 'min' => 2, 'max' => 255],
['price', 'number', 'min' => 0.01],
['category_id', 'exist', 'targetClass' => Category::class, 'targetAttribute' => 'id'],
['attributes', 'safe'],
['is_active', 'boolean'],
['is_active', 'default', 'value' => true],
];
}
public function getCategory(): ActiveQuery { return $this->hasOne(Category::class, ['id' => 'category_id']); }
public function getVariants(): ActiveQuery { return $this->hasMany(ProductVariant::class, ['product_id' => 'id']); }
public static function find(): ProductQuery { return new ProductQuery(static::class); }
}
class ProductQuery extends ActiveQuery
{
public function active(): static { return $this->andWhere(['is_active' => true]); }
public function byCategory(int $categoryId): static { return $this->andWhere(['category_id' => $categoryId]); }
}
REST API через yii\rest
Yii2 має вбудовану підтримку REST API:
namespace app\modules\api\controllers;
use yii\rest\ActiveController;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\Cors;
class ProductController extends ActiveController
{
public string $modelClass = Product::class;
public function behaviors(): array
{
$behaviors = parent::behaviors();
$behaviors['corsFilter'] = ['class' => Cors::class, 'cors' => ['Origin' => explode(',', getenv('ALLOWED_ORIGINS') ?: '*'), 'Access-Control-Allow-Credentials' => true]];
$behaviors['authenticator'] = ['class' => HttpBearerAuth::class, 'except' => ['index', 'view']];
return $behaviors;
}
public function actions(): array
{
$actions = parent::actions();
$actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider'];
return $actions;
}
public function prepareDataProvider(): ActiveDataProvider
{
$params = Yii::$app->request->queryParams;
return (new ProductSearch())->search($params);
}
public function actionFeatured(): array
{
return Product::find()->active()->orderBy(['views' => SORT_DESC])->limit(10)->all();
}
}
JWT аутентифікація
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use yii\filters\auth\AuthMethod;
class JwtAuth extends AuthMethod
{
public function authenticate($user, $request, $response)
{
$authHeader = $request->getHeaders()->get('Authorization');
if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) return null;
try {
$token = substr($authHeader, 7);
$decoded = JWT::decode($token, new Key(getenv('JWT_SECRET'), 'HS256'));
return User::findOne($decoded->sub);
} catch (\Exception $e) {
throw new UnauthorizedHttpException('Invalid token');
}
}
}
Gii — генератор коду
Gii автоматично створює моделі, CRUD та REST-контролери:
php yii gii/model --tableName=products --modelClass=Product
php yii gii/crud --modelClass=Product --controllerClass=ProductController
php yii gii/rest-controller --modelClass=Product
Gii економить 30–40% часу на стандартних операціях. Наприклад, для каталогу з 20 сутностями вся базова структура генерується за один день.
Процес і терміни розробки
| Етап | Термін |
|---|---|
| Аналітика та архітектура | 2–5 днів |
| Проектування схеми БД та моделей | 3–7 днів |
| Реалізація REST API та бізнес-логіки | 1–3 тижні |
| Налаштування аутентифікації та RBAC | 3–5 днів |
| Кешування та черги | 2–4 дні |
| Тестування та налагодження | 5–10 днів |
| Деплой та документація | 3–5 днів |
Типовий проект займає 4–8 тижнів. Для прискорення використовуємо Gii та готові шаблони. Зв'яжіться з нами для точної оцінки вашого проекту.
Що входить у розробку?
- Аналіз вимог та архітектура
- Моделі та міграції
- REST API з документацією (OpenAPI/Swagger)
- RBAC та аутентифікація (JWT, OAuth)
- Кешування (Redis, Memcached) та черги (RabbitMQ, Redis)
- Деплой на staging та production
- Інструкція з експлуатації
- Навчання команди (2–5 годин)
- Пост-релізна підтримка 1 місяць
Готові почати? Замовте безкоштовну консультацію, і ми підготуємо детальну пропозицію для вашого проекту. Зв'яжіться з нашими інженерами через форму зворотного зв'язку для оперативної відповіді.







