* @since 2.0.6 */ abstract class MultiFieldSession extends Session { /** * @var callable a callback that will be called during session data reading. * The signature of the callback should be as follows: * * ``` * function ($fields) * ``` * * where `$fields` is the storage field set for read session and `$session` is this session instance. * If callback returns an array, it will be merged into the session data. * * For example: * * ```php * function ($fields) { * return [ * 'expireDate' => Yii::$app->formatter->asDate($fields['expire']), * ]; * } * ``` */ public $readCallback; /** * @var callable a callback that will be called during session data writing. * The signature of the callback should be as follows: * * ``` * function ($session) * ``` * * where `$session` is this session instance, this variable can be used to retrieve session data. * Callback should return the actual fields set, which should be saved into the session storage. * * For example: * * ```php * function ($session) { * return [ * 'user_id' => Yii::$app->user->id, * 'ip' => $_SERVER['REMOTE_ADDR'], * 'is_trusted' => $session->get('is_trusted', false), * ]; * } * ``` */ public $writeCallback; /** * Returns a value indicating whether to use custom session storage. * This method overrides the parent implementation and always returns true. * @return bool whether to use custom storage. */ public function getUseCustomStorage() { return true; } /** * Composes storage field set for session writing. * @param string $id session id * @param string $data session data * @return array storage fields */ protected function composeFields($id, $data) { $fields = [ 'data' => $data, ]; if ($this->writeCallback !== null) { $fields = array_merge( $fields, call_user_func($this->writeCallback, $this) ); if (!is_string($fields['data'])) { $_SESSION = $fields['data']; $fields['data'] = session_encode(); } } // ensure 'id' and 'expire' are never affected by [[writeCallback]] $fields = array_merge($fields, [ 'id' => $id, 'expire' => time() + $this->getTimeout(), ]); return $fields; } /** * Extracts session data from storage field set. * @param array $fields storage fields. * @return string session data. */ protected function extractData($fields) { if ($this->readCallback !== null) { if (!isset($fields['data'])) { $fields['data'] = ''; } $extraData = call_user_func($this->readCallback, $fields); if (!empty($extraData)) { session_decode($fields['data']); $_SESSION = array_merge((array) $_SESSION, (array) $extraData); return session_encode(); } return $fields['data']; } return isset($fields['data']) ? $fields['data'] : ''; } }