Laravel’s Eloquent ORM is a versatile and powerful tool that allows developers to interact with databases in a way that feels almost like working with objects. While many developers are familiar with the basics of Eloquent, there are several methods and features that are often overlooked or not well-documented. These hidden gems can significantly enhance your development workflow, make your code more efficient, and help you build more robust applications.

In this blog post, we’ll delve into some of the least known but highly useful Eloquent methods in Laravel. We’ll explore these methods with code examples, hacks, and tips on how to use them effectively. By the end of this article, you’ll be armed with knowledge that will help you write cleaner, more efficient code.


1. increment and decrement Methods

What They Do

The increment and decrement methods allow you to perform atomic operations on a model’s attributes. These operations are useful for tracking quantities, such as points, ratings, or inventory levels, where you want to ensure that updates happen atomically.

Example Usage

Suppose you have a Point model with the following migration:

public function up()
{
    Schema::create('points', function (Blueprint $table) {
        $table->id();
        $table->bigInteger('total_points')->default(0);
        $table->timestamps();
    });
}

Code Example

$model = Point::findOrNew(['user_id' => 1]);

if ($model) {
    // Increment points for user 1 by 10
    $model->increment('total_points', 10);

    // Decrement points for user 1 by 5
    $model->decrement('total_points', 5);
} else {
    // Create a new point entry
    Point::create(['user_id' => 1]);
}

Hacks and Tips

  • Atomic Updates: These methods ensure that your database operations are atomic, meaning that either all changes succeed or none do. This is crucial for maintaining data integrity.
  • Custom Keys: You can use increment and decrement on any numeric field, not just total_points. For example, you could track a user’s progress through a series of steps.

2. whereHas, orWhereHas, and doesNotHave Methods

What They Do

These methods allow you to query relationships between models using sub-queries. They are particularly useful when dealing with polymorphic relationships or when you need to filter based on related models.

Example Usage

Suppose you have a Post model that belongs to a User, and a Comment model that also belongs to a User. You want to find all posts written by users who have made at least 5 comments.

Code Example

$users = User::whereHas('comments', function ($query) {
    $query->where('comment_text', 'like', '%test%');
})->orWhereHas('posts', function ($query) {
    $query->where('post_title', 'like', '%hello%');
})->get();

// Alternatively, using doesNotHave:
$users = User::doesNotHave('comments')->get();

Hacks and Tips

  • Combining Queries: Use orWhereHas to combine multiple conditions in a single query. For example, you could search for users who have both posts and comments.
  • Complex Conditions: These methods allow you to build complex queries that might be difficult or impossible with basic Eloquent operations.
  • Avoid N+1 Queries: Using these methods can help reduce the number of database queries by leveraging the relationships between models.

3. orderByRaw Method

What It Does

The orderByRaw method allows you to specify a custom ordering for your query results based on a raw SQL expression. This is useful when the default ordering doesn’t meet your requirements or when you need to perform complex sorting that isn’t easily achievable with Eloquent’s standard order methods.

Example Usage

Suppose you have a Product model and want to sort products by a custom criterion, such as the sum of two columns divided by their average. The SQL expression might look like ROUND((price + weight) / 2).

Code Example

$products = Product::query()
    ->orderByRaw('ROUND((price + weight) / 2) DESC')
    ->get();

Hacks and Tips

  • Custom Sorting: Use this method to sort results based on any arbitrary condition that can’t be easily expressed with Eloquent’s built-in order methods.
  • Performance Consideration: Be cautious when using orderByRaw with complex expressions, as it might negatively impact query performance.

4. afterCreate Method

What It Does

The afterCreate method is a hook that allows you to execute custom code after a model has been successfully created or updated in the database. This can be useful for triggering additional actions, such as sending notifications, updating related models, or performing data transformations.

Example Usage

Suppose you have a User model and want to send an email to a user whenever they are created or their profile is updated.

Code Example

public function store()
{
    $user = new User([
        'name' => request('name'),
        'email' => request('email'),
        'password' => request('password')
    ]);

    if ($user->save()) {
        Log::info('New user registered: ' . $user->name);

        // Send registration email
        Mail::to($user->email)->send(new RegisterEmail($user));
    }

    return redirect('/login');
}

Hacks and Tips

  • Real-Time Notifications: Use this method to trigger real-time updates or notifications when a model is created or updated.
  • Data Transformation: You can use afterCreate to modify related models or perform transformations on the newly created/updated data.

5. chunk Method

What It Does

