PHP code example of neuron-php / orm

1. Go to this page and download the library: Download neuron-php/orm 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/ */

    

neuron-php / orm example snippets


use Neuron\Orm\Model;

// Set the PDO connection for all models
Model::setPdo($pdo);

use Neuron\Orm\Model;
use Neuron\Orm\Attributes\{Table, BelongsTo, BelongsToMany};

#[Table('posts')]
class Post extends Model
{
    private ?int $_id = null;
    private string $_title;
    private string $_body;
    private int $_authorId;

    #[BelongsTo(User::class, foreignKey: 'author_id')]
    private ?User $_author = null;

    #[BelongsToMany(Category::class, pivotTable: 'post_categories')]
    private array $_categories = [];

    #[BelongsToMany(Tag::class, pivotTable: 'post_tags')]
    private array $_tags = [];

    // Implement fromArray() method
    public static function fromArray(array $data): static
    {
        $post = new self();
        $post->_id = $data['id'] ?? null;
        $post->_title = $data['title'] ?? '';
        $post->_body = $data['body'] ?? '';
        $post->_authorId = $data['author_id'] ?? 0;
        return $post;
    }

    // Getters and setters...
}

// Find by ID
$post = Post::find(1);

// Access relations (lazy loading)
echo $post->author->username;
foreach ($post->categories as $category) {
    echo $category->name;
}

// Eager loading (N+1 prevention)
$posts = Post::with(['author', 'categories', 'tags'])->all();

// Query builder
$posts = Post::where('status', 'published')
    ->with('author')
    ->orderBy('created_at', 'DESC')
    ->limit(10)
    ->get();

// Get all
$allPosts = Post::all();

// Count
$count = Post::where('status', 'published')->count();

#[Table('posts')]
class Post extends Model
{
    #[BelongsTo(User::class, foreignKey: 'author_id')]
    private ?User $_author = null;
}

// Usage
$post = Post::find(1);
$authorName = $post->author->username;

#[Table('users')]
class User extends Model
{
    #[HasMany(Post::class, foreignKey: 'author_id')]
    private array $_posts = [];
}

// Usage
$user = User::find(1);
foreach ($user->posts as $post) {
    echo $post->title;
}

#[Table('users')]
class User extends Model
{
    #[HasOne(Profile::class, foreignKey: 'user_id')]
    private ?Profile $_profile = null;
}

// Usage
$user = User::find(1);
echo $user->profile->bio;

#[Table('posts')]
class Post extends Model
{
    #[BelongsToMany(
        Category::class,
        pivotTable: 'post_categories',
        foreignPivotKey: 'post_id',
        relatedPivotKey: 'category_id'
    )]
    private array $_categories = [];
}

// Usage
$post = Post::find(1);
foreach ($post->categories as $category) {
    echo $category->name;
}

// Attach new relationships
$post->relation('categories')->attach(3);           // Attach single category
$post->relation('categories')->attach([4, 5]);      // Attach multiple

// Detach relationships
$post->relation('categories')->detach(3);           // Detach single
$post->relation('categories')->detach([4, 5]);      // Detach multiple
$post->relation('categories')->detach();            // Detach all

// Sync relationships (replace all with new set)
$post->relation('categories')->sync([1, 2, 3]);     // Keep only 1, 2, 3
$post->relation('categories')->sync([]);            // Remove all

// Where clauses
$posts = Post::where('status', 'published')
    ->where('views', '>', 100)
    ->get();

// Where in
$posts = Post::whereIn('id', [1, 2, 3])->get();

// Or where
$posts = Post::where('status', 'published')
    ->orWhere('status', 'featured')
    ->get();

// Order by
$posts = Post::orderBy('created_at', 'DESC')->get();

// Limit and offset
$posts = Post::limit(10)->offset(20)->get();

// Count
$count = Post::where('status', 'published')->count();

// First
$post = Post::where('slug', 'hello-world')->first();

// Combining methods
$posts = Post::where('status', 'published')
    ->with(['author', 'categories'])
    ->orderBy('created_at', 'DESC')
    ->limit(5)
    ->get();

// Select specific columns
$users = User::query()
    ->select(['id', 'username', 'email'])
    ->where('active', true)
    ->get();

// Add columns to existing selection
$users = User::query()
    ->select('id')
    ->addSelect(['username', 'email'])
    ->get();

// Raw SQL expressions
$posts = Post::query()
    ->select(['posts.*'])
    ->selectRaw('LENGTH(title) as title_length')
    ->get();

// Distinct results
$usernames = User::query()
    ->select('username')
    ->distinct()
    ->get();

