awareness/aware
Aware is a lightweight Laravel package that helps you add awareness-focused functionality to your app. It offers simple configuration, an intuitive PHP API, and clean integration with existing Laravel projects.
Install (Laravel 4 era — Composer only, no auto-discovery):
composer require awareness/aware:dev-master
Then register the provider in app/config/app.php under providers:
'Awareness\Aware\AwareServiceProvider',
If the package ships a config file, publish it and inspect it before writing any models:
php artisan config:publish awareness/aware
Look here first — in this order:
vendor/awareness/aware/src/ — the base class/trait name and the exact method signatures matter more than the README here. This package is small; read the whole source in ten minutes. Confirm whether you get a Model base class, a trait, or both, and whether the public API is validate(), errors(), save(), forceSave().README.md for the canonical rules-property name ($rules vs $validationRules).composer.json — check the illuminate/* constraints actually match your Laravel 4.x point release.First use case — a Post model that refuses to persist invalid data:
use Awareness\Aware\Model as AwareModel;
class Post extends AwareModel
{
protected $rules = [
'title' => 'required|min:3|max:120',
'slug' => 'required|alpha_dash|unique:posts,slug',
'body' => 'required',
'user_id' => 'required|exists:users,id',
];
}
$post = new Post(Input::all());
if (! $post->save()) {
return Redirect::back()->withErrors($post->errors())->withInput();
}
The mental model: save() returns false (not an exception) when validation fails, and errors() gives you a MessageBag that drops straight into Laravel 4's withErrors() / Blade $errors handling. If that's not the shape of the API in the source you read, stop and adjust before building on it.
Base class vs trait. If the package offers a trait, prefer use AwareTrait; on models that already extend something (a soft-deleting base model, a tenant-scoped model, an existing BaseModel in your app). The base-class route is fine for a greenfield app but will fight you the moment you need multiple inheritance-ish behavior. Pick one and be consistent — mixing both in one codebase produces confusing validation paths.
Rule sets for create vs update. The classic pitfall is unique on update: the record's own row must be excluded. Two workable approaches:
protected $rulesets = [
'creating' => ['slug' => 'required|alpha_dash|unique:posts,slug'],
'updating' => ['slug' => 'required|alpha_dash'],
];
Or, if the package exposes a pre-validation hook (Ardent-lineage packages usually have beforeValidate / beforeSave), mutate $this->rules there:
public function beforeValidate()
{
if ($this->exists) {
$this->rules['slug'] .= ',slug,' . $this->getKey();
}
return true;
}
Do not compute dynamic rules as class-property defaults. protected $rules = ['email' => 'unique:users,email,' . Auth::id()] will explode — property defaults are evaluated at class-definition time, before the auth session or request exists. Always defer to a hook or an instance method.
Controller flow. Keep controllers thin; let validation failures fall through naturally:
public function store()
{
$post = new Post(Input::all());
if (! $post->save()) {
return Redirect::back()->withErrors($post->errors())->withInput();
}
return Redirect::route('posts.show', $post);
}
Validate without persisting. For previews, draft states, or AJAX validation endpoints, call the validation method alone and return JSON:
if (! $post->validate()) {
return Response::json(['errors' => $post->errors()->toArray()], 422);
}
This is the single biggest win over cramming rules into controllers: one source of truth for web, API, and console entry points.
Custom messages and attribute names. Mirror Laravel 4's validator conventions — $messages for per-field overrides, $attributes for human-readable names ("body" → "post body"). Without $attributes, your error messages leak database column names into the UI.
Seeders, imports, and fixtures must bypass validation. If you generate demo data or migrate legacy rows, validated save() will silently drop records. Use forceSave() (or whatever the package calls the unvalidated write) in seeders and importers, and assert on the return of save() everywhere else so you notice dropped rows. Silent data loss during a bulk import is the most common way this package bites a team.
Composition with relations. Validating a parent does not validate its children. For a Post with Comment children, either validate children explicitly in a loop before saving, or move the whole operation into a service that validates then persists inside a DB::transaction.
save() returns false, it does not throw. A failed validation in a foreach over imported rows will look like a successful run. Always check the return value; if you can't, wrap bulk operations in a helper that throws on false so failures are loud.
Errors are reset per validation run. $model->errors() reflects the last validate()/save() call, not an accumulated history. Don't stash a model and inspect its errors an hour later — copy errors()->all() into a variable at the failure site.
Ordering of mutators and validation. If you hash passwords or slugify strings in setters, whether the validator sees the raw or mutated value depends on where the package hooks in. Test it explicitly: set a password, call validate(), and see whether min:8 was checked against the plaintext or the 60-character hash. This is the second-most-common source of "why did this pass?" confusion.
unique rules and soft deletes. unique:posts,slug counts soft-deleted rows unless you exclude them. Either add the deletion-column condition to the rule or accept that you can never reuse a slug after deletion — decide deliberately.
Mass assignment and validation are separate gates. fillable/guarded protects against unwanted attributes; the validator checks presence and format. A field blocked by guarded will show up as required failing, which reads like a user error but is a config error. Check $model->getAttributes() right after hydration when a required rule fails on data the user clearly submitted.
Laravel 4 is end-of-life. You are pinning PHP 5.x and an unpatched framework. For anything new, don't start here — Laravel's FormRequest classes (5.0+) or a maintained validating-Eloquent package give you the same self-validating model pattern on a supported stack. If you're inheriting an Aware codebase, treat the validation layer as the thing you preserve during a migration: lift $rules into FormRequest or dedicated validator classes first, then port the framework.
Debugging checklist when a save mysteriously fails:
dd($model->errors()->all()) — is it validation, or something else?dd($model->getDirty()) — is anything actually changing?class_parents() / class_uses()).false once the validator passes.Extension points worth knowing. Pre/post validation and pre/post save hooks are the intended customization surface — use them for timestamps, slug generation, and cross-field rules rather than overriding save() wholesale and reimplementing the flow. If you must override, call the parent and propagate its boolean return verbatim; swallowing that return is how validation quietly stops working for one model.
How can I help you explore Laravel packages today?