EloSQL – Automatically Generate Migrations and Eloquent Models based on your SQL Database Schema

https://opengraph.githubassets.com/744ff4f3b9a5010fa8a9d56714cd15bf3cacdd32eaedb67499cb7811b54762c8/sepehr-mohseni/elosql

Tests
Latest Stable Version
Total Downloads
License
PHP Version

Elosql is a production-grade Laravel package that intelligently analyzes existing database schemas and generates precise migrations and Eloquent models. It supports MySQL, PostgreSQL, SQLite, and SQL Server, making it perfect for legacy database integration, reverse engineering, and rapid application scaffolding.

  • 🔍 Smart Schema Analysis – Automatically detects columns, indexes, foreign keys, and table relationships
  • 🚀 Multi-Database Support – Works with MySQL/MariaDB, PostgreSQL, SQLite, and SQL Server
  • 📁 Migration Generation – Creates Laravel migrations with proper dependency ordering
  • 🏗️ Model Scaffolding – Generates Eloquent models with relationships, casts, and fillable attributes
  • 🔗 Relationship Detection – Automatically detects belongsTo, hasMany, hasOne, belongsToMany, and polymorphic relationships
  • 📊 Schema Diff – Compare database schema with existing migrations
  • ⚙️ Highly Configurable – Customize every aspect of generation through config or command options
  • ✅ Production Ready – Comprehensive test suite with 90%+ coverage
  • PHP 8.1 or higher
  • Laravel 10.0 or 11.0

Install via Composer:

composer require sepehr-mohseni/elosql

The package will auto-register its service provider. Optionally, publish the configuration file:

php artisan vendor:publish --tag=elosql-config

Generate migrations and models for your entire database:

php artisan elosql:schema

See what will be generated without creating any files:

php artisan elosql:preview
php artisan elosql:migrations
php artisan elosql:models

The main command that generates both migrations and models.

php artisan elosql:schema [options]

Options:
  --connection=       Database connection to use (default: default connection)
  --table=            Generate for specific table(s), comma-separated
  --exclude=          Exclude specific table(s), comma-separated
  --migrations-path=  Custom path for migrations (default: database/migrations)
  --models-path=      Custom path for models (default: app/Models)
  --models-namespace= Custom namespace for models (default: App\Models)
  --no-migrations     Skip migration generation
  --no-models         Skip model generation
  --force             Overwrite existing files

Examples:

# Generate for specific tables
php artisan elosql:schema --table=users,posts,comments

# Exclude certain tables
php artisan elosql:schema --exclude=migrations,cache,sessions

# Custom output paths
php artisan elosql:schema --migrations-path=database/generated --models-path=app/Domain/Models

# Use a different database connection
php artisan elosql:schema --connection=legacy_db

Generate migration files from database schema.

php artisan elosql:migrations [options]

Options:
  --connection=   Database connection to use
  --table=        Generate for specific table(s)
  --exclude=      Exclude specific table(s)
  --path=         Custom output path
  --fresh         Generate fresh migrations (ignore existing)
  --diff          Only generate migrations for schema differences
  --force         Overwrite existing files

Examples:

# Generate migrations for a legacy database
php artisan elosql:migrations --connection=legacy --path=database/legacy-migrations

# Generate only new/changed tables
php artisan elosql:migrations --diff

Generate Eloquent model files.

php artisan elosql:models [options]

Options:
  --connection=   Database connection to use
  --table=        Generate for specific table(s)
  --exclude=      Exclude specific table(s)
  --path=         Custom output path
  --namespace=    Custom namespace
  --preview       Preview generated code without writing files
  --force         Overwrite existing files

Examples:

# Preview model generation
php artisan elosql:models --preview --table=users

# Generate with custom namespace
php artisan elosql:models --namespace="Domain\\User\\Models"

Preview the schema analysis without generating any files.

php artisan elosql:preview [options]

Options:
  --connection=   Database connection to use
  --table=        Preview specific table(s)
  --format=       Output format: table, json, yaml (default: table)

Examples:

# JSON output for processing
php artisan elosql:preview --format=json > schema.json

# View specific table structure
php artisan elosql:preview --table=users

Show differences between database schema and existing migrations.

php artisan elosql:diff [options]

Options:
  --connection=   Database connection to use
  --format=       Output format: table, json (default: table)

After publishing the config file (config/elosql.php), you can customize:

'connection' => env('ELOSQL_CONNECTION', null), // null = default connection
'exclude_tables' => [
    'migrations',
    'failed_jobs',
    'password_resets',
    'personal_access_tokens',
    'cache',
    'sessions',
],
'migrations' => [
    'path' => database_path('migrations'),
    'separate_foreign_keys' => true, // Generate FK migrations separately
    'include_drop_tables' => true,   // Include down() method
],
'models' => [
    'path' => app_path('Models'),
    'namespace' => 'App\\Models',
    'base_class' => \Illuminate\Database\Eloquent\Model::class,
    'use_guarded' => false,           // Use $guarded instead of $fillable
    'generate_phpdoc' => true,        // Generate PHPDoc blocks
    'detect_soft_deletes' => true,    // Auto-detect SoftDeletes trait
    'detect_timestamps' => true,      // Auto-detect timestamp columns
],

