/
delphin
/
CatRW
Обзор
Документация
Войти
/
delphin
/
CatRW
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
api/ModelsService.php
291 строка
11 KB
delphin
start project
02 мар 2026, 09:14
Верифицирован
02 мар 2026, 09:14
4b0ee03
Код
Авторство
О чём код?
<?php // /api/ModelsService.php - ПОЛНАЯ ВЕРСИЯ С CRUD class ModelsService { public function getModels($filters = [], $page = 1, $perPage = 20) { $sql = "SELECT SQL_CALC_FOUND_ROWS cm.*, m.name as manufacturer_name, m.country_code as manufacturer_country, rc.name as railway_company_name, rc.code as railway_company_code FROM catalog_models cm LEFT JOIN manufacturers m ON cm.manufacturer_id = m.id LEFT JOIN railway_companies rc ON cm.railway_company = rc.id -- <-- ИЗМЕНЕНИЕ: railway_company вместо railway_company_id WHERE 1=1"; $params = []; // Добавляем фильтры $filterIndex = 0; foreach ($filters as $key => $value) { if ($value !== null && $value !== '') { switch ($key) { case 'railway_company': // <-- ТЕПЕРЬ ПРИНИМАЕТ ID $sql .= " AND cm.railway_company = ?"; $params[] = (int)$value; break; case 'manufacturer_id': $sql .= " AND cm.manufacturer_id = ?"; $params[] = (int)$value; break; case 'type_code': $sql .= " AND cm.type_code = ?"; $params[] = $value; break; case 'scale_code': $sql .= " AND cm.scale_code = ?"; $params[] = $value; break; case 'era_code': $sql .= " AND cm.era_code = ?"; $params[] = $value; break; case 'status': $sql .= " AND cm.status = ?"; $params[] = $value; break; case 'country_code': $sql .= " AND cm.country_code = ?"; $params[] = strtoupper($value); break; } } } // Сортировка $sql .= " ORDER BY cm.id DESC"; // Пагинация $offset = ($page - 1) * $perPage; $sql .= " LIMIT ? OFFSET ?"; $params[] = $perPage; $params[] = $offset; // Выполняем запрос $models = Database::select($sql, $params); // Получаем общее количество $totalResult = Database::selectOne("SELECT FOUND_ROWS() as total"); $total = $totalResult['total'] ?? 0; return [ 'models' => $models, 'total' => $total, 'page' => $page, 'perPage' => $perPage, 'pages' => ceil($total / $perPage) ]; } public function getModel($id) { return Database::selectOne(" SELECT cm.*, m.name as manufacturer_name, m.country_code as manufacturer_country FROM catalog_models cm LEFT JOIN manufacturers m ON cm.manufacturer_id = m.id WHERE cm.id = ? ", [$id]); } public function addModel($data) { // Валидация if (empty($data['name'])) { throw new Exception("Название обязательно"); } if (empty($data['type_code'])) { throw new Exception("Тип модели обязателен"); } if (empty($data['manufacturer_id'])) { throw new Exception("Производитель обязателен"); } // Очистка данных $cleanData = [ 'name' => trim($data['name']), 'type_code' => trim($data['type_code']), 'subtype_code' => !empty($data['subtype_code']) ? trim($data['subtype_code']) : null, 'scale_code' => !empty($data['scale_code']) ? trim($data['scale_code']) : 'H0', 'era_code' => !empty($data['era_code']) ? trim($data['era_code']) : null, 'manufacturer_id' => (int)$data['manufacturer_id'], 'railway_company' => !empty($data['railway_company']) ? (int)$data['railway_company'] : null, // <-- ИЗМЕНЕНИЕ: INT 'model_number' => !empty($data['model_number']) ? trim($data['model_number']) : null, 'road_number' => !empty($data['road_number']) ? trim($data['road_number']) : null, 'country_code' => !empty($data['country_code']) ? strtoupper(trim($data['country_code'])) : null, 'length_mm' => !empty($data['length_mm']) ? (float)$data['length_mm'] : null, 'weight_gr' => !empty($data['weight_gr']) ? (float)$data['weight_gr'] : null, 'coupling_code' => !empty($data['coupling_code']) ? trim($data['coupling_code']) : null, 'has_dcc_decoder' => !empty($data['has_dcc_decoder']) ? 1 : 0, 'has_sound' => !empty($data['has_sound']) ? 1 : 0, 'has_lights' => !empty($data['has_lights']) ? 1 : 0, 'rec_price' => !empty($data['rec_price']) ? (float)$data['rec_price'] : null, 'currency_code' => !empty($data['currency_code']) ? trim($data['currency_code']) : 'EUR', 'description' => !empty($data['description']) ? trim($data['description']) : null, 'prototype_info' => !empty($data['prototype_info']) ? trim($data['prototype_info']) : null, 'status' => !empty($data['status']) ? trim($data['status']) : 'draft', 'created_by' => !empty($data['created_by']) ? (int)$data['created_by'] : null ]; return Database::insert('catalog_models', $cleanData); } public function updateModel($id, $data) { // Проверяем существование $model = $this->getModel($id); if (!$model) { throw new Exception("Модель не найдена"); } // Очистка данных $cleanData = []; $fields = [ 'name', 'type_code', 'subtype_code', 'scale_code', 'era_code', 'manufacturer_id', 'railway_company', 'model_number', 'road_number', 'country_code', 'length_mm', 'weight_gr', 'coupling_code', 'has_dcc_decoder', 'has_sound', 'has_lights', 'rec_price', 'currency_code', 'description', 'prototype_info', 'status' ]; foreach ($fields as $field) { if (isset($data[$field])) { if (in_array($field, ['length_mm', 'weight_gr', 'rec_price'])) { $cleanData[$field] = !empty($data[$field]) ? (float)$data[$field] : null; } elseif (in_array($field, ['manufacturer_id', 'railway_company'])) { // <-- railway_company тоже INT $cleanData[$field] = !empty($data[$field]) ? (int)$data[$field] : null; } elseif (in_array($field, ['has_dcc_decoder', 'has_sound', 'has_lights'])) { $cleanData[$field] = !empty($data[$field]) ? 1 : 0; } else { $cleanData[$field] = !empty($data[$field]) ? trim($data[$field]) : null; } } } if (empty($cleanData)) { throw new Exception("Нет данных для обновления"); } return Database::update('catalog_models', $cleanData, 'id = :id', ['id' => $id]); } public function deleteModel($id) { $model = $this->getModel($id); if (!$model) { throw new Exception("Модель #$id не найдена"); } // Проверяем, есть ли модель в коллекциях $collectionsCount = Database::selectOne( "SELECT COUNT(*) as cnt FROM personal_collections WHERE catalog_model_id = ?", [$id] ); if ($collectionsCount && $collectionsCount['cnt'] > 0) { // Не удаляем, а архивируем Database::update( 'catalog_models', ['status' => 'archived'], 'id = ?', [$id] ); return [ 'type' => 'archived', 'message' => 'Модель архивирована (используется в коллекциях)' ]; } // Удаляем модель Database::delete('catalog_models', 'id = ?', [$id]); return [ 'type' => 'deleted', 'message' => 'Модель удалена' ]; } public function search($query) { if (empty($query)) { return $this->getModels([], 1, 50)['models']; } return Database::select(" SELECT cm.*, m.name as manufacturer_name FROM catalog_models cm LEFT JOIN manufacturers m ON cm.manufacturer_id = m.id WHERE cm.name LIKE ? OR cm.model_number LIKE ? OR cm.road_number LIKE ? OR m.name LIKE ? ORDER BY cm.name LIMIT 50 ", [ "%$query%", "%$query%", "%$query%", "%$query%" ]); } public function getStats() { return Database::selectOne(" SELECT COUNT(*) as total_models, SUM(CASE WHEN status='published' THEN 1 ELSE 0 END) as published, SUM(CASE WHEN status='draft' THEN 1 ELSE 0 END) as draft, SUM(CASE WHEN status='archived' THEN 1 ELSE 0 END) as archived, COUNT(DISTINCT scale_code) as scales_count, COUNT(DISTINCT type_code) as types_count, COUNT(DISTINCT manufacturer_id) as manufacturers_count FROM catalog_models "); } public function getScales() { return Database::select(" SELECT DISTINCT scale_code FROM catalog_models ORDER BY scale_code "); } public function getTypes() { return Database::select(" SELECT DISTINCT type_code FROM catalog_models ORDER BY type_code "); } public function getSubtypes($type = null) { if ($type) { return Database::select(" SELECT DISTINCT subtype_code FROM catalog_models WHERE type_code = ? ORDER BY subtype_code ", [$type]); } return Database::select(" SELECT DISTINCT subtype_code FROM catalog_models ORDER BY subtype_code "); } public function getEras() { return Database::select(" SELECT DISTINCT era_code FROM catalog_models WHERE era_code IS NOT NULL ORDER BY era_code "); } } ?>