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

Malaysiaholiday Laravel Package

afiqiqmal/malaysiaholiday

A Laravel package for retrieving Malaysian public holidays. Look up holiday dates by state and year, with a simple API for querying and integrating holiday data into your PHP applications.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is a data-provisioning package for Malaysian public and school holidays — most likely a service provider plus facade over a bundled/derived dataset with caching. It fits any Laravel application with calendar-sensitive business logic: payroll and statutory holiday pay, leave and attendance systems, SLA/response-time clocks, logistics cutoffs, billing-cycle shifting, and scheduled-job gating. It is not infrastructure-critical, but it is correctness-critical: a wrong answer silently corrupts downstream calculations rather than throwing.

Integration feasibility. Straightforward. Composer install, package discovery, one facade call. The 4.2.1 change is additive — a new source key plus a fallback data path — so existing consumers reading name/date are unaffected. The only integration hazard is consumers doing strict shape assertions (DTO constructors, assertSame on arrays, JSON-schema validation, snapshot tests) which will fail on the extra key. That is a mechanical fix, not a design problem.

Technical risk. This release meaningfully widens the risk surface, and that is the headline. Previously the package leaned on a single structured-ish upstream; 4.2.1 introduces a second upstream (calendarmalaysia.com) for 2025 onwards, which in practice means HTML parsing of a third-party site we do not control. Concretely: (1) the two sources will disagree at the 2024/2025 boundary, producing visible discontinuities; (2) the Malay state-note parsing (sahaja = "only", kecuali = "except") is semantically load-bearing — a misparse flips a state-restricted holiday into a national one or vice versa, which is exactly the failure mode that breaks payroll; (3) whether the fallback is a build-time fetch or a runtime HTTP call is the single most important unknown, since runtime egress to a scraped site is both a latency and an availability dependency.

Key questions.

  • Is source always populated, or nullable for older/bundled data? What are its enumerated values, and is it stable enough to key on?
  • Is the calendarmalaysia.com fetch performed at package build/release time (dataset shipped in the repo) or on demand at runtime?
  • If runtime: what are the timeout, retry, cache TTL, and negative-caching semantics when the upstream is down or rate-limits us?
  • What is the package's semver discipline? Would a future upstream change be a major or a patch?
  • How is the 2024→2025 source transition reconciled — deduplicated, preferred-source-wins, or naive concatenation?
  • Are the sahaja/kecuali notes covered by unit tests with fixtures per state, or is the parsing heuristic untested against real page variants?
  • Coverage: all 16 states/federal territories? Distinction between observed and gazetted holidays? Timezone fixed to Asia/Kuala_Lumpur?
  • What is calendarmalaysia.com's terms-of-service posture on automated access, and what is our exposure if it blocks or changes markup?
  • Does the package handle post-publication amendments (replacement holidays, one-off election or coronation days)?

Integration Approach

Stack fit. PHP 8.x, Laravel 9–11, standard Composer delivery. No infrastructure prerequisites. Fits cleanly alongside an existing CalendarService or scheduling layer.

Migration path. Greenfield — there is no prior assessment and no incumbent. Treat this as a new dependency and adopt it behind a seam rather than calling the facade directly from business logic:

  1. Define an internal HolidayCalendar interface (isHoliday(CarbonInterface $date, ?string $state): bool, plus a source-carrying DTO).
  2. Implement it with this package as the fetch/seed mechanism, not the query mechanism.
  3. Persist resolved holidays into our own holidays table with date, name, states, is_observed, source, fetched_at, package_version. Business logic reads our table; the package is a seeder.

This decouples correctness-critical reads from a scraping dependency and gives us an audit trail when a number is questioned.

Compatibility. Pin ^4.2. Audit tests and API contracts for strict array-shape assumptions before bumping. Anything serialising the package's raw array to an external consumer now leaks source — decide deliberately whether to expose or strip it.

Sequencing.

  1. Spike (1–2 days): install on a branch, dump 2024–2026 for a representative set (e.g. Johor, Selangor, Sabah, KL), and manually diff against official state gazettes. Pay specific attention to the 2024/2025 boundary and to sahaja/kecuali entries.
  2. Decision gate: if the fallback requires runtime egress, stop and require a bundled/vendored dataset instead — do not ship a payroll dependency that fails closed on a third-party outage.
  3. Adapter + persistence schema, including source and fetched_at.
  4. Historical backfill from a single pinned snapshot so prior years are internally consistent.
  5. Scheduled refresh job with alerting on parse-yield anomalies (e.g. "returned fewer than N holidays for year Y" → page).
  6. Roll out read path behind a feature flag, keep the old path available for one cycle.

Operational Impact

Maintenance. Double the parsing surface. Two upstreams with different structures and different editorial conventions means a bug can live in either path, and the newer path is HTML-scraped — the most brittle class of integration. Budget a standing allowance rather than a one-off: realistically one to two breakage events per year, each needing a same-day patch because the alternative is silently wrong holiday data.

Support. The source key is the most operationally valuable thing in this release — it converts "the system says 3 May is a holiday" into "the system says 3 May is a holiday and here is which upstream told us so." Surface it in internal admin tooling and in any user-facing discrepancy workflow. Without it, every data dispute starts with a bisect.

Scaling. Read volume is trivially cacheable — this is a handful of rows per year. The real scaling concern is a cache stampede on cold start if the fallback triggers live HTTP: one expired cache plus a burst of requests becomes a burst of requests to a third-party site, which invites rate-limiting precisely when you can least afford it. Mitigate with a warm-up job, a lock around refresh, and negative-result caching.

Failure modes (ranked by blast radius).

  1. Silent partial parse — scraper returns a truncated list and the package reports "not a holiday" for a real one. Worst case: payroll or SLA clocks run on a gazetted holiday. Requires anomaly-count alerting, not just exception logging.
  2. State-note inversion — sahaja/kecuali misread, promoting a state-only holiday to national. Plausible, hard to notice, and produces confidently wrong output.
  3. 2024/2025 discontinuity — the two sources disagree; whichever the package prefers, downstream trend or accrual logic sees a one-year step change.
  4. Upstream refusal — 403, rate limit, or markup change. Must fail loudly at refresh time, never degrade to an empty calendar.
  5. Timezone/observed-date drift — substitution rules (holiday falling on a weekend shifting to Monday) handled by one source but not the other.
  6. Post-publication amendment — government-announced replacement or one-off holidays. The package will not self-correct; our refresh cadence is the only mitigation.

Ramp-up. Low for consumption — a developer can call it in an afternoon. Medium-to-high for ownership: whoever maintains this needs to read Malay, understand the distinction between federal and state observance, know why Kelantan and Terengganu differ on weekends, and be able to judge whether a source is wrong or merely unfamiliar. That is a single-person knowledge concentration. Document the state-note semantics and the 2025 source boundary in the repo, and name a secondary owner.

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.
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
noith/settings
kda/laravel-package