Skip to content

Cheat Sheet

This is purely informative.

Change user password

shell
$ ./app/admin/console fos:user:change-password <username> <password>
...
$ ./app/admin/console fos:user:change-password admin ..admin
...

Config favicon.ico

Config the html-layout-header setting to add the <link... element.

It is a snippet configured in settings:

Admin -> Advanced admin -> Snippets -> snp-logo

Config the snp-logo setting to add the <svg... element.

Create the menu if it doesn't exist

We can create a menu using this url: site/menu/form. Example: https://admin-starbase.xalok.com/menu/form.

To create a menu for the covers, we will create one called admin-boards and then we can manage the menu.

Custom default/404 imagen

Cuando en un prouecto queremos reemplazar la imagen por defecto de Xalok por una custom podemos hacer lo siguiente:

  1. cambiar la imagen ~/codata/image_placeholder_source.jpg
  2. eliminar todas las imágenes **/image_placeholder.jpg del bucket.
  3. solicitar a HS que purguen de cachés esas imágenes.

Scheduler Tasks

Stateful scheduled tasks

Sometimes when some configurations change, i.e. inside page templates, we need purge all site pages. The purge should be done slowly to not do much presure. The next scheluder count from zero to N in each execution heartbit, then ends using an exception. You can restart the process simply flipping the flip-flop value:

php
// specific key to store this executor's state
$REDIS_STATE = "CustomStateExecutor";

// flip-flop resetting state, simply change flip-flop to reset values
$rstate = [
    'flip-flop' => true,
    'currentId' => 0
];

// services
$redis = $this->container->get('wf_cms.publish.manager');

// read current state
$redisStateKey = sprintf("%s:scheduler:%s", $redis->getPrefix(), $REDIS_STATE);
$cstate = json_decode($redis->getRedis()->get($redisStateKey), true) ?? $rstate;
if( $rstate['flip-flop'] != $cstate['flip-flop'] ) {
    $cstate = $rstate;
}

// do something and update the state
$cstate['currentId'] = $cstate['currentId'] + 1;

// if you need a stopping condition use an exception
if( $cstate['currentId'] > 3 ) {
    throw new \Exception("Process ended!");
}

// store the state
$redis->getRedis()->set($redisStateKey, json_encode($cstate));

// return info
$return = sprintf("Current Id := %d", $cstate['currentId']);

Purge all pages

php
/*
    Purge all `page-{page-id}` from the MAX(page.id) down to 1.
    
    You could see the current state using:
    
       bastion:~$ redis-cli -h redis get $REDIS_STATE
    
    Change `flip-flop` value to restart the process.
*/

// specific key to store this executor's state
$REDIS_STATE = "SlowPurgeAllPages";

// time ref
//   |                   |
//   V                   V
//   [job][...waiting...][job][...waiting...]...
$timeRef = new \DateTime();

// flip-flop resetting state, simply change flip-flop to reset values
$rstate = [
    'flip-flop' => false,
    'lastTopId' => 0,                   // from MAX(page.id) to 0
    'maxId'     => 0,                   // MAX(page.id)
    'chunkSize' => 100,                 // pages to purge every heartbit
    'firstRun'  => $timeRef             // start time
                            ->format(\DateTime::ATOM),
];

// services
$redis = $this->container->get('wf_cms.publish.manager');
$cacheManager = $this->container->get('FOS\\HttpCacheBundle\\CacheManager');

// read current state
$redisStateKey = sprintf("%s:scheduler:%s", $redis->getPrefix(), $REDIS_STATE);
$jstate = $redis->getRedis()->get($redisStateKey);
$restart = !$jstate;
$cstate = json_decode($jstate, true) ?? $rstate;
if( $restart || $rstate['flip-flop'] != $cstate['flip-flop'] ) {
    $cstate = $rstate;
    $pageRepository = $this->container->get('wf_cms.repository.page');
    $cstate['maxId'] = $pageRepository
                        ->createQueryBuilder('p')
                        ->select('MAX(p.id) as maxId')
                        ->getQuery()
                        ->getSingleResult()['maxId'];
    $cstate['lastTopId'] = $cstate['maxId'];
}

$firstRun   = new \DateTime($cstate['firstRun']);
$chunkSize  = intval($cstate['chunkSize']);
$lastTopId  = intval($cstate['lastTopId']);

if($chunkSize < 1 || $chunkSize > 100000) {
    throw new \Exception(sprintf("the specified chunk size of %d is wrong", $chunkSize));
}

if($lastTopId > intval($cstate['maxId'])) {
    throw new \Exception("bad state, the lastTopId value is wrong, please restart");
}

if($lastTopId < 1) {
    throw new \Exception("PROCESS END, no more pages to purge\n");
}

// do something and update the state
$chunkTo   = $lastTopId;
$chunkFrom = $lastTopId - $chunkSize;
 
$purgeTags = [];
for ($i = $chunkFrom; $i <= $chunkTo; $i++) {
    $purgeTags[] = "page-" . $i;
}

$cacheManager->invalidateTags($purgeTags);

// update and store the state
$cstate['lastTopId'] = $chunkFrom - 1;
$redis->getRedis()->set($redisStateKey, json_encode($cstate));

// return info
$elapsedSecs = $timeRef->getTimestamp() - $firstRun->getTimestamp();
$totalRuns = ceil($cstate['maxId'] / $chunkSize);
if($elapsedSecs < 1) {
    $return = sprintf("Starting...\nTotal pages: %d\nTotal runs: %d\n",
            $cstate['maxId'],
            $totalRuns
        );
} else {
    $pendingRuns = ceil($cstate['lastTopId'] / $chunkSize);
    $avgSecsPerRun = $elapsedSecs / ($totalRuns - $pendingRuns);
    $pendingSecs = $pendingRuns * $avgSecsPerRun;
    $return = sprintf("Running (%.1f %%)...\nRun %d of %d\nETA: %s\nLast Id: %d\n",
            100.0 - 100.0 * $pendingRuns / $totalRuns,
            $totalRuns - $pendingRuns, $totalRuns,
            gmdate("H:i:s", ceil($pendingSecs)),
            $chunkFrom
        );
}