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

Courses Laravel Package

escolalms/courses

Laravel package for managing courses in the eSkool LMS: define courses, attach lessons and content, handle enrollment, and expose course data through Eloquent models and APIs so you can build e-learning features into your PHP application.

View on GitHub
Deep Wiki
Context7

Getting Started

This package (escolalms/courses) is the course-structure layer of the EscolaLMS/Wellms stack: it owns Course, lessons/topics, course authorship, course assignment to users, and the deadline that governs how long a learner has access. It sits on top of escolalms/core (users, auth, roles/permissions) and is normally consumed alongside escolalms/topic-types, escolalms/lessons-style content packages, and a frontend hitting the JSON:API-ish endpoints.

Minimal setup:

  1. composer require escolalms/courses (expect escolalms/core and spatie/laravel-permission as transitive requirements — install/configure core first, since migrations reference the users table).
  2. Publish and run migrations, and publish the package config:
    • php artisan vendor:publish --provider="EscolaLMS\Courses\EscolaLMSCoursesServiceProvider"
    • php artisan migrate
  3. Seed roles/permissions (EscolaLMS ships seeders for admin, tutor, student style roles). Without them the API endpoints will 403 rather than fail loudly.
  4. Authenticate against the core auth guard (auth:api / Passport or Sanctum depending on your core version) and hit the courses routes registered under the package's API prefix.

Where to look first:

  • src/Models/ — Course and the assignment/pivot models. Read the casts and date columns before writing anything; deadline behaviour lives here.
  • src/Events/ — CourseAssigned (and its siblings such as unassign/start events). Events are the intended integration seam, not direct writes.
  • src/Listeners/ and the service provider's $listen array — this is where the 0.4.45 deadline recalculation lives conceptually.
  • config/courses.php — table names, model bindings, and any feature toggles.
  • src/Http/Controllers/API/ + src/Http/Resources/ — the contract your frontend will code against.

First use case to validate your install: create a course with a duration/active window, assign it to a user, and confirm the resulting assignment row has a deadline. Then log in as that user and confirm the course appears with access gated correctly.

Implementation Patterns

Assign through the package, never by inserting pivot rows. The whole point of the 0.4.45 fix is that CourseAssigned now carries deadline recalculation. Any code path that assigns a course must dispatch that event (usually just by using the package's assign action/service). Raw DB::table(...)->insert() or ->sync() on the pivot will produce assignments with stale or null deadlines — a silent bug that only shows up weeks later when learners lose access at the wrong time.

Treat the deadline as derived, not authored. Compute it from the course's duration/template and the assignment timestamp, and let the package own that calculation. If you need a custom rule (e.g. deadline = end of academic term, or extended for a cohort), implement it as a listener on CourseAssigned that adjusts after the package has done its work, using $event->course / $event->user rather than re-deriving from scratch. Queue that listener (ShouldQueue) if it touches external systems, but keep the recalculation itself synchronous so the API response reflects the final deadline.

Wrap assignment + enrolment side effects in one transaction boundary conceptually, not literally. The event fires after the write; if your listener throws, the assignment may already be persisted. Make listeners idempotent (look up the assignment, upsert the deadline) so retries from failed jobs don't compound.

Drive access control off the deadline. In your own controllers/policies, gate topic/lesson access on the assignment's deadline rather than on the course's static end date. A user re-assigned to a course should get a fresh deadline (this is precisely what changed), so caching a "course is active" boolean per user is a trap — key your cache on the assignment row and invalidate on CourseAssigned/CourseUnassigned.

Customise at the edges. Prefer:

  • API Resources / ->additional() overrides in your own controller layer,
  • an event listener over forking the package,
  • config model bindings over subclassing models in app/.

Forking is the last resort — EscolaLMS packages move fast in the 0.4.x line and merge conflicts in src/Models/Course.php are painful.

Testing pattern. For feature tests around enrolment, assert on the event (Event::assertDispatched(CourseAssigned::class)) and on the persisted deadline. For unit tests of your own listeners, call them directly with a hand-built event so you don't depend on the package's dispatch order.

Gotchas and Tips

  • 0.4.45 is a patch, not a migration. No schema or signature changes; you can bump within ^0.4 safely. But if you have a workaround that recalculated deadlines manually on assignment, remove it now — double recalculation can shift a deadline forward on every re-assignment.
  • Re-assignment semantics matter. With recalculation on CourseAssigned, assigning an already-assigned user (e.g. an idempotent admin action or a CSV import re-run) may reset their deadline. Decide whether that's desired; if not, guard your import so it only assigns when no active assignment exists.
  • Events are skipped by bulk operations. Model::insert(), query-builder updates, and ->update(['deadline' => ...]) on the pivot bypass everything. If you import enrolments at scale, dispatch CourseAssigned per row (chunked + queued) or accept that you must backfill deadlines in a follow-up job.
  • Timezones. Deadlines are stored in the app timezone/UTC depending on your config/app.php; comparing against now() in a user's local timezone produces off-by-hours access errors around midnight. Always compare in the app timezone and let the frontend format.
  • Date casting surprises. Check $dates/$casts on the assignment model before assuming a deadline is a Carbon instance — a raw string from a query builder read will happily strtotime() into the wrong thing.
  • config:cache after upgrade. EscolaLMS config files are read at boot; after composer update on a cached deployment, php artisan config:clear (or rebuild the cache in your deploy script) to pick up new keys. Stale config is the usual cause of "the fix isn't working".
  • Permissions, not just auth. A 403 on assignment endpoints is nearly always a missing permission seeded from the core package, not a route/guard problem. php artisan permission:cache-reset after seeding.
  • Debugging tip. Event::fake() in a test silently disables the new recalculation and will make a bug look fixed. Run the failing scenario once with Event::fake() removed and DB::listen() or Log::info inside your listener to see the actual deadline written.
  • Extension point to bookmark. The package's service provider $listen array is where you hook CourseAssigned → your own deadline policy, notification, or enrolment sync. Register listeners there (or in your own EventServiceProvider) rather than in the model's booted() method — model events don't fire for the package's internal service-level operations.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin