Пример #1
0
/**
 * @param int $levelsToSkip
 * Позволяет при записи стека вызовов пропустить несколько последних вызовов функций,
 * которые и так очевидны (например, вызов данной функции, вызов df_bt() и т.п.)
 * @return void
 */
function df_bt($levelsToSkip = 0)
{
    /** @var array $bt */
    $bt = array_slice(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), $levelsToSkip);
    /** @var array $compactBT */
    $compactBT = [];
    /** @var int $traceLength */
    $traceLength = count($bt);
    /**
     * 2015-07-23
     * 1) Удаляем часть файлового пути до корневой папки Magento.
     * 2) Заменяем разделитель папок на унифицированный.
     */
    /** @var string $bp */
    $bp = BP . DS;
    /** @var bool $nonStandardDS */
    $nonStandardDS = DS !== '/';
    for ($traceIndex = 0; $traceIndex < $traceLength; $traceIndex++) {
        /** @var array $currentState */
        $currentState = dfa($bt, $traceIndex);
        /** @var array(string => string) $nextState */
        $nextState = dfa($bt, 1 + $traceIndex, []);
        /** @var string $file */
        $file = str_replace($bp, '', dfa($currentState, 'file'));
        if ($nonStandardDS) {
            $file = df_path_n($file);
        }
        $compactBT[] = ['File' => $file, 'Line' => dfa($currentState, 'line'), 'Caller' => !$nextState ? '' : df_cc_method($nextState), 'Callee' => !$currentState ? '' : df_cc_method($currentState)];
    }
    df_report('bt-{date}-{time}.log', print_r($compactBT, true));
}
Пример #2
0
/**
 * 2016-01-29
 * @param AE|E $e
 * @param string|null $key [optional]
 * @param string|null|callable $default [optional]
 * @return string|null|array(string => mixed)
 */
function df_fe_fc(AE $e, $key = null, $default = null)
{
    /** @var array(string => mixed) $result */
    $result = df_fe_top($e)->getFieldConfig();
    df_assert_array($result);
    return $key ? dfa($result, $key, $default) : $result;
}
Пример #3
0
/**
 * Создаёт объект-дату по строке вида «20131115153657».
 * @param string $timestamp
 * @param string|null $offsetType [optional]
 * @return ZD
 */
function df_date_from_timestamp_14($timestamp, $offsetType = null)
{
    df_assert(ctype_digit($timestamp));
    df_assert_eq(14, strlen($timestamp));
    // Почему-то new Zend_Date($timestamp, 'yMMddHHmmss') у меня не работает
    /** @var string $pattern */
    $pattern = '#(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})#';
    /** @var int[] $matches */
    $matches = [];
    /** @var int $r */
    $r = preg_match($pattern, $timestamp, $matches);
    df_assert_eq(1, $r);
    /** @var int $hour */
    $hour = df_nat0(dfa($matches, 4));
    if ($offsetType) {
        df_assert_in($offsetType, ['UTC', 'GMT']);
        /** @var int $offsetFromGMT */
        $offsetFromGMT = df_round(df_int(df_dts(ZD::now(), ZD::TIMEZONE_SECS)) / 3600);
        $hour += $offsetFromGMT;
        if ('UTC' === $offsetType) {
            $hour++;
        }
    }
    return new ZD(['year' => dfa($matches, 1), 'month' => dfa($matches, 2), 'day' => dfa($matches, 3), 'hour' => $hour, 'minute' => dfa($matches, 5), 'second' => dfa($matches, 6)]);
}
Пример #4
0
 /**
  * @param int $amount
  * @param array $forms
  * @return string
  */
 public function getForm($amount, array $forms)
 {
     df_param_integer($amount, 0);
     /** @var string $result */
     $result = dfa($forms, $this->getIndex($amount));
     df_result_string($result);
     return $result;
 }
Пример #5
0
 /**
  * 2016-08-02
  * @param string $tabName
  * @param string $tabProperty
  * @return string|null
  */
 public static function tab($tabName, $tabProperty)
 {
     /** @var Structure $s */
     $s = df_config_structure();
     if (!isset($s->_data['tabs'])) {
         $s->getTabs();
     }
     return dfa(dfa($s->_data['tabs'], $tabName, []), $tabProperty);
 }
