attogram/attogram

View on GitHub
public/index.php

Summary

Maintainability
D
2 days
Test Coverage
<?php
// Attogram Framework - Guru Meditation Loader - v0.6.0

namespace Attogram;

use Symfony\Component\HttpFoundation\Request;

$guru = new GuruMeditationLoader(
    'config.php', // $configFile
    'https://github.com/attogram/attogram-vendor/archive/master.zip' // $vendorDownload
);

/** ************************************************************************* */
class GuruMeditationLoader
{

    /** @var array List of debug messages */
    public $debugLog;

    /** @var string The Main Configuration File */
    public $configFile;

    /** @var array List of configuration settings */
    public $config;

    /** @var string URL to download vendor directory */
    public $vendorDownload;

    /** @var string The composer autoloader.php file */
    public $autoloader;

    /**
     * start the Guru Meditation Loader
     * @param string $configFile
     * @param string $vendorDownload
     */
    public function __construct(
        $configFile,
        $vendorDownload
    ) {
        $this->errorSetup();
        $this->debug('START Guru Meditation Loader');
        $this->configFile         = $configFile;
        $this->vendorDownload     = $vendorDownload;
        $this->meditate();            // load the main Attogram configuration

        if (isset($this->config['isRouter']) && $this->config['isRouter']) {
            //
        }

        $this->expandConsciousness(); // run the composer vendor autoloader
        $this->focusInnerEye();       // include modules includes
        $this->meditateDeeper();      // load the modules configurations
        $this->tranquility();         // Load The Attogram Framework

    } // end function __construct()

    /**
     * load the main Attogram configuration
     * @see GuruMeditationLoader::configFile
     * @see GuruMeditationLoader::config
     */
    public function meditate()
    {
        // Set default configuration
        $this->config = array();
        $this->config['attogramDirectory']  = '..'.DIRECTORY_SEPARATOR;
        $this->config['autoloader']         = '..'.DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR.'autoload.php';
        $this->config['modulesDirectory']   = '..'.DIRECTORY_SEPARATOR.'modules';
        $this->config['templatesDirectory'] = '..'.DIRECTORY_SEPARATOR.'templates';
        $this->config['databaseName']       = '..'.DIRECTORY_SEPARATOR.'db'.DIRECTORY_SEPARATOR.'global';
        $this->config['debug']              = false;
        $this->config['siteName']           = 'Attogram Framework';
        $this->config['admins']             = array('127.0.0.1', '::1');

        if (!is_file($this->configFile)) {
            $this->debug('meditate: NOT FOUND: ConfigFile: '.$this->configFile);
            $this->logDefaultConfiguration();
            return;
        }
        if (!is_readable($this->configFile)) {
            $this->debug('meditate: NOT READABLE: ConfigFile: '.$this->configFile);
            $this->logDefaultConfiguration();
            return;
        }
        if (!(include($this->configFile))) {
            $this->debug('meditate: INCLUDE FAILED: ConfigFile: '.$this->configFile);
            $this->logDefaultConfiguration();
            return;
        }
        //$this->debug('meditate: LOADED OK: ConfigFile: '.$this->configFile);

        if (!isset($config)) {
            $this->debug('meditation: NOT FOUND: no config variable in ConfigFile');
            $this->logDefaultConfiguration();
            return;
        }
        if (!is_array($config)) {
            $this->debug('meditation: NOT FOUND: no config array in ConfigFile');
            $this->logDefaultConfiguration();
            return;
        }
        // Override default settings with ConfigFile configuration
        foreach ($config as $configName => $configValue) {
            $this->config[$configName] = $configValue;
        }
        //$this->debug('meditate: CONFIG OK: '.print_r($this->config, true));
    } // end function meditate()

