Підступна війна росії проти України. Орієнтовні втрати ворога
(станом на 15.03.2024)
428420
осіб
347
літаків
325
гелікоптерів
6758
танків
12949
ББМ
10580
артилерія
717
ППО
1017
РСЗВ
13993
машин
26
кораблі і катери
Magento для PHP MVC розробників – Особлива конфігурація системи (ч.7/11)
Опубліковано Оновлено: 05.01.2018

Magento для PHP MVC розробників – Особлива конфігурація системи (ч.7/11)

Однією з найбільш потужних частин Magento є адмінський розділ Конфігурації системи. Вам, як розробникам, потрібно знати, як тут все влаштовано та як воно робиться.

Як і багато речей у Magento, спочатку це може відлякувати, але як тільки ви спробуєте це, вам сподобається вся потужність системи. Тож, давайте розпочнемо.

Ми створимо модуль, який ми вже створювали в статті Розбір Контролера, хоча будь-якого порожнього модуля повинно бути достатньо.

 

Нижче представлено частину великої серії статей, орієнтовану на Мадженто розробників, що знайомі з PHP MVC. Хоча кожна стаття може бути прочитана окремо, кожна з них спирається на поняття та код, описаний у попередніх статтях. Якщо ви збилися з пантелику, для початку перегляньте попередні статті.

 

 

Додавання файлу конфігурації системи

Перше, що нам потрібно зробити – додати в модуль файл системної конфігурації. Цей файл йде окремо від config.xml і його можна знайти в наступному місці:

app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

 

Подібно до глобальної конфігурації, інформація про конфігурацію системи зберігається окремо. Якщо вам потрібно переглянути файл конфігурації системи в якості власного об’єкту, виконайте наступний код з будь-якого екшена контролера:

 

//header('Content-Type: text/xml');
header('Content-Type: text/plain');
echo $config = Mage::getConfig()
->loadModulesConfiguration('system.xml')
->getNode()
->asXML();
exit;

 

Метод loadModulesConfiguration буде оглядати кожну теку etc в кожному включеному модулі в пошуках файлу з вказаною назвою (в даному випадку, system.xml). Magento має ряд інших конфігураційних файлів (api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml), і як розробник модулів ви можете використати цю функцію для створення власного файлу.

 

 

Додавання нової вкладки

Перше, що ми збираємось зробити – це додати власну “вкладку” до конфігурації системи. Вкладки – це заголовки навігації в лівому меню адмінки System -> Configuration (Система -> Конфігурація). Вкладки за замовчуванням такі: Загальне, Каталог, Клієнти, Продажі, Сервіси та Розширені.

 

Створимо нову вкладку з назвою “Hello Config“. Створіть новий файл конфігурації системи та додайте наступне:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

<config>
  <tabs>
    <helloconfig translate="label" module="helloworld">
     <label>Hello Config</label>
     <sort_order>99999</sort_order>
    </helloconfig>
  </tabs>
</config>

 

Тут потрібно зробити кілька пояснень. Назва вузла <helloconfig/> є довільною, але має бути унікальною серед вкладок. Вона буде служити ідентифікатором вашої вкладки, яку ми використаємо пізніше в конфігурації.

Атрибут module="helloworld" визначає, якому модулю ця вкладка “належить”, <label> визначає ім’я, яке буде використовуватися для вкладки, а <sort_order> визначає, як відображається вкладка по відношенню до інших вкладок у лівому меню.

 

Після цього перейдіть до розділу Система -> Конфігурація. І одна з двох подій повинна відбутися:

  1. Сторінка буде завантажуватися, але без вашої нової вкладки
  2. Ви отримаєте помилку типу:
    Fatal error: Class 'Mage_Helloworld_Helper_Data' not found in

 

 

Короткий огляд Хелпер класів

Як і в інших популярних PHP MVC-системах, у Magento також є Helper класи, які використовуються для різних завдань, що не застосовні до Model, View або Controller. Хелпер клас – це один із прикладів абстрактних групових імен класів, що означає, що користувачі системи можуть перевизначати класи за замовчуванням, і розробникам модулів потрібно додавати відповідний розділ до файлів config.xml, щоб вказувати ім’я базового класу для Хелперів.