// INNER JOIN
$posts = Post::query()
    ->select(['posts.*', 'users.username'])
    ->join('users', 'posts.author_id', '=', 'users.id')
    ->where('posts.status', 'published')
    ->get();

// LEFT JOIN
$posts = Post::query()
    ->leftJoin('users', 'posts.author_id', '=', 'users.id')
    ->get();

// Multiple JOINs with aliases
$posts = Post::query()
    ->from('posts', 'p')
    ->select(['p.*', 'u.username', 'c.name as category_name'])
    ->join('users u', 'p.author_id', '=', 'u.id')
    ->leftJoin('categories c', 'p.category_id', '=', 'c.id')
    ->orderBy('p.created_at', 'DESC')
    ->get();

// CROSS JOIN
$combinations = Product::query()
    ->crossJoin('colors')
    ->get();

// Sum
$totalViews = Post::query()
    ->where('status', 'published')
    ->sum('view_count');

// Average
$avgAge = User::query()->avg('age');

// Maximum
$maxPrice = Product::query()->max('price');

// Minimum
$minPrice = Product::query()
    ->where('in_stock', true)
    ->min('price');

// Count posts by category
$results = Post::query()
    ->select(['category_id', 'COUNT(*) as post_count'])
    ->groupBy('category_id')
    ->get();

// Group by multiple columns
$results = Post::query()
    ->select(['category_id', 'status', 'COUNT(*) as count'])
    ->groupBy(['category_id', 'status'])
    ->get();

// With JOIN and aggregation
$results = Category::query()
    ->select(['categories.name', 'COUNT(posts.id) as post_count'])
    ->leftJoin('posts', 'categories.id', '=', 'posts.category_id')
    ->groupBy('categories.id')
    ->orderBy('post_count', 'DESC')
    ->get();

// Sum views by category
$results = Post::query()
    ->select(['category_id', 'SUM(view_count) as total_views'])
    ->groupBy('category_id')
    ->orderBy('total_views', 'DESC')
    ->get();

// Get raw results with aggregate columns preserved
$results = Category::query()
    ->select(['categories.name', 'COUNT(posts.id) as post_count'])
    ->leftJoin('posts', 'categories.id', '=', 'posts.category_id')
    ->groupBy('categories.id')
    ->orderBy('post_count', 'DESC')
    ->getRaw();

foreach ($results as $row) {
    echo "{$row['name']}: {$row['post_count']} posts\n";
    // $row is an array, not a model object
}

// Multiple aggregate functions
$stats = Post::query()
    ->select([
        'category_id',
        'COUNT(*) as count',
        'SUM(view_count) as total_views',
        'AVG(view_count) as avg_views'
    ])
    ->groupBy('category_id')
    ->getRaw();

// With complex queries
$report = User::query()
    ->select([
        'users.role',
        'COUNT(posts.id) as post_count',
        'MAX(posts.created_at) as latest_post'
    ])
    ->leftJoin('posts', 'users.id', '=', 'posts.author_id')
    ->groupBy('users.role')
    ->getRaw();

// Increment view count by 1
Post::where('id', 1)->increment('view_count');

// Increment by specific amount
Post::where('id', 1)->increment('view_count', 5);

// Decrement
User::where('id', 1)->decrement('credits', 10);

// Update all matching records
$affected = Post::where('status', 'draft')
    ->update(['status' => 'published']);

echo "Updated {$affected} posts";

// Manual transaction control
Model::beginTransaction();

try {
    $user = User::create(['username' => 'john']);
    $profile = Profile::create(['user_id' => $user->getId()]);

    Model::commit();
} catch (Exception $e) {
    Model::rollBack();
    throw $e;
}

// Transaction with callback (automatic commit/rollback)
$userId = Model::transaction(function() {
    $user = User::create(['username' => 'jane']);

    Profile::create([
        'user_id' => $user->getId(),
        'bio' => 'Hello world'
    ]);

    return $user->getId();
});

// Check transaction status
if (Model::inTransaction()) {
    echo "Currently in a transaction";
}

// Begin a transaction
Model::beginTransaction();

// Commit the transaction
Model::commit();

// Rollback the transaction
Model::rollBack();

// Check if in transaction
$inTransaction = Model::inTransaction();

// Execute callback in transaction (auto commit/rollback)
$result = Model::transaction(function() {
    // Your database operations
    return $someValue;
});

// Without eager loading (N+1 problem)
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // Triggers a query for each post
}

// With eager loading (2 queries total)
$posts = Post::with('author')->all();
foreach ($posts as $post) {
    echo $post->author->name; // No additional queries
}