The chunk method allows you to process large sets of data in manageable chunks. This is particularly useful when dealing with paginated data or when working with large databases that might otherwise cause memory issues.

Example Usage

Suppose you’re fetching a large number of records from the database and want to process them in batches.

Code Example

$users = User::query()
    ->skip(100)
    ->take(100)
    ->chunk(function ($chunk, $key) {
        // Process each batch of 100 users
        foreach ($chunk as $user) {
            // Do something with $user...
        }
    })
    ->get();

Hacks and Tips

  • Lazy Loading: Use chunk to lazy load data into your application, reducing the initial load time.
  • Batch Processing: This method is especially useful when dealing with large datasets or APIs that can only return a limited number of results at a time.

6. lazyLoading Method

What It Does

The lazyLoading method allows you to defer the loading of related models until they’re actually needed. This can save memory by only fetching related data when it’s required, which is especially useful for large applications with many relationships.

Example Usage

Suppose you have a Post model that belongs to a User. You want to load the user only when you need to display their profile.

Code Example

class Post extends Model {
    public function user()
    {
        return $this->lazyLoading(function ($query) {
            $query->where('user_id', $this->id);
        });
    }
}

Hacks and Tips

  • Memory Optimization: Use this method to optimize memory usage in applications with deep or complex relationships.
  • Performance Boost: By delaying the loading of related models, you can reduce the initial load time of your application.

7. getRelated Method

What It Does

The getRelated method allows you to access all related models in a single query. This is particularly useful when dealing with complex relationships where you need to fetch multiple levels of related data at once.

Example Usage

Suppose you have a User model that has many Posts, and each Post belongs to a Category. You want to fetch all posts for a user along with their categories in one query.

Code Example

$user = User::find(1);

$postsWithCategories = $user->getRelated(function ($query) {
    $query->with(['posts' => function ($query) use ($user) {
        $query->where('user_id', $user->id);
    }]);
});

Hacks and Tips

  • Eager Loading: Use getRelated to eagerly load all related models in a single query, reducing the number of database hits.
  • Custom Relationships: You can pass custom closures or builders to fetch specific relationships.

8. getKey and getRouteKey Methods

What They Do

The getKey method returns the primary key (or ID) of the model, while getRouteKey returns the route key for the model (which is typically the same as the key if using the default routing setup).

Example Usage

These methods are particularly useful when integrating with other systems or frameworks that require an identifier.

Code Example

public function show()
{
    $user = User::findOrNew(['slug' => $this->route('user.slug')]);

    if ($user) {
        return view('users.show', compact('user'));
    }

    return redirect('/');
}

Hacks and Tips

  • URL Generation: Use getRouteKey to generate URLs for models when integrating with routing systems.
  • Custom Keys: These methods can be useful when your database uses a custom primary key that doesn’t match the model’s natural key.

9. deleteWhere Method

What It Does

The deleteWhere method allows you to delete multiple records from the database in a single query based on specific conditions, rather than deleting all related entries. This is particularly useful when you need to perform bulk deletions without affecting other parts of your application.

Example Usage

Suppose you have a User model with a deleted_at column for soft deletes. You want to delete all users who haven’t been active in the last 30 days.

Code Example

User::deleteWhere(['created_at', '>', Carbon::now()->subtractMonths(3)]);

Hacks and Tips

  • Soft Deletes: Use this method to implement soft deletes by using a deleted_at column.
  • Conditional Deletions: This method allows for selective deletions based on custom conditions.

10. updateWhere Method

What It Does

The updateWhere method allows you to update multiple records in the database based on specific conditions, rather than updating all related entries. This is particularly useful when you need to perform partial updates without affecting other parts of your application.

Example Usage

Suppose you have a User model and want to update their profile picture only if it hasn’t been updated in the last year.

Code Example

User::updateWhere(['profile_image' => 'new_photo.jpg'], function ($query) {
    $query->where('updated_at', '<', Carbon::now()->subtractYears(1));
});

Hacks and Tips

  • Selective Updates: Use this method to perform selective updates based on custom conditions.
  • Efficiency: This method can improve efficiency by only updating the necessary records.

11. doesntHave Method

What It Does

The doesntHave method is similar to doesNotHave, but it allows for more complex conditions, such as querying for models that have at least one of a set of relationships.

Example Usage

Suppose you have a User model with a posts and comments relationship. You want to find all users who don’t have any posts or comments.

Code Example

$users = User::doesntHave(['posts', 'comments']);

Hacks and Tips

  • Inverse Conditions: This method allows you to query for models that don’t have certain relationships.
  • Custom Conditions: Use this method to build complex conditions based on your application’s requirements.

12. addGlobalScope Method

What It Does

The addGlobalScope method allows you to define global scopes for your models, which can be applied by default or conditionally. This is particularly useful when you want to apply common filters or conditions across multiple queries.

Example Usage

Suppose you have a User model with a deleted_at column for soft deletes. You want to ensure that all queries on users return only active records by default.

Code Example

protected function boot()
{
    User::addGlobalScope('active', function ($query) {
        $query->whereNotNull('deleted_at');
    });

    // Conditionally apply the scope
    $query = User::query();
    $query->scope('active');
}

Hacks and Tips

  • Default Scopes: Use this method to define default scopes that apply to all queries on a model.
  • Conditional Scopes: You can conditionally apply scopes based on your application’s logic.

13. increment Method

What It Does

The increment method allows you to increment the value of a specified column by a given amount, similar to a SELECT INTO operation. This is useful for incrementing counters or tracking increments in your database.

Example Usage

Suppose you have a click_count column in your User model. You want to track how many times each user has clicked on a specific button.

Code Example

$user = User::findOrNew(['id' => 1]);

if ($user->increment('click_count', 1)) {
    Log::info('User #' . $user->id . ' clicked!');
}

Hacks and Tips

  • Counter Usage: Use this method to implement counters for various actions in your application.
  • Atomic Operations: This method ensures that the increment operation is atomic, meaning that it will only update if there’s no conflict.

14. decrement Method

What It Does

The decrement method allows you to decrement the value of a specified column by a given amount, similar to an INVERT operation. This is useful for tracking decreases in your database.

Example Usage

Suppose you have a score column in your User model. You want to deduct points from a user’s score when they perform an action.

Code Example

$user = User::findOrNew(['id' => 1]);

if ($user->decrement('score', -5)) {
    Log::info('User #' . $user->id . ' lost 5 points!');
}

Hacks and Tips

  • Tracking Changes: Use this method to track decreases in your application, such as demoting users or deducting points.

15. touch Method

What It Does

The touch method allows you to create a new record for a related model, using the current model’s ID as a foreign key. This is particularly useful when dealing with one-to-many relationships.

Example Usage

Suppose you have a User model and a Comment model. You want to create a comment for a user whenever they perform an action.

Code Example

public function store()
{
    $user = User::findOrNew(['id' => 1]);

    if ($user->touch('comments', ['body' => 'Hello World'])) {
        Log::info('Comment created successfully!');
    }
}

Hacks and Tips

  • Relationship Handling: Use this method to handle relationships by creating or updating related models.
  • Conditional Creation: You can pass conditions to only create a record if certain criteria are met.

16. incrementUnique Method

What It Does

The incrementUnique method increments the value of a specified column, ensuring that it doesn’t exceed a unique constraint or reach a maximum value. This is useful for tracking unique identifiers or preventing overuse of certain values.

Example Usage

Suppose you have an invitation_code column in your User model with a unique constraint. You want to send an invitation and track how many times a user has been invited.

Code Example

$user = User::findOrNew(['email' => 'test@example.com']);

if ($user->incrementUnique('invitation_code', 'unique_invitation')) {
    Log::info('Invitation sent successfully!');
}

Hacks and Tips

  • Unique Constraints: Use this method to manage unique identifiers or tokens in your application.
  • Max Value Handling: This method also prevents values from exceeding a specified maximum.

17. scope Method

What It Does

The scope method allows you to define custom scopes for your queries, making it easier to reuse complex query conditions across multiple parts of your application.

Example Usage

Suppose you have a User model with a scope called active, which applies a filter to only return active users.

Code Example

public function boot()
{
    User::addGlobalScope('active', function ($query) {
        $query->whereNotNull('deleted_at');
    });

    // Apply the scope in a query
    $users = User::scope('active')->get();
}

Hacks and Tips

  • Reusable Queries: Use scopes to define reusable query conditions that can be applied across multiple queries.
  • Custom Logic: Scopes allow you to encapsulate complex querying logic, making your code cleaner and more maintainable.

18. nowOrInInterval Method

What It Does

The nowOrInInterval method checks if a column contains the current date or falls within a specified interval. This is particularly useful for time-based conditions.

Example Usage

Suppose you have a created_at column in your User model. You want to find all users who were created today or yesterday.

Code Example

