The PHP framework behind SitioYa

Koshkil documentation

Services

Cache, logs and debugging

Cache

CacheManager returns a cache engine per usage domain. Each domain can use its own engine, path and time to live.

Koshkil::Uses('sys.cache.CacheManager');

$cache = CacheManager::engine('query');          // or 'default', 'models', 'i18n', 'plugins'…
$key = 'productos:destacados';

$list = $cache->get($key);
if ($list === null) {
    $list = TMProductos::where('prd_destacado', '1')->getAsArray();
    $cache->set($key, $list, 300);               // 5 minutes
}

Methods available in every engine (CacheInterface):

Method Purpose
get($key, $default = null) Reads a value.
set($key, $value, $ttl = 0) Stores it (0 = the domain's TTL).
has($key), delete($key)
getMultiple(), setMultiple(), deleteMultiple() Group operations.
increment($key), decrement($key) Counters.
clear() / flush() Empties the domain / the engine.
getStats() Statistics.

Configuration

// config/cache.php (summary)
$CONFIG = [
    'Cache' => [
        'enabled'   => true,
        'default'   => 'file',             // 'file', 'redis' or 'null'
        'globalTTL' => 3600,
        'engines' => [
            'file'  => ['path' => Koshkil::getPath('/tmp/cache', true), 'format' => 'json', 'subdirectories' => 2],
            'redis' => ['enabled' => false, 'host' => '127.0.0.1', 'port' => 6379, 'prefix' => 'koshkil_'],
            'null'  => ['enabled' => true],
        ],
        'domains' => [
            'i18n'    => ['engine' => 'file',    'ttl' => 3600],
            'models'  => ['engine' => 'default', 'ttl' => 86400],
            'plugins' => ['engine' => 'default', 'ttl' => 3600],
            'query'   => ['engine' => 'default', 'ttl' => 300, 'enabled' => false],
            'session' => ['engine' => 'default', 'ttl' => 7200],
        ],
    ],
];
Domain What the framework stores
models Each table's structure, invalidated when the model file changes.
i18n Parsed translation JSON files.
plugins Each plugin's configuration and permissions.
query Free for your own queries (disabled by default).

The null engine stores nothing: use it for tests or to disable a domain. Redis requires PHP's redis extension.

Clearing and warming

  • In the admin panel, Sistema → Caché shows per-domain statistics and lets you clear or warm the caches.
  • From the terminal, after deploying:
./app/bin/warm-cache.sh                     # translations, models and plugins
php app/bin/warm-cache.php --domain=i18n --verbose
php app/bin/warm-cache.php --force          # clear before warming
  • ?reset_plugins on any URL re-reads the plugin configuration.
  • Files in tmp/cache/ can be deleted safely: they are rebuilt automatically.

Logs

KoshkilLog writes to tmp/logs/<name>.log. With Debug.Level at 0 nothing is written.

KoshkilLog::error('Payment failed', ['order' => 123]);        // error.log
KoshkilLog::warning('Low stock', $producto->record());        // warning.log
KoshkilLog::info('Order confirmed');                          // info.log
KoshkilLog::debug('Supplier response', $json);                // debug.log
KoshkilLog::addLog('payments', 'Webhook received', $_POST);   // payments.log
Debug.Level Effect
0 No logs.
1 Logs; attached data has passwords and full card numbers masked.
2 Logs; passwords and card numbers are masked.
3 Logs; card numbers are masked.
6 or more Also logs every SQL query to debug.log.
7 or more Also profiles the initialization of every model.

Files rotate once they exceed Log.MaxSize (for example '1M'), keeping Log.MaxHistory copies if Log.KeepHistory is true. Other framework logs: not_found.log (URLs without a controller), rewrite.log (with Debug.Rewrite ≥ 5), i18n.log (missing translation keys) and db_query.log.

Profiler

It measures how long each stage of the request takes and writes it to tmp/logs/profile.log. It is enabled with Debug.Level ≥ 2 and:

'Debug' => [
    'Level'    => 2,
    'Profiler' => ['Enabled' => true, 'lowThreshold' => 0.001],  // only logs what takes more than 1 ms
],

The core already measures routing, the dispatcher, the controller hooks, every SQL query and rendering. To measure your own code:

$result = Profiler::profileCallable(function () {
    return buildReport();
}, 'Monthly report');

Quick debugging

dump_var($variable);          // prints the variable (and its methods if it is an object) and stops
dump_var($variable, false);   // without stopping
echo TMProductos::where('prd_destacado', '1')->compile();   // the SQL that would run
Koshkil::dumpConfig();        // the whole configuration
RewriteManager::dumpRules();  // active rewrite rules

?php_info=1 on any URL shows phpinfo(). Disable or restrict it in production.