- Notifications
You must be signed in to change notification settings - Fork0
Eloquent's missing "array" driver.
License
popjelev/sushi
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Eloquent's missing "array" driver.
Sometimes you want to use Eloquent, but without dealing with a database.
Originally, this package was only available to my sponsors on GitHub Sponsors until I reached 75 sponsors.
Now that we've reached the goal, the package is fully open source.
Enjoy, and thanks for the support! ❤️
Learn more aboutSponsorware atgithub.com/sponsorware/docs 💰.
composer require calebporzio/sushi
Using this package consists of two steps:
- Add the
Sushi
trait to a model. - Add a
$rows
property to the model.
That's it.
class Stateextends Model{use \Sushi\Sushi;protected$rows = [ ['abbr' =>'NY','name' =>'New York', ], ['abbr' =>'CA','name' =>'California', ], ];}
Now, you can use this model anywhere you like, and it will behave as if you created a table with the rows you provided.
$stateName = State::whereAbbr('NY')->first()->name;
This is really useful for "Fixture" data, like states, countries, zip codes, user_roles, sites_settings, etc...
Let's say you created aRole
model, based on an array using Sushi, that looked like this:
class Roleextends Model{use \Sushi\Sushi;protected$rows = [ ['id' =>1,'label' =>'admin'], ['id' =>2,'label' =>'manager'], ['id' =>3,'label' =>'user'], ];}
You can add a relationship to another standard model, just like you normally would:
class Userextends Model{ ...publicfunctionrole() {return$this->belongsTo(Role::class); }}
Assuming theusers
table has arole_id
column, you can do things like this:
// Grab a User.$user = User::first();// Grab a Role.$role = Role::whereLabel('admin')->first();// Associate them.$user->role()->associate($role);// Access like normal.$user->role;// Eager load.$user->load('role');User::with('role')->first();
Note: There is one caveat when dealing with Sushi model relationships. The
whereHas
method will NOT work. This is because the two models are spread across two separate databases.
You can even use Laravel'sexists:table,column
database checking request validation rule.
$data =request()->validate(['state' => ['required','exists:App\Models\State,abbr'],]);
Note: Be aware that you must use the fully-qualified namespace of the model instead of a table name. This ensures that Laravel will correctly resolve the model's connection.
If Sushi's schema auto-detection system doesn't meet your specific requirements for the supplied row data, you can customize them with the$schema
property or thegetSchema()
method.
class Productsextends Model{use \Sushi\Sushi;protected$rows = [ ['name' =>'Lawn Mower','price' =>'226.99'], ['name' =>'Leaf Blower','price' =>'134.99'], ['name' =>'Rake','price' =>'9.99'], ];protected$schema = ['price' =>'float', ];}
When you need more flexibility, you can implement theafterMigrate(BluePrint $table)
method, allowing you to customize the table after it has been created. This might be useful for adding indexes to certain columns.
class Productsextends Model{use \Sushi\Sushi;protected$rows = [ ['name' =>'Lawn Mower','price' =>'226.99'], ['name' =>'Leaf Blower','price' =>'134.99'], ['name' =>'Rake','price' =>'9.99'], ];protectedfunctionafterMigrate(Blueprint$table) {$table->index('name'); }}
Under the hood, this package creates and caches a SQLite database JUST for this model. It creates a table and populates the rows. If, for whatever reason, it can't cache a .sqlite file, it will default to using an in-memory sqlite database.
You can optionally opt out of using theprotected $rows
property, and directly implement your owngetRows()
method.
This will allow you to determine the rows for the model at runtime. You can even generate the model's rows from an external source like a third-party API.
class Roleextends Model{use \Sushi\Sushi;publicfunctiongetRows() {return [ ['id' =>1,'label' =>'admin'], ['id' =>2,'label' =>'manager'], ['id' =>3,'label' =>'user'], ]; }}
If you choose to use your own ->getRows() method, the rows will NOT be cached between requests by default.
You can force Sushi to cache your dataset with the following method:sushiShouldCache()
.
Let's look at a configuration where->getRows()
datasets would be cached as an example:
class Roleextends Model{use \Sushi\Sushi;publicfunctiongetRows() {return [ ['id' =>1,'label' =>'admin'], ['id' =>2,'label' =>'manager'], ['id' =>3,'label' =>'user'], ]; }protectedfunctionsushiShouldCache() {returntrue; }}
By default, Sushi looks at the "last modified" timestamp of your model PHP file and compares it with its internal.sqlite
cache file. If the model file has been changed more recently than the.sqlite
cache file, then Sushi will destroy and rebuild the.sqlite
cache.Additionally, you can configure an external file for Sushi to reference when determining if the cache is up to date or needs to be refreshed.
If, for example, you are using Sushi to provide an Eloquent model for an external data source file like an.csv
file, you can usesushiCacheReferencePath
to force Sushi to reference the.csv
file when determining if the cache is stale.
For example:
class Roleextends Model{use \Sushi\Sushi;publicfunctiongetRows() {returnCSV::fromFile(__DIR__.'/roles.csv')->toArray(); }protectedfunctionsushiShouldCache() {returntrue; }protectedfunctionsushiCacheReferencePath() {return__DIR__.'/roles.csv'; }}
Now, Sushi will only "bust" its internal cache ifroles.csv
changes, rather than looking at theRole.php
model.
Sushi reads the first row in your dataset to work out the scheme of the SQLite table. If you are usinggetRows()
and this returns an empty array (e.g an API returns nothing back) then Sushi would throw an error.
If you would like Sushi to work even if the dataset is empty, you can define your schema in the optionalprotected $schema
array.
Note: If you choose to use your own ->getRows() method, the rows will NOT be cached between requests.
class Currencyextends Model{use \Sushi\Sushi;protected$schema = ['id' =>'integer','name' =>'string','symbol' =>'string','precision' =>'float' ];publicfunctiongetRows() {return []; }}
Sushi requires you to add two properties to your model, if it uses a string-based primary key -$incrementing
and$keyType
:
class Roleextends Model{use \Sushi\Sushi;public$incrementing =false;protected$keyType ='string';protected$rows = [ ['id' =>'admin','label' =>'Admin'], ['id' =>'manager','label' =>'Manager'], ['id' =>'user','label' =>'User'], ];}
ERROR:SQLSTATE[HY000]: General error: 1 too many SQL variables
By default Sushi uses chunks of100
to insert your data in the SQLite database. In some scenarios this might hit some SQLite limits.You can configure the chunk size in the model:public $sushiInsertChunkSize = 50;
About
Eloquent's missing "array" driver.
Resources
License
Stars
Watchers
Forks
Packages0
Languages
- PHP100.0%