Пример #6
0
 /**
  * 2015-11-29
  * @param string $name
  * @return Variant
  * @throws \Exception
  */
 public function variant($name)
 {
     /** @var Variant|null $result */
     $result = dfa($this->variants(), $name);
     if (!$result) {
         throw new \Exception("Variant «{$name}» of font «{$this->family()}» is not found.");
     }
     return $result;
 }
Пример #7
0
 /**
  * 2015-11-14
  * Цель плагина — алфавитное упорядочивание моих модулей
  * в разделе административных настроек модулей.
  * @see \Magento\Config\Model\Config\Structure\Element\Iterator\Tab::setElements()
  * @param Sb $sb
  * @param array(string => array(string => string)) $elements
  * @param string $scope
  * @return array()
  */
 public function beforeSetElements(Sb $sb, array $elements, $scope)
 {
     /** @var array(string => string)|null $sections */
     $sections = dfa_deep($elements, '_df/children');
     if ($sections) {
         uasort($sections, function ($a, $b) {
             return strcasecmp(dfa($a, 'label'), dfa($b, 'label'));
         });
         $elements['_df']['children'] = $sections;
     }
     return [$elements, $scope];
 }
Пример #8
0
 /**
  * 2015-12-30
  * @param string|null $key [optional]
  * @return ArrayItem|array(string => ArrayItem)|null
  */
 public function get($key = null)
 {
     if (!isset($this->{__METHOD__})) {
         /** @var string $class */
         $class = $this[self::$P__ITEM_CLASS];
         $this->{__METHOD__} = df_index(function (ArrayItem $o) {
             return $o->getId();
         }, array_map(function ($data) use($class) {
             return new $class($data);
         }, $this->a()));
     }
     return is_null($key) ? $this->{__METHOD__} : dfa($this->{__METHOD__}, $key);
 }
Пример #9
0
 /**
  * 2016-05-13
  * Наша проблема заключается в том, что Magento передаёт флаг $isMultiselect = true
  * только для элементов типа multiselect:
  * How is the isMultiselect parameter passed
  * to the toOptionArray method of @see \Magento\Framework\Data\OptionSourceInterface?
  * https://mage2.pro/t/1613
  * Наш же элемент управления имеет другой тип: type='Df\Framework\Form\Element\Multiselect'
  * https://code.dmitry-fedyuk.com/m2e/stripe/blob/b105882/etc/adminhtml/system.xml#L250
  * Получается, что флаг $isMultiselect имеет значение false,
  * и тогда метод @see \Magento\Directory\Model\Config\Source\Country::toOptionArray()
  * и другие аналогичные методы добавляют фэйковую опцию «--Please Select--».
  * Нам она не нужна, поэтому удаляем её здесь.
  *
  * @override
  * @see \Magento\Framework\DataObject::__call()
  * @used-by \Magento\Config\Block\System\Config\Form::_initElement()
  * https://github.com/magento/magento2/blob/ffea3cd/app/code/Magento/Config/Block/System/Config/Form.php#L375-L377
  * How are the options set to a select/multiselect form element? https://mage2.pro/t/1615
  * How is @see \Magento\Config\Model\Config\Structure\Element\Field::getOptions()
  * implemented and used? https://mage2.pro/t/1616
  * @param array $values
  */
 public function setValues(array $values)
 {
     /** @var array(string => string)|null $first */
     $first = df_first($values);
     /**
      * 2016-05-13
      * @see \Magento\Directory\Model\Config\Source\Country::toOptionArray()
      * https://github.com/magento/magento2/blob/ffea3cd/app/code/Magento/Directory/Model/Config/Source/Country.php#L51-L51
      */
     if ($first && (string) __('--Please Select--') === (string) dfa($first, 'label')) {
         array_shift($values);
     }
     $this['values'] = $values;
 }