Customize how database types map to Laravel migration methods:

'type_mappings' => [
    'mysql' => [
        'tinyint(1)' => 'boolean',
        'json' => 'json',
        // Add custom mappings
    ],
    'pgsql' => [
        'jsonb' => 'jsonb',
        'uuid' => 'uuid',
    ],
],
'relationships' => [
    'detect_belongs_to' => true,
    'detect_has_many' => true,
    'detect_has_one' => true,
    'detect_belongs_to_many' => true,
    'detect_morph' => true,
    'pivot_table_patterns' => [
        // Regex patterns for detecting pivot tables
        '/^([a-z]+)_([a-z]+)$/',
    ],
],
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->string('title', 255);
            $table->text('content');
            $table->enum('status', ['draft', 'published', 'archived'])->default('draft');
            $table->json('metadata')->nullable();
            $table->timestamps();
            $table->softDeletes();
            
            $table->index('status');
            $table->fullText('content');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * @property int $id
 * @property int $user_id
 * @property string $title
 * @property string $content
 * @property string $status
 * @property array|null $metadata
 * @property \Carbon\Carbon $created_at
 * @property \Carbon\Carbon $updated_at
 * @property \Carbon\Carbon|null $deleted_at
 * 
 * @property-read User $user
 * @property-read \Illuminate\Database\Eloquent\Collection|Comment[] $comments
 * @property-read \Illuminate\Database\Eloquent\Collection|Tag[] $tags
 */
class Post extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'user_id',
        'title',
        'content',
        'status',
        'metadata',
    ];

    protected $casts = [
        'metadata' => 'array',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

    public function tags(): BelongsToMany
    {
        return $this->belongsToMany(Tag::class, 'post_tag');
    }
}

You can also use Elosql programmatically:

use Sepehr_Mohseni\Elosql\Parsers\SchemaParserFactory;
use Sepehr_Mohseni\Elosql\Generators\MigrationGenerator;
use Sepehr_Mohseni\Elosql\Generators\ModelGenerator;

// Get the parser for your database
$parser = app(SchemaParserFactory::class)->make('mysql');

// Parse all tables
$tables = $parser->getTables();

// Or parse specific tables
$tables = $parser->getTables([
    'include' => ['users', 'posts'],
    'exclude' => ['migrations'],
]);

// Generate migrations
$migrationGenerator = app(MigrationGenerator::class);
$files = $migrationGenerator->generateAll($tables, 'mysql', database_path('migrations'));

// Generate models
$modelGenerator = app(ModelGenerator::class);
foreach ($tables as $table) {
    $content = $modelGenerator->generate($table, 'mysql', $tables);
    // Write to file or process as needed
}

Elosql handles foreign key dependencies intelligently:

  1. Dependency Resolution – Tables are ordered based on their foreign key dependencies using topological sorting
  2. Separate FK Migrations – Foreign keys are generated in separate migration files that run after all tables are created
  3. Circular Dependencies – Detected and reported with suggestions for resolution

This ensures migrations can be run without foreign key constraint violations.

  • Integers: tinyint, smallint, mediumint, int, bigint
  • Floating point: float, double, decimal
  • Strings: char, varchar, text, mediumtext, longtext
  • Binary: binary, varbinary, blob
  • Date/Time: date, datetime, timestamp, time, year
  • Special: json, enum, set, boolean
  • Spatial: point, linestring, polygon, geometry
  • All standard types plus: uuid, jsonb, inet, macaddr, cidr
  • Array types
  • Range types
  • integer, real, text, blob, numeric
  • All standard types plus: uniqueidentifier, nvarchar, ntext

Run the test suite:

Run with coverage:

Run static analysis:

Fix code style:

Contributions are welcome! Please see CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

If you discover any security-related issues, please email isepehrmohseni@gmail.com instead of using the issue tracker.

The MIT License (MIT). Please see License File for more information.

Laravel News Links

1000 Ants vs. an Obstacle Course

https://theawesomer.com/photos/2026/01/ants_vs_obstacles_t.jpg

1000 Ants vs. an Obstacle Course

After seeing videos of how ant colonies work together, TerraGreen thought it would be interesting to see how they behave up close. So he gathered up roughly 1000 ants from an ant nest and put them to the test in a series of collaborative challenges and obstacle courses. Antony is quite the overachiever.

The Awesomer

America Is Falling Out of Love With Pizza

