codingmatters/personnel-management-package
Laravel package for basic personnel management. Provides an Employees module for organizing employee records and related data inside your application, packaged for easy installation and integration. AGPL-3.0 licensed.
Installation
composer require codingmatters/personnel-management-package
Publish the package configuration and migrations:
php artisan vendor:publish --provider="CodingMatters\PersonnelManagement\PersonnelManagementServiceProvider" --tag="config"
php artisan vendor:publish --provider="CodingMatters\PersonnelManagement\PersonnelManagementServiceProvider" --tag="migrations"
php artisan migrate
Service Provider Registration
Ensure the package is registered in config/app.php under providers:
CodingMatters\PersonnelManagement\PersonnelManagementServiceProvider::class,
First Use Case: Employee Creation
Use the Employee facade or service container binding:
use CodingMatters\PersonnelManagement\Facades\Employee;
$employee = Employee::create([
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john.doe@example.com',
'department' => 'Engineering',
]);
Key Classes to Explore
Employee facade (or EmployeeService class)EmployeeRepository (for custom queries)EmployeeModel (Eloquent model)PersonnelManagementServiceProvider (for bindings and macros)Leverage the facade or service for standard operations:
// Create
$employee = Employee::create($data);
// Read
$employee = Employee::find(1);
$employees = Employee::all();
// Update
Employee::find(1)->update(['salary' => 100000]);
// Delete
Employee::find(1)->delete();
Use built-in query scopes or extend them:
// Built-in scopes (if provided)
$activeEmployees = Employee::active()->get();
// Custom scopes (extend via repository)
$engineers = Employee::whereDepartment('Engineering')->get();
Listen to employee lifecycle events (e.g., EmployeeCreated, EmployeeUpdated):
// In EventServiceProvider
protected $listen = [
'CodingMatters\PersonnelManagement\Events\EmployeeCreated' => [
'App\Listeners\SendWelcomeEmail',
],
];
Use the package with Laravel API Resources:
// EmployeeResource.php
public function toArray($request)
{
return [
'id' => $this->id,
'name' => "{$this->first_name} {$this->last_name}",
'email' => $this->email,
'department' => $this->department,
];
}
Bind the service manually for testing or custom logic:
$this->app->bind('employee', function ($app) {
return new \CodingMatters\PersonnelManagement\Services\EmployeeService(
new \CodingMatters\PersonnelManagement\Repositories\EmployeeRepository(
new \CodingMatters\PersonnelManagement\Models\Employee
)
);
});
Custom Fields
Extend the Employee model to add custom attributes:
class Employee extends \CodingMatters\PersonnelManagement\Models\Employee
{
protected $casts = [
'is_manager' => 'boolean',
];
}
Validation Rules Use Form Requests or custom validation:
use Illuminate\Validation\Rule;
$validated = Validator::make($request->all(), [
'email' => [
'required',
'email',
Rule::unique('employees')->ignore($employee->id),
],
]);
Policy Integration Attach policies for authorization:
// EmployeePolicy.php
public function update(User $user, Employee $employee)
{
return $user->isAdmin() || $user->id === $employee->manager_id;
}
Testing Use package-specific factories or mock the service:
$employee = Employee::factory()->create();
$this->actingAs($user)->post('/employees', $data);
Migration Conflicts
employees table), rename the table in the package’s config:
'table_name' => 'custom_employees',
Facade vs. Service
// Bad: Mixing facade and service
$employee = Employee::find(1); // Facade
$service = app('employee')->update($employee, $data); // Service
// Good: Stick to one
$service = app('employee')->find(1)->update($data);
Event Dispatching
EventServiceProvider; otherwise, they won’t trigger:
// Missing binding = silent failure
Caching Quirks
Employee::find(1)->update($data);
Cache::forget('employees');
Log Queries Enable Eloquent logging to debug queries:
\DB::enableQueryLog();
$employee = Employee::find(1);
\Log::info(\DB::getQueryLog());
Check Config Verify the published config matches your expectations:
php artisan config:clear
Service Container Dumps Inspect bindings:
php artisan container:dump
Custom Repositories Override the default repository:
$this->app->bind(
\CodingMatters\PersonnelManagement\Contracts\EmployeeRepository::class,
\App\Repositories\CustomEmployeeRepository::class
);
Macros Add custom methods to the facade:
Employee::macro('promote', function ($employeeId, $newRole) {
return Employee::find($employeeId)->update(['role' => $newRole]);
});
Observers Extend model observers for side effects:
class EmployeeObserver
{
public function created(Employee $employee)
{
// Send Slack notification
}
}
API Resources Override default serialization:
class EmployeeResource extends \CodingMatters\PersonnelManagement\Http\Resources\EmployeeResource
{
public function toArray($request)
{
return array_merge(parent::toArray($request), [
'custom_field' => $this->custom_field,
]);
}
}
Default Values
Override defaults in config/personnel-management.php:
'defaults' => [
'department' => 'Unassigned',
'status' => 'active',
],
Soft Deletes If using soft deletes, ensure the model and queries account for it:
$employees = Employee::withTrashed()->get();
Multi-Tenancy For multi-tenant apps, scope queries by tenant:
$employees = Employee::where('tenant_id', auth()->tenant()->id)->get();
How can I help you explore Laravel packages today?