Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcastro committed Jul 12, 2019
0 parents commit 7932748
Show file tree
Hide file tree
Showing 5 changed files with 459 additions and 0 deletions.
29 changes: 29 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "ajcastro/insert-update-many",
"description": "Laravel's batch insert or batch update for collection of eloquent models.",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Arjon Jason Castro",
"email": "ajcastro29@gmail.com"
}
],
"require": {
"php": ">=5.4.0"
},
"autoload": {
"psr-4": {
"AjCastro\\InsertUpdateMany\\": "src"
}
},
"extra": {
"laravel": {
"providers": [
"AjCastro\\InsertUpdateMany\\ServiceProvider"
],
"aliases": {
}
}
}
}
115 changes: 115 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Laravel Eloquent's Insert/Update Many

Laravel's batch insert or batch update for collection of eloquent models.
Perform single query for batch insert or update operations.
This updates the `created_at` and `updated_at` column of the models and the tables.
The method names `insertMany` and `updateMany` is based from the eloquent method name `saveMany`.
Both `insertMany` and `updateMany` can accept collection of models or just plain array data.

## Installation

```
composer require ajcastro/insert-update-many
```

## Usage

### Insert Many

Directly pass array or collection of models unlike Laravel's built-in `insert()` which only accept arrays.
This already sets the `created_at` and `updated_at` columns.

```php
$users = factory(User::class, 10)->make();
User::insertMany($users);
```

#### How it works

The passed collection of models is transformed to its array form, only including fillable attributes, and passed its array
form to Laravel's native `insert()` method.

### Update Many

Update array or collection of models. This perform a single update query for all the passed models.
Only the dirty or changed attributes will be included in the update.
This updates the `updated_at` column of the models and the tables.

```php
User::updateMany($users); // update many models using id as the default key
User::updateMany($users, 'id'); // same as above
User::updateMany($users, 'username'); // use username as key instead of id

```

#### Specifying which columns to be updated

```php
User::updateMany($users, 'id', ['email', 'first_name', 'last_name']);
```

#### How it works

This will produce a query like this:

```sql
UPDATE
`users`
SET
`email` =
CASE
WHEN
`id` = '426'
THEN
'favian.russel@example.com'
WHEN
`id` = '427'
THEN
'opurdy@example.org'
WHEN
`id` = '428'
THEN
'kaylah.hyatt@example.com'
ELSE
`email`
END
, `first_name` =
CASE
WHEN
`id` = '426'
THEN
'Orie'
WHEN
`id` = '427'
THEN
'Hubert'
WHEN
`id` = '428'
THEN
'Mikayla'
ELSE
`first_name`
END
, `last_name` =
CASE
WHEN
`id` = '426'
THEN
'Weissnat'
WHEN
`id` = '427'
THEN
'Wiza'
WHEN
`id` = '428'
THEN
'Keeling'
ELSE
`last_name`
END
WHERE
`id` IN
(
426, 427, 428
);
```
50 changes: 50 additions & 0 deletions src/InsertMany.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace AjCastro\InsertUpdateMany;

use Illuminate\Database\Eloquent\Model;

class InsertMany
{
protected $query;
public $timestamps = true;
protected $createdAtColumn;
protected $updatedAtColumn;

public function __construct($query, $timestamps = true, $createdAtColumn = 'created_at', $updatedAtColumn = 'updated_at')
{
$this->query = $query;
$this->timestamps = $timestamps;
$this->createdAtColumn = $createdAtColumn;
$this->updatedAtColumn = $updatedAtColumn;
}

public function insert($rows)
{
$ts = now();

$rows = collect($rows)->map(function ($row) use ($ts) {
$timestamps = $this->timestamps;
$createdAtColumn = $this->createdAtColumn;
$updatedAtColumn = $this->updatedAtColumn;

if ($row instanceof Model) {
$timestamps = $row->usesTimestamps();
$createdAtColumn = $row->getCreatedAtColumn();
$updatedAtColumn = $row->getUpdatedAtColumn();
$row->{$createdAtColumn} = $ts;
$row->{$updatedAtColumn} = $ts;
$row = array_only($row->getAttributes(), $row->getFillable());
}

if ($timestamps) {
$row = $row + [$createdAtColumn => $ts, $updatedAtColumn => $ts];
}

return $row;
})
->all();

return $this->query->insert($rows);
}
}
42 changes: 42 additions & 0 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace AjCastro\InsertUpdateMany;

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;

class ServiceProvider extends BaseServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
Builder::macro('updateMany', function ($rows, $key = 'id', $columns = []) {
return (new UpdateMany(
$this->from,
$key,
$columns
))->update($rows);
});

EloquentBuilder::macro('updateMany', function ($rows, $key = 'id', $columns = []) {
return (new UpdateMany(
$this->getModel()->getTable(),
$key,
!empty($columns) ? $columns : $this->getModel()->getFillable()
))->update($rows);
});

Builder::macro('insertMany', function ($rows) {
return (new InsertMany($this))->insert($rows);
});

EloquentBuilder::macro('insertMany', function ($rows) {
return $this->getQuery()->insertMany($rows);
});
}
}
Loading

0 comments on commit 7932748

Please sign in to comment.