    public function logDefaultConfiguration()
    {
        $this->debug('DEFAULT CONFIG: '.print_r($this->config, true));
    }
    /**
     * run the vendor autoloader
     */
    public function expandConsciousness()
    {
        if (isset($this->config['autoloader'])
            && is_file($this->config['autoloader'])
            && is_readable($this->config['autoloader'])
        ) {
            $included = (include($this->config['autoloader']));
            if (!$included) {
                $this->guruMeditationError(
                    'Autoloader file exists, but include failed: '.$this->config['autoloader']
                );
            }
            $this->debug('expandConsciousness: OK: '.$this->config['autoloader']);
            return;
        }
        $this->guruMeditationError(
            'autoloader file not found: '.$this->config['autoloader'],
            'Possibile Fixes:'
            .'<br /><br />- Is the path to the autoloader wrong?  Edit <strong>'
            .$this->configFile
            .'</strong> and set <strong>$config[\'autoloader\']</strong>'
            .'<br /><br />- Was <a href="http://getcomposer.org/">composer</a> not run yet?'
            .' Run <strong>composer install</strong>'
            .'<br /><br />- Can\'t run composer? <a href="'.$this->vendorDownload
            .'"><strong>download the vendor zip file</strong></a> and install manually'
        );
    } // end function expandConsciousness()

    public function focusInnerEye()
    {
        $counts = Attogram::loadModuleSubdirectories(
            $this->config['modulesDirectory'],
            'includes'
        );
        $this->debug('focusInnerEye: OK: '.implode(', ', $counts));
    }

    /**
     * load module configuration files
     */
    public function meditateDeeper()
    {
        global $config; // for loading of $config variable from within the module config files
        $configDirs = Attogram::getAllSubdirectories(
            $this->config['modulesDirectory'],
            'configs'
        );
        if (!$configDirs) {
            $this->debug('meditateDeeper: NOT FOUND: no module configs directories');
            return;
        }
        foreach ($configDirs as $dir) {
            //$this->debug('meditateDeeper: dir: ' . $dir);
            Attogram::includeAllPhpFilesInDirectory($dir);
        }
        if (!$config) {
            $this->debug('meditateDeeper: NOT FOUND: no config in module configs directories');
            return;
        }
        foreach ($config as $configName => $configValue) {
            $this->config[$configName] = $configValue;
        }
        //$this->debug('meditateDeeper: Module Config OK: ' . print_r($config, true));
    }

    public function tranquility()
    {
        // Speed things up! gz compession
        //if (ob_start('ob_gzhandler')) {
        //    $this->debug('tranquility: ob_gzhandler active');
        //}

        // Create the Request object
        $request = Request::createFromGlobals();

        // Create the Debug Logger
        if ((isset($this->config['debug'])   // debug is true...
            && is_bool($this->config['debug'])
            && $this->config['debug'])
            ||
            ($request->query->has('debug')   // admin debug url override ?debug
            && isset($this->config['admins'])
            && is_array($this->config['admins'])
            && in_array($request->getClientIp(), $this->config['admins']))
        ) {
            $log = new \Monolog\Logger('debug');
            $streamHandler = new \Monolog\Handler\StreamHandler('php://output');
            $format = '<p class="text-danger squished">%datetime%|%level_name%: %message% %context%</p>'; // %extra%
            $dateformat = 'Y-m-d|H:i:s:u';
            $streamHandler->setFormatter(new \Monolog\Formatter\LineFormatter($format, $dateformat));
            $log->pushHandler(new \Monolog\Handler\BufferHandler($streamHandler));
            // $log->pushHandler( new \Monolog\Handler\BrowserConsoleHandler ); // dev
        } else {
            $log = new \Psr\Log\NullLogger();
        }
        // Save guru startup log to the Debug logger
        if (isset($this->configLog) && is_array($this->configLog)) {
            foreach ($this->configLog as $message) {
                $log->debug($message);
            }
        }

        // Create database and event objects
        if (class_exists('\Attogram\SqliteDatabase')) { // if database module installed...
            $database = new SqliteDatabase( // init the database, sans-connection
                $this->config['databaseName'],
                $this->config['modulesDirectory'],
                $log
            );
            $event = new \Monolog\Logger('event'); // Setup the Event Logger
            $event->pushHandler(new \Attogram\EventLogger($database));
        }
        if (!isset($database) || !$database) {
            $database = new NullDatabase();
            $event = new \Psr\Log\NullLogger();
        }

        new Attogram(     // Start the Attogram Framework!
            $log,         // The Debug Logger Object
            $event,       // The Event Logger Object
            $database,    // The Attogram Database Object
            $request,     // The Request Object
            $this->config // Configuration for this installation
        );

    } // end function tranquility()

    /**
     * Log a debug message
     * @param string $msg  The debug message
     */
    public function debug($msg)
    {
        $this->configLog[] = $msg;
    }