Пример #10
0
 /**
  * 2016-08-03
  * Начиная с Magento 2.1.0 backend model создаётся только если данные присутствуют в базе данных
  * для конкретной области действия настроек (scope и scopeId).
  * https://github.com/magento/magento2/blob/2.1.0/app/code/Magento/Config/Block/System/Config/Form.php#L309-L327
  * Если данные отсутстствуют в БД для конкретной области действия настроек,
  * то backend model вообще не создаётся,
  * однако данные всё равно извлекаются из БД из общей области действия настроек:
  * https://github.com/magento/magento2/blob/2.1.0/app/code/Magento/Config/Block/System/Config/Form.php#L323-L327
  * Видимо, такое поведение дефектно: данные могут попасть в форму
  * в обход обработки и валидации их в backend model.
  *
  * Ранее (до версии 2.1.0) backend model создавалась в любом случае:
  * такое поведение я считаю более верным:
  * https://github.com/magento/magento2/blob/2.0.8/app/code/Magento/Config/Block/System/Config/Form.php#L330-L342
  *
  * В плагин мы попадаем отсюда: @see \Magento\Config\Block\System\Config\Form::_initElement()
  * https://github.com/magento/magento2/blob/2.1.0/app/code/Magento/Config/Block/System/Config/Form.php#L347-L367
  *
  * @see \Magento\Framework\Data\Form\Element\Fieldset::addField()
  * @param Sb|El $sb
  * @param string $elementId
  * @param string $type
  * @param array(string => mixed) $config
  * @param bool $after [optional]
  * @param bool $isAdvanced [optional]
  * @return array(string|bool|array(string => mixed))
  */
 public function beforeAddField(Sb $sb, $elementId, $type, array $config, $after = false, $isAdvanced = false)
 {
     /** @var array(string => mixed)|null $fc */
     $fc = dfa($config, 'field_config');
     /**
      * 2016-09-27
      * Модуль Unirgy Dropship ошибочно пихает в $fc объект класса stdClass вместо массива:
      * https://code.dmitry-fedyuk.com/m2e/stripe/issues/5
      */
     if ($fc && is_array($fc)) {
         /** @var string|null $path */
         $path = df_cc_path(dfa($fc, 'path'), dfa($fc, 'id'));
         /** @var string|null $backendC */
         $backendC = dfa($fc, 'backend_model');
         /**
          * 2016-08-03
          * Конкретное значение тега «type» из system.xml можно получить вызовом dfa($fc, 'type')
          * Однако нам это не нужно: достаточно использовать аргумент $type:
          * @see \Magento\Config\Model\Config\Structure\Element\Field::getType()
          */
         /** @var mixed|null $value */
         $value = dfa($config, 'value');
         if ($path && $backendC && !B::isProcessed($path) && is_a($type, El::class, true) && !is_null($value)) {
             /**
              * 2016-08-03
              * По аналогии с @see \Magento\Config\Block\System\Config\Form::_initElement()
              * https://github.com/magento/magento2/blob/2.1.0/app/code/Magento/Config/Block/System/Config/Form.php#L314-L320
              */
             /** @var B $b */
             $b = df_create($backendC);
             $b->setPath($path);
             $b->setValue($value);
             /**
              * 2016-08-03
              * По аналогии с @see \Magento\Config\Block\System\Config\Form::getWebsiteCode()
              */
             $b->setWebsite(df_request('website', ''));
             /**
              * 2016-08-03
              * По аналогии с @see \Magento\Config\Block\System\Config\Form::getStoreCode()
              */
             $b->setStore(df_request('store', ''));
             $b->afterLoad();
             $config['value'] = $b->getValue();
         }
     }
     return [$elementId, $type, $config, $after, $isAdvanced];
 }
