/** * @used-by df_notify_exception() * @used-by \Df\Qa\Message_Failure_Error::check() * @return void * @throws \Exception */ public final function log() { /** * 2015-04-04 * Нам нужно правильно обработать ситуацию, * когда при формировании диагностического отчёта о сбое происходит новый сбой. * 1) Статическая переменная $inProcess предотвращает нас от бесконечной рекурсии. * 2) try... catch позволяет нам перехватить внутренний сбой, * сформировать диагностическое сообщение о нём, * а затем перевозбудить его снова, чтобы вывести на экран. * Обратите внимание, что внутренний сбой не будет виден на экране при асинхронном запросе * (много таких запросов делает, например, страница оформления заказа), * поэтому try... catch с целью записи отчёта крайне важно: * без этого при сбое асинхроноого запроса диагностичекское сообщение о сбое * окажется утраченным. */ static $inProcess; if (!$inProcess) { $inProcess = true; try { df_report($this->reportName(), $this->report()); $inProcess = false; } catch (\Exception $e) { df_log(df_ets($e)); throw $e; } } }
/** * 2015-04-05 * Оборачиваем код в try..catch, * чтобы не утратить сообщение о внутреннем сбое при асинхронном запросе. * @used-by \Df\Core\Boot::init() * @return void */ public static function check() { try { if (error_get_last() && self::isFatal()) { self::i()->log(); } } catch (\Exception $e) { df_log(df_ets($e)); } }
/** * 2016-07-18 * 2016-10-24 * Сообщение для покупателя функция возвращает, * а сообщение для администратора — логирует. * @param \Exception|Exception $e * @return string */ function message(\Exception $e) { /** @var bool $isSpecific */ $isSpecific = $e instanceof Exception; if (!$isSpecific) { $e = df_ef($e); } df_log($e); /** @var string $mc */ /** @var string $md */ list($mc, $md) = $isSpecific ? [$e->messageC(), df_tag_if($e->messageD(), $e->isMessageHtml(), 'pre')] : [dfp_error_message(), df_etsd($e)]; return !$this->ss()->test() ? $mc : df_cc_br($mc, __('Debug message:'), $md); }
/** * 2015-12-01 * Изначально реализация была «ленивой»: $this->exists() ? df_media_url($this->path()) : df_url_frontend('df-api/google/fontPreview', ['_query' => [ 'family' => implode(':', [$this->family(), $this->variant()->name()]) ] + $this->params()->getData()]) * Однако оказалось, что она крайне неэффективна: * в клиентской части мы создаём много тегов IMG, и при добавлении в DOM * браузер сразу делает кучу запросов к серверу по адресу src. * Получается, что намного эффективнее сразу построить все картинки в едином запросе. * * Но df-api/google/fontPreview нам всё равно пригодится для динамических запросов! * * @return string */ public function url() { if (!isset($this->{__METHOD__})) { try { $this->createIfNeeded(); $this->{__METHOD__} = df_media_url($this->path()); } catch (\Exception $e) { df_log($e->getMessage()); $this->{__METHOD__} = ''; } } return $this->{__METHOD__}; }
/** * 2015-12-07 * Конечно, хотелось бы задействовать стандартные методы * @see \Magento\Framework\Model\AbstractModel::beforeSave() и * @see \Magento\Framework\Model\AbstractModel::afterSave() * или же * @see \Magento\Framework\Model\ResourceModel\Db\AbstractDb::_beforeSave() и * @see \Magento\Framework\Model\ResourceModel\Db\AbstractDb::_afterSave() * или же * @see \Magento\Framework\Model\ResourceModel\Db\AbstractDb::_serializeFields() и * @see \Magento\Framework\Model\ResourceModel\Db\AbstractDb::unserializeFields() * однако меня смутило, что в случае исключительной ситуации * модель может остаться в несогласованном состоянии: * https://mage2.pro/t/283 * https://mage2.pro/t/284 * Поэтому разработал свои аналогичные методы. * * @override * @see \Magento\Framework\App\Config\Value::save() * @return $this * @throws \Exception */ public function save() { try { $this->dfSaveBefore(); parent::save(); } catch (\Exception $e) { df_log($e); throw df_le($e); } finally { $this->dfSaveAfter(); } return $this; }
/** * @param array(string => string) $attributes * @return $this */ public function addAttributes(array $attributes) { foreach ($attributes as $name => $value) { /** @var string $name */ /** @var mixed $value */ df_assert_string($name); // убрал strval($value) для ускорения системы if (is_object($value) || is_array($value)) { df_log($attributes); df_error('Значение поля «%s» должно быть строкой, однако является %s.', $name, is_object($value) ? sprintf('объектом класса %s', get_class($value)) : 'массивом'); } $this->addAttribute($name, $value); } return $this; }
/** * @used-by \Df\Qa\Message_Failure::traceS() * @override * @return string */ public function __toString() { if (!isset($this->{__METHOD__})) { /** * Метод @see __toString() не имеет права возбуждать исключительных ситуаций. * Fatal error: Method __toString() must not throw an exception * http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring */ try { /** @var string[] $resultA */ /** @uses param() */ $resultA = array_filter(array_map([__CLASS__, 'param'], [['File', str_replace(DIRECTORY_SEPARATOR, '/', df_trim_text_left($this->filePath(), BP . DIRECTORY_SEPARATOR))], ['Line', $this->line()], ['Caller', !$this->_next ? '' : $this->_next->methodName()], ['Callee', $this->methodName()]])); if ($this[self::$P__SHOW_CONTEXT] && $this->context()) { $resultA[] = self::param(['Context', "\n" . $this->context()]); } $this->{__METHOD__} = df_cc_n($resultA); } catch (\Exception $e) { df_log(df_ets($e)); $this->{__METHOD__} = df_ets($e); } } return $this->{__METHOD__}; }
/** * 2015-12-08 * @return array(string => int[]) */ private function datumPoints() { if (!$this->_datumPoints) { if (file_exists($this->pathToDatumPoints())) { try { $this->_datumPoints = df_json_decode(df_media_read($this->pathToDatumPoints())); } catch (\Exception $e) { df_log($e->getMessage()); } } if (!$this->_datumPoints) { $this->create(); df_assert_array($this->_datumPoints); } } return $this->_datumPoints; }
/** * 2016-07-04 * @override * @return Result */ public function handle() { /** @var Result $result */ try { $this->handleBefore(); dfp_report($this, $this->getData()); $this->validate(); $this->addTransaction(); /** * 2016-07-14 * Если покупатель не смог или не захотел оплатить заказ, * то мы заказ отменяем, а затем, когда платёжная система возврат покупателя в магазин, * то мы проверим, не отменён ли последний заказ, * и если он отменён — то восстановим корзину покупателя. */ if (!$this->isSuccessful()) { $this->order()->cancel(); } else { if ($this->needCapture()) { $this->capture(); } } $this->order()->save(); /** * 2016-08-17 * https://code.dmitry-fedyuk.com/m2e/allpay/issues/17 * Письмо отсылаем только если isSuccessful() вернуло true * (при этом не факт, что оплата уже прошла: при оффлайновом способе оплаты * isSuccessful() говорит лишь о том, что покупатель успешно выбрал оффлайновый способ оплаты, * а подтверждение платежа придёт лишь потом, через несколько дней). */ if ($this->isSuccessful()) { $this->sendEmail(); } $result = $this->resultSuccess(); df_log('OK'); } catch (\Exception $e) { /** * 2016-07-15 * Раньше тут стояло if ($this->_order) { $this->_order->cancel(); $this->_order->save(); } * На самом деле, исключительная ситуация свидетельствует о сбое в программе, * либо о некорректном запросе якобы от платёжного сервера (хакерской попытке, например), * поэтому отменять заказ тут неразумно. * В случае сбоя платёжная система будет присылать * повторные оповещения — вот пусть и присылает, * авось мы к тому времени уже починим программу, если поломка была на нашей строне */ $result = static::resultError($e); df_log('FAILURE'); df_log($e); } return $result; }
/** * 2016-07-30 * @used-by \Df\Config\Backend\Serialized::valueSerialize() * @used-by \Df\Config\Backend\Serialized::valueUnserialize() * @param array(string => mixed) $result * @return array(string => mixed) * @throws \Exception */ private function processA(array $result) { try { $result = $this->processI($result); } catch (\Exception $e) { /** * 2016-08-02 * Если некорректость данных обнаружена при их сохранении, * то там удобнее возбудить исключительную ситуацию, * чтобы администратор магазина увидел диагностическое сообщение на экране. * Далее администратор может скорректировать данные посредством интерфейса. * * Если же некорректость данных обнаружена при их загрузке, * то это значит, что некорректные данные находятся в базе данных, * и администратор всё равно не сможет скорректировать их посредством интерфейса. * Поэтому вместо возбуждения исключительной ситуации просто сбрасываем данные. * * Некорректость данных при их загрузке возможна, например, * если поменялся формат данных в ещё разрабатываемом модуле: * тогда нам вместо конквертации данных проще их сбросить, * чтобы не сопровождать код по такой конвертации, * который с релизом модуля больше никогда не понадобится. */ if ($this->isSaving()) { throw $e; } $result = []; //df_cfg_delete($this->getPath()); //df_cfg_save($this->getPath(), null, ); df_log($e); df_message_error(__("The store's database contains incorrect data for the «<b>%1</b>» option." . "<br/>The data for this options are reset.", $this->label())); } return $result; }