AbstractException.php 7.99 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 1/29/16
 * Time: 8:03 AM
 */

namespace qfq;

11
require_once(__DIR__ . '/../Constants.php');
12
require_once(__DIR__ . '/../store/Store.php');
13
require_once(__DIR__ . '/../store/T3Info.php');
14
15
16
17
require_once(__DIR__ . '/../store/Store.php');
require_once(__DIR__ . '/../report/Link.php');
require_once(__DIR__ . '/../database/Database.php');
require_once(__DIR__ . '/UserFormException.php');
18
require_once(__DIR__ . '/../helper/OnArray.php');
19
require_once(__DIR__ . '/../helper/Logger.php');
20
require_once(__DIR__ . '/../helper/Support.php');
21

22

23
24
25
26
/**
 * Class AbstractException
 * @package qfq
 */
27
28
29
class AbstractException extends \Exception {

    public $messageArray = array();
30
31
    public $messageArrayDebug = [EXCEPTION_MESSAGE_DEBUG => ''];

32
    public $store = null;
33

34
35
36
    protected $file = '';
    protected $line = '';

37
    /**
38
39
40
     * $this->getMessage() might give
     *   a) a simple string, or
     *   b) an JSON String.
41
     *
42
     * If it is a JSON String: There are 3+1 different messages:
43
44
45
46
     *   [ERROR_MESSAGE_TO_USER] 'toUser' - shown in the client to the user - no details here!!!
     *   [ERROR_MESSAGE_SUPPORT] 'support' - help for the developer
     *   [ERROR_MESSAGE_OS] 'os' - message from the OS, like 'file not found'
     *
47
48
     * Stacktrace, Form, FormElement, Report level, T3 page, T3 tt_content uid, ...
     *
49
     * @return string
50
51
     * @throws CodeException
     * @throws UserFormException
52
53
     */
    public function formatException() {
54

55
        $t3Vars = array();
56
57
        $arrShow = $this->messageArray;
        $htmlDebug = '';
58
        $arrDebugShow = array();
59
        $editForm='';
60

61
62
63
        try {
            // In a very early stage, it might be possible that Store can't be initialized: take care not to use it.
            $store = Store::getInstance();
64
            $t3Vars = $store->getStore(STORE_TYPO3);
65
66
        } catch (CodeException $e) {
            $store = null;
67
        } catch (\Exception $exception) {
68
            $store = null;
69
70
        }

71
72
73
        if (empty($t3Vars)) {
            $t3Vars = T3Info::getVars();
        }
74

75
76
        $arrShow[EXCEPTION_TIMESTAMP] = date('Y.m.d H:i:s O');
        $arrShow[EXCEPTION_CODE] = $this->getCode();
77
78
79
80
81
82
83
84
85
86
        $arrShow[EXCEPTION_UNIQID] = uniqid();

        // Get exception message and if JSON, decode it.
        $msg = $this->getMessage();
        $arrMsg = json_decode($msg, true);
        if ($arrMsg === null) {
            $arrShow[EXCEPTION_MESSAGE] = $msg;
            $arrMsg[ERROR_MESSAGE_TO_USER] = $msg;
        } else {
            $arrShow[EXCEPTION_MESSAGE] = $arrMsg[ERROR_MESSAGE_TO_USER];
87
        }
88

89
90
91
92
93
94
95
96
//        // Unset empty elements
//        foreach ([EXCEPTION_FORM, EXCEPTION_FORM_ELEMENT, EXCEPTION_FORM_ELEMENT_COLUMN] as $key) {
//            if (isset($arrShow[$key])) {
//                if ($arrShow[$key] == '') {
//                    unset($arrShow[$key]);
//                }
//            }
//        }
97

98
99
        $arrDebugHidden[EXCEPTION_FILE] = $this->getFile();
        $arrDebugHidden[EXCEPTION_LINE] = $this->getLine();
100

101
102
        $arrTrace = $this->getExtensionTraceAsArray();
        if ($store !== null) {
103

104
            $this->messageArrayDebug[EXCEPTION_MESSAGE_DEBUG] = Store::getVar(EXCEPTION_MESSAGE_DEBUG, STORE_SYSTEM);
105

106
            $arrDebugShow = array_merge([EXCEPTION_REPORT_FULL_LEVEL => Store::getVar(SYSTEM_REPORT_FULL_LEVEL, STORE_SYSTEM)], $this->messageArrayDebug);
107

108
109
110
            $arrDebugShow[EXCEPTION_SIP] = $store->getStore(STORE_SIP);
            $arrDebugShow[EXCEPTION_PAGE_ID] = $t3Vars[TYPO3_PAGE_ID];
            $arrDebugShow[EXCEPTION_TT_CONTENT_UID] = $t3Vars[TYPO3_TT_CONTENT_UID];
111

112
113
114
            // Optional existing arrays will be flatten.
            $arrDebugShow = OnArray::varExportArray($arrDebugShow);
            $arrDebugHidden = OnArray::varExportArray($arrDebugHidden);
115

116
117
            // Debug Information
            if (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_YES, $store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM))) {
118

119
120
121
122
                // In case there is a 'form' name given in SIP, we probably have a problem in a form and a direct link to
                // edit the broken form will be helpful.
                $storeSystem = $store->getStore(STORE_SYSTEM);
                if (!empty($storeSystem[SYSTEM_FORM])) {
123
                    $editForm = $this->buildFormLink($storeSystem);
124
                }
125

126
127
                $htmlDebug = OnArray::arrayToHtmlTable(
                    array_merge(OnArray::htmlentitiesOnArray(array_merge($arrMsg, $arrDebugShow)), [ 'Edit' => $editForm ]), 'Debug', EXCEPTION_TABLE_CLASS);
128
                $htmlDebug = str_replace("\n", "<br>", $htmlDebug);
129

130
131
                $arrDebugHiddenClean = OnArray::htmlentitiesOnArray($arrDebugHidden);
                $arrDebugHiddenClean[EXCEPTION_STACKTRACE] = implode($arrTrace, '<br>');
132
                $arrDebugHiddenClean[EXCEPTION_EDIT_FORM] = implode($arrTrace, '<br>');
133
134
135
136
137
138
                $hidden = OnArray::arrayToHtmlTable($arrDebugHiddenClean, 'Details', EXCEPTION_TABLE_CLASS);

                // Show / hide with just CSS: http://jsfiddle.net/t5Nf8/1/
                $htmlDebug .= "<style>input[type=checkbox]:checked + label + table { display: none; }</style>" .
                    "<input type='checkbox' checked id='stacktrace'><label for='stacktrace'>&nbsp;Show/hide more details</label>$hidden";
            }
139
140
        }