Пример #11
0
/**
* 2015-12-14
* Добавил возможность передачи в качестве первого параметра @see O
* причём как в виде объекта, так и строки-класса.
*
* Такая возможность позволяет нам эффективно рендерить шаблоны без иерархии своих классов-блоков.
* В Российской сборке для Magento 1.x
* нам приходилось дублировать один и тот же код в классе базовой модели (аналоге класса O),
* и в 2-х базовых классах блоков (абстрактном и блоке с шаблоном), т.е. в 3 местах.
* Теперь же нам этого делать не нужно.
*
* @used-by df_phtml()
* @param string|O|null $type
* @param string|array(string => mixed) $data [optional]
* @param string|null $template [optional]
*
* 2016-11-22
* @param array $vars [optional]
* Параметры $vars будут доступны в шаблоне в качестве переменных:
* @see \Magento\Framework\View\TemplateEngine\Php::render()
		extract($dictionary, EXTR_SKIP);
* https://github.com/magento/magento2/blob/2.1.2/lib/internal/Magento/Framework/View/TemplateEngine/Php.php#L58
*
* @return AbstractBlock|BlockInterface|Template
*/
function df_block($type, $data = [], $template = null, array $vars = [])
{
    /**
     * 2015-12-14
     * $type может быть как объектом, так и строкой:
     * https://3v4l.org/udMMH
     */
    /** @var O $context */
    if (!is_a($type, O::class, true)) {
        $context = null;
    } else {
        $context = is_object($type) ? $type : new $type();
        $type = null;
    }
    if (is_null($type)) {
        $type = df_is_backend() ? BackendTemplate::class : Template::class;
    }
    /** @var string|null $template */
    if (is_string($data)) {
        $template = $data;
        $data = [];
    }
    /** @var AbstractBlock|BlockInterface|Template $result */
    /**
     * 2016-11-22
     * В отличие от Magento 1.x, в Magento 2 нам нужен синтаксис ['data' => $data]:
     * @see \Magento\Framework\View\Layout\Generator\Block::createBlock():
     * $block->addData(isset($arguments['data']) ? $arguments['data'] : []);
     * https://github.com/magento/magento2/blob/2.1.2/lib/internal/Magento/Framework/View/Layout/Generator/Block.php#L240
     * В Magento 1.x было не так:
     * https://github.com/OpenMage/magento-mirror/blob/1.9.3.1/app/code/core/Mage/Core/Model/Layout.php#L482-L491
     */
    $result = df_layout()->createBlock($type, dfa($data, 'name'), ['data' => $data]);
    // 2016-11-22
    $result->assign($vars);
    if ($template && $result instanceof Template) {
        $result->setTemplate(df_append($template, '.phtml'));
    }
    if ($context) {
        // 2016-11-22
        // «Sets the object that should represent $block in template.»
        $result->setTemplateContext($context);
    }
    return $result;
}
Пример #12
0
 /**
  * @used-by \Df\Qa\Method::raiseErrorParam()
  * @param int $paramOrdering  		zero-based
  * @return \ReflectionParameter
  */
 public function methodParameter($paramOrdering)
 {
     df_param_integer($paramOrdering, 0);
     if (!isset($this->{__METHOD__}[$paramOrdering])) {
         // Метод должен существовать
         df_assert($this->method());
         // Параметр должен существовать
         if ($paramOrdering >= count($this->method()->getParameters())) {
             df_error("Программист ошибочно пытается получить значение параметра с индексом {$paramOrdering}" . " метода «{$this->methodName()}», хотя этот метод принимает всего %d параметров.", count($this->method()->getParameters()));
         }
         df_assert_lt(count($this->method()->getParameters()), $paramOrdering);
         /** @var \ReflectionParameter $result */
         $result = dfa($this->method()->getParameters(), $paramOrdering);
         df_assert($result instanceof \ReflectionParameter);
         $this->{__METHOD__}[$paramOrdering] = $result;
     }
     return $this->{__METHOD__}[$paramOrdering];
 }
Пример #13
0
 /**
  * Sets validator options
  * Accepts the following option keys:
  *   'min' => scalar, minimum border
  *   'max' => scalar, maximum border
  *   'inclusive' => boolean, inclusive border values
  * @override
  * @param array|\Zend_Config $options
  */
 public function __construct(array $options)
 {
     /**
      * Спецификация конструктора класса Zend_Validate_Between
      * различается между Zend Framework 1.9.6 (Magento 1.4.0.1)
      * и Zend Framework 1.11.1 (Magento 1.5.0.1).
      *
      * Именно для устранения для пользователя данных различий
      * служит наш класс-посредник \Df\Zf\Validate\Between
      */
     if (version_compare(\Zend_Version::VERSION, '1.10', '>=')) {
         /** @noinspection PhpParamsInspection */
         parent::__construct($options);
     } else {
         /** @noinspection PhpParamsInspection */
         parent::__construct(dfa($options, 'min'), dfa($options, 'max'), dfa($options, 'inclusive'));
     }
 }
