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

Products Laravel Package

jn-devops/products

A Laravel package for adding product catalog functionality to your application, with models, migrations, and configuration for managing products, variants, pricing, and inventory through a clean, framework-friendly API.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm the package is installable. With zero stars and zero dependents there is no guarantee it is on Packagist. Check composer show jn-devops/products after adding it; if it fails, wire it in as a VCS repository:

"repositories": [
  { "type": "vcs", "url": "https://github.com/jn-devops/products" }
],
"require": { "jn-devops/products": "dev-main" }

Pin to a tag or a commit SHA rather than dev-main — you are the only thing keeping this dependency stable.

2. Read these files first, in order:

  • composer.json → extra.laravel.providers and extra.laravel.aliases tells you exactly what gets auto-registered.
  • src/*ServiceProvider.php → what is bound in the container, what is publishable, what migrations/routes load.
  • config/products.php (if present) → table names, model class overrides, currency, morph aliases.
  • database/migrations/ → the actual schema is the real API. Read it before the models.
  • src/Models/ → base classes you will extend or wrap.
  • README.md → often stale in low-adoption packages; trust the code.

3. Publish and migrate.

php artisan vendor:publish --provider="JnDevops\Products\ProductsServiceProvider"
php artisan migrate

Publish tags selectively (--tag=products-config, --tag=products-migrations) so you do not overwrite unrelated assets.

4. First use case — get a product into your app and out again:

use JnDevops\Products\Models\Product;

$product = Product::create([
    'name' => 'Starter Plan',
    'sku'  => 'PLAN-STARTER',
    'price' => 4900, // check the package's unit convention first
]);

return Product::query()->where('is_active', true)->paginate();

Verify the migration column names before writing this — most first-run errors in packages like this are a mismatch between the README's example and the actual schema.

5. Smoke-test in a throwaway route or tinker session before integrating into domain code, so you learn the package's conventions (key type, soft deletes, scopes) in isolation.

Implementation Patterns

Wrap, don't leak. The highest-value pattern with a low-adoption dependency is a thin boundary: your App\Models\Product extends the package model, and your controllers/resources only ever see your class. When the package stalls or you replace it, you change one file.

namespace App\Models;

class Product extends \JnDevops\Products\Models\Product
{
    protected $table = 'products';
}

If the package exposes contracts/interfaces, bind your implementation in a service provider instead — that is the cleaner seam.

Catalog service for read paths. Keep query logic out of controllers:

class Catalog
{
    public function active(): Collection
    {
        return Product::query()
            ->where('is_active', true)
            ->with('prices')
            ->orderBy('name')
            ->get();
    }
}

Pricing as a separate concern. Product/pricing packages almost always separate a product from its price records (currency, effective dates, price lists). Read the price model before assuming $product->price exists as a column. Model "current price" as a resolver method on your own class rather than scattering where('effective_from', '<=', now()) through views.

Seed reference data in tests, not fixtures. Use RefreshDatabase plus the package's factories if published; otherwise a small ProductFactory of your own that calls the package model directly. Do not depend on package seeders in tests — they tend to be environment-specific.

Listen to what the package emits. If it fires ProductCreated/ProductUpdated events, attach your cache invalidation and search-index sync there rather than in booted() model hooks, which fight the package's own observers.

Cache the catalog, invalidate on write. These lookups are read-heavy and change rarely. A tagged cache key (products:active) cleared from the model's saved/deleted events removes the most common performance complaint.

Morph maps are your friend. If the package uses polymorphic relations (attributes, media, prices), register the aliases in Relation::enforceMorphMap(); otherwise the package writes raw FQCNs into your database and refactors become migrations.

Gotchas and Tips

Migration collisions. If your app already has a products table, the published migration will fail or, worse, silently add columns to your table. Publish the migrations, review them, rename the table in the config and the migration, and re-run. Never run migrate:fresh in anything shared while exploring.

Config cache. After publishing config, php artisan config:clear — a cached config from before install is the usual cause of "my settings are ignored."

Money units. Determine whether the schema stores integer minor units or decimals before you write a single price. Mixing the two produces errors that are invisible until someone is charged 100× too much.

Autoload and namespace drift. Packages with a GitHub org differing from the composer vendor (jn-devops vs. jn_devops) occasionally have stale PSR-4 entries; if classes 404, run composer dump-autoload -o and check vendor/jn-devops/products/composer.json against the actual directory layout.

Soft deletes and unique keys. A soft-deleted product keeps its sku/slug. Use Rule::unique(...)->whereNull('deleted_at') on validation, or restore instead of re-create.

SQLite in tests. JSON columns, enums, and generated columns behave differently on SQLite. If the package's migrations use json heavily, run CI against MySQL/Postgres, not just :memory:.

Version pinning and fork readiness. With no dependents, no release history, and no issue traffic, treat this as vendored code: pin an exact SHA, and be prepared to fork. Keep your integration surface (the App\Models subclass, the Catalog service) small enough that forking is a one-hour job rather than a rewrite.

Extension points to check before hacking. In order of preference: published config class overrides → contracts bound in your service provider → model subclassing → package events/listeners → macros on package query builders. Only patch vendor/ as a last resort, and if you do, use composer-patches so it survives composer install.

Debugging checklist when something does not work: php artisan about (is the provider loaded?), composer show jn-devops/products (which version is actually installed?), php artisan route:list | grep product (does it ship routes?), and php artisan vendor:publish --list (did you publish everything it expects?).

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource