- # It's your code
- # Customizing a generated module
- # Changing the stubs
- # Adding admin pages
- # Theme
- # Testing
- # Contributing
It's your code
Up to 1.0, customizing LaraAdmin meant forking the dwij/laraadmin package. Since 1.1 there is nothing to fork: LaraAdmin's code is part of your application. Change controllers, models, views, the theme and even LAModule directly, and commit them like the rest of your code. To get new LaraAdmin versions later, merge them with git (see Upgrading). The fewer LaraAdmin core files you change, the easier those merges are.
Customizing a generated module
After generating a CRUD, its files are ordinary Laravel code:
app/Http/Controllers/LA/CoursesController.php: add actions, change what the listing shows (dtajax()), or redirect elsewhere after saving. Keep theLAModule::hasAccess()checks.app/Models/Course.php: add relations, scopes and casts.app/Observers/CourseObserver.php: react to records being created, updated or deleted.resources/views/la/courses/*.blade.php: change the layout. Use@la_input($module, 'fees')and@la_display($module, 'fees')to place single fields, so field types, labels and access stay handled for you.
la:crud again, overwrite the controller, model, observer, views and language file. Once you customize a module, change its fields in Module Manager but don't regenerate it.
Changing the stubs
The generator builds every new module from app/Stubs/: controller.stub, model.stub, observer.stub, views/*.blade.stub, routes.stub, migration.stub, language.stub. Edit them to change what every new module looks like, for example to add a column to all listings or a default scope to all models. Keep the __token__ placeholders.
When you change a pattern in your existing modules (say, a new access check), change the matching stub too, or the next generated module brings the old pattern back.
Don't remove the markers the generator inserts at (see Architecture).
Adding admin pages
Add your own admin routes inside the second group of routes/admin.php (above its last });, which the generator also uses), and check access in the controller:
// routes/admin.php, inside the 'permission:ADMIN_PANEL' group
Route::get(config('laraadmin.adminRoute').'/reports/courses', 'ReportsController@courses');
// app/Http/Controllers/LA/ReportsController.php
public function courses()
{
if (! LAModule::hasAccess('Courses', 'view')) {
return redirect(config('laraadmin.adminRoute').'/');
}
return view('la.reports.courses', ['courses' => Course::all()]);
}
Make the view @extends('la.layouts.app') to get the admin layout, and add a custom link in the Menu Manager. Use POST for anything that changes data.
Theme
The admin theme is AdminLTE 2 on Bootstrap 3, in resources/less/. After changing it, rebuild public/la-assets/ with npm install and npm run dev (Laravel Mix 6). Skin and layout can be switched without code on the Configure page.
Testing
The test suite
LaraAdmin 1.13.1 comes with PHPUnit 12 tests. They need a MySQL database named laraadmin_test (see phpunit.xml); each test migrates and seeds it from scratch. Run them with ./vendor/bin/phpunit.
| Test | Covers |
|---|---|
Feature/AdminSmokeTest | Every admin page and listing data endpoint |
Feature/ModuleSchemaTest | All 31 field types: create, save again, change type |
Feature/CrudGeneratorTest | Runs la:crud, uses the generated CRUD, then deletes the module. It writes real files and restores them afterwards. |
Feature/Access/* | Every route as six users: guest, customer, admin (admin panel, no module access), viewer (read-only role), manager (full module access) and super_admin. Forms are filled from the real rendered HTML. |
Feature/Access/RouteCoverageTest | Fails when a route is not listed in RouteCatalogue |
Tests that run the code generators snapshot the files they touch and restore them in tearDown(). If a run crashes with a PHP fatal error, tearDown() doesn't run: check git status afterwards. The backup tests need mysqldump.
Testing your modules
When you generate a module, RouteCoverageTest starts failing: that is intended. Add the module's routes to tests/Feature/Access/RouteCatalogue.php:
// PAGES: GET pages opened by every role. uri => [group, module, access, status]
'admin/courses' => ['panel', 'Courses', 'view', 200],
'admin/courses/{course}' => ['panel', 'Courses', 'view', 200],
'admin/courses/{course}/edit' => ['panel', 'Courses', 'edit', 200],
'admin/course_dt_ajax' => ['panel', 'Courses', 'view', 200],
// ACTIONS: every other route => the test that covers it
'POST admin/courses' => CourseActionsTest::class.'::test_add_course',
Use the traits in tests/Concerns: ActsAsRoles creates the six users and logs in as one ($this->asRole('viewer')), and FillsForms reads a form from the rendered page and submits it, so tests use the same fields as a real user.
GET routes with side effects
Never let a crawler or link checker follow every admin link. Some GET routes change things: la_modules/generate_crud|generate_migr|generate_update|generate_migr_crud/{id} regenerate source files and migrations, and la_module_fields/{id}/delete, la_configs/ajax_destroy/{id}, la_modules/{id}/set_view_col/{col}, update_local_upload_paths and git-status change data or run commands.
Contributing
Found a bug or improved something that other LaraAdmin users would want? Fork the repository on GitHub, make the change with a test, run ./vendor/bin/phpunit and composer sniff, and open a pull request. Report security issues privately to ganesh@dwij.in. Known issues and planned work are listed in engg-debt.md.