// Multiple relations
$posts = Post::with(['author', 'categories', 'tags'])->all();

// Using create() - creates and saves in one step
$user = User::create([
    'username' => 'john',
    'email' => '[email protected]'
]);

// Using save() on a new instance
$user = new User();
$user->setUsername('jane');
$user->setEmail('[email protected]');
$user->save();

// Using fromArray() and save()
$user = User::fromArray([
    'username' => 'bob',
    'email' => '[email protected]'
]);
$user->save();

// Using update() method
$user = User::find(1);
$user->update([
    'email' => '[email protected]'
]);

// Using setters and save()
$user = User::find(1);
$user->setEmail('[email protected]');
$user->save();

// Using fill() for mass assignment
$user = User::find(1);
$user->fill([
    'username' => 'updated',
    'email' => '[email protected]'
])->save();

// Simple delete (no cascade)
$user = User::find(1);
$user->delete();

// Destroy with dependent cascade
$user = User::find(1);
$user->destroy(); // Cascades to related records based on dependent strategy

// Destroy multiple by IDs
User::destroyMany([1, 2, 3]); // Returns count of deleted records
User::destroyMany(1); // Can also pass single ID

// Delete via query builder
Post::where('status', 'draft')->delete(); // Returns count of deleted records

use Neuron\Orm\DependentStrategy;

DependentStrategy::Destroy     // Call destroy() on each related record (cascades further)
DependentStrategy::DeleteAll   // Delete with SQL (faster, no cascade)
DependentStrategy::Nullify     // Set foreign key to NULL
DependentStrategy::Restrict    // Prevent deletion if relations exist

use Neuron\Orm\Attributes\{Table, HasMany, HasOne, BelongsToMany};
use Neuron\Orm\DependentStrategy;

#[Table('users')]
class User extends Model
{
    // Destroy: Calls destroy() on each post (cascades to post's relations)
    #[HasMany(Post::class, foreignKey: 'author_id', dependent: DependentStrategy::Destroy)]
    private array $_posts = [];

    // DeleteAll: Fast SQL delete of profile (no cascade)
    #[HasOne(Profile::class, foreignKey: 'user_id', dependent: DependentStrategy::DeleteAll)]
    private ?Profile $_profile = null;

    // Restrict: Prevents user deletion if comments exist
    #[HasMany(Comment::class, dependent: DependentStrategy::Restrict)]
    private array $_comments = [];
}

#[Table('posts')]
class Post extends Model
{
    // DeleteAll: Remove pivot table entries only (genres remain)
    #[BelongsToMany(Category::class, pivotTable: 'post_categories', dependent: DependentStrategy::DeleteAll)]
    private array $_categories = [];

    // Nullify: Set comment.post_id = NULL instead of deleting
    #[HasMany(Comment::class, dependent: DependentStrategy::Nullify)]
    private array $_comments = [];
}

// With Destroy strategy
$user = User::find(1);
$user->destroy(); // Deletes user, all posts, AND all post categories (nested cascade)

// With DeleteAll strategy
$post = Post::find(1);
$post->destroy(); // Deletes post AND pivot entries, but NOT the categories themselves

// With Nullify strategy
$post = Post::find(1);
$post->destroy(); // Deletes post, sets comment.post_id = NULL for all comments

// With Restrict strategy
try {
    $user = User::find(1);
    $user->destroy(); // Throws RelationException if user has comments
} catch (RelationException $e) {
    echo "Cannot delete user: " . $e->getMessage();
}

// delete() - Simple deletion, NO cascade
$user = User::find(1);
$user->delete(); // Only deletes user, leaves posts orphaned

// destroy() - Respects dependent strategies
$user = User::find(1);
$user->destroy(); // Cascades to related records based on dependent attribute

#[Table('posts', primaryKey: 'id')]
class Post extends Model {}

#[Column(name: 'email_address', type: 'string', nullable: false)]
private string $_email;

#[BelongsTo(User::class, foreignKey: 'author_id', ownerKey: 'id')]
private ?User $_author = null;

#[HasMany(Post::class, foreignKey: 'author_id', localKey: 'id')]
private array $_posts = [];

#[HasOne(Profile::class, foreignKey: 'user_id', localKey: 'id')]
private ?Profile $_profile = null;

#[BelongsToMany(
    Category::class,
    pivotTable: 'post_categories',
    foreignPivotKey: 'post_id',
    relatedPivotKey: 'category_id',
    parentKey: 'id',
    relatedKey: 'id'
)]
private array $_categories = [];
bash
composer