Більшість коду в системі Magento передбачає, що модуль має дефолтний Хелпер клас. Якщо ви отримали вищезгадане виключення, це пов’язано з тим, що ваш модуль Helloworld не має цього Хелпер класу, але система намагалася його використати. Тож, давайте додамо його зараз.

По-перше, нам потрібно додати розділ до основного файлу config.xml модуля (НЕ системної конфігурації):

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml

<!-- ... -->
<global>
<!-- ... -->
  <helpers>
    <helloworld>
       <class>Alanstormdotcom_Helloworld_Helper</class>
    </helloworld>
  </helpers>
<!-- ... -->
</global>
<!-- ... -->

 

Якщо ви вже налаштовували конфігурацію Magento, цей запис повинен бути вам зрозумілим. Тег <helloworld/> слід іменувати назвою модуля, а тег <class/> повинен містити базову назву всіх Helper класів, яка іменується відповідно до стандартної конвенції Magento:

Packagename_Modulename_Helper

 

Хелпери завантажуються статичним методом helper глобального об’єкта Mage. Наступний виклик (припускаючи, що вищевказаний конфігураційний файл наявний):

Mage::helper('helloworld/foo');

 

буде завантажувати наступний клас:

app/code/local/Alanstormdotcom/Helloworld/Helper/Foo.php

class Alanstormdotcom_Helloworld_Helper_Foo

 

Magento також має поняття Хелпера за замовчуванням для модуля. Якщо ви вказуєте клас Хелпера лише з ім’ям модуля:

Mage::helper('helloworld');

 

він буде шукати дані Хелпера, що знаходяться в:

app/code/local/Alanstormdotcom/Helloworld/Helper/Data.php

class Alanstormdotcom_Helloworld_Helper_Data ...

 

Це означає, що наступні два виклики еквівалентні:

Mage::helper('helloworld');
Mage::helper('helloworld/data');

 

Нарешті, нам потрібно додати актуальний Helper клас. Додайте наступний файл, і все запрацює:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/Helper/Data.php

class Alanstormdotcom_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract {

}

 

Після цього виконайте очистку кешу та перезавантажте сторінку адміністратора системи. Повідомлення про помилку повинно зникнути, але нова вкладка так і не з’явиться.

Примітка. Якщо вас цікавить те, що може дати вам метод helper, перевірте клас Mage_Core_Helper_Abstract для огляду списку корисних методів, що матимуть усі Хелпери.

 

 

Додавання нової секції

Реалізація Хелпера не підійшла, тож нашим наступним кроком буде з’ясування того, чому налаштована вкладка не відображається. Кожна вкладка має ряд секцій. Наприклад, вкладка Розширені має (за замовчуванням) такі секції: “Адміністратор”, “Система”, “Розширені” та “Розробник”.

Якщо вкладка налаштована без секцій, вона не буде відображатись. Отже, виправимо помилку, додавши вузол <sections/> до файлу системної конфігурації:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

<config>
  <tabs>
    <helloconfig translate="label" module="helloworld">
      <label>Hello Config</label>
      <sort_order>99999</sort_order>
    </helloconfig>
  </tabs>
  <sections>
    <helloworld_options translate="label" module="helloworld">
      <label>Hello World Config Options</label>
      <tab>helloconfig</tab>
      <frontend_type>text</frontend_type>
      <sort_order>1000</sort_order>
      <show_in_default>1</show_in_default>
      <show_in_website>1</show_in_website>
      <show_in_store>1</show_in_store>
    </helloworld_options>
  </sections>
</config>

 

У цій новій частині конфігурації є кілька знайомих вузлів, а також кілька нових.

 

Що таке <helloworld_options/>?

Цей тег подібний до тегу <helloconfig/>, що визначений вище. Він за допомогою довільного імені визначає опції нового розділу (секції).

 

Що таке <label/>?

Тег label визначає відображення значення, яке використовується в інтерфейсі HTML для нового розділу (тобто, це заголовок секції).

 

Що таке <tab/>?