The restaurant industry is trying to figure out whether America has hit peak pizza. From a report: Once the second-most common U.S. restaurant type, pizzerias are now outnumbered by coffee shops and Mexican food eateries, according to industry data. Sales growth at pizza restaurants has lagged behind the broader fast-food market for years, and the outlook ahead isn’t much brighter. "Pizza is disrupted right now," Ravi Thanawala, chief financial officer and North America president at Papa John’s International, said in an interview. "That’s what the consumer tells us." The parent of the Pieology Pizzeria chain filed for chapter 11 bankruptcy protection in December. Others, including the parent of Anthony’s Coal Fired Pizza & Wings and Bertucci’s Brick Oven Pizza & Pasta, earlier filed for bankruptcy. Pizza once was a novelty outside big U.S. cities, providing room for growth for independent shops and then chains such as Pizza Hut with its red roof dine-in restaurants. Purpose-made cardboard boxes and fleets of delivery drivers helped make pizza a takeout staple for those seeking low-stress meals. Today, pizza shops are engaged in price wars with one another and other kinds of fast food. Food-delivery apps have put a wider range of cuisines and options at Americans’ fingertips. And $20 a pie for a family can feel expensive compared with $5 fast-food deals, frozen pizzas or eating a home-cooked meal. […] Pizza’s dominance in American restaurant fare is declining, however. Among different cuisines, it ranked sixth in terms of U.S. sales in 2024 among restaurant chains, down from second place during the 1990s, Technomic said. The number of pizza restaurants in the U.S. hit a record high in 2019 and has declined since then, figures from the market-research firm Datassential show. Further reading, at WSJ: The Feds Need to Bail Out the Pizza Industry.


Read more of this story at Slashdot.

Slashdot

Logitech Caused Its Mice To Freak Out By Not Renewing a Certificate

An anonymous reader shares a report: If you’re among the macOS users experiencing some weird issues with your Logitech mouse, then good news: Logitech has now released a fix. This comes after multiple Reddit users reported yesterday that Logi Options Plus — the app required to manage and configure the controls on Logitech accessories — had stopped working, preventing them from using customized scrolling features, button actions, and gestures. One Reddit user said that the scroll directions and extra buttons on their Logitech mouse "were not working as I intended" and that the Logi Options Plus app became stuck in a boot loop upon opening it to identify the cause. Logitech has since acknowledged the situation and said that its G Hub app — a similar management software for gaming devices under the Logitech G brand — was also affected. According to Logitech’s support page, the problem was caused by "an expired certificate" required for the apps to run. Windows users were unaffected. The issues only impacted Mac users because macOS prevents certain applications from running if it doesn’t detect a valid Developer ID certificate, something that has affected other apps in the past.


Read more of this story at Slashdot.

Slashdot

How we reduced archive storage costs by 100x and saved millions

♦

In this post, we introduce a new storage system that we built in order to cost-efficiently store log data while providing interactive query latency. We’ll cover some motivations, architecture, migration process, and interesting optimizations we made along the way.

Archive Data

Going into 2024, cost savings was one of the major goals for the storage team. Our AWS MySQL RDS storage footprintPlanet for the MySQL Community

The X-Men Are Back in the Next ‘Avengers: Doomsday’ Trailer

https://gizmodo.com/app/uploads/2026/01/avengers-doomsday-cyclops-1280×853.jpg

The first teaser for Avengers: Doomsday heralded the return of Chris Evans’ Steve Rogers, aka Captain America, and our second checked in on Chris Hemsworth’s Thor. And for week three? It’s all X-Men, baby.

Well, “all” in the sense that it’s about the superteam. The teaser here chooses to focus on three returning actors: Charles Xavier (Patrick Stewart), Magneto (Ian McKellen), and a tiny tease of Cyclops (James Marsden). We get shots of the Xavier Institute, which looks to be empty of students and staff, and Charles and Erik playing chess like they did in the old movies.

Then, Cyclops yanks off his visor to use a full-force optic blast in the middle of battle. And after that shot of Cyclops? “The X-Men will return…”

The MCU has been flirting with bringing back the OG Fox-Men for a while, starting with Doctor Strange in the Multiverse of Madness featuring an Xavier variant and continuing that thread with The Marvels and Deadpool & Wolverine.

With Avengers: Doomsday, one-third of the film’s main cast consists of these comeback characters: along with Charles, Erik, and Scott, we’ll be seeing older versions of Nightcrawler (Alan Cumming), Mystique (Rebecca Romijn), Beast (Kelsey Grammer), and Gambit (Channing Tatum). The jury’s out on if we’ll see other X-actors like Wolverine (Hugh Jackman), Storm (Halle Berry), or Jean Grey (Famke Janssen), but it certainly could happen.

Avengers: Doomsday hits theaters on December 18.

Want more io9 news? Check out when to expect the latest Marvel, Star Wars, and Star Trek releases, what’s next for the DC Universe on film and TV, and everything you need to know about the future of Doctor Who.

Gizmodo