smorken/model
smorken/model is a Laravel package that provides reusable Eloquent model utilities and a lightweight base model, helping developers standardize common model behavior, reduce boilerplate, and keep application models consistent and maintainable.
smorken/model is not on Packagist, so the first step is teaching Composer where to find it. Add the Bitbucket repository as a VCS source before requiring the package:
{
"repositories": [
{ "type": "vcs", "url": "https://bitbucket.org/scott_morken/laravel-model.git" }
]
}
composer require smorken/model
Bitbucket Git over HTTPS will prompt for credentials (or require an app password / SSH key configured on the machine and in CI). Budget for that before you assume the package is broken.
Where to look first, roughly in this order:
php artisan vendor:publish --provider="Smorken\\Model\\..." if one exists.Smorken\Model\Model (or similar) that your Eloquent models extend instead of Illuminate\Database\Eloquent\Model. Read its boot/bootTraits methods to see what it silently adds.use, and any custom cast classes.First use case: take one existing model, change extends Model to extend the package's base model, run your model's test suite, and diff the behavior. Do this on a single throwaway model before touching the rest of the app — the package overrides Eloquent defaults, and you want to see exactly which ones.
use Smorken\Model\Model; // verify the actual FQCN in the repo
class Post extends Model
{
//
}
Introduce a project-level base model as a buffer. Don't have fifty models extend the vendor class directly. Create App\Models\BaseModel extends Smorken\Model\Model and have everything extend that. When the package is abandoned or you outgrow it, you change one line instead of fifty.
namespace App\Models;
use Smorken\Model\Model as SmorkenModel;
abstract class BaseModel extends SmorkenModel
{
// project-wide defaults live here, not in vendor land
}
Treat it as a trait bundle when possible. If the package is mostly traits (soft-delete helpers, slugging, UUID keys, ordered scopes), use only what you need per model rather than adopting the base class wholesale. Selective adoption dramatically reduces the blast radius of an upgrade.
Wrap package-specific behavior in your own scopes and accessors. If the package gives you a ->active() scope or an auto-slugging boot hook, re-expose it under your own domain language:
public function scopePublished(Builder $q): Builder
{
return $q->where('status', 'published'); // don't leak vendor scope names into controllers
}
This keeps controllers and Blade templates free of vendor terminology and makes replacement trivial.
Integration with the rest of the stack. Eloquent extensions interact unpredictably with:
laravel/framework version bumps (the package's constraint will tell you how far you can upgrade)Model::unguard() behavior may differ if the base model changes $guardedphp artisan ide-helper:models — regenerating docblocks after switching base classes is worth the two minutestoArray or $hidden, your JSON contracts can shift silentlyTesting pattern. Keep a small tests/Feature/BaseModelTest.php that asserts the vendor behaviors you actually rely on (e.g. "a slug is generated on save", "soft-deleted rows are excluded"). That file is your regression net when you pin or bump the package.
No Packagist listing means CI is on you. Every pipeline needs Bitbucket auth configured (Composer auth JSON, COMPOSER_AUTH env var, or a deploy key). This is the single most common reason a fresh clone fails with "could not be found in any version."
Zero dependents and a low signal score is a risk statement. Assume no upstream fixes. Before adopting in production: fork it into your own namespace, or at minimum vendor it with a pinned commit hash ("smorken/model": "dev-master#abc1234") rather than a branch. Branch references can move under you.
Check the base class before assuming Eloquent semantics. Extended models frequently:
$guarded = [] (mass-assignment surprise)getRouteKeyName() or resolveRouteBinding() (route model binding changes)booted() hooks that fire on every save, including in queue workers and seeders$casts defaultsDiff the vendor base class against Illuminate\Database\Eloquent\Model and read every overridden method. There are usually fewer than a dozen, and they define everything.
Debugging surprises. If attributes vanish, timestamps behave oddly, or save() triggers unexpected writes, drop a dd(static::class, $this->getAttributes()) inside a temporary override of save() on your project base model to see whether the vendor hook is the culprit. Also check Model::getEventDispatcher() — a boot hook registering observers is a common gotcha.
Extension points to prefer. Override booted() and call parent::booted() (not boot()), use $casts and custom cast classes over mutators, and use query scopes over overridden builder methods. These are the seams most likely to survive an upgrade because they're Laravel's contracts, not the package's.
Migration exit plan. Write it down on day one: which traits, which overridden methods, which scopes. If the list is short, replacing the package with 40 lines of your own BaseModel is often the better long-term move — for a dependency this obscure, "copy the useful bits and own them" is a legitimate architecture decision, not a cop-out.
How can I help you explore Laravel packages today?