Цей тег визначає, в яку вкладку повинен бути згрупований нижче новий розділ. Ми хочемо, щоб наш розділ відображався під новою вкладкою helloconfig. Назва helloconfig походить від тегу, який використовується для створення вкладки (<helloconfig/>)

 

Що таке <frontend_type/>?

Це досить складний тег. <frontend_type/> має значення в інших розділах конфігурації (див. нижче), але, здається, тут він нічого не робить. Однак, секції в Core модулях використовують цей тег, тому найкраще буде слідувати за конвенцією, навіть якщо ви не знаєте, що вона практично робить.

 

Що таке <sort_order/>?

Знову ж таки, <sort_order/> визначає розподіл вертикального відображення секцій в меню, порівняно з іншими секціями вкладки.

 

Що таке <show_in_default/>, <show_in_website/>, <show_in_store/>?

Це булеві параметри конфігурації, зі значенням або 1, або 0. Вони визначають рівень відображення конфігурації цього розділу для різних меж адміністрування.

 

Налаштувавши цей розділ, давайте знову перейдемо до System -> Config (Система -> Конфігурація). Тепер ви повинні побачити свій розділ і вкладку в нижній частині лівого меню. Ви можете додати інші розділи, додавши до вузла <sections/> додаткові вузли.

 

 

Контроль доступу

Якщо ви натиснете на посилання нової секції, ви будете розчаровані результатами. Буде завантажена порожня сторінка адміністратора, а меню зліва повністю зникне. Це відбувається тому, що додаток Adminhtml не може знайти запис для нової секції у Списку Контролю Доступу (ACL).

 

ACL – це досить широка тема, але тут я намагатимусь пояснити достатньо для перших кроків. Є певні ресурси, які вимагають, щоб користувач був автентифікований перед їх використанням. Ресурс тут – це абстрагований термін. Це може бути сторінка адміністратора, або це може бути доступ до певної функції. Група розробників Magento вирішила, що розділи System Config повинні мати захист ACL.

 

Ресурси визначаються через URI. Наприклад, розділ “веб-конфігурація” (web) (на вкладці “Загальні”) визначається URI:

admin/system/config/web

 

тоді наша секція helloworld_options матиме наступне URI:

admin/system/config/helloworld_options

 

Додаток для Адміністрування (часто називається adminhtml) побудований з використанням того ж фреймворку, що й додаток для Магазину (додаток для Магазину часто називається додатком frontend). У контролері дій Adminhml, коли користувачеві потрібно отримати доступ до ресурсу, захищеного ACL, розробник Adminhtml повинен:

  1. Визначити URI для будь-якого ресурсу, до якого користувач намагається отримати доступ
  2. Перевірити, чи вказане це URI в системі ACL, яка визначатиме, чи має залогінений користувач право доступу до цього конкретного ресурсу
  3. Якщо користувач має правильні права доступу, продовжити виконання додатку. Якщо не має – відхилити виконання, або зробити щось подібне (наприклад, зупинити відображення меню та контенту)

 

Для тих, хто цікавиться цим більше, ця процедура робиться для розділів System Config за допомогою методу _isSectionAllowed у наступному контролері:

app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php

 

Якщо ви перейдете до Система -> Дозволи -> Ролі та натиснете кнопку «Додати нову роль», ви зможете побачити графічне представлення дерева всіх ресурсів ролі, визначеної у поточній інсталяції Magento.

 

 

Додавання ролі ACL

Ми повинні визначити ресурс ACL для нашого нового розділу. Вам потрібно робити це лише, якщо ви додаєте новий розділ. Якщо ви додаєте параметри налаштування до існуючого розділу, вам не потрібно втручатися в ACL.

 

У конфігураційному файлі модуля config.xml додайте наступний розділ:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml

<config>
<!-- ... -->
  <adminhtml>
   <acl>
    <resources>
     <admin>
      <children>
       <system>
        <children>
         <config>
          <children>
           <helloworld_options>
            <title>Store Hello World Module Section</title>
           </helloworld_options>
          </children>
         </config>
        </children>
       </system>
      </children>
     </admin>
    </resources>
   </acl>
  </adminhtml>
<!-- ... -->
</config>

 

Так, тут досить багато коду. Давайте розіб’ємо його на складові. По-перше, всі визначені ресурси містяться в наступній структурі вузла:

 

