/** * @param $s|null $string * @param bool $throw [optional] * @return mixed|bool|null * @throws Exception * Returns the value encoded in json in appropriate PHP type. * Values true, false and null are returned as TRUE, FALSE and NULL respectively. * NULL is returned if the json cannot be decoded * or if the encoded data is deeper than the recursion limit. * http://php.net/manual/function.json-decode.php */ function df_json_decode($s, $throw = true) { /** @var mixed|bool|null $result */ /** * 2015-12-19 * PHP 7.0.1 почему-то приводит к сбою при декодировании пустой строки: * «Decoding failed: Syntax error» */ if ('' === $s || is_null($s)) { $result = $s; } else { /** * 2016-10-30 * json_decode('7700000000000000000000000') возвращает 7.7E+24 * https://3v4l.org/NnUhk * http://stackoverflow.com/questions/28109419 * Такие длинные числоподобные строки используются как идентификаторы КЛАДР * (модулем доставки «Деловые Линии»), и поэтому их нельзя так корёжить. * Поэтому используем константу JSON_BIGINT_AS_STRING * https://3v4l.org/vvFaF */ $result = json_decode($s, true, 512, JSON_BIGINT_AS_STRING); /** * 2016-10-28 * json_encode(null) возвращает строку 'null', * а json_decode('null') возвращает null. * Добавил проверку для этой ситуации, чтобы не считать её сбоем. */ if (is_null($result) && 'null' !== $s && $throw) { df_assert_ne(JSON_ERROR_NONE, json_last_error()); df_error("Parsing a JSON document failed with the message «%s».\nThe document:\n{$s}", json_last_error_msg()); } } return $result; }
/** * 2015-11-19 * @override * @see \Df\Framework\Form\Element\Fieldset::onFormInitialized() * @used-by \Df\Framework\Plugin\Data\Form\Element\AbstractElement::afterSetForm() * @return void */ public function onFormInitialized() { parent::onFormInitialized(); $this->addClass('df-array'); // 2015-12-29 // Невидимая строка-шаблон. df_hide($this->field('template', $this->itemFormElement())); /** @var int $itemId */ $itemId = 0; foreach ($this->v() as $key => $data) { /** @var string|int $key */ /** @var string|array(string => mixed) $data */ /** * 2016-07-30 * Раньше тут стоял код: // 2015-12-30 // https://github.com/mage2pro/core/tree/b1f6809b7723d8426636bb892b852f408bdc5650/Framework/view/adminhtml/web/formElement/array/main.js#L131 if (\Df\Config\A::FAKE !== $key) { $this->field($itemId++, $this->itemType(), null, $data); } * Теперь у нас ключ @see \Df\Config\A::FAKE удаляется в методе * @see \Df\Config\Backend\ArrayT::processA() * поэтому здесь его уже быть не должно. */ df_assert_ne(\Df\Config\A::FAKE, $key); $this->field($itemId++, $this->itemFormElement(), null, $data); } df_fe_init($this, __CLASS__, df_fa(), [], 'array'); }
/** @return string */ private function context() { if (!isset($this->{__METHOD__})) { /** @var string $result */ $result = ''; if (is_file($this->filePath()) && $this->line()) { /** @var string[] $fileContents */ $fileContents = file($this->filePath()); if (is_array($fileContents)) { /** * Перенос строки здесь не нужен, * потому что строки с кодом * уже содержат переносы на следующую стоку * http://php.net/manual/function.file.php */ /** @var int $fileLength */ $fileLength = count($fileContents); /** @var int $radius */ $radius = 8; /** @var int $start */ $start = max(0, $this->line() - $radius); /** @var int $end */ $end = min($fileLength, $start + 2 * $radius); // 2016-07-31 // Нам нужна информация именно функции next (caller). if ($this->_next) { /** @var RFA|null $func */ $func = $this->_next->functionA(); /** * 2016-07-31 * Если @uses \ReflectionFunctionAbstract::isInternal() вернёт true, * то @uses \ReflectionFunctionAbstract::getStartLine() и * @uses \ReflectionFunctionAbstract::getEndLine() вернут false. * http://stackoverflow.com/questions/2222142#comment25428181_2222404 * isInternal() === TRUE means ->getFileName() and ->getStartLine() will return FALSE */ if ($func && !$func->isInternal()) { /** @var int|false $fStart */ $fStart = $func->getStartLine(); df_assert_ne(false, $fStart); /** @var int|false $fEnd */ $fEnd = $func->getEndLine(); df_assert_ne(false, $fEnd); // 2016-07-31 // http://stackoverflow.com/a/7027198 // It's actually - 1, otherwise you wont get the function() block. $start = max($start, $fStart - 1); $end = min($end, $fEnd); } } $result = df_trim(implode(array_slice($fileContents, $start, $end - $start)), $charlist = "\r\n"); } } $this->{__METHOD__} = $result; } return $this->{__METHOD__}; }
/** * Возвращает неиспользуемое имя файла в заданной папке $directory по заданному шаблону $template. * Результатом всегда является непустая строка. * @param string $directory * @param string $template * @param string $ds [optional] * @return string */ function df_file_name($directory, $template, $ds = '-') { // 2016-11-09 // Отныне $template может содержать файловый путь: // в этом случае этот файловый путь убираем из $template и добавляем к $directory. $directory = df_path_n($directory); $template = df_path_n($template); if (df_contains($template, '/')) { /** @var string $templateA */ $templateA = explode('/', $template); $template = array_pop($templateA); $directory = df_cc_path($directory, $templateA); } /** @var string $result */ /** @var int $counter */ $counter = 1; /** @var bool $hasOrderingPosition */ $hasOrderingPosition = df_contains($template, '{ordering}'); /** @var \Zend_Date $now */ $now = \Zend_Date::now()->setTimezone('Europe/Moscow'); /** @var array(string => string) */ $vars = df_map_k(function ($k, $v) use($ds, $now) { return df_dts($now, implode($ds, $v)); }, ['date' => ['y', 'MM', 'dd'], 'time' => ['HH', 'mm'], 'time-full' => ['HH', 'mm', 'ss']]); /** * 2016-11-09 * @see \Zend_Date неправильно работает с миллисекундами: * всегда возвращает 0 вместо реального количества миллисекунд. * Так происходит из-за дефекта в методах * @see \Zend_Date::addMilliSecond() * @see \Zend_Date::setMilliSecond() * Там такой код: list($milli, $time) = explode(" ", microtime()); $milli = intval($milli); * https://github.com/OpenMage/magento-mirror/blob/1.9.3.0/lib/Zend/Date.php#L4490-L4491 * Этот код ошибочен, потому что после первой операции * $milli содержит дробное значение меньше 1, например: 0.653... * А вторая операция тупо делает из этого значения 0. */ $vars['time-full-ms'] = implode($ds, [$vars['time-full'], sprintf('%02d', round(100 * df_first(explode(' ', microtime()))))]); while (true) { /** @var string $fileName */ $fileName = df_var($template, ['ordering' => sprintf('%03d', $counter)] + $vars); /** @var string $fileFullPath */ $fileFullPath = $directory . DS . $fileName; if (!file_exists($fileFullPath)) { /** * Раньше здесь стояло file_put_contents, * и иногда почему-то возникал сбой: * failed to open stream: No such file or directory. * Может быть, такой сбой возникает, если папка не существует? */ $result = $fileFullPath; break; } else { if ($counter > 999) { df_error("Счётчик достиг предела ({$counter})."); } else { $counter++; /** * Если в шаблоне имени файла * нет переменной «{ordering}» — значит, надо добавить её, * чтобы в следующей интерации имя файла стало уникальным. * Вставляем «{ordering}» непосредственно перед расширением файла. * Например, rm.shipping.log преобразуем в rm.shipping-{ordering}.log */ if (!$hasOrderingPosition && 2 === $counter) { /** @var string[] $fileNameTemplateExploded */ $fileNameTemplateExploded = explode('.', $template); /** @var int $secondFromLastPartIndex*/ $secondFromLastPartIndex = max(0, count($fileNameTemplateExploded) - 2); /** @var string $secondFromLastPart */ $secondFromLastPart = dfa($fileNameTemplateExploded, $secondFromLastPartIndex); df_assert_string_not_empty($secondFromLastPart); $fileNameTemplateExploded[$secondFromLastPartIndex] = implode('--', [$secondFromLastPart, '{ordering}']); /** @var string $newFileNameTemplate */ $newFileNameTemplate = implode('.', $fileNameTemplateExploded); df_assert_ne($template, $newFileNameTemplate); $template = $newFileNameTemplate; } } } } return df_path_n($result); }
/** * 2016-08-31 * @return string */ private function _p() { /** @var string $result */ /** * Обратите внимание, что метод ядра Magento CE * @see \Magento\Framework\Simplexml\Element::asNiceXml() * не сохраняет в документе XML блоки CDATA, * а вместо этого заменяет недопустимые для XML символы их допустимыми кодами, * например: & => & * * Также @see \Magento\Framework\Simplexml\Element::asNiceXml() * не добавляет к документу заголовок XML: его надо добавить вручную. * * 2015-02-27 * Обратите внимание, что для конвертации объекта класса @see SimpleXMLElement в строку * надо использовать именно метод @uses SimpleXMLElement::asXML(), * а не @see SimpleXMLElement::__toString() или оператор (string)$this. * * @see SimpleXMLElement::__toString() и (string)$this * возвращают непустую строку только для концевых узлов (листьев дерева XML). * Пример: <?xml version='1.0' encoding='utf-8'?> <menu> <product> <cms> <class>aaa</class> <weight>1</weight> </cms> <test> <class>bbb</class> <weight>2</weight> </test> </product> </menu> * Здесь для $e1 = $xml->{'product'}->{'cms'}->{'class'} * мы можем использовать $e1->__toString() и (string)$e1. * http://3v4l.org/rAq3F * Однако для $e2 = $xml->{'product'}->{'cms'} * мы не можем использовать $e2->__toString() и (string)$e2, * потому что узел «cms» не является концевым узлом (листом дерева XML). * http://3v4l.org/Pkj37 * Более того, метод @see SimpleXMLElement::__toString() * отсутствует в PHP версий 5.2.17 и ниже: * http://3v4l.org/Wiia2#v500 */ /** @var string $header */ $header = $this[self::P__SKIP_HEADER] ? '' : df_xml_header($this[self::P__1251] ? 'Windows-1251' : 'UTF-8'); /** @var X $x */ $x = df_xml_parse(df_cc_n($header, $this[self::P__DOC_TYPE], sprintf('<%s/>', $this[self::$P__TAG]))); $x->addAttributes($this[self::P__ATTRIBUTES]); $x->importArray($this[self::$P__CONTENTS], $this[self::P__WRAP_IN_CDATA]); /** @var bool $pretty */ $pretty = $this[self::P__PRETTY]; $result = $this[self::P__SKIP_HEADER] ? $x->asXMLPart() : ($pretty || $this[self::P__1251] ? df_cc_n($header, $pretty ? $x->asNiceXml() : $x->asXMLPart()) : $x->asXML()); // Убеждаемся, что asXML вернуло строку, а не false. df_assert_ne(false, $result); /** * Символ 0xB (вертикальная табуляция) допустим в UTF-8, но недопустим в XML: * http://stackoverflow.com/a/10095901 */ $result = str_replace("\v", "", $result); if ($this[self::P__1251]) { $result = df_1251_to($result); } if ($this[self::P__REMOVE_LINE_BREAKS]) { $result = df_t()->removeLineBreaks($result); } if ($this[self::P__DECODE_ENTITIES]) { $result = html_entity_decode($result, ENT_NOQUOTES, 'UTF-8'); } return $result; }