Utility Libraries
All utilities use static methods and have no external dependencies. Their namespace is _Flexagon\Libs.
| Class | Key Features |
|---|---|
StringUtil |
case conversion, UTF-8 cleanup, hex encoding, random string generation |
ArrayUtil |
camelCase key conversion, array diff, nested-array key lookup |
ValidUtil |
email, integer, float, alphanumeric, and ID validation |
CryptoUtil |
AES-256-CBC encryption/decryption (deterministic encryptString() for columns; random-IV encrypt() for strings / arrays) |
FileUtil |
directory traversal, recursive creation, extension detection |
HttpUtil |
URL parsing, query-string parsing, request-path resolution |
NetUtil |
GET/POST HTTP client, JSON response parsing, file uploads |
HtmlUtil |
redirects, HTML tag/attribute removal, image URL extraction |
TimeDateUtil |
timestamp conversion, timezone offsets, relative time formatting |
SqlUtil |
parameter normalization/expansion, SQL escaping, SELECT → COUNT conversion |
ClassUtil |
class name, path, property, and caller inspection |
PhpDocUtil |
PHPDoc tag parsing (basis of annotation support) |
AssetLoader |
CSS/JS management |
TemplateLoader |
template loading |
DataSourceManager |
connection reuse and global transactions |
Env |
settings and secrets from the environment and .env.php |
Global Helper Functions
The three functions defined by Libs/_Util.php are available globally without a namespace.
_echo('Hello, {name}', ['name' => $user->getName()]); // substitute and output
$msg = _t('{count} results found', ['count' => 42]); // substitute and return
___() is an alias of _t(). Placeholders are substituted in a single pass, so a value that itself contains {name} is not substituted again.
Translation (I18n)
The helpers translate a message through the translator registered with _Flexagon\I18n\Translator before substituting placeholders. If no translator is registered, the original message is used as is.
A translator implements a single method.
namespace _Flexagon\I18n;
interface TranslatorInterface
{
public function translate(string $message): string;
}
Register it once, early in the request (public/_entry.php or application/_Config.php).
// public/_entry.php
use _Flexagon\I18n\Translator;
setlocale(LC_MESSAGES, 'ko_KR.UTF-8');
bindtextdomain('messages', LOCALE_ROOT);
textdomain('messages');
Translator::setTranslator(new \I18n\GettextTranslator());
The skeleton ships three example adapters in application/I18n/.
| Class | Translates with | Requires |
|---|---|---|
GettextTranslator |
gettext() |
ext-gettext |
MoTranslator |
__() |
A library that defines __() (e.g. a .mo reader) |
SymfonyTranslator |
trans() |
symfony/translation |
Translator::setTranslator(new \I18n\SymfonyTranslator($symfonyTranslator));
LOCALE_ROOT defaults to PROJECT_ROOT . '/locale'. To change it, define() it before the framework boots.
Keep these points in mind:
- Output is not escaped.
_echo()prints the translated, substituted string as is. Escape user-supplied values withhtmlspecialchars()before passing them in, and treat translation catalogs as trusted HTML sources. - The translator is static, per process. That fits the PHP-FPM model, where every request starts clean. In long-running workers (Swoole, RoadRunner, FrankenPHP worker mode), re-register the translator for every request.
setlocale()is process-wide and not safe across threads. - The adapter determines the cost. The framework adds about 0.3 µs per call. gettext caches
.mofiles per process (restart PHP-FPM after updating them); some.molibraries parse the file on every request; Symfony Translation reloads catalogs on each request unlesscache_diris set.
Enum Helpers
Add the EnumSupporter trait to a backed enum to enable convenience methods.
use _Flexagon\Supporters\EnumSupporter;
enum UserRole: string {
use EnumSupporter;
case ADMIN = 'ADMIN';
case USER = 'USER';
}
UserRole::keys(); // ['ADMIN', 'USER']
UserRole::values(); // ['ADMIN', 'USER']
UserRole::toArray(); // ['ADMIN' => 'ADMIN', 'USER' => 'USER']
UserRole::toCommaString(); // 'ADMIN,USER'
When generating DDL for an ENUM column, use toQuotedCommaString(). It quotes each value and escapes embedded quotes by doubling them.
UserRole::toQuotedCommaString(); // "'ADMIN','USER'"
UserRole::toQuotedCommaString('"'); // '"ADMIN","USER"'
// Safe even when values contain quotes or commas
// case A = "it's"; case B = 'a,b';
// toCommaString() → it's,a,b (breaks DDL)
// toQuotedCommaString() → 'it''s','a,b'
For pure enums without backing values, keys() and toCommaString() return case names, while values() and toArray() return null values.
Enum-typed properties are also handled automatically by DAO mapping. Scalar database values are converted to matching enum cases when models are hydrated, and ->value is bound when values are stored.