<adminhtml>
  <acl>
    <resources>
    </resources>
  </acl>
</adminhtml>

 

Усередині ресурсу (<resources>) кожен низхідний вузол представляє собою частину URI. Отже, нижче йде:

<admin>
 <children>
  <system>
   <children>

 

що дає нам URI:

admin/system

 

Якщо ви уважно стежите за уроком, ви не проґавите вузол для нашої конфігурації:

<helloworld_options>
  <title>Store Hello World Module Section</title>
</helloworld_options>

 

Тег title – це той заголовок, який відображатиметься на сторінці адміністрування дозволів.

 

Додавши цей код у конфігурацію та очистивши кеш, вам слід переглянути розділ налаштувань. Можливо для цього вам доведеться вийти з адмінки та потім повторно залогінитись. Адже розділ Адміністратора має своє додаткове кешування на додачу до стандартного кешу Magento.

Перейдіть до свого нового розділу і ви побачите порожню сторінку конфігурації під назвою “Hello World Config Options”.

 

 

Додавання груп

Отже, у нас тепер є порожній розділ конфігурації. Нашим наступним кроком є додавання групи.

Групи використовуються для групування різних варіантів конфігурації, і вони відображаються в адміністративній частині за допомогою вкладки, що розкривається. Наприклад, у початковій інсталяції розділ Розширені має одну групу під назвою “Вимкнути вивід модулів”.

Створимо групу під назвою “messages”, додавши вузол <groups/> у нашу конфігурацію, що вкладена в вузол <sections>:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

<config>
  <tabs>
   <helloconfig translate="label" module="helloworld">
    <label>Hello Config</label>
    <sort_order>99999</sort_order>
   </helloconfig>
  </tabs>
  <sections>
   <helloworld_options translate="label" module="helloworld">
    <label>Hello World Config Options</label>
    <tab>helloconfig</tab>
    <frontend_type>text</frontend_type>
    <sort_order>1000</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>1</show_in_store>
    <groups>
     <messages translate="label">
      <label>Demo Of Config Fields</label>
      <frontend_type>text</frontend_type>
      <sort_order>1</sort_order>
      <show_in_default>1</show_in_default>
      <show_in_website>1</show_in_website>
      <show_in_store>1</show_in_store>
     </messages>
    </groups>
   </helloworld_options>
  </sections>
</config>

 

Кожен тег у цьому вузлі аналогічний тегам з вузла верхнього рівня <sections/>.

 

Якщо ви перезавантажите сторінку, повинна з’явитись порожня вкладка, що розкривається, з назвою “Demo Of Config Fields”.

 

 

Додавання полів конфігурації

Нарешті, нам потрібно додати окремі поля налаштувань. Ви можете зробите це, додавши у вузол <messages/> вузол <fields/>. Почнемо з текстового поля “hello_message”:

 

<!-- ... -->
<messages translate="label">
 <label>Demo Of Config Fields</label>
 <frontend_type>text</frontend_type>
 <sort_order>1</sort_order>
 <show_in_default>1</show_in_default>
 <show_in_website>1</show_in_website>
 <show_in_store>1</show_in_store>
 <fields>
  <hello_message>
   <label>Message</label>
   <frontend_type>text</frontend_type>
   <sort_order>1</sort_order>
   <show_in_default>1</show_in_default>
   <show_in_website>1</show_in_website>
   <show_in_store>1</show_in_store>
  </hello_message>
 </fields>
</messages>
<!-- ... -->

 

Знову ж таки, поля у новому вузлі <hello_message> аналогічні іншим вузлам, які ми додавали до цих пір. Однак на цей раз <frontend_type>text</frontend_type> дійсно робить корисну річ, вказуючи системі, який елемент форми нам потрібен. Перезавантажте сторінку, і тепер ви побачите окреме текстове поле в вікні налаштувань, що розгортається.

Коли вся ця інформація про конфігурацію записана, більше нічого не потрібно робити. Не потрібно ніякого коду для збереження/завантаження/оновлення значень налаштування. Система обробить це все самостійно.

 

