asorasoft/chhankitek
A Laravel/PHP package for working with the Khmer Chhankitek calendar. It helps convert and handle Cambodian lunar dates, supporting calendar calculations and related helpers for Khmer-language applications and Laravel projects.
Install and confirm discovery.
composer require asorasoft/chhankitek
Laravel should auto-register the service provider via package discovery. If it doesn't, open vendor/asorasoft/chhankitek/composer.json, read the extra.laravel block, and add the provider (and facade alias, if present) to config/app.php manually.
Find the entry point before writing any code. The README is short, so read src/ directly. Look for the facade class, the underlying converter class, and the return type of the main conversion method. Note whether it returns an object, an array, or a value object — this determines everything about how you consume it.
Publish config if offered. Run php artisan vendor:publish --provider="Asorasoft\Chhankitek\...ServiceProvider" and check for a timezone or locale key. Default to Asia/Phnom_Penh.
First use case — display the lunar date under a Gregorian date. The canonical day-one win is an event card or invoice header that shows both:
$lunar = Chhankitek::convert(Carbon::parse($event->starts_at));
// Inspect with dd() first: field names are the real contract.
Typical fields you'll find: lunar day (កើត/រោច), lunar month, Chhankitek year, zodiac animal/year name. Dump one known date (e.g. Khmer New Year, mid-April) and confirm the values against a printed Khmer calendar before building UI around them.
Wrap it immediately. Even on day one, put the package behind your own LunarDateService or a Blade component. With 0 dependents and a single-digit star count, you want one file to change if you swap implementations.
Store AD, compute lunar on read. Persist starts_at as a normal timestamp and derive the lunar representation at render time. Only denormalize lunar fields into columns if you need to query by lunar month — and if you do, store them as integers plus a rendered string, not as a formatted blob.
Blade component for display. A <x-lunar-date :date="$event->starts_at" /> component keeps Khmer formatting, digit conversion, and font classes in one place instead of scattered across views. Give it a format prop (short → "១៥ រោច ខែផល្គុន", long → full Chhankitek string).
API resources. Map the converter output into a stable shape with both scripts:
return [
'gregorian' => $event->starts_at->toDateString(),
'lunar' => [
'khmer' => $khmerString,
'latin' => $romanizedString, // for non-Khmer readers / search
'day' => $out->day, 'month' => $out->month, 'year' => $out->year,
],
];
Never leak the package's raw return object into JSON — its shape is not a public API and will change across versions.
Calendar-grid / bulk generation. Rendering a month view means 30+ conversions. Compute them in a loop and memoize per date key ($date->toDateString()), or better, build a Collection of the whole month in one service call. Cache the result per month with Cache::remember("lunar.{$year}-{$month}", now()->addDay(), ...) since lunar data for a past month never changes.
Testing with a fixture table. Write a data provider with 10–15 dates you have verified against an authoritative almanac, including Khmer New Year, Pchum Ben, Visak Bochea, and one leap-month year. This is your regression net — it catches package upgrades that silently shift a day.
Digit and script helpers. Khmer numerals (០១២៣៤៥៦៧៨៩) are a common requirement and usually not included. Keep a KhmerNumerals::convert(string $ascii) helper and apply at the presentation layer only, never before storing.
2026-04-14 23:00 UTC is already the 15th in Phnom Penh. Set app.timezone to Asia/Phnom_Penh or explicitly pass a timezone-localized Carbon instance; do not pass raw now() from a UTC process.CE + 543. The Khmer Buddhist Era year increments at Khmer New Year (mid-April), not January 1st. Don't compute it yourself as a sanity check and conclude the package is broken — verify against a reference table first.abort(422)) rather than rendering a wrong date. Add a min/max config and a Rule for it.utf8mb4_unicode_ci. Beware strlen()/substr() on Khmer strings — use mb_* or Str:: helpers. Khmer rendering also needs a font that supports the script (Noto Sans Khmer, Hanuman) or you'll ship tofu boxes.composer require asorasoft/chhankitek:^x.y with a real constraint, and commit the lockfile. No dependents means no downstream community pressure to catch regressions.vendor/. If you genuinely need to swap the engine later, bind your own interface in a service provider so a future replacement is a one-line container change.How can I help you explore Laravel packages today?