Пример #14
0
 /**
  * @param int|string $index
  * @param string|array(array(string => int|string|mixed[])) $option
  * @return string
  */
 private function renderOption($index, $option)
 {
     /** @var string $result */
     if (!is_array($option)) {
         // опция имеет формат array('RU' => 'Россия')
         $result = $this->renderOptionTag($index, $option);
     } else {
         /** @var int|string|array(string => string)|array(array(string => string|array(string => string))) $value */
         $value = dfa($option, 'value');
         /** @var string $label */
         $label = dfa($option, 'label');
         if (!is_array($value)) {
             // опция имеет формат array('label' => 'Россия', 'value' => 'RU')
             $result = $this->renderOptionTag($value, $label);
         } else {
             // опция имеет формат array('label' => 'группа опций', 'value' => array(...))
             $result = df_tag('optgroup', ['label' => $label], $this->implodeTags($this->renderOptions($value)));
         }
     }
     return $result;
 }
Пример #15
0
 /**
  * 2016-07-30
  * @override
  * @see \Df\Framework\Form\Element\Text::onFormInitialized()
  * @used-by \Df\Framework\Plugin\Data\Form\Element\AbstractElement::afterSetForm()
  * @return void
  */
 public function onFormInitialized()
 {
     parent::onFormInitialized();
     $this->addClass('df-quantity');
     /** @var string|null|Phrase $title */
     $title = $this->getTitle();
     $this->unsTitle();
     /** @var Text|E $input */
     $input = $this->text('value', $this->getLabel(), ['title' => $title]);
     $this->unsLabel();
     /** @var array(int|string => string)|string $values */
     $values = dfa($this->_data, self::P__VALUES, []);
     if (is_string($values)) {
         $values = [$values];
     }
     $this->unsetData(self::P__VALUES);
     if (1 < count($values)) {
         $this->select('units', null, $values, ['title' => $title]);
     } else {
         $input->setAfterElementHtml(df_first($values));
     }
     df_fe_init($this, __CLASS__);
 }
Пример #16
0
 /**
  * 2016-08-09
  * @used-by \Dfe\AllPay\Block\Info\BankCard::prepareDic()
  * @param string $nameToFind
  * @param string $name
  * @param string|Phrase $value
  * @param int $weight [optional]
  */
 public function addAfter($nameToFind, $name, $value, $weight = 0)
 {
     /** @var Entry|null $itemToFind */
     $itemToFind = dfa($this->_items, $nameToFind);
     $this->add($name, $value, !$itemToFind ? 0 : 1 + $itemToFind->weight());
 }
Пример #17
0
/**      
 * 2016-05-20
 * Возвращает 2-буквенный код страны по стандарту ISO 3166-1 alpha-2
 * по названию страны для заданной локали (или системной локали по умолчанию)
 * https://ru.wikipedia.org/wiki/ISO_3166-1
 * @param string $name
 * @param string|null $locale [optional]
 * @return string|null
 */
function df_country_ntc($name, $locale = null)
{
    df_param_string_not_empty($name, 0);
    return dfa(df_countries_ntc($locale), mb_strtoupper(df_trim($name)));
}
Пример #18
0
 /**
  * @param string[] $matches
  * @return string
  */
 private static function nl2brCallback(array $matches)
 {
     return str_replace('{rm-newline}', '{rm-newline-preserve}', dfa($matches, 0, ''));
 }
Пример #19
0
 /**
  * 2015-12-16
  * @return string
  */
 private function variant()
 {
     if (!isset($this->{__METHOD__})) {
         $this->{__METHOD__} = dfa($this->familyA(), 1, '');
     }
     return $this->{__METHOD__};
 }