Вас ніхто не обмежує лише текстовими полями. Тож, давайте додамо інше поле, яке називається <hello_time/>:

 

<!-- ...-->
<fields>
 <hello_message>
  <label>Message</label>
  <frontend_type>text</frontend_type>
  <sort_order>1</sort_order>
  <show_in_default>1</show_in_default>
  <show_in_website>1</show_in_website>
  <show_in_store>1</show_in_store>
 </hello_message>
 <hello_time>
  <label>Time to Say Hello</label>
  <frontend_type>time</frontend_type>
  <sort_order>1</sort_order>
  <show_in_default>1</show_in_default>
  <show_in_website>1</show_in_website>
  <show_in_store>1</show_in_store>
 </hello_time>
</fields>
<!-- ... -->

 

Зверніть увагу, що головна відмінність тут – це наступний тег:

<frontend_type>time</frontend_type>

 

Перезавантажте сторінку, і тепер у вас буде поле конфігурації для збереження значення часу.

Багато, але не всі з вбудованих в клас Varien форм даних (lib/Varien/Data/Form/Element) підтримуються. Тег <frontend_type/> виступає в якості ідентифікатора патерну. Давайте спробуємо змінити наше привітальне повідомлення на select (випадаючий список):

 

<!-- ... -->
<hello_message>
  <label>Message</label>
  <frontend_type>select</frontend_type>
  <sort_order>1</sort_order>
  <show_in_default>1</show_in_default>
  <show_in_website>1</show_in_website>
  <show_in_store>1</show_in_store>
</hello_message>
<!-- ... -->

 

Якщо ви після цього перезавантажите сторінку, то побачите, що у вас є випадаючий список HTML, але він не містить ніяких значень. Нам потрібно буде додати джерело Моделі для визначення нашого поля. Спробуйте такий код замість верхнього:

 

<hello_message>
  <label>Message</label>
  <frontend_type>select</frontend_type>
  <!-- додаємо ресурс Моделі -->
  <source_model>helloworld/words</source_model>
  <sort_order>1</sort_order>
  <show_in_default>1</show_in_default>
  <show_in_website>1</show_in_website>
  <show_in_store>1</show_in_store>
</hello_message>

 

Елемент <source_model> визначає URI для класу Моделі, яке ми використовуватимемо для надання значень за замовчуванням для випадаючого списку. Це означає, що ми повинні переконатися, що наш файл config.xml модуля має набір розділів Моделей:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml
<config>
 <!-- ... -->
 <global>
  <!-- ... -->
  <models>
  <!-- ... -->
   <helloworld>
     <class>Alanstormdotcom_Helloworld_Model</class>
   </helloworld>
  <!-- ... -->
  </models>
 </global>
</config>

 

Дивіться попередні статті серії, якщо ви не знаєте, що відбувається в цій конфігурації.

 

Отже, якщо ми додамо вищевказаний код та перезавантажимо нашу сторінку після очищення кешу, ми отримаємо помилку типу:

Warning: include(Alanstormdotcom/Helloworld/Model/Words.php)

 

Це сталося тому, що ми не визначили наш клас ресурсу Моделі. Давайте зробимо це зараз.

Примітка. Якщо в попередженні вказується шлях Mage/Helloworld/..., це означає, що ви неправильно налаштували розділ <models/> у файлі config.xml.

 

Щоб визначити наш ресурс Моделі, додайте наступний файл:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/Model/Words.php

class Alanstormdotcom_Helloworld_Model_Words {
  public function toOptionArray() {
   return array(
    array('value'=>1, 'label'=>Mage::helper('helloworld')->__('Hello')),
    array('value'=>2, 'label'=>Mage::helper('helloworld')->__('Goodbye')),
    array('value'=>3, 'label'=>Mage::helper('helloworld')->__('Yes')),
    array('value'=>4, 'label'=>Mage::helper('helloworld')->__('No')),
   );
  }
}

 

