PHP code example of diogodg / neoorm

1. Go to this page and download the library: Download diogodg/neoorm library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

diogodg / neoorm example snippets


use Diogodg\Neoorm\Query\Database;
use App\Models\Generated\Tables;

use function Diogodg\Neoorm\Query\{eq, gt, desc};

$db = Database::fromConfig();
$u  = Tables::users();

$maiores = $db->select()->from($u)
    ->where(gt($u->age, 18))
    ->orderBy(desc($u->created_at))
    ->limit(10)
    ->all();                       // list<UsersRow> — tipado de verdade



namespace App\Models;

use App\Models\Generated\StateTable;
use Diogodg\Neoorm\Abstract\Model;
use Diogodg\Neoorm\Migrations\Col;
use Diogodg\Neoorm\Migrations\Table;

/**
 * @extends Model<StateTable>
 */
class State extends Model
{
    public const table = 'state';

    public static function table(): Table
    {
        return Table::make(self::table, comment: 'States table')
            ->columns([
                'id'           => Col::id(),
                'name'         => Col::varchar(120)->notNull(),
                'abbreviation' => Col::char(2)->notNull(),
                'country'      => Col::int()->notNull()->references(Country::class),
                'ibge'         => Col::int()->unique(),
            ]);
    }
}

$dinheiro = Col::decimal(19, 4)->notNull()->default(0);

'saldo'  => $dinheiro,
'limite' => $dinheiro->comment('Limite de crédito'),   // não mexe em $dinheiro

Table::make('produto_categoria')
    ->columns([
        'produto'   => Col::int()->notNull(),
        'categoria' => Col::int()->notNull(),
        'nota'      => Col::decimal(3, 1),
    ])
    ->primary(['produto', 'categoria'])              // chave composta
    ->unique('pc_nota_unique', ['produto', 'nota'])  // unicidade multi-coluna
    ->index('pc_nota_index', ['nota'])
    ->check('nota >= 0')
    ->foreignKey('outra', ['a', 'b'], ['x', 'y'])    // foreign key composta
    ->timestamps();                                  // created_at + updated_at



namespace App\Seeders;

use App\Models\Generated\Inserts\StateInsert;
use App\Models\Generated\Tables;
use App\Models\State;
use Diogodg\Neoorm\Migrations\Seed\Seeder;
use Diogodg\Neoorm\Query\Executor;

final class StateSeeder extends Seeder
{
    public static function table(): string
    {
        return State::table;
    }

    public function run(Executor $db): void
    {
        if ($db->select()->from(Tables::state())->count() > 0) {
            return;
        }

        $db->insert(Tables::state())
            ->values(new StateInsert(name: 'Acre', abbreviation: 'AC', country: 1, ibge: 12))
            ->execute();
    }
}

$s = State::ref();                              // StateTable, colunas tipadas
$db->select()->from($s)->where(eq($s->ibge, 12))->one();

$vizinho = State::ref('vizinho');               // com alias, para self-join

$db = Database::fromConfig();
$u = Tables::users();

$db->select()->from($u)->all();                     // list<UsersRow>
$db->select()->from($u)->where(eq($u->id, 1))->one();      // ?UsersRow
$db->select()->from($u)->where(eq($u->id, 1))->oneOrFail();// UsersRow, ou lança
$db->select()->from($u)->count();                   // int
$db->select()->from($u)->cursor();                  // Generator<UsersRow>, sem materializar

use Diogodg\Neoorm\Query\Op;
use function Diogodg\Neoorm\Query\{eq, ne, gt, gte, lt, lte, like, notLike, ilike,
    inArray, notInArray, between, notBetween, isNull, isNotNull, asc, desc, sql};

$db->select()->from($u)
    ->where(Op::and(
        gte($u->age, 18),
        Op::or(ilike($u->name, 'd%'), inArray($u->status, ['active', 'trial'])),
        isNotNull($u->email),
    ))
    ->all();

->where(sql('LENGTH(name) > ?', 10))

use Diogodg\Neoorm\Query\Func;
use Diogodg\Neoorm\Query\Expr\{Aliased, NullsPlacement};

$pagina = $db->select()->from($u)
    ->orderBy(desc($u->created_at, NullsPlacement::Last), asc($u->name))
    ->limit(20)->offset(40)
    ->all();

$porStatus = $db->selectFields([$u->status, new Aliased(Func::count(), 'total')])
    ->from($u)
    ->groupBy($u->status)
    ->having(gt(Func::count(), 5))
    ->all();                                  // list<array<string,mixed>>

$p = Tables::posts();

$linhas = $db->selectFields([$u->id, $u->name, $p->title])
    ->from($u)
    ->leftJoin($p, eq($p->author_id, $u->id))
    ->all();

$linhas[0]['id'];            // da tabela base
$linhas[0]['posts__title'];  // da tabela juntada

$vizinho = Tables::state('vizinho');
$db->selectFields([$s->id, $vizinho->id])
   ->from($s)->innerJoin($vizinho, eq($vizinho->country, $s->country))->all();

$db->insert($u)->values(new UsersInsert(name: 'Diogo', email: '[email protected]'))->execute();

// RETURNING no PostgreSQL; INSERT + lastInsertId() + SELECT no MySQL.
$novo = $db->insert($u)->values(new UsersInsert(name: 'Ana', email: '[email protected]'))->returningOne();

$db->update($u)->set(['phone' => '...'])->where(eq($u->id, 1))->execute();
$db->delete($u)->where(eq($u->id, 1))->execute();

$db->update($u)->set(['ativo' => false])->allowFullTableScan()->execute();

$ativos = $db->select()->from($u)->where(eq($u->status, 'active'));

$pagina = $ativos->limit(10)->all();
$total  = $ativos->count();          // $ativos intacto

use Diogodg\Neoorm\Query\Tx;

$db->transaction(function (Tx $tx) use ($u, $p) {
    $autor = $tx->insert($u)->values(new UsersInsert(name: 'Ana', email: '[email protected]'))->returningOne();

    $tx->insert($p)->values(new PostsInsert(author_id: $autor->id, title: 'Olá'))->execute();
});

$query = $db->select()->from($u)->where(eq($u->id, 1))->toSql();

$query->sql;       // SELECT "users"."id", ... FROM "users" WHERE "users"."id" = :p0
$query->values();  // ['p0' => 1]

App/Models/
  Country.php                 App\Models\Country
  Billing/Invoice.php         App\Models\Billing\Invoice
  Generated/                  pulado

App/Models/Generated/
  Tables.php              Tables::users(), Tables::scheduleUser(), ...
  UsersTable.php          $u->email — propriedade declarada, com tipo
  Rows/UsersRow.php       final readonly, com fromRow() e toArray()
  Inserts/UsersInsert.php construtor de argumentos nomeados
  Enums/UsersStatus.php   enum PHP para coluna ENUM

Migrations/
  pgsql/
    0000_initial.sql          <- commitado
    0001_add_slug.sql         <- commitado
    journal.json              <- commitado
    meta/0000_snapshot.json   <- commitado
  mysql/  (mesmo layout)
bash
docker compose up -d
docker compose exec php composer test         # unit + integração nos dois dialetos
docker compose exec php composer test:unit    # sem banco, poucos segundos
docker compose exec php composer test:types   # PHPStan nível 8