Compare commits

...

3 Commits

Author SHA1 Message Date
anthony 4ea8ce6569 added tracks and perfomers tables, fixed queries 2026-06-17 12:04:26 +03:00
anthony 23b5b4a9b2 fixed routes and phone numbers in places list 2026-06-17 08:23:54 +00:00
Антон Михайлов 3a7e8c30ac updated env.example and Makefile 2026-06-17 10:53:31 +03:00
12 changed files with 220 additions and 17 deletions
+3 -3
View File
@@ -21,11 +21,11 @@ LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug LOG_LEVEL=debug
DB_CONNECTION=mysql DB_CONNECTION=mysql
DB_HOST=127.0.0.1 DB_HOST=db
DB_PORT=3306 DB_PORT=3306
DB_DATABASE=ledstarband DB_DATABASE=ledstarband
DB_USERNAME=root DB_USERNAME=ledstarband
DB_PASSWORD= DB_PASSWORD=AnotherOneBitesTheDust
SESSION_DRIVER=database SESSION_DRIVER=database
SESSION_LIFETIME=120 SESSION_LIFETIME=120
+1
View File
@@ -15,6 +15,7 @@ down:
# Установка зависимостей Composer внутри контейнера app # Установка зависимостей Composer внутри контейнера app
install: install:
$(DOCKER_COMPOSE) exec app composer install $(DOCKER_COMPOSE) exec app composer install
$(DOCKER_COMPOSE) exec app php artisan key:generate
# Запуск миграций базы данных внутри контейнера app # Запуск миграций базы данных внутри контейнера app
migrate: migrate:
+6 -6
View File
@@ -9,12 +9,12 @@ class PlaylistLoader
public function getPlaylist(): array public function getPlaylist(): array
{ {
$data = Track::select( $data = Track::select(
"Track.Name as Track", "tracks.name as Track",
"Performer.Name as Performer" "performers.name as Performer"
)->join('Performer', function ($join) { )->join('performers', function ($join) {
$join->on('Performer.Id', "=", "Track.Performer") $join->on('performers.id', "=", "tracks.performer_id")
->where('Performer.DeleteDate', NULL); ->where('performers.deleted_at', NULL);
})->orderBy('Performer')->get(); })->orderBy('performer_id')->get();
return $data ? $data->toArray() : []; return $data ? $data->toArray() : [];
} }
+24
View File
@@ -4,6 +4,7 @@ namespace App\Models\ORM;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Place extends Model class Place extends Model
{ {
@@ -19,4 +20,27 @@ class Place extends Model
protected $fillable = [ protected $fillable = [
'name','gps', 'phone', 'description', 'url', 'address' 'name','gps', 'phone', 'description', 'url', 'address'
]; ];
protected function formattedPhone(): Attribute
{
return Attribute::make(
get: function () {
// Берем оригинальное значение из базы (например: 79991110101)
$phone = $this->phone;
// Если номер начинается с 8 или 7 и в нем 11 цифр
if (strlen($phone) === 11) {
return '+7 (' . substr($phone, 1, 3) . ') ' . substr($phone, 4, 3) . '-' . substr($phone, 7, 2) . '-' . substr($phone, 9, 2);
}
// Если номер записан без семерки (всего 10 цифр, например: 9991110101)
if (strlen($phone) === 10) {
return '+7 (' . substr($phone, 0, 3) . ') ' . substr($phone, 3, 3) . '-' . substr($phone, 6, 2) . '-' . substr($phone, 8, 2);
}
// Если формат странный (например, городской короткий), выводим как есть
return $phone;
}
);
}
} }
+5 -5
View File
@@ -9,11 +9,11 @@ class Track extends Model
{ {
use SoftDeletes; use SoftDeletes;
const DELETED_AT = 'DeleteDate'; const DELETED_AT = 'deleted_at';
const UPDATED_AT = 'UpdatedDate'; const UPDATED_AT = 'updated_at';
const CREATED_AT = 'DateOfCreation'; const CREATED_AT = 'created_at';
protected $primaryKey = 'Id'; protected $primaryKey = 'Id';
protected $table = 'Track'; protected $table = 'tracks';
protected $fillable = ['Name', 'Length']; protected $fillable = [ 'name', 'length' ];
} }
@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('performers', function (Blueprint $table) {
$table->id(); // id (bigint unsigned, auto-increment)
$table->string('name'); // name (имя исполнителя / название группы)
$table->timestamps(); // created_at и updated_at
$table->softDeletes(); // deleted_at (для мягкого удаления)
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('performers');
}
};
@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tracks', function (Blueprint $table) {
$table->id(); // id (bigint unsigned, auto-increment)
$table->string('name'); // name (varchar 255)
$table->unsignedInteger('length'); // length (длительность трека в секундах)
// performer_id (внешний ключ, связываем с таблицей performers)
$table->foreignId('performer_id')
->constrained('performers')
->onDelete('cascade'); // если удалить исполнителя, удалятся и его треки
$table->timestamps(); // created_at и updated_at
$table->softDeletes(); // deleted_at (для мягкого удаления)
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('tracks');
}
};
+3 -1
View File
@@ -25,7 +25,9 @@ class DatabaseSeeder extends Seeder
$this->call([ $this->call([
UserSeeder::class, UserSeeder::class,
EventSeeder::class, EventSeeder::class,
PlaceSeeder::class PlaceSeeder::class,
PerformerSeeder::class,
TrackSeeder::class
]); ]);
} }
} }
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class PerformerSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// Массив исполнителей для вставки
$performers = [
['name' => 'Deep Purple'],
['name' => 'Rainbow'],
['name' => 'DIO'],
['name' => 'Black Sabbath'],
];
// Добавляем к каждой записи метки времени, чтобы поля не были пустыми
$now = Carbon::now();
foreach ($performers as &$performer) {
$performer['created_at'] = $now;
$performer['updated_at'] = $now;
}
// Чистим таблицу перед заполнением (опционально, чтобы не дублировать)
// DB::table('performers')->truncate();
// Массовая вставка в базу данных
DB::table('performers')->insert($performers);
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class TrackSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// SQL-запрос для проверки существования таблицы
$tableExists = DB::select("SHOW TABLES LIKE 'performers'");
if (empty($tableExists)) {
$this->command->error("Таблица 'performers' отсутствует в базе данных!");
}
// Очищаем таблицу перед заполнением
DB::table('tracks')->truncate();
// 1. Получаем ID исполнителей из базы по их именам
$rainbowId = DB::table('performers')->where('name', 'Rainbow')->value('id');
$blackSabbathId = DB::table('performers')->where('name', 'Black Sabbath')->value('id');
$dioId = DB::table('performers')->where('name', 'DIO')->value('id');
// Если сидер запускается отдельно и исполнителей нет, остановим процесс
if (!$rainbowId || !$blackSabbathId || !$dioId) {
$this->command->error('Исполнители не найдены в базе данных. Сначала запустите PerformerSeeder!');
return;
}
// 2. Список треков со связями
$tracksData = [
// Rainbow
['name' => 'Gates Of Babylon', 'performer_id' => $rainbowId],
['name' => 'Lady Of The Lake', 'performer_id' => $rainbowId],
['name' => 'Tarot Woman', 'performer_id' => $rainbowId],
['name' => 'Long Live Rock\'n\'Roll', 'performer_id' => $rainbowId],
['name' => 'Man On The Silver Mountain', 'performer_id' => $rainbowId],
['name' => 'Kill The King', 'performer_id' => $rainbowId],
['name' => 'Can\'t Let You Go', 'performer_id' => $rainbowId],
['name' => 'Rainbow\'s Eyes', 'performer_id' => $rainbowId],
['name' => 'Sixteen Century Greensleeves', 'performer_id' => $rainbowId],
// Black Sabbath
['name' => 'Neon Knights', 'performer_id' => $blackSabbathId],
['name' => 'Children Of The Sea', 'performer_id' => $blackSabbathId],
['name' => 'Heaven And Hell', 'performer_id' => $blackSabbathId],
// DIO
['name' => 'Holy Diver', 'performer_id' => $dioId],
['name' => 'Last In Line', 'performer_id' => $dioId],
['name' => 'All The Fools Sailed Away', 'performer_id' => $dioId],
['name' => 'One Night In The City', 'performer_id' => $dioId],
['name' => 'Straight Through The Heart', 'performer_id' => $dioId],
];
// 3. Подготовка данных (добавляем случайную длину и метки времени)
$now = Carbon::now();
foreach ($tracksData as &$track) {
$track['length'] = rand(180, 420); // Генерируем длину трека от 3 до 7 минут (в секундах)
$track['created_at'] = $now;
$track['updated_at'] = $now;
}
// 4. Массовая вставка в базу данных
DB::table('tracks')->insert($tracksData);
}
}
+1 -1
View File
@@ -44,7 +44,7 @@
<td><a class="text-indigo-600 hover:text-indigo-900 transition-colors" <td><a class="text-indigo-600 hover:text-indigo-900 transition-colors"
href="{{ $place->url }}">{{ $place->name }}</a></td> href="{{ $place->url }}">{{ $place->name }}</a></td>
<td>{{ $place->address ?? '—' }}</td> <td>{{ $place->address ?? '—' }}</td>
<td>{{ $place->phone }}</td> <td>{{ $place->formattedPhone }}</td>
<td class="text-center"> <td class="text-center">
<a href="#" title="Показать на карте" <a href="#" title="Показать на карте"
class="text-gray-500 hover:text-blue-600 transition-colors flex items-center justify-center" class="text-gray-500 hover:text-blue-600 transition-colors flex items-center justify-center"
+1 -1
View File
@@ -15,10 +15,10 @@ use App\Http\Controllers\VkBotController;
Route::middleware('auth') Route::middleware('auth')
->group(function () { ->group(function () {
Route::get('/places/create', [PlacesController::class, 'create'])->name('places.create');
Route::get('/places', [PlacesController::class, 'index'])->name('places.index'); Route::get('/places', [PlacesController::class, 'index'])->name('places.index');
Route::get('/places/{id}', [PlacesController::class, 'edit'])->name('places.edit'); Route::get('/places/{id}', [PlacesController::class, 'edit'])->name('places.edit');
Route::put('/places/{id}', [PlacesController::class, 'update'])->name('places.update'); Route::put('/places/{id}', [PlacesController::class, 'update'])->name('places.update');
Route::get('/places/create', [PlacesController::class, 'create'])->name('places.create');
Route::post('/places/store', [PlacesController::class, 'store'])->name('places.store'); Route::post('/places/store', [PlacesController::class, 'store'])->name('places.store');
Route::delete('/places/{id}', [PlacesController::class, 'delete'])->name('places.delete'); Route::delete('/places/{id}', [PlacesController::class, 'delete'])->name('places.delete');
}); });