Пример #20
0
 /**
  * @param string $name
  * @return Entity[]
  */
 public function findByNameAll($name)
 {
     $this->getItems();
     /** @noinspection PhpParamsInspection */
     return df_nta(dfa($this->_mapFromNameToEntity, $name));
 }
Пример #21
0
 /**
  * @param int $errorCode
  * @return string|null
  */
 private function translateErrorCode($errorCode)
 {
     return dfa(self::getErrorCodeMap(), $errorCode);
 }
Пример #22
0
/**
 * 2016-09-05
 * @param int|string $value
 * @param array(int|string => mixed) $map
 * @return int|string|mixed
 */
function dftr($value, array $map)
{
    return dfa($map, $value, $value);
}
Пример #23
0
 /**
  * 2015-08-10
  * В случае отсутствия значения в кэше возвращаем не null, а false
  * ради согласованности с долгосрочным кэшем.
  * @param string $key
  * @return mixed|bool
  */
 public function ramGet($key)
 {
     return dfa($this->_ram, $key, false);
 }
Пример #24
0
 /**
  * 2016-05-19
  * Родительский метод зачем-то делает цикл про элементам коллекции.
  * А мы, по сути, берём реализацию из @see \Magento\Framework\Data\Collection::getItemById()
  * @override
  * @see \Magento\Directory\Model\ResourceModel\Country\Collection::getItemById()
  * @param string $idValue
  * @return Country|null
  */
 public function getItemById($idValue)
 {
     $this->load();
     return dfa($this->_items, $idValue);
 }
Пример #25
0
 /**
  * @param resource $image
  * @param int[] $rgba
  * @return int
  */
 protected function colorAllocateAlpha($image, array $rgba)
 {
     /** @var int|bool $result */
     $result = imagecolorallocatealpha($image, $rgba[0], $rgba[1], $rgba[2], dfa($rgba, 3, 0));
     df_assert(false !== $result);
     return $result;
 }
Пример #26
0
 /**
  * @param $number
  * @param string $gender
  * @return string
  */
 private static function getNum1E9($number, $gender)
 {
     /** @var array(int => string) $words */
     static $words = ['миллион', 'миллиона', 'миллионов'];
     return $number < 1000000.0 ? self::getNum1E6($number, $gender) : df_cc_s(self::getNum1000((int) ($number / 1000000.0), self::GENDER__FEMALE), dfa($words, self::getNum125((int) ($number / 1000000.0))), self::getNum1E6($number % 1000000.0, $gender));
 }
Пример #27
0
/**
 * @param string $resource
 * @return \Magento\Framework\View\Asset\File
 */
function df_asset_create($resource)
{
    return !df_starts_with($resource, 'http') && !df_starts_with($resource, '//') ? df_asset()->createAsset($resource) : df_asset()->createRemoteAsset($resource, dfa(['css' => 'text/css', 'js' => 'application/javascript'], df_file_ext($resource)));
}
Пример #28
0
 /**
  * 2016-07-30
  * Синтаксис вызова таков: self::fdCssClass($data, 'df-fe-money');
  * В настоящее время нигде не используется.
  * @param array(string => mixed) $data
  * @param string $class
  * @return void
  */
 private static function fdCssClass(&$data, $class)
 {
     $data[self::$FD__CSS_CLASS] = df_cc_s(dfa($data, self::$FD__CSS_CLASS), $class);
 }
Пример #29
0
 /**
  * @param string $key
  * @return string|null
  */
 private function r($key)
 {
     return dfa($this->responseA(), $key);
 }
Пример #30
0
/**
 * 2016-07-13
 * @param T $t
 * @param string|null $key [optional]
 * @param mixed|null $default [optional]
 * @return array(string => mixed)|mixed
 */
function df_trans_raw_details(T $t, $key = null, $default = null)
{
    /** @var array(string => mixed)|mixed $result */
    $result = $t->getAdditionalInformation(T::RAW_DETAILS);
    return null === $key ? $result : dfa($result, $key, $default);
}