Database Models & Relationships Documentation
Table of Contents
- Overview
- Core Models
- Event Management Models
- User Management Models
- Payment & Order Models
- Ranking Models
- Merchandise Models
- Communication Models
- Configuration Models
- Model Relationships
- Model Scopes & Accessors
- Database Migrations
Overview
The event management system uses Laravel’s Eloquent ORM with a well-structured database design. The models are organized into logical groups and include proper relationships, scopes, and accessors for efficient data handling.Core Models
Evento (Event)
The central model representing events in the system.class Evento extends Model
{
const STATE_ACTIVE = true;
const STATE_INACTIVE = false;
const TABLE_NAME = 'eventos';
protected $fillable = [
'name',
'description',
'ciudad',
'pais',
'pagina_web',
'date_from',
'date_to',
'participants',
'enrolled',
'category',
'date_from_register',
'date_to_register',
'facebook',
'instagram',
'phone_number',
'x',
'organizador_id',
'created_by',
'email',
'latitude',
'longitude',
'address',
'json_forms',
'flag_active',
'general_aspect',
'url_image',
'timezone'
];
protected $casts = [
'tarifas' => 'array',
'general_aspect' => 'array',
'date_from' => 'datetime',
'date_to' => 'datetime',
'date_from_register' => 'datetime',
'date_to_register' => 'datetime',
'json_maps' => 'array',
'json_forms' => 'array',
];
protected $appends = [
'created_at_format',
'category_name',
'date_from_format',
'date_from_format_input',
'date_to_format',
'date_to_format_input',
'date_from_register_format',
'date_from_register_format_input',
'date_to_register_format',
'date_to_register_format_input',
'tarifas_full'
];
}
Relationships
// Event belongs to an organizer
public function organizador() {
return $this->belongsTo(Organizador::class, 'organizador_id');
}
// Event belongs to a category
public function category() {
return $this->belongsTo(CategoriaDeEvento::class, 'category');
}
// Event has many registrations
public function eventoXUsuario() {
return $this->hasMany(EventoXUsuario::class, 'evento_id');
}
// Event has many rankings
public function rankings() {
return $this->hasMany(Ranking::class, 'evento_id')
->whereNull('deleted_at');
}
// Event has many event rankings
public function eventRankings() {
return $this->hasMany(EventRanking::class, 'evento_id')
->whereNull('deleted_at');
}
// Event has many bookings
public function booking() {
return $this->hasMany(Booking::class, 'evento_id')
->whereNull('deleted_at');
}
// Event has many registrations with user data
public function eventoXUsuarioFull() {
return $this->hasMany(EventoXUsuario::class, 'evento_id')
->with('usuario');
}
// Event has many catalogs (merchandise)
public function catalogos() {
return $this->hasMany(Catalogo::class, 'evento_id');
}
Accessors & Mutators
// Get formatted created date
public function getCreatedAtFormatAttribute() {
if (!is_null($this->created_at)) {
return $this->created_at->format("d/m/Y H:i:s");
}
return "--";
}
// Get formatted start date
public function getDateFromFormatAttribute() {
if (!is_null($this->date_from)) {
return $this->date_from->format("d/m/Y H:i:s");
}
return "--";
}
// Get formatted start date for input fields
public function getDateFromFormatInputAttribute() {
if (!is_null($this->date_from)) {
return $this->date_from->format("Y-m-d H:i");
}
return "--";
}
// Get category name
public function getCategoryNameAttribute() {
if ($this->categoryObj) {
return $this->categoryObj->name;
}
return "--";
}
// Get full tariff objects
public function getTarifasFullAttribute() {
$tarifas = [];
try {
if (!is_null($this->tarifas)) {
$tarifasIds = is_string($this->tarifas) ?
json_decode($this->tarifas, true) : $this->tarifas;
if (is_array($tarifasIds) && !empty($tarifasIds)) {
$tarifa = TarifaDeEvento::whereNull(TarifaDeEvento::TABLE_NAME . '.deleted_at')
->whereIn('id', $tarifasIds)
->get();
if ($tarifa && $tarifa->count() > 0) {
foreach ($tarifa as $t) {
$tarifas[] = is_array($t) ? (object) $t : $t;
}
}
}
}
} catch (\Exception $e) {
\Log::error('Error in getTarifasFullAttribute: ' . $e->getMessage());
}
return $tarifas;
}
User
The user model representing system users.class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
'organizador_id',
'phone',
'address'
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
Relationships
// User belongs to an organizer
public function organizador() {
return $this->belongsTo(Organizador::class, 'organizador_id');
}
// User has many event registrations
public function eventoXUsuario() {
return $this->hasMany(EventoXUsuario::class, 'user_id');
}
// User has many orders
public function orders() {
return $this->hasMany(Order::class, 'user_id');
}
Organizador (Organizer)
Represents event organizers.class Organizador extends Model
{
protected $fillable = [
'name',
'email',
'phone',
'address',
'description',
'logo_url',
'website',
'flag_active'
];
protected $casts = [
'flag_active' => 'boolean'
];
}
Relationships
// Organizer has many events
public function eventos() {
return $this->hasMany(Evento::class, 'organizador_id');
}
// Organizer has many users
public function users() {
return $this->hasMany(User::class, 'organizador_id');
}
Event Management Models
EventoXUsuario (Event Registration)
Represents user registrations for events.class EventoXUsuario extends Model
{
protected $fillable = [
'evento_id',
'user_id',
'tarifa_id',
'status',
'payment_status',
'total_amount',
'discount_amount',
'form_data',
'transaction_id',
'payment_method'
];
protected $casts = [
'form_data' => 'array',
'total_amount' => 'decimal:2',
'discount_amount' => 'decimal:2'
];
}
Relationships
// Registration belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Registration belongs to a user
public function usuario() {
return $this->belongsTo(User::class, 'user_id');
}
// Registration belongs to a tariff
public function tarifa() {
return $this->belongsTo(TarifaDeEvento::class, 'tarifa_id');
}
CategoriaDeEvento (Event Category)
Represents event categories.class CategoriaDeEvento extends Model
{
protected $fillable = [
'name',
'description',
'color',
'icon',
'flag_active'
];
protected $casts = [
'flag_active' => 'boolean'
];
}
Relationships
// Category has many events
public function eventos() {
return $this->hasMany(Evento::class, 'category');
}
TarifaDeEvento (Event Tariff)
Represents pricing tiers for events.class TarifaDeEvento extends Model
{
protected $fillable = [
'name',
'description',
'prices',
'evento_id',
'flag_active',
'max_participants',
'registration_deadline'
];
protected $casts = [
'prices' => 'array',
'flag_active' => 'boolean',
'registration_deadline' => 'datetime'
];
}
Relationships
// Tariff belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Tariff has many registrations
public function registrations() {
return $this->hasMany(EventoXUsuario::class, 'tarifa_id');
}
User Management Models
Role & Permission Models
class Role extends Model
{
protected $fillable = [
'name',
'guard_name'
];
}
class ModelHasRole extends Model
{
protected $fillable = [
'role_id',
'model_type',
'model_id'
];
}
Payment & Order Models
Order
Represents payment orders.class Order extends Model
{
protected $fillable = [
'user_id',
'evento_id',
'order_number',
'total_amount',
'status',
'payment_method',
'transaction_id',
'payment_date',
'billing_address',
'shipping_address'
];
protected $casts = [
'total_amount' => 'decimal:2',
'payment_date' => 'datetime',
'billing_address' => 'array',
'shipping_address' => 'array'
];
}
Relationships
// Order belongs to a user
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
// Order belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Order has many items
public function items() {
return $this->hasMany(OrderItem::class, 'order_id');
}
OrderItem
Represents individual items in an order.class OrderItem extends Model
{
protected $fillable = [
'order_id',
'product_id',
'variant_id',
'quantity',
'unit_price',
'total_price',
'product_name',
'variant_attributes'
];
protected $casts = [
'unit_price' => 'decimal:2',
'total_price' => 'decimal:2',
'variant_attributes' => 'array'
];
}
Relationships
// Order item belongs to an order
public function order() {
return $this->belongsTo(Order::class, 'order_id');
}
// Order item belongs to a product
public function product() {
return $this->belongsTo(Producto::class, 'product_id');
}
// Order item belongs to a variant
public function variant() {
return $this->belongsTo(Variant::class, 'variant_id');
}
Refund
Represents payment refunds.class Refund extends Model
{
protected $fillable = [
'order_id',
'amount',
'reason',
'status',
'processed_at'
];
protected $casts = [
'amount' => 'decimal:2',
'processed_at' => 'datetime'
];
}
Ranking Models
EventRanking
Represents rankings for specific events.class EventRanking extends Model
{
protected $fillable = [
'evento_id',
'name',
'description',
'criteria',
'results',
'is_active',
'calculated_at'
];
protected $casts = [
'criteria' => 'array',
'results' => 'array',
'is_active' => 'boolean',
'calculated_at' => 'datetime'
];
}
Relationships
// Ranking belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
GeneralRanking
Represents general rankings across multiple events.class GeneralRanking extends Model
{
protected $fillable = [
'name',
'description',
'criteria',
'results',
'is_active',
'calculated_at',
'period_start',
'period_end'
];
protected $casts = [
'criteria' => 'array',
'results' => 'array',
'is_active' => 'boolean',
'calculated_at' => 'datetime',
'period_start' => 'datetime',
'period_end' => 'datetime'
];
}
Ranking
Base ranking model.class Ranking extends Model
{
protected $fillable = [
'evento_id',
'user_id',
'position',
'score',
'category',
'ranking_date'
];
protected $casts = [
'score' => 'decimal:2',
'ranking_date' => 'datetime'
];
}
Relationships
// Ranking belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Ranking belongs to a user
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
Merchandise Models
Catalogo (Catalog)
Represents merchandise catalogs.class Catalogo extends Model
{
protected $fillable = [
'name',
'description',
'evento_id',
'is_active',
'image_url'
];
protected $casts = [
'is_active' => 'boolean'
];
}
Relationships
// Catalog belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Catalog has many products
public function productos() {
return $this->hasMany(Producto::class, 'catalogo_id');
}
Producto (Product)
Represents merchandise products.class Producto extends Model
{
protected $fillable = [
'name',
'description',
'price',
'stock',
'catalogo_id',
'is_active',
'images',
'attributes'
];
protected $casts = [
'price' => 'decimal:2',
'stock' => 'integer',
'is_active' => 'boolean',
'images' => 'array',
'attributes' => 'array'
];
}
Relationships
// Product belongs to a catalog
public function catalogo() {
return $this->belongsTo(Catalogo::class, 'catalogo_id');
}
// Product has many variants
public function variants() {
return $this->hasMany(Variant::class, 'producto_id');
}
Variant
Represents product variants (size, color, etc.).class Variant extends Model
{
protected $fillable = [
'producto_id',
'name',
'attributes',
'price',
'stock',
'sku'
];
protected $casts = [
'price' => 'decimal:2',
'stock' => 'integer',
'attributes' => 'array'
];
}
Relationships
// Variant belongs to a product
public function producto() {
return $this->belongsTo(Producto::class, 'producto_id');
}
VariantName
Represents attribute names for variants.class VariantName extends Model
{
protected $fillable = [
'name',
'type',
'options'
];
protected $casts = [
'options' => 'array'
];
}
Communication Models
Communication
Represents communication templates.class Communication extends Model
{
protected $fillable = [
'name',
'subject',
'message',
'evento_id',
'type',
'is_active'
];
protected $casts = [
'is_active' => 'boolean'
];
}
Relationships
// Communication belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Communication has many logs
public function logs() {
return $this->hasMany(CommunicationLog::class, 'communication_id');
}
CommunicationLog
Represents communication delivery logs.class CommunicationLog extends Model
{
protected $fillable = [
'communication_id',
'user_id',
'status',
'sent_at',
'error_message'
];
protected $casts = [
'sent_at' => 'datetime'
];
}
Relationships
// Log belongs to a communication
public function communication() {
return $this->belongsTo(Communication::class, 'communication_id');
}
// Log belongs to a user
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
Configuration Models
Discount
Represents discount codes and promotions.class Discount extends Model
{
protected $fillable = [
'name',
'code',
'amount',
'type_amount',
'quantity',
'in_use',
'evento_id',
'flag_active',
'cumulative',
'valid_from',
'valid_to'
];
protected $casts = [
'amount' => 'decimal:2',
'quantity' => 'integer',
'in_use' => 'integer',
'flag_active' => 'boolean',
'cumulative' => 'boolean',
'valid_from' => 'datetime',
'valid_to' => 'datetime'
];
}
Relationships
// Discount belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
Idioma (Language)
Represents supported languages.class Idioma extends Model
{
protected $fillable = [
'name',
'code',
'url_image',
'flag_active'
];
protected $casts = [
'flag_active' => 'boolean'
];
}
Tarifa (Tariff)
Represents base tariff templates.class Tarifa extends Model
{
protected $fillable = [
'name',
'description',
'prices',
'flag_active'
];
protected $casts = [
'prices' => 'array',
'flag_active' => 'boolean'
];
}
Booking
Represents event bookings and reservations.class Booking extends Model
{
protected $fillable = [
'evento_id',
'user_id',
'booking_date',
'status',
'notes',
'total_amount'
];
protected $casts = [
'booking_date' => 'datetime',
'total_amount' => 'decimal:2'
];
}
Relationships
// Booking belongs to an event
public function evento() {
return $this->belongsTo(Evento::class, 'evento_id');
}
// Booking belongs to a user
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
Cities & Countries
Geographic data models.class Cities extends Model
{
protected $fillable = [
'name',
'country_code',
'state_code',
'latitude',
'longitude'
];
protected $casts = [
'latitude' => 'decimal:8',
'longitude' => 'decimal:8'
];
}
class Countries extends Model
{
protected $fillable = [
'name',
'iso2',
'iso3',
'flag_active'
];
protected $casts = [
'flag_active' => 'boolean'
];
}
Model Relationships
Complete Relationship Diagram
// Event Relationships
Evento
├── belongsTo(Organizador)
├── belongsTo(CategoriaDeEvento)
├── hasMany(EventoXUsuario)
├── hasMany(Ranking)
├── hasMany(EventRanking)
├── hasMany(Booking)
├── hasMany(Catalogo)
└── hasMany(Order)
// User Relationships
User
├── belongsTo(Organizador)
├── hasMany(EventoXUsuario)
├── hasMany(Order)
└── hasMany(Booking)
// Organizer Relationships
Organizador
├── hasMany(Evento)
└── hasMany(User)
// Event Registration Relationships
EventoXUsuario
├── belongsTo(Evento)
├── belongsTo(User)
└── belongsTo(TarifaDeEvento)
// Order Relationships
Order
├── belongsTo(User)
├── belongsTo(Evento)
└── hasMany(OrderItem)
// Product Relationships
Producto
├── belongsTo(Catalogo)
└── hasMany(Variant)
// Catalog Relationships
Catalogo
├── belongsTo(Evento)
└── hasMany(Producto)
Model Scopes & Accessors
Common Scopes
// Active scope for most models
public function scopeActive($query) {
return $query->where('flag_active', true);
}
// Recent scope for events
public function scopeRecent($query, $days = 30) {
return $query->where('created_at', '>=', now()->subDays($days));
}
// Upcoming events scope
public function scopeUpcoming($query) {
return $query->where('date_from', '>=', now());
}
// Past events scope
public function scopePast($query) {
return $query->where('date_from', '<', now());
}
// Available scope for products
public function scopeAvailable($query) {
return $query->where('stock', '>', 0)->where('is_active', true);
}
Custom Accessors
// Get full name for users
public function getFullNameAttribute() {
return $this->name;
}
// Get status label
public function getStatusLabelAttribute() {
$statuses = [
'active' => 'Active',
'inactive' => 'Inactive',
'pending' => 'Pending',
'cancelled' => 'Cancelled'
];
return $statuses[$this->status] ?? $this->status;
}
// Get formatted price
public function getFormattedPriceAttribute() {
return number_format($this->price, 2) . ' €';
}
// Get remaining stock
public function getRemainingStockAttribute() {
return max(0, $this->stock - $this->reserved_stock);
}
Database Migrations
Key Migration Examples
// Events table migration
Schema::create('eventos', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->string('ciudad');
$table->string('pais');
$table->string('pagina_web');
$table->datetime('date_from');
$table->datetime('date_to')->nullable();
$table->integer('participants');
$table->integer('enrolled')->default(0);
$table->foreignId('category')->constrained('categorias_de_eventos');
$table->datetime('date_from_register');
$table->datetime('date_to_register');
$table->string('facebook')->nullable();
$table->string('instagram')->nullable();
$table->string('phone_number')->nullable();
$table->string('x')->nullable();
$table->foreignId('organizador_id')->constrained('organizadores');
$table->foreignId('created_by')->constrained('users');
$table->string('email');
$table->decimal('latitude', 10, 8);
$table->decimal('longitude', 11, 8);
$table->string('address');
$table->json('json_forms')->nullable();
$table->boolean('flag_active')->default(true);
$table->json('general_aspect')->nullable();
$table->string('url_image')->nullable();
$table->string('timezone')->default('UTC');
$table->timestamps();
$table->softDeletes();
});
// Event registrations table migration
Schema::create('eventos_x_usuarios', function (Blueprint $table) {
$table->id();
$table->foreignId('evento_id')->constrained('eventos')->onDelete('cascade');
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->foreignId('tarifa_id')->constrained('tarifas_de_eventos');
$table->enum('status', ['PENDING', 'CONFIRMED', 'CANCELLED'])->default('PENDING');
$table->enum('payment_status', ['PENDING', 'PAID', 'FAILED', 'REFUNDED'])->default('PENDING');
$table->decimal('total_amount', 10, 2);
$table->decimal('discount_amount', 10, 2)->default(0);
$table->json('form_data')->nullable();
$table->string('transaction_id')->nullable();
$table->string('payment_method')->nullable();
$table->timestamps();
});
// Orders table migration
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users');
$table->foreignId('evento_id')->constrained('eventos');
$table->string('order_number')->unique();
$table->decimal('total_amount', 10, 2);
$table->enum('status', ['PENDING', 'PAID', 'CANCELLED', 'REFUNDED'])->default('PENDING');
$table->string('payment_method')->nullable();
$table->string('transaction_id')->nullable();
$table->datetime('payment_date')->nullable();
$table->json('billing_address')->nullable();
$table->json('shipping_address')->nullable();
$table->timestamps();
$table->softDeletes();
});
Indexes and Constraints
// Add indexes for better performance
$table->index(['evento_id', 'status']);
$table->index(['user_id', 'created_at']);
$table->index(['date_from', 'flag_active']);
$table->index(['organizador_id', 'flag_active']);
// Add unique constraints
$table->unique(['evento_id', 'user_id'], 'unique_event_registration');
$table->unique('order_number');
$table->unique(['code', 'evento_id'], 'unique_discount_code');