Ресурси Моделі – це класи, які реагують на метод під назвою toOptionsArray. Цей метод повинен повертати масив значень, які використовуються для заповнення значень за замовчуванням в наших елементах форми (які успадковуються від класу Varien_Data_Form_Element_Abstract). Для елемента випадаючого списку це означає визначення набору пари значення/заголовок. У наведеному вище прикладі ми передаємо наші заголовки через Хелпер метод перекладу (__). Хоча це і не є необхідним, використання такого коду завжди є гарною практикою. Адже ви ніколи не знаєте, на яку мову потрібно буде перекладати ваш модуль!

 

Перезавантажте сторінку, і у вас повинен бути робочий випадаючий список.

 

Для тих, хто цікавиться більш детально влаштуванням Magento, метод initFields в наступному класі – це те місце, де ресурс Моделі використовується для визначення значення поля:

app/code/core/Mage/Adminhtml/Block/System/Config/Form.php

 

 

Додавання полів до існуючих розділів/груп конфігурації

Окрім налаштування конфігурації власних вкладок та розділів, ви можете додати до існуючого розділу System Config поля за допомогою відповідних розділів у своєму власному файлі system.xml.

 

Наприклад, якщо ви додасте наступне:

 

Файл: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

<config>
 <!-- ... -->
 <sections>
  <!-- ... -->
  <general>
   <groups>
    <example>
     <label>Example of Adding a Group</label>
     <frontend_type>text</frontend_type>
     <sort_order>1</sort_order>
     <show_in_default>1</show_in_default>
     <show_in_website>1</show_in_website>
     <show_in_store>1</show_in_store>
    </example>
   </groups>
  </general>
  <!-- ... -->
 </section>
</config>

 

у вас буде нова група “Example of Adding a Group” в загальній вкладці (General).

 

 

Отримання значень

Ми розглянули процес налаштування форми для створення значень конфігурації. Щоб отримати значення у додатках і модулях, ми будемо використовувати метод getStoreConfig глобального об’єкта Mage. Наприклад, щоб отримати значення випадаючого списку, створеного вище, ми будемо використовувати:

Mage::getStoreConfig('helloworld_options/messages/hello_message');

 

Метод getStoreConfig приймає один параметр, який є URI у наступному форматі:

section_name/group_name/field_name

 

Ви також можете отримати масив всіх значень налаштування, вказавши частковий шлях:

Mage::getStoreConfig('helloworld_options/messages');
Mage::getStoreConfig('helloworld_options');

 

Нарешті, якщо вам потрібно отримати значення для магазину, який не використовується в поточній сесії, getStoreConfig приймає другий параметр, – ідентифікатор магазину

Mage::getStoreConfig('helloworld_options',1);

 

 

Підсумок статті

Ми розпочали цю статтю з розгляду встановлення окремих розділів у налаштуванні системи (System Config) і закінчили вивченням Хелпер класів, Списку контролю доступу (ACL) та ієрархії Varian Form. Окрім того, що ми розглянули вище, є можливість створення параметрів System Config, які використовують спеціальні frontend та backend Моделі. Це ми оглянемо в наступній статті.

 

 

 

Автор: Alan Storm (http://alanstorm.com/custom_magento_system_configuration/)

Переклад українською: SebWeo

 
 

Всі статті даної серії:

  1. Magento для PHP MVC розробників (Alan Storm) – ч.1/11
  2. Magento для PHP MVC розробників – розбір Контролера (ч.2/11)
  3. Magento для PHP MVC розробників – Макети, Блоки та Шаблони (ч.3/11)
  4. Magento для PHP MVC розробників – Моделі та основи ORM (ч.4/11)
  5. Magento для PHP MVC розробників – Інсталювання Ресурсу (ч.5/11)
  6. Magento для PHP MVC розробників – Розширений ORM – EAV (ч.6/11)
  7. Magento для PHP MVC розробників – Особлива конфігурація системи (ч.7/11)
  8. Magento для PHP MVC розробників – Поглиблене налаштування системи (ч.8/11)
  9. Magento для PHP MVC розробників – Колекції Varien Data (ч.9/11)
  10. Magento для PHP MVC розробників – Перевизначення і оновлюваність системи (ч.10/11)
  11. Magento для PHP MVC розробників – Конфігурація системи за замовчуванням (ч.11/11)

 

 

Напишіть тут свою думку/питання

Ваша пошта не публікуватиметься. Обов’язкові поля позначені *