141
        $qfqLog = ($store == null) ? SYSTEM_QFQ_LOG_FILE : $store->getVar(SYSTEM_QFQ_LOG, STORE_SYSTEM);
142
143
144
145
        $arrDebugHidden[EXCEPTION_STACKTRACE] = PHP_EOL . implode($arrTrace, PHP_EOL);
        $arrLogAll = array_merge($arrMsg, $arrShow, $arrDebugShow, $arrDebugHidden);
        $logAll = OnArray::arrayToLog($arrLogAll);
        Logger::logMessage($logAll, $qfqLog);
146

147
148
        // Sanitize any HTML content.
        $arrShow = OnArray::htmlentitiesOnArray($arrShow);
149

150
151
        return $this->formatMessageUser($arrShow) . $htmlDebug;
    }
152

153
154
155
156
157
158
159
160
161
    /**
     * @return array
     */
    private function getExtensionTraceAsArray() {

        $trace = $this->getTraceAsString();
        $arrTrace = explode(PHP_EOL, $trace);

        return OnArray::filterValueSubstring($arrTrace, '/typo3conf/ext/' . EXT_KEY . '/');
162
    }
163

164
165
166
167
168
169
170
171
    /**
     * @param $arrShow
     * @return string
     */
    private function formatMessageUser($arrShow) {

        $html = '<p><em>' . $arrShow[EXCEPTION_TIMESTAMP] . ', Reference: ' . $arrShow[EXCEPTION_UNIQID] . '</em></p>';
        $html .= '<p>' . $arrShow[EXCEPTION_MESSAGE] . '</p>';
172

173
174
        return $html;
    }
175

176
177
    /**
     * Build a FormEditor link to the broken form.
178
179
     * @param $storeSystem
     * @return string
180
181
182
183
184
185
186
187
188
189
190
191
192
     */
    private function buildFormLink($storeSystem) {

        $linkForm = '';
        $linkFormElement = '';
        try {
            $db = new Database();
            $sql = "SELECT id FROM Form WHERE name='" . $storeSystem[SYSTEM_FORM] . "'";

            $r = $db->sql($sql, ROW_EXPECT_0_1);
            if (!is_numeric($r[F_ID])) {
                return '';
            }
193

194
195
196
197
            $sip = new Sip();
            $link = new Link($sip);

            // Link to 'Form'
198
199
            $linkForm = $link->renderLink(TOKEN_SIP . '|' . TOKEN_BOOTSTRAP_BUTTON . '|' . TOKEN_PAGE . ':' .
                $storeSystem[SYSTEM_EDIT_FORM_PAGE] . '&' . CLIENT_FORM . '=' . FORM_NAME_FORM . '&' .
200
201
202
203
                CLIENT_RECORD_ID . '=' . $r[F_ID] . '|' . TOKEN_TEXT . ':' . $storeSystem[SYSTEM_FORM]);

            // Link to 'FormElement'
            if (!empty($storeSystem[SYSTEM_FORM_ELEMENT_ID])) {
204
205
206
207
                $linkFormElement = $link->renderLink(TOKEN_SIP . '|' . TOKEN_BOOTSTRAP_BUTTON . '|' . TOKEN_PAGE .
                    ':' . $storeSystem[SYSTEM_EDIT_FORM_PAGE] . '&' . CLIENT_FORM . '=' . FORM_NAME_FORM_ELEMENT . '&' .
                    CLIENT_RECORD_ID . '=' . $storeSystem[SYSTEM_FORM_ELEMENT_ID] . '|' .
                    TOKEN_TEXT . ':' . $storeSystem[SYSTEM_FORM_ELEMENT_ID]);
208
            }
209

210
        } catch (\exception $e) {
211
            // none, should rise up
212
        }
Carsten  Rose's avatar
Carsten Rose committed
213

214
        return 'Form: ' . $linkForm . '&nbsp;&nbsp;  FormElement: ' . $linkFormElement;
215
216
    }
}