Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Notifynder Laravel Package

fenos/notifynder

Notifynder is a Laravel package for database-backed user notifications. It makes it easy to send notifications, retrieve and count unread items, mark them as read, and integrate with Eloquent models to build alerts and activity feeds.

View on GitHub
Deep Wiki
Context7

Getting Started

Version 4.3.0 is an additive minor release (#280 add eager loading) — no breaking changes, no migration or config republish required. Upgrading is a composer update away, but it's worth pinning ^4.3 so the new eager-loading API is available consistently across environments.

First steps:

  1. Confirm your platform matrix. Check composer.json in the tagged release for the supported PHP/Laravel range before bumping — the eager-loading work often rides on newer Eloquent APIs (withOnly, Model::preventLazyLoading), and the package may have quietly dropped older Laravel versions in the same window.
  2. Read the PR diff and its tests. #280 is the authoritative spec for how relations are declared and resolved. The test fixtures are the fastest way to see the intended call signature — faster than the README, which may lag a minor release by a few days.
  3. Find the extension point. Locate where the package builds its query — typically a repository, query builder, or a relations/with option on the facade, resource, or config block. That single seam is where nearly all of your day-to-day usage will live.
  4. First real use case: take one listing endpoint or index page that currently triggers N+1 queries (check Telescope or DB::listen for repeated select * from ... where id = ?). Add the relation(s) via the new option, then re-measure the query count.

A good smoke test before touching production code:

DB::listen(fn ($q) => logger()->debug($q->sql, $q->bindings));

$results = YourPackage::query()->with(['author', 'comments.user'])->get();
// expect the query count to stay flat as $results->count() grows

Implementation Patterns

Declarative eager loading at the call site. Pass relations alongside your existing filters rather than reaching into the model layer. This keeps the load strategy visible where the query is written, which matters when different consumers of the same resource need different graphs (an API index vs. a detail view vs. an export).

$rows = Model::query()
    ->with(['owner', 'tags'])
    ->paginate(50);

Default to $with only for genuinely ubiquitous relations. If a relation is needed on ~every read of the model, protected $with = ['owner']; removes a whole class of N+1 bugs. Be conservative — anything loaded by default is loaded in queued jobs, console commands, and test factories too, and that cost compounds silently.

Nested graphs with dot notation, but budget for them. Each nesting level is an additional query. with(['comments.user.profile']) is three queries regardless of row count — cheap compared to N+1, but not free. For deep graphs on large pages, prefer splitting into two queries or loading the outer relation and letting the inner one lazy-load behind a cached accessor.

Pair with aggregate counts instead of loading full relations. When you only need "how many", withCount is dramatically cheaper than loading the collection and calling ->count().

Guard against regressions in tests, not in production. Turn on strict lazy-loading in your non-production environments so a future refactor that drops the with() fails loudly:

// AppServiceProvider::boot()
Model::preventLazyLoading(! app()->isProduction());

Then assert query counts on the endpoints that motivated the upgrade — this is the regression test that actually protects the 4.3.0 win.

Compose with pagination and chunking. The payoff scales with result set size, which means the eager-loaded path pairs naturally with paginate(), cursorPaginate(), and chunkById() in exports and scheduled jobs. Verify each of these paths separately; chunked iteration re-runs the eager load per chunk, so relation count matters more there than on a single page.

Constrain eager loads where the package supports it. Filtering a relation (e.g. only published comments) inside the eager-load closure avoids loading rows you'll discard in the view — the most common way an eager-loaded endpoint ends up slower in memory than the N+1 version it replaced.

Gotchas and Tips

  • Column selection silently nulls relations. If you narrow the parent query with select('id', 'title'), you must include the foreign key (user_id) or the eager load resolves to null with no error. This is the single most common cause of "the eager loading doesn't work" reports.
  • withCount and with interact. Both add subqueries or joins; combining several on a wide table can produce a surprising query plan. Check EXPLAIN on your largest table before shipping a page that uses both.
  • Memory, not query count, becomes the new ceiling. Eager loading trades many small queries for few large ones. A page that loads 50 parents × 2,000 children each is now one query returning 100k hydrated models — better for the DB, worse for PHP memory. Use withOnly on collections you've already loaded, or constrain the relation.
  • Relations aren't refreshed on cached models. If you cache serialized models and rehydrate them, the eager-loaded relations come from cache and will be stale relative to the database. Cache the parent ID and re-query with with() on the hot path, or version your cache keys on write.
  • Debugging: DB::listen, Laravel Telescope's query tab, and Model::preventLazyLoading() cover almost every case. If the relation still lazy-loads despite the with(), check for a $with override on a child model or a global scope adding its own constraints.
  • Extension points: the relation resolver is usually swappable via the container or a config key. If you need a custom load strategy (e.g. batching across tenants), bind a decorator rather than forking — that keeps you on the upgrade path for 4.4.
  • Config quirks: if the package publishes config, re-check it after the bump. Minor releases frequently add a new key with a default that's correct for new installs but absent from your published copy, leaving the feature inert until you diff the stub.
  • Watch the patch releases. Eager loading changes tend to surface follow-up fixes in 4.3.x around duplicate rows from belongsToMany joins and ordering inside constrained eager loads. Read 4.3.1+ notes before pinning an exact version.

Bottom line for 4.3.0: adopt it for the N+1 fix, not for new surface area. The upgrade is low-risk, the payoff concentrates in index/listing endpoints and exports, and the durable value comes from the lazy-loading guard you add alongside it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console