    public function guruMeditationError($error = '', $fix = '')
    {
        echo '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">'
        .'<meta name="viewport" content="width=device-width, initial-scale=1">'
        .'<title>Guru Meditation Error</title>'
        .'<style>'
        .' body { margin:0 0 0 30px; font-size:22px; font-family:"Helvetica Neue",Helvetica,Arial,sans-serif; }'
        .' a { text-decoration:none; }'
        .' .icon { font-size:60px; vertical-align:middle; padding:0px; margin:10px; }'
        .' .err { color:red; }'
        .' .fix { font-size:18px; color:black;  }'
        .' .log { font-size:15px; color:#333366; }'
        .'</style></head><body>'
        .'<p><a href=""><span class="icon">😢</span></a> Guru Meditation Error</p>';
        if ($error) {
            echo '<p class="err"><a href=""><span class="icon">💔</span></a> '.$error.'</p>';
        }
        if ($fix) {
            echo '<p class="fix"><a href=""><span class="icon">🔧</span></a> '.$fix.'</p>';
        }
        if (isset($_GET['debug']) && isset($this->configLog)) {
            echo '<p class="log">🕑 '.gmdate('Y-m-d H:i:s').' UTC<br />💭 ';
            echo implode('<br />💭 ', $this->configLog);
        }
        echo '</body></html>';
        exit; // Exit everything
    } // end function guruMeditationError()

    /**
     * Catch any errors.
     */
    public function guruMeditationErrorHandler(
        $level,
        $message,
        $file = '',
        $line = '',
        $context = array()
    ) {
        switch ($level) {
            case 1:
                $this->debug("E_ERROR: file:$file line:$line $message");
                break;
            case 2:
                $this->debug("E_WARNING: file:$file line:$line $message");
                return;
            case 4:
                $this->debug("E_PARSE: file:$file line:$line $message");
                return;
            case 8:
                $this->debug("E_NOTICE: file:$file line:$line $message");
                return;
            case 16:
                $this->debug("E_CORE_ERROR: file:$file line:$line $message");
                break;
            case 32:
                $this->debug("E_CORE_WARNING: file:$file line:$line $message");
                return;
            case 64:
                $this->debug("E_COMPILE_ERROR: file:$file line:$line $message");
                break;
            case 128:
                $this->debug("E_COMPILE_WARNING: file:$file line:$line $message");
                return;
            case 256:
                $this->debug("E_USER_ERROR: file:$file line:$line $message");
                break;
            case 512:
                $this->debug("E_USER_WARNING: file:$file line:$line $message");
                return;
            case 1024:
                $this->debug("E_USER_NOTICE: file:$file line:$line $message");
                return;
            case 2048:
                $this->debug("E_STRICT: file:$file line:$line $message");
                return;
            case 4096:
                $this->debug("E_RECOVERABLE_EROR: file:$file line:$line $message");
                return;
            case 8192:
                $this->debug("E_DEPECIATED: file:$file line:$line $message");
                return;
            case 16384:
                $this->debug("E_USER_DEPECIATED: file:$file line:$line $message");
                return;
            case 30719:
                $this->debug("E_ALL: file:$file line:$line $message");
                break;
            default:
                $this->debug("E_UNKNOWN: file:$file line:$line $message");
                break;
        }

        $this->guruMeditationError(
            "Sadness $level: $message"
            . ((isset($file) && $file) ? "<pre>File: $file</pre>" : '')
            . ((isset($line) && $line) ? "<pre>Line: $line</pre>" : '')
            . (isset($context['project_name']) ? '<pre>Context: ' . $context['project_name'] . '</pre>' : '')
        );
    }

    /**
     * Catch any fatal errors at shutdown.
     */
    public function guruMeditationShutdown()
    {
        $last = error_get_last();
        switch ($last['type']) {
            case E_ERROR:
                $this->guruMeditationError(
                    'Shutdown due to Fatal Error:<br />'.str_replace("\n", '<br />', $last['message'])
                );
                // shutdown
        }
    }

    /**
     * setup error and shutdown handling
     */
    public function errorSetup()
    {
        error_reporting(E_ALL); // display all errors
        ini_set('display_errors', E_ALL); // display all errors
        set_error_handler(array($this, 'guruMeditationErrorHandler'));
        register_shutdown_function(array($this, 'guruMeditationShutdown'));
    }
} // end class GuruMeditationLoader