$users = User::query()
    ->where('created_at', 'nowOrInInterval', '1 day')
    ->get();

Hacks and Tips

  • Time-Based Queries: Use this method to build time-based queries that are difficult to achieve with standard Eloquent operations.
  • Custom Intervals: You can specify any interval, not just one day.

19. `getAttribute Method**

What It Does

The getAttribute method allows you to retrieve a specific attribute of the model. This is useful when dealing with attributes that aren’t directly accessible through standard getter methods.

Example Usage

Suppose your User model has a computed attribute full_name, but it’s not defined in the model class.

Code Example

public function getFullName()
{
    return $this->getAttribute('full_name');
}

Hacks and Tips

  • Computed Attributes: Use this method to access attributes that are computed or derived from other fields.
  • Dynamic Access: This method allows for dynamic access to any attribute, regardless of how it’s defined.

20. `hasOneThrough Method**

What It Does

The hasOneThrough method is a helper function to create a one-to-many relationship query through an intermediate model. It’s particularly useful when dealing with complex relationships that involve multiple levels.

Example Usage

Suppose you have a User model with a posts relationship, and each post belongs to a Category. You want to find all categories that have posts written by a specific user.

Code Example

$categories = Category::hasOneThrough('posts', function ($query) {
    $query->where('user_id', 1);
});

Hacks and Tips

  • Multiple Levels: Use this method to handle relationships that span multiple models.
  • Custom Conditions: You can pass custom conditions to filter the results.

Final Thoughts

Creating a Laravel application can be complex, especially when dealing with advanced querying and relationship management. By leveraging the eloquent library’s powerful features, you can build efficient, maintainable, and scalable applications. However, it’s crucial to follow best practices, such as using scopes for reusable queries, properly handling relationships, and ensuring that your database queries are optimized for performance.

In conclusion, Laravel’s Eloquent provides a robust set of tools for working with databases, but mastering these tools requires practice and experimentation. By exploring the methods we’ve covered in this post, you’ll be well on your way to writing efficient and maintainable code in your Laravel applications.

To create and use Eloquent effectively in your Laravel application, follow these best practices:

  1. Understand Eloquent Relationships:
  • Use belongsToMany, hasOne, and belongsTo to define relationships between models.
  • For a one-to-many relationship, use hasMany on the target model and include the foreign key in the related model.
  1. Query Optimization:
  • Always use select to fetch only necessary columns.
  • Optimize joins by using join or whereHas/LikeSubstitutes instead of nested queries for complex conditions.
  • Use scopes (addScope method) for reusable query conditions.
  1. Efficient Updates and Increments:
  • Use increment and decrement to update numeric fields without affecting other columns.
  • Use touch to create or update related models, especially in one-to-many relationships.
  1. Handling Time-Based Queries:
  • Utilize Eloquent’s time-based methods like nowOrInInterval for queries involving dates and intervals.
  1. Scoping Queries:
  • Define custom scopes using the scope method to reuse complex query conditions across multiple parts of your application.
  1. Error Handling and Validation:
  • Use Eloquent’s validation rules (like required, unique, sometimes) to ensure data integrity.
  • Handle errors gracefully and provide meaningful feedback to users.
  1. Avoid N+1 Queries:
  • Use eager loading (with method) to load related models in a single query, reducing the number of database hits.
  1. Use Global Scopes for Consistency:
  • Apply default scopes (like active or trashed) to ensure consistent querying across your application.
  1. Optimize for Performance:
  • Minimize the use of select * and instead select only necessary columns.
  • Use caching mechanisms (like Laravel’s cache) to store frequently accessed data.
  1. Regular Updates and Migrations:
    • Regularly update your models and run migrations to keep your database schema in sync with your application logic.

By following these best practices, you can leverage Eloquent’s power to build efficient, scalable applications while maintaining code clarity and performance.

Leave a Reply

Your email address will not be published. Required fields are marked *

I’m Avinash Tirumala

Hi there! Welcome to my site. I’m Avinash Tirumala, a full-stack developer and AI enthusiast with a deep background in Laravel, Symfony, and CodeIgniter, and a growing passion for building intelligent applications. I regularly work with modern frontend tools like Tailwind CSS, React, and Next.js, and explore rapid prototyping with frameworks like Gradio, Streamlit, and Flask. My work spans web, API, and machine learning development, and I’ve recently started diving into mobile app development. This blog is where I share tutorials, code experiments, and thoughts on tech—hoping to teach, learn, and build in public.

Let’s connect

Share this page