class LessCompiler extends RevisionCompiler

Traits

Constants

EMPTY_REVISION

Properties

protected callable[] $sourcesCallbacks from HasSources
protected array<string,string> $pendingSidecars Sidecar files (e.g. JsCompiler's `.map`) queued by renderOutput() during the current commit, written only if the primary file is — so an unchanged bundle rewrites nothing at all. from RevisionCompiler
protected string $cacheDir
protected array $importDirs
protected array $customFunctions
protected Collection|null $lessImportOverrides
protected Collection|null $fileSourceOverrides
protected string|null $fontsDir

Methods

void
addSources(callable $callback)

No description

array
getSources()

No description

array
allowedSourceTypes()

No description

__construct(Cloud $assetsDir, string $filename, SettingsRepositoryInterface $settings, VersionerInterface $versioner)

No description

string|null
getFilename()

No description

void
setFilename(string $filename)

No description

void
commit(bool $force = false)

Recompile this asset and record its revision. Files are only written when the compiled output actually differs from what the revision manifest says is on disk (or the file has gone missing) — so routine rebuilds of unchanged assets are complete no-ops with zero writes.

void
writePendingSidecars()

No description

string
hashOutput(string $content)

No description

string|null
renderOutput(array $sources)

Produce the exact bytes to write to the primary asset file, or null when there is nothing to write (empty sources). This is what the revision is hashed from, so it must be identical to what gets committed — subclasses that transform or add to the output (e.g. JsCompiler's sourcemap handling) override this and queue any sidecar files (like the `.map`) on {$pendingSidecars} rather than writing them, so sidecars are only written when the bundle itself is.

string|null
getUrl()

No description

string
compile(array $sources)

No description

string
format(string $string)

No description

void
flush()

No description

void
delete(string $file)

No description

string
getCacheDir()

No description

void
setFontsDir(string|null $fontsDir)

The directory holding the webfonts that get published to `assets/fonts`.

void
setCacheDir(string $cacheDir)

No description

array
getImportDirs()

No description

void
setImportDirs(array $importDirs)

No description

void
setLessImportOverrides(array $lessImportOverrides)

No description

void
setFileSourceOverrides(array $fileSourceOverrides)

No description

void
setCustomFunctions(array $customFunctions)

No description

mixed
readCache(Less_Parser $parser, string $filePath, string $cacheFile)

Read a cached parse result for less.php. Returns the cached rules, or null to signal a miss so less.php reparses the file.

void
writeCache(Less_Parser $parser, string $filePath, string $cacheFile, mixed $rules)

Persist a parse result for less.php, writing atomically so a concurrent reader never observes a half-written cache file: serialize to a temporary file in the same directory, then rename() it into place (atomic on the same filesystem).

void
pruneCacheOnce()

Prune expired cache files at most once per request. less.php's own GC (Less_Cache::CleanCache) only runs from its high-level Less_Cache::Get() API, which Flarum doesn't use — the direct Less_Parser path GC'd inline on every serialize write instead. In callback mode neither fires, so without this the directory would grow unbounded.

string
finalize(string $parsedCss)

Point font URLs at the published `assets/fonts` directory, and stamp each with a revision derived from the font file itself.

string|null
fontRevision(string $file)

A short hash of a webfont's contents, or null when it can't be read — fonts are published separately, so a compile must never fail just because the directory isn't there yet.

array
overrideSources(array $sources)

No description

Details

void addSources(callable $callback)

Parameters

callable $callback

Return Value

void

protected array getSources()

Return Value

array

abstract protected array allowedSourceTypes()

Return Value

array

__construct(Cloud $assetsDir, string $filename, SettingsRepositoryInterface $settings, VersionerInterface $versioner)

Parameters

Cloud $assetsDir
string $filename
SettingsRepositoryInterface $settings
VersionerInterface $versioner

string|null getFilename()

Return Value

string|null

void setFilename(string $filename)

Parameters

string $filename

Return Value

void

void commit(bool $force = false)

Recompile this asset and record its revision. Files are only written when the compiled output actually differs from what the revision manifest says is on disk (or the file has gone missing) — so routine rebuilds of unchanged assets are complete no-ops with zero writes.

Parameters

bool $force

Return Value

void

protected void writePendingSidecars()

Return Value

void

protected string hashOutput(string $content)

Parameters

string $content

Return Value

string

protected string|null renderOutput(array $sources)

Produce the exact bytes to write to the primary asset file, or null when there is nothing to write (empty sources). This is what the revision is hashed from, so it must be identical to what gets committed — subclasses that transform or add to the output (e.g. JsCompiler's sourcemap handling) override this and queue any sidecar files (like the `.map`) on {$pendingSidecars} rather than writing them, so sidecars are only written when the bundle itself is.

Parameters

array $sources

Return Value

string|null

string|null getUrl()

Return Value

string|null

protected string compile(array $sources)

Parameters

array $sources

Return Value

string

Exceptions

Less_Exception_Parser

protected string format(string $string)

Parameters

string $string

Return Value

string

void flush()

Return Value

void

protected void delete(string $file)

Parameters

string $file

Return Value

void

string getCacheDir()

Return Value

string

void setFontsDir(string|null $fontsDir)

The directory holding the webfonts that get published to `assets/fonts`.

Used to revision the font URLs emitted into the compiled CSS.

Parameters

string|null $fontsDir

Return Value

void

void setCacheDir(string $cacheDir)

Parameters

string $cacheDir

Return Value

void

array getImportDirs()

Return Value

array

void setImportDirs(array $importDirs)

Parameters

array $importDirs

Return Value

void

void setLessImportOverrides(array $lessImportOverrides)

Parameters

array $lessImportOverrides

Return Value

void

void setFileSourceOverrides(array $fileSourceOverrides)

Parameters

array $fileSourceOverrides

Return Value

void

void setCustomFunctions(array $customFunctions)

Parameters

array $customFunctions

Return Value

void

protected mixed readCache(Less_Parser $parser, string $filePath, string $cacheFile)

Read a cached parse result for less.php. Returns the cached rules, or null to signal a miss so less.php reparses the file.

A corrupt or unreadable cache file (e.g. a partial write from a raced compile) is treated as a miss rather than allowed to fatal on unserialize()'s "Extra data" warning, which Flarum's error handler would otherwise escalate to an uncaught exception.

Parameters

Less_Parser $parser
string $filePath
string $cacheFile

Return Value

mixed

protected void writeCache(Less_Parser $parser, string $filePath, string $cacheFile, mixed $rules)

Persist a parse result for less.php, writing atomically so a concurrent reader never observes a half-written cache file: serialize to a temporary file in the same directory, then rename() it into place (atomic on the same filesystem).

Parameters

Less_Parser $parser
string $filePath
string $cacheFile
mixed $rules

Return Value

void

protected void pruneCacheOnce()

Prune expired cache files at most once per request. less.php's own GC (Less_Cache::CleanCache) only runs from its high-level Less_Cache::Get() API, which Flarum doesn't use — the direct Less_Parser path GC'd inline on every serialize write instead. In callback mode neither fires, so without this the directory would grow unbounded.

We prune here rather than call CleanCache() because that method is deprecated-internal, and hand-rolling the sweep lets us tolerate the scandir/unlink race (a concurrent sweep removing the same aged file) by simply suppressing the "No such file" and moving on. Files are removed by mtime, matching less.php's own policy; a cache hit re-reads and is not touched, so anything past the lifetime is genuinely stale.

Return Value

void

protected string finalize(string $parsedCss)

Point font URLs at the published `assets/fonts` directory, and stamp each with a revision derived from the font file itself.

The stylesheet is already cache-busted (`forum.css?v=<rev>`), but the font URLs inside it were not. On a FontAwesome major upgrade every browser therefore picked up the new CSS immediately while continuing to serve the *previous* font file from cache — same filename, same URL, long max-age. The new CSS asks for codepoints the old font doesn't contain, so every icon rendered as a placeholder box until that cache entry happened to expire. Revisioning the URL means a changed font is always a new URL, for browser and CDN caches alike. Because the asset revision is a hash of this compiled output, a font change also moves the stylesheet's own revision — so connected clients get the usual "reload for the new version" prompt without any extra wiring.

Parameters

string $parsedCss

Return Value

string

protected string|null fontRevision(string $file)

A short hash of a webfont's contents, or null when it can't be read — fonts are published separately, so a compile must never fail just because the directory isn't there yet.

Parameters

string $file

Return Value

string|null

protected array overrideSources(array $sources)

Parameters

array $sources

Return Value

array