visiosoft/profile-module
Visiosoft Profile Module is a Laravel/PHP package for managing user profiles within Visiosoft applications, offering profile data structures and module integration to help add, organize, and display profile information in a modular CMS-style setup.
What it actually is. visiosoft/profile-module is not a standalone Laravel package — it is a Streams Platform addon built for OpenClassify / PyroCMS-style applications. It packages a profile Streams namespace (fields, assignments, form/table builders, and a repository) that extends the host app's users module with profile data. If you are not running OpenClassify or a Streams-based app, there is nothing here to install; the service provider depends on Streams' addon bootstrapping.
Minimal steps (inside an OpenClassify host):
composer require visiosoft/profile-module # confirm exact name in the repo's composer.json
php artisan addon:install visiosoft.module.profile
php artisan migrate
php artisan streams:compile
Then verify the addon is registered and enabled:
php artisan addon:list
php artisan streams:namespaces # look for the namespace the module ships
Where to look first, in this order:
composer.json — confirm the addon type (streams-addon), required host version, and the addon slug used by addon:install.src/ProfileModuleServiceProvider.php — reveals bindings, route loading, event listeners, and which classes are actually public API.migrations/ and any seeder — this is the de facto documentation. The field slugs, stream slug, and namespace are defined here, not in a README.resources/config/ — config keys, route prefixes, settings schema.src/Profile/* — the Streams model, repository, form builder, and table builder.First use case: add one custom field to the profile and render it. Create the field (admin UI or a small addon migration), assign it to the profile stream, run php artisan streams:compile, then read it off the profile entry:
$user = auth()->user();
$profile = $user->profile; // null-check — not every user has an entry
echo $profile?->presenter()->phone;
That single loop — define field → assign to stream → compile → render through the repository/presenter — is 80% of day-to-day work with this package.
Treat it as a Streams namespace, not an ORM module. The public surface is the stream slug, field slugs, and the repository/form/table builders. Query through the repository so Streams criteria (locale, published state, relations) apply:
$profiles = app(\Visiosoft\ProfileModule\Profile\ProfileRepository::class);
$profile = $profiles->findByUserId($userId); // check the repo for the real method names
Extend builders instead of writing new forms. Streams' FormBuilder/TableBuilder are designed for inheritance. Add columns or fields by extending the shipped builder and rebinding it in your own service provider, rather than duplicating the form.
Add fields from your own addon, never by editing vendor migrations. Write a migration in your app/addon that uses the Streams field API, assigns the field to the profile stream, then run streams:compile. This keeps upgrades of profile-module safe.
Publish and override. Anything you want to change in config, views, or translations should go through php artisan addon:publish visiosoft.module.profile, then be edited under resources/{addon} or app-level overrides.
Blade integration. Use the presenter for display-formatted values and the raw attribute for logic. For listings, eager-load the relation to avoid N+1:
User::with('profile')->paginate(); // relation name per the module's model
Workflow for a typical change: define/assign field → php artisan streams:compile → php artisan view:clear → check the admin form renders → check the front-end presenter output. Keep streams:compile in your loop; it is cheap and prevents most "field doesn't exist" confusion.
Integration points worth using: model observers/events (EntryWasCreated, EntryWasUpdated) on the profile entry, custom field types if the profile needs a non-standard input, and settings in resources/config/ for any per-site toggles. For anything involving permissions on profile fields, implement it in your app's policy layer — do not assume the module enforces view/edit rules.
addon:install flow; dropping it in composer.json and running composer dump-autoload leaves you with a provider that never boots. Enable the addon, then clear caches.streams:compile is mandatory after any field change. Skipping it produces misleading errors ("column not found", "field does not exist") that look like code bugs.php artisan migrate alone may not produce the profile table if the addon was never installed/enabled. If the table is missing, re-run addon:install rather than hand-editing migrations.$user->profile->... in Blade or a controller is a potential Trying to get property of non-object. Use ?-> or optional().$entry->presenter()->field and $entry->field are not interchangeable; presenters wrap, format, and can emit markup. Mixing them in one template is a common source of double-escaped or unescaped output.php artisan config:clear && php artisan view:clear && php artisan cache:clear. Streams caches compiled addon metadata too.APP_DEBUG=true, tail storage/logs/laravel.log, and use php artisan tinker against the repository to isolate whether a failure is in Streams bootstrapping, field compilation, or your own code. Streams' exception rendering often hides the original cause; wrap suspect calls in a try/catch that logs $e->getPrevious().How can I help you explore Laravel packages today?