Set up modern PHP MVC project structure for GetYourBand platform

- Implemented clean MVC architecture with Router, Controller, and Model base classes
- Created database migrations for users, bands, bookings, reviews, and availability
- Set up Tailwind CSS with yellow color scheme and modern design
- Added Alpine.js for reactive JavaScript components
- Configured Vite for asset building and hot module replacement
- Created authentication and role-based middleware
- Implemented helper functions and configuration system
- Added comprehensive README with setup instructions
- Configured Apache with proper rewrite rules and security headers
- Set up Composer and npm package management with modern dependencies
This commit is contained in:
Claude
2025-12-02 21:31:08 +00:00
parent 798a2785e7
commit 143fe3d488
37 changed files with 2015 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
<?php
namespace App\Models;
use App\Core\Model;
class Band extends Model
{
protected string $table = 'bands';
protected array $fillable = [
'user_id',
'name',
'slug',
'description',
'genre',
'location',
'postal_code',
'price_min',
'price_max',
'member_count',
'phone',
'website',
'facebook',
'instagram',
'youtube',
'profile_image',
'cover_image',
'is_approved',
'is_active',
];
public function findBySlug(string $slug): ?array
{
return $this->first('slug', $slug);
}
public function search(array $filters): array
{
$sql = "SELECT * FROM {$this->table} WHERE is_approved = 1 AND is_active = 1";
$params = [];
if (!empty($filters['genre'])) {
$sql .= " AND genre = ?";
$params[] = $filters['genre'];
}
if (!empty($filters['location'])) {
$sql .= " AND (location LIKE ? OR postal_code LIKE ?)";
$params[] = "%{$filters['location']}%";
$params[] = "%{$filters['location']}%";
}
if (!empty($filters['price_max'])) {
$sql .= " AND price_min <= ?";
$params[] = $filters['price_max'];
}
if (!empty($filters['q'])) {
$sql .= " AND MATCH(name, description, genre) AGAINST (? IN NATURAL LANGUAGE MODE)";
$params[] = $filters['q'];
}
$sql .= " ORDER BY average_rating DESC, total_reviews DESC";
return $this->query($sql, $params);
}
public function incrementViews(int $id): bool
{
return $this->execute(
"UPDATE {$this->table} SET view_count = view_count + 1 WHERE id = ?",
[$id]
);
}
public function updateRating(int $bandId): void
{
$sql = "
UPDATE bands
SET average_rating = (
SELECT AVG(rating)
FROM reviews
WHERE band_id = ? AND is_approved = 1
),
total_reviews = (
SELECT COUNT(*)
FROM reviews
WHERE band_id = ? AND is_approved = 1
)
WHERE id = ?
";
$this->execute($sql, [$bandId, $bandId, $bandId]);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use App\Core\Model;
class User extends Model
{
protected string $table = 'users';
protected array $fillable = [
'email',
'password',
'name',
'role',
'verification_token',
'email_verified_at',
'is_active',
];
public function findByEmail(string $email): ?array
{
return $this->first('email', $email);
}
public function verifyEmail(string $token): bool
{
$user = $this->first('verification_token', $token);
if (!$user) {
return false;
}
return $this->update($user['id'], [
'email_verified_at' => date('Y-m-d H:i:s'),
'verification_token' => null,
]);
}
public static function hashPassword(string $password): string
{
return password_hash($password, PASSWORD_BCRYPT);
}
public static function verifyPassword(string $password, string $hash): bool
{
return password_verify($password, $hash);
}
}