/**
 * 
 * 
 * @param int $argc
 * @param array $argv
 * 
 * @return void
 * 
 * @throws \InvalidArgumentException
 * @throws \RuntimeException if this function is called in a script that is not run at the command line.
 */
function createController($argc, array $argv)
{
    //////////////////////////////////////////
    // START: Environment and Args Validation
    //////////////////////////////////////////
    if (!isPhpRunningInCliMode()) {
        $err_msg = '`' . __FUNCTION__ . '($argc, array $argv)` should only be called from within' . ' php scripts that should be run via the command line!!!' . PHP_EOL;
        throw new \RuntimeException($err_msg);
    }
    if (is_string($argc) && is_numeric($argc)) {
        $argc = (int) $argc;
    }
    if (!is_int($argc)) {
        $err_msg = 'The expected value for the first argument to ' . '`' . __FUNCTION__ . '($argc, array $argv)` should be an int.' . ' `' . ucfirst(gettype($argc)) . '` with the value below was supplied:' . PHP_EOL . var_export($argc, true) . PHP_EOL . PHP_EOL . 'Good bye!!!';
        throw new \InvalidArgumentException($err_msg);
    }
    if (count($argv) < 1) {
        $err_msg = 'The expected value for the second argument to ' . '`' . __FUNCTION__ . '($argc, array $argv)` should be an array with at least one element. Empty Array was supplied.' . 'This second argument is expected to be the $argv array passed by PHP to the script calling this function.';
        throw new \InvalidArgumentException($err_msg);
    }
    //////////////////////////////////////////
    // END: Environment and Args Validation
    //////////////////////////////////////////
    //////////////////////////////////
    ///START: COMMAND PROCESSING
    //////////////////////////////////
    $ds = DIRECTORY_SEPARATOR;
    if ($argc < 5 || in_array('--help', $argv) || in_array('-help', $argv) || in_array('-h', $argv) || in_array('-?', $argv)) {
        displayHelp(basename($argv[0]));
    } else {
        if ($argc === 5 && (in_array('--controller-name', $argv) || in_array('-c', $argv)) && (in_array('--path-to-src-folder', $argv) || in_array('-p', $argv)) || $argc >= 7 && (in_array('--controller-name', $argv) || in_array('-c', $argv)) && (in_array('--path-to-src-folder', $argv) || in_array('-p', $argv)) && (in_array('--extends-controller', $argv) || in_array('-e', $argv))) {
            $templates_dir = dirname(__DIR__) . $ds . 'templates' . $ds;
            $controller_name = getOptVal('--controller-name', $argv);
            if ($controller_name === false) {
                $controller_name = getOptVal('-c', $argv);
            }
            $studly_controller_name = \Slim3MvcTools\Functions\Str\dashesToStudly(\Slim3MvcTools\Functions\Str\underToStudly($controller_name));
            $dashed_controller_name = \Slim3MvcTools\Functions\Str\toDashes($controller_name);
            if (!isValidClassName($studly_controller_name)) {
                printError("Invalid controller class name `{$controller_name}` supplied. Goodbye!!");
                return;
            }
            $src_folder_path = getOptVal('--path-to-src-folder', $argv);
            if ($src_folder_path === false) {
                $src_folder_path = getOptVal('-p', $argv);
            }
            $src_folder_path = normalizeFolderPathForOs($src_folder_path);
            if (!file_exists($src_folder_path) || !is_dir($src_folder_path)) {
                printError("The src folder path `{$src_folder_path}` supplied is a non-existent directory. Goodbye!!");
                return;
            }
            ////////////////////////////////////////////////////////////////////////////
            $default_controller_2_extend = '\\Slim3MvcTools\\Controllers\\BaseController';
            $controller_2_extend = getOptVal('--extends-controller', $argv);
            if ($controller_2_extend === false) {
                $controller_2_extend = getOptVal('-e', $argv);
                if ($controller_2_extend !== false) {
                    if (!isValidExtendsClassName($controller_2_extend)) {
                        printError("Invalid controller class name `{$controller_2_extend}` for extension supplied. Goodbye!!");
                        return;
                    }
                } else {
                    //use default controller class to be extended
                    $controller_2_extend = $default_controller_2_extend;
                }
            } else {
                if (!isValidExtendsClassName($controller_2_extend)) {
                    printError("Invalid controller class name `{$controller_2_extend}` for extension supplied. Goodbye!!");
                    return;
                }
            }
            ////////////////////////////////////////////////////////////////////////////
            $namepace_declaration = '';
            //omit namespace declaration by default
            $namepace_4_controller = getOptVal('--namespace-4-controller', $argv);
            if ($namepace_4_controller === false) {
                $namepace_4_controller = getOptVal('-n', $argv);
                if ($namepace_4_controller !== false) {
                    if (!isValidNamespaceName($namepace_4_controller)) {
                        printError("Invalid namespace `{$namepace_4_controller}` supplied. Goodbye!!");
                        return;
                    }
                    //validation passed
                    $namepace_declaration = "namespace {$namepace_4_controller};";
                } else {
                    $namepace_4_controller = '';
                }
            } else {
                if (!isValidNamespaceName($namepace_4_controller)) {
                    printError("Invalid namespace `{$namepace_4_controller}` supplied. Goodbye!!");
                    return;
                }
                //validation passed
                $namepace_declaration = "namespace {$namepace_4_controller};";
            }
            //read template controller and substitute __TEMPLTATE_CONTROLLER__ with given controller name \Slim3MvcTools\Functions\Str\underToStudly(dashesToStudly($controller_name_from_cli))
            //substitute {{TEMPLTATE_CONTROLLER_VIEW_FOLDER}} with the view folder name \Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            //write processed controller file to S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'controllers'.$ds
            //make the dir S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'views'.$ds.\Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            //read template controller index view and substitute __TEMPLTATE_CONTROLLER__ with given controller name \Slim3MvcTools\Functions\Str\underToStudly(dashesToStudly($controller_name_from_cli))
            //write processed controller file to S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'views'.$ds.\Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            $template_controller_file = $templates_dir . 'controller-class-template.php.tpl';
            $dest_controller_class_file_folder = $src_folder_path . 'controllers' . $ds;
            $dest_controller_class_file = $dest_controller_class_file_folder . "{$studly_controller_name}.php";
            if (!file_exists($dest_controller_class_file_folder) && !mkdir($dest_controller_class_file_folder, 0775, true)) {
                printError("Failed to create `{$dest_controller_class_file_folder}`; the folder supposed to contain the controller named `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            $template_view_file = $templates_dir . 'index-view-template.php';
            $dest_view_file_folder = $src_folder_path . 'views' . $ds . "{$dashed_controller_name}{$ds}";
            $dest_view_file = "{$dest_view_file_folder}index.php";
            if (!file_exists($dest_view_file_folder) && !mkdir($dest_view_file_folder, 0775, true)) {
                printError("Failed to create `{$dest_view_file_folder}`; the folder supposed to contain views for the controller named `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            if (file_exists($dest_controller_class_file)) {
                printError("Controller class `{$studly_controller_name}` already exists in `{$dest_controller_class_file}`. Goodbye!!");
                return;
            }
            if (file_exists($dest_view_file)) {
                printError("View file `{$dest_view_file}` already exists for Controller class `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            printInfo("Creating Controller Class `{$studly_controller_name}` in `{$dest_controller_class_file}` ....");
            ////////////////////////////////////////////////////////////////////////////
            $replaces = ['__CONTROLLER_2_EXTEND__' => $controller_2_extend, '__TEMPLTATE_CONTROLLER__' => $studly_controller_name, 'namespace __NAMESPACE_2_REPLACE__;' => $namepace_declaration, '{{TEMPLTATE_CONTROLLER_VIEW_FOLDER}}' => $dashed_controller_name, "'__login_success_redirect_controller__'" => "'{$dashed_controller_name}'"];
            if (processTemplateFile($template_controller_file, $dest_controller_class_file, $replaces) === false) {
                printError("Failed transforming template controller `{$template_controller_file}` to `{$dest_controller_class_file}`. Goodbye!!");
            } else {
                printInfo("Successfully created `{$dest_controller_class_file}` ...." . PHP_EOL);
            }
            printInfo("Creating index view for `{$studly_controller_name}::actionIndex()` in `{$dest_view_file}` ....");
            $replaces['__TEMPLTATE_CONTROLLER__'] = rtrim($namepace_4_controller, '\\') . '\\' . $studly_controller_name;
            if (processTemplateFile($template_view_file, $dest_view_file, $replaces) === false) {
                printError("Failed creating index view for `{$studly_controller_name}::actionIndex()` in `{$dest_view_file}`.");
                printInfo("Deleting `{$dest_controller_class_file}` ....");
                if (!unlink($dest_controller_class_file)) {
                    printInfo("Failed to delete `{$dest_controller_class_file}`. Please delete it manually. Goodbye!!");
                } else {
                    printInfo("Goodbye!!");
                }
                return;
            } else {
                printInfo("Successfully created `{$dest_view_file}` ...." . PHP_EOL);
            }
            printInfo("All done!!");
            if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
                //test if composer is avaliable only if server OS on which this script is being run
                //is not windows
                if (isCommandAvailableOnOs('composer')) {
                    passthru('composer dumpautoload');
                } else {
                    printInfo("Remember to run `composer dumpautoload` so that composer can pick up the newly created controller class `{$studly_controller_name}` in `{$dest_controller_class_file}`.");
                }
            } else {
                printInfo("Remember to run `composer dumpautoload` so that composer can pick up the newly created controller class `{$studly_controller_name}` in `{$dest_controller_class_file}`.");
            }
            //we are done
        } else {
            displayHelp(basename($argv[0]));
        }
    }
    //////////////////////////////////
    ///END: COMMAND PROCESSING
    //////////////////////////////////
}
 /**
  * 
  * Executes a PHP file and returns its output as a string. This file is 
  * supposed to contain the output markup (usually html) for the current 
  * controller action method being executed.
  * 
  * @param string $file_name name of the file (including extension eg. `read.php`) 
  *                          containing valid php to be executed and returned as
  *                          string.
  * @param array $data an array of data to be passed to the view file. Each
  *                    key in this array is automatically converted to php
  *                    variables accessible in the view file. 
  *                    Eg. passing ['content'=>'yabadabadoo'] to this method 
  *                    will result in a variable named $content (with a 
  *                    value of 'yabadabadoo') being available in the view
  *                    file (i.e. the file named $file_name).
  * @return string
  * 
  * @throws \Slim3MvcTools\Controllers\Exceptions\IncorrectlySetPropertyException
  * 
  */
 public function renderView($file_name, array $data = [])
 {
     if (!$this->view_renderer instanceof \Rotexsoft\FileRenderer\Renderer) {
         try {
             $this->view_renderer = $this->getContainerItem('new_view_renderer');
         } catch (ExpectedContainerItemMissingException $ex) {
             $msg = "ERROR: The `view_renderer` property of `" . get_class($this) . "`" . " must be set via a call to `" . get_class($this) . '::setViewRenderer(...)` ' . " before calling `" . get_class($this) . '::' . __FUNCTION__ . '(...)`.' . PHP_EOL;
             throw new IncorrectlySetPropertyException($msg);
         }
     }
     $parent_classes = [];
     $parent_class = get_parent_class($this);
     while ($parent_class !== __CLASS__ && !empty($parent_class)) {
         $parent_classes[] = (new \ReflectionClass($parent_class))->getShortName();
         $parent_class = get_parent_class($parent_class);
     }
     //Try to prepend view folder for this controller.
     //It takes precedence over the view folder
     //for the base controller.
     $ds = DIRECTORY_SEPARATOR;
     $path_2_view_files = S3MVC_APP_ROOT_PATH . $ds . 'src' . $ds . 'views' . $ds;
     while ($parent_class = array_pop($parent_classes)) {
         $parent_class_folder = \Slim3MvcTools\Functions\Str\toDashes($parent_class);
         if (!$this->view_renderer->hasPath($path_2_view_files . $parent_class_folder) && file_exists($path_2_view_files . $parent_class_folder)) {
             $this->view_renderer->prependPath($path_2_view_files . $parent_class_folder);
         }
     }
     //finally add my view folder
     if (!$this->view_renderer->hasPath($path_2_view_files . $this->controller_name_from_uri) && file_exists($path_2_view_files . $this->controller_name_from_uri)) {
         $this->view_renderer->prependPath($path_2_view_files . $this->controller_name_from_uri);
     }
     return $this->view_renderer->renderToString($file_name, $data);
 }
            //not found page.
            $resp = $controller_obj;
        }
    }
    return $resp;
};
$s3mvc_controller_only_route_handler = function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, $args) use($app) {
    //NOTE: inside this function $this refers to the Slim app's container.
    //      It is automatically bound to this closure by Slim 3 when any of
    //      $app->map or $app->get or $app->post, etc is called.
    //No action was specified, so invoke the default action on specified
    //controller.
    $default_action = S3MVC_APP_DEFAULT_ACTION_NAME;
    //s3MVC_CreateController could return a Response object if $args['controller']
    //doesn't match any existing controller class.
    $controller_object = s3MVC_CreateController($app, $args['controller'], \Slim3MvcTools\Functions\Str\toDashes($default_action), $request, $response);
    if ($controller_object instanceof \Slim3MvcTools\Controllers\BaseController && !method_exists($controller_object, $default_action)) {
        $controller_class_name = get_class($controller_object);
        //404 Not Found: Action method does not exist in the controller object.
        $this->get('logger')->notice("`" . __FILE__ . "` on line " . __LINE__ . ": The action method `{$default_action}` does not exist in class `{$controller_class_name}`.");
        $notFoundHandler = $this->get('notFoundHandler');
        //invoke the not found handler
        return $notFoundHandler($request, $response);
    }
    //invoke default action
    $actn_res = $controller_object instanceof \Slim3MvcTools\Controllers\BaseController ? $controller_object->{$default_action}() : $controller_object;
    if (is_string($actn_res)) {
        //write the string in the response object as the response body
        $response->getBody()->write($actn_res);
    } elseif ($actn_res instanceof \Psr\Http\Message\ResponseInterface) {
        $response = $actn_res;