Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/wp-cerber/includes/Revalt.php
<?php
/**
* Class Revalt
*
* A return-value object that carries the complete outcome of an operation:
* the result payload, the error state, and an optional diagnostic chain
* across architectural layers.
*
* Revalt always represents a COMPLETED operation. It is returned by value
* and never passed down the call stack for lower-level code to populate.
*
* USAGE
* -----
* - Instantiate inside the function or method that owns the operation.
* - Return the Revalt instance as the completed operation outcome.
* - Manage successful results with put_results(), merge(), get_results().
* - Handle errors with add_error(), get_error_messages(), get_error_data().
* - Check error presence using has_errors() before reading results.
* - When propagating errors across layers, see PROPAGATION PATTERNS below.
*
* AT A GLANCE
* -----------
* - Unified return type: callers always receive a Revalt, never a union of payload-or-error.
* - Multiple errors per instance, each with a code, one or more messages, and arbitrary structured data.
* - Execution stack: a Revalt may reference the Revalt returned by a lower layer, forming a single-linked chain similar to Exception::$previous.
* - Root cause traversal: get_root_cause() returns the deepest error in the chain; get_stack() returns the full trace for logging.
* - Result helpers for common payload shapes: get_element(), get_slice(), get_results_list(), count_results().
*
* CALLER CONTRACT
* ---------------
* Every caller MUST check has_errors() before using get_results().
* A Revalt may technically hold both a payload and errors. Treat
* has_errors() === true as authoritative: do not rely on get_results()
* when errors are present unless the specific producer documents
* partial-success semantics.
*
* PRODUCING A REVALT
* ------------------
* Success:
* return new Revalt( $results );
*
* Success, assembled incrementally:
* $result = new Revalt();
* $result->put_results( $partial );
* $result->merge( $more );
* return $result;
*
* Error:
* return new Revalt( null, 'unique_error_code', 'Human readable message' );
*
* Error with structured data:
* return new Revalt( null, 'invalid_input', 'Field foo is missing', array( 'field' => 'foo' ) );
*
*
* PROPAGATION PATTERNS
* --------------------
* When the current layer receives an erroring Revalt from below:
*
* Pattern A. Pass through unchanged. Use when this layer adds no context:
*
* $lower = lower_layer();
* if ( $lower->has_errors() ) {
* return $lower;
* }
*
* Pattern B. Wrap with this layer's context. Use when the caller needs
* an error code at this layer's abstraction, while diagnostics still
* need to reach the original root cause:
*
* $lower = lower_layer();
* if ( $lower->has_errors() ) {
* return new Revalt( null, 'upper_failed', 'Could not complete X', null, $lower );
* }
*
* Pattern C. Mutate via add_error(). ONLY on a Revalt this layer created. Never on a Revalt returned from a lower layer.
*
* ANTI-PATTERNS
* -------------
* Do NOT mutate a Revalt received from a lower layer:
*
* // WRONG
* $lower = lower_layer();
* $lower->add_error( 'upper_failed', '...' );
* return $lower;
*
* Do NOT call get_results() without checking has_errors() first.
*
* ERROR LOGGING (OPTIONAL)
* ------------------------
* Revalt can send errors to an external logger configured globally via
* Revalt::set_error_logger(). Two modes:
*
* - Revalt::LOG_BUFFERED (default): errors accumulate in the Revalt instance and
* are sent to the logger only when log_errors() is explicitly called.
*
* - Revalt::LOG_INSTANT: errors are sent to the logger the moment add_error() is called.
*
* @version 8.6
*/
class Revalt {
/**
* Stores the results of an operation, which may be a scalar value, object, or collection.
*
* @var mixed
*
*/
protected $operation_results = null;
/**
* Stores the list of errors.
*
* @var array<string, string[]>
*/
protected array $errors = array();
/**
* Stores optional error data for each error code.
*
* @var array<string, array>
*/
protected array $error_data = array();
/**
* Reference to the previous Revalt instance in the execution stack.
*
* This property establishes a single directional chain of result objects.
* Each Revalt represents a logical layer and may reference the layer below it.
* The chain forms a simple linked structure similar to PHP Exception::$previous,
* but used here for propagating structured execution results instead of exceptions.
*
* It enables propagating low-level diagnostic information up the execution stack.
*
* Null if no execution stack was involved.
*
* @var Revalt|null
*
* @since 7.0
*/
protected ?Revalt $previous_result = null;
const MAX_STACK_DEPTH = 100;
/**
* Errors accumulate in the instance and are sent to the logger only when log_errors() is explicitly called. Default mode.
*/
const LOG_BUFFERED = 0;
/**
* Errors are sent to the logger the moment add_error() is called.
*/
const LOG_INSTANT = 1;
/** @var callable|null */
private static $error_logger = null;
/** @var int */
private static int $log_mode = self::LOG_BUFFERED;
/**
* Initializes the results of operations with optional error message and error data.
*
* @param mixed $results Results of operations.
* @param string $error_code Optional. Error code.
* @param string $error_message Optional. Error message.
* @param mixed $error_data Optional. Error data.
* @param Revalt|null $previous_result Optional. Reference to the previous Revalt instance in the execution stack. It enables context and error propagation in multi-level architectures.
*
*
*/
public function __construct( $results = null, string $error_code = '', string $error_message = '', $error_data = null, ?Revalt $previous_result = null ) {
$this->operation_results = $results;
$this->set_previous_result( $previous_result );
if ( empty( $error_code ) ) {
return;
}
$this->add_error( $error_code, $error_message, $error_data );
}
/**
* Put results of operations. Replaces existing ones.
*
* @param mixed $results Results of operations
* @param Revalt|null $previous_result Optional. Reference to the previous Revalt instance in the execution stack. It enables context and error propagation in multi-level architectures.
*
* @return void
*/
public function put_results( $results, ?Revalt $previous_result = null ) {
$this->operation_results = $results;
$this->set_previous_result( $previous_result );
}
/**
* Sets the previous operation result used as lower-level diagnostic context.
*
* @param Revalt|null $previous_result Reference to the previous Revalt instance in the execution stack.
*
* @return void
*
* @since 8.1
*/
private function set_previous_result( ?Revalt $previous_result = null ): void {
if ( ! ( $previous_result instanceof Revalt )
|| $previous_result === $this ) {
return;
}
$this->previous_result = $previous_result;
}
/**
* Merges the elements of results and the given array together.
* Note: existing non-array (scalar) results will be destroyed.
*
* @param array $results Results of operations
* @param Revalt|null $previous_result Optional. Reference to the previous Revalt instance in the execution stack. It enables context and error propagation in multi-level architectures.
*
* @return void
*/
public function merge( array $results, ?Revalt $previous_result = null ) {
if ( ! is_array( $this->operation_results ) ) {
$this->operation_results = array();
}
$this->operation_results = array_merge( $this->operation_results, $results );
$this->set_previous_result( $previous_result );
}
/**
* A handler for a fully successful operation.
*
* Note: It cleans all existing/accumulated errors and replaces the operation results with new results.
* Use this method if operations completely went well. For a partial success result, use Revalt::put_results() or new Revalt().
*
* @param mixed $results Results of operations
* @param Revalt|null $previous_result Optional. Reference to the previous Revalt instance in the execution stack. It enables context propagation in multi-level architectures.
*
* @return void
*/
public function success( $results, ?Revalt $previous_result = null ) {
$this->put_results( $results, $previous_result );
// Explicitly clean the error state, making the successful outcome self-contained.
$this->errors = array();
$this->error_data = array();
}
/**
* Returns the results of operations.
*
* @param mixed $default Default value returned when no result payload exists.
*
* @return mixed The result payload previously set by the constructor, Revalt::put_results(), Revalt::success(), or Revalt::merge().
*/
public function get_results( $default = null ) {
if ( $this->operation_results === null ) {
return $default;
}
return $this->operation_results;
}
/**
* Retrieve the preceding Revalt instance in the execution stack.
*
* This method allows traversing the result chain to get underlying results
* or to inspect the underlying diagnostic information (errors) of the current operation.
*
* @return Revalt|null Preceding Revalt instance. Null if this is the root of the stack OR no execution stack was involved.
*
* @since 7.0
*/
public function get_previous_result(): ?Revalt {
return $this->previous_result;
}
/**
* Returns the results of operations as an array, ensuring the return type is always array.
*
* @param array $default Default value if no results.
*
* @return array Results of operations as an array.
*/
public function get_results_list( array $default = array() ): array {
$val = $this->get_results( $default );
if ( ! is_array( $val ) ) {
$val = array( $val );
}
return $val;
}
/**
* Returns a slice of the results
*
* @param int $offset
* @param int|null $length
* @param bool $preserve_keys
*
* @return array
*
* @see array_slice()
*
*/
public function get_slice( int $offset, ?int $length, bool $preserve_keys = false ): array {
if ( ! is_array( $this->operation_results ) ) {
return array();
}
return array_slice( $this->operation_results, $offset, $length, $preserve_keys );
}
/**
* Returns an element from the results
*
* @param string|int $key The array key to return the value for
* @param mixed $default Default value if no element can be returned
*
* @return mixed Value from the results
*
*/
public function get_element( $key, $default = null ) {
if ( ! is_array( $this->operation_results ) ) {
return $default;
}
return $this->operation_results[ $key ] ?? $default;
}
/**
* Returns the number of elements in the results.
*
* Note: this method returns 1 if the stored result is a non-array value (e.g., string, int, or object)
*
* @return int
*/
public function count_results(): int {
if ( $this->operation_results === null ) {
return 0;
}
if ( is_array( $this->operation_results ) ) {
return count( $this->operation_results );
}
return 1;
}
/**
* Retrieves all error codes.
*
*
* @return array List of error codes, if available.
*/
public function get_all_error_codes(): array {
if ( ! $this->has_errors() ) {
return array();
}
return array_keys( $this->errors );
}
/**
* Retrieves the first error code available.
*
*
* @return string Empty string, if no error codes.
*/
public function get_error_code(): string {
$codes = $this->get_all_error_codes();
if ( empty( $codes ) ) {
return '';
}
return (string) $codes[0];
}
/**
* Retrieves all error messages, or the error messages for the given error code.
*
*
* @param string $code Optional. Error code to retrieve the messages for.
* Default empty string.
*
* @return string[] Error strings on success, or empty array if there are none.
*
*/
public function get_error_messages( string $code = '' ): array {
// Return all messages if no code specified.
if ( empty( $code ) ) {
$all_messages = array();
foreach ( $this->errors as $code => $messages ) {
$all_messages = array_merge( $all_messages, $messages );
}
return $all_messages;
}
return $this->errors[ $code ] ?? array();
}
/**
* Gets a single error message.
*
* This will get the first message available for the code. If no code is
* given then the first code available will be used.
*
* @param string $code Optional. Error code to retrieve the message for.
* Default empty string.
*
* @return string The error message.
*
*/
public function get_error_message( string $code = '' ): string {
if ( empty( $code ) ) {
$code = $this->get_error_code();
}
$messages = $this->get_error_messages( $code );
if ( empty( $messages ) ) {
return '';
}
return $messages[0];
}
/**
* Retrieves the most recently added error data for an error code.
*
* @param string $code Optional. Error code. Default empty string.
*
* @return mixed Error data, if it exists, otherwise NULL.
*
*/
public function get_error_data( string $code = '' ) {
if ( empty( $code ) ) {
$code = $this->get_error_code();
}
if ( ! empty( $this->error_data[ $code ] ) ) {
$count = count( $this->error_data[ $code ] );
return $this->error_data[ $code ][ $count - 1 ];
}
return null;
}
/**
* Retrieves all error data for an error code in the order in which the data was added.
*
* @param string $code Error code.
*
* @return array Array of error data, if it exists.
*
* @since 5.6.0
*/
public function get_all_error_data( string $code = '' ): array {
if ( empty( $code ) ) {
$code = $this->get_error_code();
}
return $this->error_data[ $code ] ?? array();
}
/**
* Verifies if the instance contains errors.
*
* @return bool If the instance contains errors.
*
* @since 5.1.0
*/
public function has_errors(): bool {
if ( ! empty( $this->errors ) ) {
return true;
}
return false;
}
/**
* Adds an error or appends an additional message to an existing error.
*
* @param string $code Error code.
* @param string $message Error message.
* @param mixed $data Optional. Error data. Stored whenever it is not null.
* @param Revalt|null $previous_result Deprecated. Still honored for backward compatibility.
*
* @return void
*
*/
public function add_error( string $code, string $message, $data = null, ?Revalt $previous_result = null ) {
$this->errors[ $code ][] = $message;
if ( $data !== null ) {
$this->add_error_data( $data, $code );
}
$this->set_previous_result( $previous_result );
if ( self::$log_mode === self::LOG_INSTANT && self::$error_logger !== null ) {
( self::$error_logger )( $code, $message, $data );
}
}
/**
* Adds data to an error with the given code.
*
* @param mixed $data Error data.
* @param string $code Optional. Error code. Default empty string.
* When empty, the first existing error code is used (see get_error_code()).
*
* @return void
*
*/
public function add_error_data( $data, string $code = '' ) {
if ( empty( $code ) ) {
$code = $this->get_error_code();
}
$this->error_data[ $code ][] = $data;
}
/**
* Get the entire execution stack as an array e.g. for debugging.
*
* Each entry describes one layer of the chain. The `data` key holds that layer's
* result payload (get_results()), not its error data.
*
* @return array<int, array{level: int, has_errors: bool, codes: array, messages: string[], data: mixed}>
* List of all layers in the chain, starting from the current one (level 0).
*
* @since 7.0
*/
public function get_stack(): array {
$trace = array();
$current = $this;
$level = 0;
while ( $current instanceof Revalt
&& $level < $this::MAX_STACK_DEPTH ) {
$trace[] = array(
'level' => $level ++,
'has_errors' => $current->has_errors(),
'codes' => $current->get_all_error_codes(),
'messages' => $current->get_error_messages(),
'data' => $current->get_results(),
);
$current = $current->get_previous_result();
}
return $trace;
}
/**
* Retrieves details of the deepest error in the execution stack (Root Cause).
*
* Traverses the stack downwards and finds the last Revalt instance that contains errors.
* Useful when the top-level error is generic (e.g., "Action failed") and you need
* the specific low-level reason (e.g., "DB Connection Refused").
*
* @return array{level: int, code: string, message: string, data: mixed}|array{} Empty array if no errors found.
*
* @since 7.0
*/
public function get_root_cause(): array {
$root_cause = array();
$current = $this;
$level = 0;
while ( $current instanceof Revalt
&& $level < $this::MAX_STACK_DEPTH ) {
if ( $current->has_errors() ) {
$root_cause = array(
'level' => $level,
'code' => $current->get_error_code(),
'message' => $current->get_error_message(),
'data' => $current->get_error_data(),
);
}
$level ++;
$current = $current->get_previous_result();
}
return $root_cause;
}
/**
* Configure error logging behavior for all Revalt instances.
*
* Note: this affects all instances.
*
* @param callable|null $logger Receives (string $code, string $message, mixed $data).
* Pass null to disable logging entirely.
* @param int $mode LOG_BUFFERED (default) or LOG_INSTANT.
* See the constants for behaviour details.
*
* @since 8.5
*/
public static function set_error_logger( ?callable $logger, int $mode = self::LOG_BUFFERED ): void {
self::$error_logger = $logger;
self::$log_mode = $mode;
}
/**
* Send all accumulated errors to the configured logger.
*
* Note: set_error_logger() must be called once, globally, beforehand to configure the logger.
*
* Walks the previous_result chain; each entry is prefixed with [L{n}],
* where n is the chain depth (L0 = current layer, higher = deeper).
*
* Note: if Revalt::LOG_INSTANT is enabled, this method may duplicate log entries.
*
* Does not clear the error state. No-op if no logger is configured.
*
* @since 8.5
*/
public function log_errors(): void {
if ( self::$error_logger === null ) {
return;
}
$current = $this;
$level = 0;
while ( $current instanceof Revalt
&& $level < self::MAX_STACK_DEPTH ) {
$prefix = '[L' . $level . '] ';
foreach ( $current->errors as $code => $messages ) {
// 1. Every message for the code. Nothing is dropped.
foreach ( $messages as $message ) {
( self::$error_logger )( $code, $prefix . $message, null );
}
// 2. Every accumulated data item, attached to the last message.
$all_data = $current->get_all_error_data( $code );
if ( ! empty( $all_data ) ) {
$last_message = $messages[ array_key_last( $messages ) ];
foreach ( $all_data as $data ) {
( self::$error_logger )( $code, $prefix . $last_message, $data );
}
}
}
$level++;
$current = $current->get_previous_result();
}
}
}
Thank you for choosing Capital GMC Buick | Regina, your premier certified Buick and GMC dealership proudly serving drivers in Regina and the surrounding communities. Whether you’re searching for a brand-new Buick or GMC vehicle or a meticulously inspected pre-owned model, we have a diverse selection to match your needs and lifestyle.
Beyond our impressive inventory, we offer a seamless and stress-free financing experience through our well-connected finance centre, where our team of experts is dedicated to securing the best loan or lease options for you, quickly, transparently, and hassle-free.
But our commitment to you doesn’t stop at the sale. Our state-of-the-art service centre is staffed with skilled Buick and GMC technicians who use the latest equipment and genuine OEM parts to keep your vehicle running at its best. From routine maintenance to complex repairs, we’ve got you covered.
Experience top-tier customer service, quality vehicles, and expert care, all in one place. Visit Capital GMC Buick | Regina today or call us at 306-205-8072 with any questions. We’re here to help!
Have a question or need assistance? Fill out the form and we will reach out to you as soon as possible.
Schedule a Visit
Let us know when you are coming and how we can assist you. We can ensure someone will be on hand to help you out at the desired date and time.
Find a Career
Have a look at our list of available positions and apply online today to join our team!
Opportunities to Grow
The auto industry is constantly changing and we want to continue to grow. We offer growth, leadership & mentorship programs to allow our staff to grow with us.
Competitive Salary
We have a significant earning potential with incentive-based pay in most roles. We also offer an employee referral bonus with paid bonuses.
Health & Dental
We offer a comprehensive benefits package including extended health, dental, and vision care. We also include paramedical, life insurance, paid sick leave, short & long-term disability coverages.
Vacation
We value our employees and want everyone to take their vacation time. We offer a minimum of 2 weeks vacation each year.
Training & Development
We have many opportunities for paid education and training in-house as well as training from the Manufacturer.
$10,000 Cash Giveaway – Terms & Conditions
All October long, stop by Capital GMC Buick Cadillac, to enter for your chance to win $10,000 cash. No purchase is required, but entries must be made in-store.
The contest is open to residents of Saskatchewan who are 18+. Dealership employees and their households are not eligible. Entries will be accepted from October 1 to October 31, 2025. A random draw will take place on November 1, 2025.
The prize is one $10,000 award, paid by cheque, and must be accepted as awarded. Winner will be contacted by phone or email and must respond within 7 days or another entry may be drawn. Odds of winning depend on the number of entries received.By entering, you agree that Capital Automotive Group may use your name and photo for winner announcements. The contest is governed by the laws of Saskatchewan.