<?xml version="1.0"?>
<rss version="2.0"><channel><title/><link>https://opencartforum.com/en/blogs/249-blog-sv2109/</link><description/><language>en</language><item><title>Python vs PHP &#x438;&#x43B;&#x438; Python &#x433;&#x43B;&#x430;&#x437;&#x430;&#x43C;&#x438; PHP &#x43F;&#x440;&#x43E;&#x433;&#x440;&#x430;&#x43C;&#x43C;&#x438;&#x441;&#x442;&#x430;</title><link>https://opencartforum.com/blogs/entry/520-python-vs-php-ili-python-glazami-php-programmista/</link><description><![CDATA[<p>
	В последнее время начал немного изучать <strong>Python</strong>.
</p>

<p>
	Это на сегодня очень популярный язык программирования, входит в тройку наиболее популярных языков и по количеству вопросов на разных сайтах типа стековерфолоу и по колличеству репозиториев на гитхабе.
</p>

<p>
	Или вот сравнение по гугл трендах
</p>

<p>
	<a href="https://trends.google.com/trends/explore?date=today%205-y&amp;geo=UA&amp;q=%2Fm%2F05z1_,PHP&amp;hl=ru" rel="external nofollow">https://trends.google.com/trends/explore?date=today 5-y&amp;geo=UA&amp;q=%2Fm%2F05z1_,PHP&amp;hl=ru</a>
</p>

<p>
	Или вот информация с сайта <strong>TIOBE</strong>, они для анализа используют очень много параметров:<br />
	<a href="https://www.tiobe.com/tiobe-index/" rel="external nofollow">https://www.tiobe.com/tiobe-index/</a>
</p>

<p>
	Согласно их данным Python сейчас занимает первую позицию в рейтинге, обограм даже C++, C, C# и Java, а PHP занимает 8 позицию (год назад была 9-тая, то есть за год немного даже подрос). За последние 15 лет Python взлетел из 7 позиции на 1-вую, а PHP медленно опустился с 5-той на 8-9. Вся информация по ссылке выше.
</p>

<p>
	 <br />
	<span style="font-size:18px;">Для чего используют Python:</span>
</p>

<ol>
	<li>
		для учебы. Если раньте школьников и студентов учили на паскале и бейсике которые вообще нигде не используются, то сейчас все дружно перешли на Python и это правильно, язык простой, живой, очень активно развивается и также активно используется. Наверное из-за этого и такой бурный рост языка, так как вчерашние студенты, которые выучили основы языка во время учебы потом начинают его использовать и в работе. 
	</li>
	<li>
		для различной автоматизации рабочих процессов. Например спарсить какой-то сайт, обработать пачку ексель документов, дернуть какую-то апишку и тысячи других не очень больших задач. На Python есть тысячи готовых библиотек с помощь которых можно делать что угодно от парсинга всего что только можно спарсить до распознавания лиц, синтеза речи и машинного обучения.
	</li>
	<li>
		для робототехники. Например можно взять какой-нибудь конструктор лего программируемый или плату типа Arduino, подключаем к ней какие-то датчики, моторчики, камеры итд. пишем на Python программу управления и вуаля получаем какую-то машинку на радиоуправлении, или квадрокоптер или сигнализацию для дома или кучу других интересных вещей, как я жалею что в годы моего детства такого не было))
	</li>
	<li>
		для обработки больших данных, дата саенс, машинного обучения, нейронных сетей итд. И тут Python вообще первый среди всех языков программирования, в нем есть огромное к-во библиотек для всего этого. Эти библиотеки часто используют часть кода на C++ для ресурсоемких задач. Часть аналогов есть на node.js, а на PHP практически ничего нету.
	</li>
	<li>
		для веба и создание API серверов. Есть там фреймворк Django, наверное самый популярный, и на нем много чего делают. Его плюс в том что к нему есть очень много модулей, но сам по себе он гм.. я немного посмотрел его возможности и это мне напомнило PHP фреймворки и микрофреймворки лет так 10-15 назад.. ну то есть все очень бедно по функционалу, если сравнить его с напр. ларавел то это просто небо и земля <img alt=":)" data-emoticon="" height="20" src="https://opencartforum.com/storage/smiles/emoticons/test_smile.png" srcset="https://opencartforum.com/storage/smiles/emoticons/smile@2x.png 2x" title=":)" width="20" /> Короче, мне сложно представить как на Python можно сделать что-то реально большое, скорее какие-то простые, небольшие сайты.<br />
		Есть фреймворк FastAPI очень популярный в последнее время, на нем делают разные api сервисы.
	</li>
	<li>
		 консольные программы
	</li>
	<li>
		игры, точнее больше или какие-то несложные 2D игры или какие-то части для больших игр по например обработке данных
	</li>
	<li>
		десктопные приложения
	</li>
	<li>
		программы для мобильных устройств.. но последние 2 пункта это как по мне скорее исключение, примерно как натягивание совы на глобус <img alt=":)" data-emoticon="" height="20" src="https://opencartforum.com/storage/smiles/emoticons/test_smile.png" srcset="https://opencartforum.com/storage/smiles/emoticons/smile@2x.png 2x" title=":)" width="20" /> так как для это есть специальные инструменты.
	</li>
	<li>
		его также майкрософт уже добавил в свой Excel, его также добавляют в браузер.. короче, скоро наверное вообще не останется ни одной области, где бы не было Python-а))
	</li>
</ol>

<p>
	 
</p>

<p>
	<span style="font-size:18px;">Плюсы Python</span>
</p>

<ol>
	<li>
		простота изучения, отлично подходит в качестве первого языка программирования, мне он очень напоминает как в студенческие годы изучал паскаль))
	</li>
	<li>
		огромное к-во библиотек на все случаи жизни
	</li>
	<li>
		огромное сообщество
	</li>
	<li>
		очень активно развивается
	</li>
	<li>
		в среде машинного обучения ему практически нету альтернативы
	</li>
	<li>
		много вакансий
	</li>
</ol>

<p>
	<br />
	<span style="font-size:18px;">Минусы Python</span>
</p>

<ol>
	<li>
		скорость, он как и все скриптовые языки достаточно медленный, причем тот же PHP последних версий 7,8 значительно обгоняет Python по скорости. Хотя, для тех задач для которых его используют скорости там вполне себе хватает.
	</li>
	<li>
		отсутствие хорошего ООП, тут нету ни нормальных приватных классов и методов, особенно протектед, здесь вообще нету интерфейсов, абстрактные классы реализованы как какой-то костыль через сторонний модуль итд. PHP версии 4! если не ошибаюсь был более функциональным в этом плане.
	</li>
	<li>
		рядом с очень классными библиотеками, написанными хорошими программистами, есть также множество говнокода и очень слабых программистов, так как пишут на Python вообще все кому не лень))
	</li>
</ol>

<p>
	<br />
	<span style="font-size:18px;">Немного сравнения синтаксиса Python и PHP</span>
</p>

<p>
	расширение файлов <strong>*.py</strong>
</p>

<p>
	не нужно открывать никаких тегов тира <strong>&lt;?php</strong> в PHP, открыли файл и пишете код
</p>

<p>
	каждый файл это модуль, можно подгрузить, импортировать не весь файл, а только какую-то его функцию или класс, напр
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="kwd">import</span><span class="pln"> random</span></pre>

<p>
	или
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="kwd">from</span><span class="pln"> random </span><span class="kwd">import</span><span class="pln"> randint</span></pre>

<p>
	нету <strong>$</strong> для переменных, <strong>;</strong> в конце каждой строки и <strong>{}</strong> для классов, функций, условий, циклов.. <strong>()</strong> для условий и циклов также не пишутся, вместо этого есть отступы!<br />
	не всем это нравится, но зато код стает очень понятным и написать код неправильно его отформатировав просто невозможно.
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="kwd">def</span><span class="pln"> my_func</span><span class="pun">(</span><span class="pln">x</span><span class="pun">):</span><span class="pln">
  </span><span class="com">#comment</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span></pre>

<p>
	<br />
	это функция, вместо function - <strong>def</strong>
</p>

<p>
	функция может возвращать не одно значение а несколько, например
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="kwd">return</span><span class="pln"> x</span><span class="pun">,</span><span class="pln">x</span><span class="pun">*</span><span class="lit">2</span><span class="pun">,</span><span class="pln">x</span><span class="pun">*</span><span class="lit">3</span></pre>

<p>
	и потом делаем
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">,</span><span class="pln">z </span><span class="pun">=</span><span class="pln"> my_func</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span></pre>

<p>
	нету оператора <strong>++</strong> вместо него просто пишут
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">x </span><span class="pun">+=</span><span class="lit">1</span></pre>

<p>
	Нету тернарного оператора
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">$x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span></pre>

<p>
	<br />
	вместо этого дают так:
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	вроде логически даже более правильно - 1 если истина иначе 0, но не привычно)
</p>

<p>
	<strong>True</strong> и <strong>False</strong> с большой буквы
</p>

<p>
	вместо NULL - <strong>None</strong>
</p>

<p>
	 
</p>

<p>
	В классах уже писал нету нормальных private, protected, interface, трейтов итд. А то, что есть скорее костыли какие-то. То есть по сути нету нормальной инкапсуляции. Скорее есть набор правил, которым должны следовать программисты, но при желании это все обходится и можно легко получить доступ к приватным переменным. Фанаты языка в один голос повторяют что Python это самый лучший язык, а раз там этого нету, значит там это и не нужно. До недавнего времени они тоже самое говорили и о динамической типизации, а потом (вроде с версии 3.6) в язык завезли типизацию (правда использовать ее не обязательно). Кстати, тоже самое буквально слово в слово можно услышать и от фанатов опенкарта)) <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr> - самый лучший, а раз там этого нету, значит оно тут и не надо)) Категорически с этим не согласен, так как наличие какого-то функционала не заставляет им пользоваться, но дает выбор, а отсутствие практически лишает вообще какого-либо выбора.
</p>

<p>
	 
</p>

<p>
	Но в тоже время классы в пайтоне имеют одну очень интересную особенность - там есть тьма магических методов (которые начинаются и заканчиваются на __), которые позволяют выполнять с этим классом почти все (или вообще все) возможные операции, разные +, -, сложение, деление, возведение в степень, сравнение, преобразование в число, строку, массив итд.<br />
	например создаете метод класса
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">__add__</span><span class="pun">()</span></pre>

<p>
	со своей логикой и можно делать
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">object3 </span><span class="pun">=</span><span class="pln"> object1</span><span class="pun">+</span><span class="pln">object2</span></pre>

<p>
	Классы также поддерживают множественное наследование, чего не поддерживает PHP, но PHP поддерживает множественную имплементацию интерфейсов и трейтов, чего нету в пайтоне.<br />
	В Python метод конструктора и деструктора это _<strong>_init__</strong> и <strong>__del__</strong> соответственно<br />
	<em>Наоборот:</em><br />
	В Python <strong>self</strong> указывает на объект класса (аналог $this в PHP), а в PHP на сам класс (для обращения к переменным класса и методам класса)<br />
	В Python есть понятие статического метода класса и метода класса. Первое это просто функция которая не имеет доступа к переменным класса, а второе - имеет, как раз второй вариант работает как статический метод в PHP.
</p>

<p>
	<br />
	Вместо одного массива array или [] как в PHP<br />
	есть аж 4 вида типа массивов:<br />
	<strong>list</strong> или список, обычный одномерные массив
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="str">"foo"</span><span class="pun">,</span><span class="str">"bar"</span><span class="pun">]</span></pre>

<p>
	<strong>tuple</strong> (кортеж) - очень похож на список, только его нельзя изменять. Через него сделаны возвраты нескольких значений из функции. Через него также можно легко поменять значения переменных местами, например
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">=</span><span class="pln">y</span><span class="pun">,</span><span class="pln">x</span></pre>

<p>
	и все) теперь в переменной x значение из y и наоборот.
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="str">"foo"</span><span class="pun">,</span><span class="str">"bar"</span><span class="pun">)</span></pre>

<p>
	<strong>set</strong> набор - имеет все элементы уникальные
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pun">{</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="str">"foo"</span><span class="pun">,</span><span class="str">"bar"</span><span class="pun">}</span></pre>

<p>
	<strong>dictionary</strong> - словарь, аналог ассотиативного массива в PHP
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pun">{</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">"foo"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"bar"</span><span class="pun">}</span></pre>

<p>
	есть срезы, очень удобная штука, например получить элементы массива с 1 по 3
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">new_list </span><span class="pun">=</span><span class="pln"> old_list</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:</span><span class="lit">3</span><span class="pun">]</span></pre>

<p>
	или перевернет все элементы, кто был первым станет последним итд.
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">seq</span><span class="pun">[::-</span><span class="lit">1</span><span class="pun">]</span></pre>

<p>
	тоже самое со строками, так как строка работает как список, можно делать срезы, использовать циклы перебора символов  итд.
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">string </span><span class="pun">=</span><span class="pln"> </span><span class="str">'строка'</span><span class="pln">
string</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="com"># 'тр'</span></pre>

<p>
	<br />
	или вот такая магия используется очень часто:
</p>

<pre class="ipsCode prettyprint prettyprinted"><span class="pln">squares </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">i </span><span class="pun">*</span><span class="pln"> i </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)]</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">squares</span><span class="pun">)</span><span class="pln">
</span><span class="com">#[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]</span></pre>

<p>
	<br />
	То есть в одну строку кода можно создать список, набор, словарь
</p>

<p>
	И достаточно много подобное магии
</p>

<p>
	 
</p>

<p>
	Если вкратце по синтаксису - все, если где ошибся то поправьте кто более знаком с этим языком или добавьте если есть что, так как я только начинаю его учить, вполне возможно что-то и упустил.
</p>

<p>
	 
</p>

<p>
	<span style="font-size:18px;">Нужно ли учить этот язык? Мне кажется - однозначно - да.</span>
</p>

<ol>
	<li>
		он простой, выучить его можно достаточно быстро, тем более что по пайтону есть просто куча бесплатных курсов, видео на ютубе итд.
	</li>
	<li>
		на нем интересно писать код, просто открываешь редактор и пишешь))
	</li>
	<li>
		он очень популярный и есть много вакансий
	</li>
	<li>
		тут огромное сообщество и тьма библиотек на все случаи жизни, это открывает большие возможности
	</li>
	<li>
		можно работать в области машинного обучение и нейронных сетей, а сейчас это вообще очень популярная область и Python тут похоже вне конкуренции, он завоевал тут почти все))
	</li>
	<li>
		очень полезно для общего развития
	</li>
	<li>
		очень полезно для резюме, даже если вы программист PHP то иметь в резюме Python как второй язык будет огромным плюсом для вас как для специалиста
	</li>
	<li>
		мне кажется, что очень хорошо подойдет для разработчиков <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>, тут нету сложных конструкций как в ларавел, тут простой код и синтаксис, ну почти как в самом опенкарте <img alt=":)" data-emoticon="" height="20" src="https://opencartforum.com/storage/smiles/emoticons/test_smile.png" srcset="https://opencartforum.com/storage/smiles/emoticons/smile@2x.png 2x" title=":)" width="20" /> <br />
		 
	</li>
</ol>
]]></description><guid isPermaLink="false">520</guid><pubDate>Fri, 08 Dec 2023 19:09:45 +0000</pubDate></item><item><title>S.O.L.I.D. &#x438; OpenCart</title><link>https://opencartforum.com/blogs/entry/519-solid-i-opencart/</link><description><![CDATA[<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">S.O.L.I.D.</strong> - это принципы программирования, которые сильно помогают при написании больших приложений, делая их более гибкими, расширяемыми, уменьшая при этом количество ошибок и конфликтов, а также время и деньги на поддержку и сопровождение этого приложения в будущем. </span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;">Принципы были описал еще в 2000 году Робертом Мартином, вы скорее всего слышали о его книгах, таких как "<em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">Чистый код</em>" и "<em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">Чистая архитектура</em>".<br />
	Эти принципы настолько важны, что многие работодатели даже указывают в вакансиях их знание как обязательное условие при устройстве на работу.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;">Попробую описать эти принципы своими словами, максимально просто и понятно.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;">Как можно было догадаться из названия - принципов всего 5 по первым буквам названия:<br />
	<strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">S</strong> - Single Responsibility Principle - Принцип единой ответственности<br />
	<strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">O</strong> - Open-closed Principle - Принцип открытости/закрытости<br />
	<strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">L</strong> - Liskov Substitution Principle - Принцип подстановки Барбары Лисков<br />
	<strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">I</strong> - Interface Segregation Principle - Принцип разделения интерфейсов<br />
	<strong style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">D</strong> - Dependency Inversion Principle - Принцип инверсии зависимостей</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><span style="border:0px;font-size:18px;padding:0px;vertical-align:baseline;">Single Responsibility Principle - Принцип единой ответственности</span><br />
	Достаточно простой, понятный но в тоже время очень важный, фундаментальный, принцип.<br />
	Он говорит о том, что любая программная сущность (класс, метод, функция итд.) должна иметь только одну ответственность, то есть решать только одну задачу. Правда Роберт Мартин изначально вкладывал в этот принцип немного другой смысл. <br />
	Этот принцип очень часто нарушается в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>, когда в контроллер добавляют все, что только можно - тут и валидация данных и создание ошибок, хлебных крошек, пагинации, картинок и вообще вся логика, так как в модели только получение данных из базы, а все остальное - в контроллере. Из-за этого мы получаем довольно распространенную ошибку MVC шаблона - очень большой контроллер, что является неправильным, контроллер должен быть очень простым и легким, его основная задача - получить запрос от пользователя (Request), передать его кому-то другому на обработку и результа вернуть назад пользователю (Response), но делать вообще всю работу он никак не должен.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><span style="border:0px;font-size:18px;padding:0px;vertical-align:baseline;">Open-closed Principle - Принцип открытости/закрытости</span><br />
	Еще один очень важные принцип, который также полностью нашурается опенкартом.<br />
	Он говорит о том, что программные сущности должны быть открыты для расширения и закрыты для изменения (модификации кода)<br />
	То есть, эти сущности должны иметь возможность расширить их функционал, но никак не через непосредственное изменение их кода, а через другие методы, например через наследование, интерфейсы, внедрение зависимостей, Events или в некоторых системах hooks, модули и плагины для CMS и так далее.<br />
	В <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> же по сути вообще вся система расширений построена на модификаторах (ocmod) или на изменении кода самого движка, то есть на полном нарушении этого принципа. </span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><span style="border:0px;font-size:18px;padding:0px;vertical-align:baseline;">Liskov Substitution Principle - Принцип подстановки Барбары Лисков</span><br />
	Он говорит о том, что если какая-то программная сущность работает с объектом класса родителя то она точно также без каких-либо изменений кода должна работать и со всеми потомками этого родителя. То есть, чтобы мы могли вместо класса родителя подставить класс любого его потомка и при этом наша программа работала точно также как и работала до этого. Это также улучшает расширяемость приложения и переплетается со вторым принципом - открытости/закрытости.<br />
	Как это достигается? Например через контроль всех возвращаемых данных методами классов, если метод родителя возвращает массив определенного формата то и все потомки должны точно также возвращать точно такой же формат массива. Или есть в родителе реализован какой-то метод то этот метод должен быть обязательно реализован и всеми потомками и так далее.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><span style="border:0px;font-size:18px;padding:0px;vertical-align:baseline;">Interface Segregation Principle - Принцип разделения интерфейсов</span><br />
	Он говорит о том, что если какой-то класс реализовывает интерфейс, то он должен реализовывать абсолютно все его методы, а не только какие-то из них.<br />
	Например, если нам нужно создать какой-то класс и мы видим, что у нас уже есть интерфейс, который очень похож на тот, который нам нужен, например там есть 10 методов из которых нам нужны 8, то использовать этот интерфейс для этого класса мы не можем, нужно разделить этот интерфейс на несколько более мелких и использовать именно то, что нам нужно (тем более что PHP поддерживает реализацию классом нескольких интерфейсов).<br />
	Иначе получится ситуация, когда какой-то наш метод работая с этим интерфейсом будет предполагать, что в любом классе, который его реализует обязательно должен быть реализован какой-то метод, но в одних классах он будет реализован, а в других будет например выбрасываться исключение и нам придется в нашей программе в куче мест писать кучу условий и держать в голове всю логику в каком классе какие методы есть а каких нету.. зачем? если сама идея интерфейсов и состоить в том, чтобы оградить нас от всех этих проблем.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;">К сожалению <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>, похоже, вообще не использует интерфейсы. Да, на весь движок из сотен файлов нету ни одного интерфейса, не считая сторонних библиотек. </span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	 
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<span style="color:#000000;"><span style="border:0px;font-size:18px;padding:0px;vertical-align:baseline;">Dependency Inversion Principle - Принцип инверсии зависимостей</span><br />
	Еще один крайне важный принцип, который отлично реализован в Laravel через сервис контейнеры.<br />
	Упрощенно он говорит о том, что все зависимости в приложении должны строится на базе интерфейсов, а не через конкретные реализации.<br />
	Объясню лучше на примере.<br />
	У нас есть больше приложение, которое сохраняет данные в базе данных. Для этого у нас есть класс <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">DB</em> и методы <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">select()</em> для получения данных из базы и <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">insert()</em> для сохранения. Все отлично работает, но в один момент нам (или заказчику) понадобилось реализовать сохранение данных в, например, файлах. И у нас даже есть готовый класс для этого <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">FileStorage</em> с методами <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">read()</em> и <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">write()</em> соответственно. Но беда в том, что нам теперь нужно переписать гору кода в десятках файлов чтобы заменить не только все названия методов но и их аргументы и возвращаемые значения.. А теперь представьте насколько было бы проще, если бы все было реализовано через интерфейсы и у нас был интерфейс <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">StorageInterface</em>, в котором бы были методы например <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">get()</em> и <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">set()</em> и везде в коде мы использует именно эти методы. Теперь, если нам нужно сохранять данные в базе, мы создаем класс <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">DB</em> который реализовывает наш интерфейс <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">StorageInterface</em> с определенными методами, а для файлов создаем другой класс, который реализовывает тот же самый интерфейс с теми же самыми методами. Если в будущем нам понадобиться работать с LLM и сохранять данные в какой-то векторной базе данных напр. Chroma или Pinecone, без проблем, мы просто реализуем новым классом <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">VectorStorage</em> наш интерфейс и без проблем сможет использовать этот класс в своем приложении и у нас ничего не поломается.<br />
	Мы сможем даже подключать разные классы работы с данными динамически в зависимости от условий, например в зависимости от переменных окружения, если мы в режиме разработки то использовать один класс данных, если в продакшене то другой, а если в режиме тестирования то какой-нибудь <em style="border:0px;font-size:inherit;padding:0px;vertical-align:baseline;">FakeStorage</em> и все будет замечательно работать без каких-либо изменений в коде.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<br />
	<span style="color:#000000;">Надеюсь, у меня получилось донести что такое принципы S.O.L.I.D., как они работают и почему так важно их использовать в работе.</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<br />
	<span style="color:#000000;">Плохо, что основной разработчик <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>, похоже, вообще ничего о них не слышал и поэтому у нас сейчас такой бардак в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>, который похоже никогда не закончится..</span>
</p>

<p style="background-color:#ffffff;border:0px;color:#656e7f;font-size:14px;padding:0px;vertical-align:baseline;">
	<br />
	<span style="color:#000000;">И <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> это как раз очень наглядный пример как незнание или игнорирования базовых принципов программирования при построении больших систем может со временем парализовать развитие всего проекта. </span>
</p>
]]></description><guid isPermaLink="false">519</guid><pubDate>Thu, 16 Nov 2023 13:41:08 +0000</pubDate></item><item><title>&#x421;&#x440;&#x430;&#x432;&#x43D;&#x435;&#x43D;&#x438;&#x435; &#x432;&#x43E;&#x437;&#x43C;&#x43E;&#x436;&#x43D;&#x43E;&#x441;&#x442;&#x435;&#x439; &#x444;&#x440;&#x435;&#x439;&#x43C;&#x432;&#x43E;&#x440;&#x43A;&#x43E;&#x432; OpenCart &#x438; Laravel.</title><link>https://opencartforum.com/blogs/entry/518-sravnenie-vozmozhnostey-freymvorkov-opencart-i-laravel/</link><description><![CDATA[<p>
	Название темы очень неоднозначное, так как многие могут сказать, что это совсем разные вещи, сравнивать которые не имеет смысла. Но многие разработчики <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> считают <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> именно фреймворком, некоторые даже пишут что это не просто фреймворк, а самый лучший фреймворк, на котором можно сделать сайт любой сложности.. Поэтому и решил сравнить именно функционал фреймворков.
</p>

<p>
	<span style="font-size:18px;">Почему Laravel</span>
</p>

<p>
	На сегодня это наверное самый популярный фреймворк на PHP. Он во много раз (и даже в десятки) популярнее самого <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>.<br />
	Для примера: <a href="https://trends.google.com.ua/trends/explore?date=today%205-y&amp;q=%2Fm%2F0jwy148,%2Fg%2F11b5m9hl85&amp;hl=uk" rel="external nofollow">https://trends.google.com.ua/trends/explore?date=today 5-y&amp;q=%2Fm%2F0jwy148,%2Fg%2F11b5m9hl85&amp;hl=uk</a><br />
	за последние 5 лет если популярность <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> упала больше как в 2 раза, то популярность Laravel наоборот выросла процентов на 30.<br />
	Это фреймворк на котором пишут всё - от всевозможных API, серверлесс решений, <em>SPA</em>, бэкенда для мобильных приложений, ботов для мессенджеров до больших и сложных сайтов, интернет магазинов и маркетплейсов.<br />
	Он простой, быстрый, функциональный, безопасный, что очень важно - очень активно поддерживается сообществом и развивается, совсем недавно вышла новая, 10 версия фреймворка, всего год назад - 9. Есть огромное количество бесплатных расширений, практически под любую задачу уже есть готовый пакет.<br />
	Он отлично работает как с обычными css библиотеками типа bootstrap так и с реактивными фреймворками типа <em>React</em> и <em>Vue</em>.
</p>

<p>
	Я недавно начал более серьезно изучать этот фреймворк, скорее в качестве спортивного интереса и расширения кругозора, так как в последнее время постоянно о нем слышу с очень разных источников.
</p>

<p>
	<strong>И был очень приятно удивлен его красотой, удобством и функционалом. </strong>А также насколько радикально он отличается от опенкарта в плане кода и работы с ним для программистов.<br />
	Тут автоматизировано почти все, что можно автоматизировать, многие действия делаются вообще в 1-2 строчки кода.
</p>

<p>
	Поэтому и решил написать данный пост, а заодно и немного сравнить функционал с <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> и даже показать примеры кода. 
</p>

<p>
	<span style="font-size:18px;">И так, некоторые возможности Laravel, которые больше всего понравились:</span>
</p>

<p>
	Тут в полном объеме раскрываются все возможности PHP - классы, интерфейсы, наследование, трейты, Enums, SOLID, шаблоны проектирования (фасады вообще везде, DI, Factory..) итд.<br />
	Работая с фреймворком реально начинаешь понимать всю красоту правильного подхода, когда в одну строчку кода можно изменить логику работы всего приложения если все спроектировано правильно. А не так как в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr>, когда чтобы поменять какую-то мелочь, нужно изменить сотни строк кода в десятках файлах, что и делается постоянно, достаточно посмотреть как в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr> сделана напр. пагинация или валидация форм или генерация ссылок или работа с базой..<br />
	Чтобы не быть голословным. Если прочитать формулировку 5 принципа SOLID - инверсии зависимостей, то там будет вот это:
</p>

<p>
	A. Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.<br />
	B. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.<br />
	Скорее всего, если вы читаете это впервые то  единственное что вы из этого поймете это то, что вы ничего не поняли))<br />
	В то же время когда начинаешь работать с Laravel то там достаточно часто методы получают в параметрах не какие-то конкретные объекты и следовательно зависят от конкретных реализаций этих объектов, а интерфейсы, то есть эти методы зависят именно от абстракций. Что это дает? В настройках Laravel можно указать какой конкретный класс нужно использовать для данного интерфейса, можно даже сделать это через условие, например в режиме разработки использовать один класс, который напр. не отсылает никуда данные а только пишет в лог, а в продакшене использовать другой.<br />
	При этом мы никак не изменяем логику самого метода, ему вообще без разницы какой объект ему передали, главное чтобы это был объект нужного интерфейса. И приложение получается очень гибким и без кучи ненужных условий, проверок и дублирования кода. Изменения делаются через изменение одной строчки кода и у нас уже все приложение работает по совсем другой логике.
</p>

<p>
	<span style="font-size:18px;">Консольные поманды</span>
</p>

<p>
	<strong>php artisan</strong> - скрипт с помощью которого можно создавать огромное к-ва кода и запускать типовые действия через 1 комманду.<br />
	Можно создавать контроллеры, модели, миграции, события, правила, ресурсы, реквесты, работать с базой данных, очередями, планировщиком, представлениями, окружение и многое другое.<br />
	Можно также создавать свои кастомные консольные комманды или изменять логику работы уже существующих.<br />
	То есть вам нужно что-то создать вы не пишете весь код вручную, вместо этого вводите 1 комманду в консоли напр.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted"><span class="pln">php artisan make:model ProductModel (+ различные параметры если нужно)</span></pre>

<p>
	<br />
	и создаете сразу новую модель для товара вместе с фабрикой, миграцией, сидом, ресурсным контроллеров (в котором уже будут созданы все необходимые методы для CRUD) а также отдельными классами реквестов.<br />
	Сколько времени это экономит? Особенно есть учесть что если писать столько кода вручную то полюбому где-то допустишь ошибку и потом еще потратить кучу времени чтобы понять почему оно не работает.<br />
	Плюс мы также получаем однотипную структуру для всех проектов, что значительно упрощает работу.
</p>

<p>
	<span style="font-size:18px;">Очень классно реализована работа с базой</span>
</p>

<p>
	Тут есть как отдельный билдер для создания запросов к базе и не нужно вручную писать кучу SQL запросов для кучи однотипных действий - получение, изменение, удаление записей в базе данных.<br />
	Тут конечно есть и <em>ORM</em>.<br />
	Вы просто создаете новую модель
</p>

<pre class="ipsCode">php artisan make:model ProductModel
</pre>

<p>
	Это будет практически пустой класс без единой строчки SQL кода, но в контроллере вы уже сможете полноценно работать с базой, например
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">$products </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Product</span><span class="pun">::</span><span class="pln">all</span><span class="pun">();</span></pre>

<p>
	получит все товары, можно также добавить различные условия, лимиты, сортировку, связи итд.<br />
	Мало того, что вы экономите кучу времени, так еще и все запросы к базе автоматически защищаются от всевозможных SQL инъекций и различных ошибок.
</p>

<p>
	Таблицы в базе данных создаются и изменяются с помощью миграций - специальный класс для изменения таблицы, с помощью которого можно как добавить изменения так и откатить их.<br />
	например миграция для таблицы постов:
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="typ">Schema</span><span class="pun">::</span><span class="pln">create</span><span class="pun">(</span><span class="str">'posts'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Blueprint</span><span class="pln"> $table</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="pln">id</span><span class="pun">();</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="kwd">string</span><span class="pun">(</span><span class="str">'title'</span><span class="pun">);</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="pln">text</span><span class="pun">(</span><span class="str">'content'</span><span class="pun">);</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="pln">unsignedBigInteger</span><span class="pun">(</span><span class="str">'category_id'</span><span class="pun">)-&gt;</span><span class="pln">nullable</span><span class="pun">();</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="pln">timestamps</span><span class="pun">();</span><span class="pln">
 
            $table</span><span class="pun">-&gt;</span><span class="pln">index</span><span class="pun">(</span><span class="str">'category_id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'post_category_idx'</span><span class="pun">);</span><span class="pln">
            $table</span><span class="pun">-&gt;</span><span class="pln">foreign</span><span class="pun">(</span><span class="str">'category_id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'post_category_fk'</span><span class="pun">)-&gt;</span><span class="pln">on</span><span class="pun">(</span><span class="str">'categories'</span><span class="pun">)-&gt;</span><span class="pln">references</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">);</span><span class="pln">
 
        </span><span class="pun">});</span></pre>

<p>
	<br />
	Можно использовать сиды - классы для заполнения таблиц какими-то данными.<br />
	Сиды можно реализовывать через фабрики - класс для автоматического создания записи, есть также класс Faker для создания фейковых данных для полей - текстовых, числовых, различных дат, кодов, картинок, телефонов,<br />
	емейлов итд. можно очень легко заполнить сайт тестовыми данными для тестирования, за пару секунд создать хоть 1000 постов с названием, описанием, картинкаим итд. Или кучу пользователей с емейлами, паролями итд.
</p>

<p>
	То есть как происходит стандартная работа - вы копируете какой-то проект на Laravel,<br />
	Одной командой создаете все необходимые таблицы для работы<br />
	Еще одной командой заполняете эти таблицы необходимыми для работы данными.
</p>

<p>
	<span style="font-size:18px;">Максимально простые контроллеры </span>
</p>

<p>
	(что по сути и должно быть по стандарту MVC, а не то что мы сейчас видим в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr>)
</p>

<p>
	пример метода контроллера для получения поста
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> show</span><span class="pun">(</span><span class="typ">Post</span><span class="pln"> $post</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> view</span><span class="pun">(</span><span class="str">'post.show'</span><span class="pun">,</span><span class="pln"> compact</span><span class="pun">(</span><span class="str">'post'</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	<br />
	Обратите внимание, очень классная фишка Laravel - если в адресе страницы есть id поста (напр. /posts/123) то мы в качестве аргумента метода контроллера можем получить не этот идентификатор чтобы потом по нему вручную создать этот пост, а фреймворк за нас сам создаст этот пост и мы в качестве аргумента получаем сразу объект этого поста, осталось передать его представлению и все. Если пост не будет найден то фреймворк вернет страницу 404. Вроде мелочь, но таких мелочей там десятки, которые очень сильно ускоряют разработку.
</p>

<p>
	или контроллер для создания постов
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> store</span><span class="pun">(</span><span class="typ">StoreRequest</span><span class="pln"> $request</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        $data </span><span class="pun">=</span><span class="pln"> $request</span><span class="pun">-&gt;</span><span class="pln">validated</span><span class="pun">();</span><span class="pln">
 
        $this</span><span class="pun">-&gt;</span><span class="pln">service</span><span class="pun">-&gt;</span><span class="pln">store</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">);</span><span class="pln">
 
        </span><span class="kwd">return</span><span class="pln"> redirect</span><span class="pun">()-&gt;</span><span class="pln">route</span><span class="pun">(</span><span class="str">'admin.post.index'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	<br />
	StoreRequest - отдельный реквест для данного метода, опять же в качестве аргумента получаем готовый объект и нам не нужно его создавать вручную самостоятельно, в нем содержаться правила валидации запроса
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">  </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> rules</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
            </span><span class="str">'title'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'required|string'</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'content'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'required|string'</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'image'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'required|file'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// можно также указать что это также картинка, определенного типа и размеров.</span><span class="pln">
            </span><span class="str">'category_id'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'required|integer|exists:categories,id'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// тут сразу проверяется наличие этого идентификатора базе в таблице категорий, чтобы не создать пост с несуществующей категорией.</span><span class="pln">
            </span><span class="str">'tag_ids'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'nullable|array'</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'tag_ids.*'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'nullable|integer|exists:tags,id'</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	то есть вам не нужно вручную для каждого поля, которое вы получаете, через кучу if конструкций прописывать кучу правил, обработку этих правил, вручную создавать и возвращать ошибки валидации, если эти правила не сработали или даже писать sql запросы если нужно проверить уникально записи в базе данных, нет. Просто создается массив со всеми правила (из коробки уже доступны десятки правил валидации с текстами ошибок, но можно создавать и свои собственные) и все.
</p>

<p>
	дальше, в
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">$data </span><span class="pun">=</span><span class="pln"> $request</span><span class="pun">-&gt;</span><span class="pln">validated</span><span class="pun">();</span></pre>

<p>
	попадет массив всех уже проверенных данных.<br />
	Если валидация не прошла то фреймворк сам возвращает пользователя на старую страницу и возвращает все ошибки валидации<br />
	все что вам нужно это прописать в шаблоне под полем
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="lit">@error</span><span class="pun">(</span><span class="str">'title'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"text-danger"</span><span class="pun">&gt;{{</span><span class="pln"> $message </span><span class="pun">}}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="lit">@enderror</span></pre>

<p>
	<br />
	и фреймворк сам выведет нужные ошибки для всех правил для каждого поля, ошибки тоже можно настраивать и переопределять.
</p>

<p>
	дальше по коду
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">service</span><span class="pun">-&gt;</span><span class="pln">store</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">);</span></pre>

<p>
	вся логика из контроллера вынесена в отдельный сервис для создания всех данных, для улучшения читабельности кода и чтобы не раздувать контроллеры.<br />
	сам метод примерно такой:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> store</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// старт транзакции, так как есть работа с несколькими таблицами</span><span class="pln">
            DB</span><span class="pun">::</span><span class="pln">beginTransaction</span><span class="pun">();</span><span class="pln">
 
            $data</span><span class="pun">[</span><span class="str">'image'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Storage</span><span class="pun">::</span><span class="pln">put</span><span class="pun">(</span><span class="str">'/images'</span><span class="pun">,</span><span class="pln"> $data</span><span class="pun">[</span><span class="str">'image'</span><span class="pun">]);</span><span class="pln">
 
            $post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">::с</span><span class="pln">reate</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">);</span><span class="pln">
 
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$tagIds</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                $post</span><span class="pun">-&gt;</span><span class="pln">tags</span><span class="pun">()-&gt;</span><span class="pln">attach</span><span class="pun">(</span><span class="pln">$tagIds</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
 
            DB</span><span class="pun">::</span><span class="pln">commit</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">\Throwable $th</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// откат если произошла какая-то ошибка</span><span class="pln">
            DB</span><span class="pun">::</span><span class="pln">rollBack</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	<br />
	Тут видно работу с транзакциями, которых вообще нету в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr> и очень зря, так как при сохранении напр. товара задействуется не одна таблица товара, а с десяток других - опции, атрибуты, акции, скидки, картинки, связи итд.
</p>

<p>
	И если где-то произойдет ошибка то в базу запишутся не валидные данные которые потом найти будет крайне сложно. Я достаточно часто встречаю ситуацию когда в базе <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr> невалидные данные, особенно после использования различных модулей импорта.
</p>

<p>
	<span style="font-size:18px;">Очень просто сделана работа с файлами.</span>
</p>

<p>
	Можно в настройках указать несколько файловых хранилищ (локальное, фтп, облачные хранилища) и легко переключаться между ними или какие-то данные загружать локально, какие-то в облако итд.
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="typ">Post</span><span class="pun">::с</span><span class="pln">reate</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">);</span></pre>

<p>
	создаст новый пост
</p>

<p>
	через метод attach к этому посту добавятся новые теги, потому что в модели поста прописана связь этого поста с тегами
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> tags</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Tag</span><span class="pun">::</span><span class="kwd">class</span><span class="pun">,</span><span class="pln"> </span><span class="str">'post_tags'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'post_id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'tag_id'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	<br />
	Эта связь дает нам возможность как автоматически получать теги для постов (через $post-&gt;tags) так и изменять их.
</p>

<p>
	<strong>При этом мы не написать ни одной строчки SQL кода! </strong>Весь код со всеми связями, проверками итд. написал за нас фреймворк. И это не только очень сильно ускоряет весь процесс разработки экономя сотни часов времени, но и страхует от кучи возможных ошибок, в том числе ошибок безопасности, например можно какие-то данные при добавлении в базу не обработать и получить потенциальную ошибку безопасности.
</p>

<p>
	<span style="font-size:18px;">Понравилась такая фишка как безопасное удаление</span>
</p>

<p>
	если в модели просто добавить трейт
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="kwd">use</span><span class="pln"> </span><span class="typ">SoftDeletes</span><span class="pun">;</span></pre>

<p>
	то при удалении записей они не будут удаляться физически, а просто помечаться что были удалены, на сайте вы их не увидите, так как почти все методы работы с базой этих записей не видят, но они будут в базе и их легко можно восстановить при необходимости.
</p>

<p>
	Что еще, для примера - пагинация
</p>

<p>
	Если нужно добавить пагинацию то в контроллере при получении постов делаем
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln">$posts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">::</span><span class="pln">paginate</span><span class="pun">(</span><span class="lit">10</span><span class="pun">);</span></pre>

<p>
	а в шаблоне<br />
	добавляем всего одну строчку кода
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pun">{{</span><span class="pln"> $posts</span><span class="pun">-&gt;</span><span class="pln">links</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></pre>

<p>
	и все, мы получаем рабочую пагинацию, стилизованную напр. под бутстрап, которая сама создает все ссылки.<br />
	А теперь сравните какую простиню кода нужно написать в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">опенкарт</abbr> для того чтобы добавить ту же самую пагинацию для каждой страницы.. это куча строк кода в каждом! контроллере.
</p>

<p>
	   
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="pln"> $url </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_name'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_name='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> urlencode</span><span class="pun">(</span><span class="pln">html_entity_decode</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_name'</span><span class="pun">],</span><span class="pln"> ENT_QUOTES</span><span class="pun">,</span><span class="pln"> </span><span class="str">'UTF-8'</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_model'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_model='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> urlencode</span><span class="pun">(</span><span class="pln">html_entity_decode</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_model'</span><span class="pun">],</span><span class="pln"> ENT_QUOTES</span><span class="pun">,</span><span class="pln"> </span><span class="str">'UTF-8'</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_price'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_price='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_price'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_quantity'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_quantity='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_quantity'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_status'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_status='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_status'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_image'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;filter_image='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'filter_image'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'sort'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;sort='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'sort'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span><span class="pln">$this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'order'</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      $url </span><span class="pun">.=</span><span class="pln"> </span><span class="str">'&amp;order='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">request</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">[</span><span class="str">'order'</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    $pagination </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Pagination</span><span class="pun">();</span><span class="pln">
    $pagination</span><span class="pun">-&gt;</span><span class="pln">total </span><span class="pun">=</span><span class="pln"> $product_total</span><span class="pun">;</span><span class="pln"> </span><span class="com">// для этого нужно эту переменную еще вручную достать из базы, создав для этого отдельный метод с кучей sql кода и передать в контроллер. </span><span class="pln">
    $pagination</span><span class="pun">-&gt;</span><span class="pln">page </span><span class="pun">=</span><span class="pln"> $page</span><span class="pun">;</span><span class="pln">
    $pagination</span><span class="pun">-&gt;</span><span class="pln">limit </span><span class="pun">=</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">config</span><span class="pun">-&gt;</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'config_limit_admin'</span><span class="pun">);</span><span class="pln">
    $pagination</span><span class="pun">-&gt;</span><span class="pln">url </span><span class="pun">=</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">url</span><span class="pun">-&gt;</span><span class="pln">link</span><span class="pun">(</span><span class="str">'catalog/product'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'token='</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">session</span><span class="pun">-&gt;</span><span class="pln">data</span><span class="pun">[</span><span class="str">'token'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> $url </span><span class="pun">.</span><span class="pln"> </span><span class="str">'&amp;page={page}'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln">
 
    $data</span><span class="pun">[</span><span class="str">'pagination'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> $pagination</span><span class="pun">-&gt;</span><span class="pln">render</span><span class="pun">();</span></pre>

<p>
	<span style="font-size:18px;">Отличный концепт - очереди и задания.</span>
</p>

<p>
	Если есть какие-то действия, напр. отправка почты или какие-то вычисления, для которых нужно обращаться к сторонним сервисам то вместо того чтобы долго ждать каждый раз пока сторонний сервер отдаст результат, можно создать новой задание Job и добавить его в очередь Queue после этого все действия в очереди будут спокойно обрабатываться в фоне и ничего на сайте не будет тормозить пока ожидается ответ от сервера.
</p>

<p>
	<span style="font-size:18px;">Еще одна отличная концепция - Middleware</span>
</p>

<p>
	Это код который выполняется перед или после реквеста.<br />
	Очень удобно делать разные ограничения доступа к некоторым страницам (например открыть доступ к странице только авторизованному пользователю или админу итд.) или обработку входящих данных, например по умолчанию для всех входных строк отображаются пробелы в начале и конце. При этом вся логика не пишется в одну кучу в контроллере через кучу условий, а лежит в отдельном классе. <br />
	Через этот механизм таже сделана защита CSRF (cross-site request forgery )<br />
	все что вам нужно это написать в шаблоне для формы
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted"><span class="lit">@csrf</span></pre>

<p>
	<br />
	и все! фреймворк сам создаст нужные токены, передаст их в форму, выведет нужный инпут, а на входе проверит все запросы (кроме гет) есть ли там токер, совпадает ли он, если не совпадает то сделает возврат с ошибкой и не даст такой форме пройти дальше.<br />
	Этот механизм работает для всех форм, то есть уже из коробки есть эта защита для всех форм. И этой защиты вообще нету в <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>.<br />
	Через Middleware также из коробки реализован троттлинг, для API вы можете указать сколько запросов напр. в минуту должен сервер обрабатывать и не больше.
</p>

<p>
	Ну и так далее, то что я описал выше <strong>это очень малая часть возможностей фреймворка, просто для примера</strong>. Всех возможностей многократно больше.<br />
	Я просто хотел показать насколько тут все продумано до мелочей, когда основные базовые действия автоматизированы настолько, что делаются буквально в 1-2 строчки кода.<br />
	И как это контрастирует с опенкартом, где для любого действия нужно писать десятки строк кода да еще и дублировать это в десятках контроллеров.<br />
	Наглядный пример сравнения когда в одном случае продукт делается программистами для программистов и когда в другом случае кто-то пишет код вообще не думая о том кто потом и как с этим кодом будет работать в будущем..<br />
	Возможно поэтому популярность Laravel растет последние 5 лет, чего к сожалению не скажешь об <abbr title="Бесплатная платформа для электронной коммерции с открытым исходным кодом">OpenCart</abbr>.. 
</p>
]]></description><guid isPermaLink="false">518</guid><pubDate>Mon, 02 Oct 2023 16:51:38 +0000</pubDate></item><item><title>3 &#x432;&#x435;&#x449;&#x438;, &#x43A;&#x43E;&#x442;&#x43E;&#x440;&#x44B;&#x445; &#x43C;&#x43D;&#x435; &#x431;&#x43E;&#x43B;&#x44C;&#x448;&#x435; &#x432;&#x441;&#x435;&#x433;&#x43E; &#x43D;&#x435; &#x445;&#x432;&#x430;&#x442;&#x430;&#x435;&#x442; &#x432; OpenCart</title><link>https://opencartforum.com/blogs/entry/411-3-veshhi-kotoryh-mne-bolshe-vsego-ne-hvataet-v-opencart/</link><description><![CDATA[<p>
	Предлагаю немного пофантазировать. Чего больше всего не хватает OpenCart, чтобы быть ну если не идеальным, то по крайней мере движком с которым было бы приятно работать всем нам? По моему мнению не так и много, как может показаться на первый взгляд.<br />
	 
</p>

<p>
	<span style="font-size:20px;"><strong>1. Конструктор форм.</strong></span><span style="font-size:22px;"><strong> </strong></span><br /><span style="font-size:16px;">Что есть сейчас? </span>
</p>

<p>
	Каждый разработчик для каждого своего дополнения вручную пишет горы HTML кода со всеми классами, проверками валидности, javascript и так далее. А когда OpenCart меняет например версию Bootstrap с 4 на 5 то с этим меняются десятки css классов и весь этот HTML код нужно вручную переписывать для каждого модуля..  <br />
	А теперь только представьте! Был бы в OpenCart какой-то простой конструктор форм, чтобы формы не создавать, как мартышки, вручную и потом изменять по пол дня каждую форму после очередного обновления. А чтобы форму создавать как-то так:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="pln">$form </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Form</span><span class="pun">(</span><span class="pln">array</span><span class="pun">(</span><span class="pln">
  </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'my-module-form'</span><span class="pln">
  </span><span class="str">'action'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'...'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'field'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> array</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'type'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'input'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'name'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'title'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'label'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'Title'</span><span class="pln">
    </span><span class="str">'rules'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> array </span><span class="pun">(</span><span class="pln">
      </span><span class="str">'required'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">'min_lenght'</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">));</span></pre>

<p>
	<br />
	и потом делаем например $form-&gt;render() и передаем результат в шаблонизатор. Все.  
</p>

<p>
	<br /><span style="font-size:16px;">Что это даст?</span>
</p>

<ol><li>
		Модулю будет вообще все равно на какой версии bootstrap или twig работает админка движка, это все нужно знать только конструктору форм и со сменой версии он сам построит нужную форму со всем новым синтаксисом. То есть, мы можем еще под 1.5 создать в контроллере модуля свою форму и эта форма будет работать даже на OpenCart 4 и 5 версии бутстрапа! А если в каком-то OpenCart 5 появится React то нам и тогда будет все равно, потому что конструктор форм поменяется все за наc и модуль и дальше будет работать! 
	</li>
	<li>
		В конструктор форм можно добавить событие, напр. <strong>form/render/before</strong> и перед рендерингом всех! форм любой модуль может получить объект этой формы и изменить его как угодно - например добавить какие-то свои поля или целый новый таб с кучей своих полей итд. То есть любой модуль может легко изменить любую форму в админке и каталоге как самого движка так и любого другого модуля. При чем сделает это не через модификаторы которые особенно при изменении шаблонов добавляют кучу конфликтов, а правильным способом через события и добавление новых полей в объект формы. 
	</li>
	<li>
		В форму также можно добавить такие приятные плюшки как: автоматическую валидацию полей по заданным правилам, с выводом нужных сообщений об ошибках, причем валидация будет работать даже без перезагрузки страницы через аякс. Плюс будет куча встроенных правил для валидации напр. емейлов, ссылок, длины и так далее, просто добавил в правило поля напр. 'required' =&gt; true и все, форма сама создаст поле, проверку, вывод ошибки если условие не соблюдено и так далее. 
	</li>
</ol><p>
	<br /><strong><span style="font-size:20px;">2. Конструктор SQL запросов. </span></strong><br />
	Я не говорю о какой сложной ORM, а об очень простом конструкторе запросов. 
</p>

<p>
	<br /><span style="font-size:16px;">Что есть сейчас? </span><br />
	Каждый разработчик пишет кучу SQL запросов вручную. При этом эти запросы изменить из своего модуля можно разве что через модификаторы, порождая тем самым кучу конфликтов. <br />
	А теперь представьте если бы в движке был конструктор запросов и запросы создавались как-то так:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="pln">$query </span><span class="pun">=</span><span class="pln"> $this</span><span class="pun">-&gt;</span><span class="pln">db</span><span class="pun">-&gt;</span><span class="kwd">select</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">)-&gt;</span><span class="kwd">from</span><span class="pun">(</span><span class="str">'product'</span><span class="pun">)-&gt;</span><span class="kwd">where</span><span class="pun">(...)-&gt;</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">);</span><span class="pln">
$results </span><span class="pun">=</span><span class="pln"> $query</span><span class="pun">-&gt;</span><span class="pln">execute</span><span class="pun">();</span></pre>

<p>
	<br /><span style="font-size:16px;">Что это даст? </span>
</p>

<ol><li>
		И читать и писать такой код легче и понятнее
	</li>
	<li>
		Можно в сам конструктор добавить и добавление префикса таблицы и автоматическую обработку данных перед выполнением, не нужно для каждого поля вручную делать $this-&gt;db-&gt;escape, а это в свою очередь и упростит написание запросов и сделает их надежнее и безопаснее.  
	</li>
	<li>
		Самое главное! Можно создать событие напр. <strong>db/execute/before</strong> и со своего модуля получить доступ ко всем! SQL запросам на сайте с возможностью изменить каждый, например добавить свой новый JOIN или условие, сортировку итд. 
	</li>
	<li>
		Имея конструктор в будущем намного проще перейти на новую базу данных, при этом не нужно будет изменять код всех модулей, а только код самого конструктора, чтобы он по готовым правилам создал другой запрос по правилам другой базы данных. 
	</li>
	<li>
		Для каких-то сложных запросов или ленивых разработчиков всегда останется возможно написать какой-то запрос вручную по-старому. 
	</li>
</ol><p>
	<br /><strong><span style="font-size:20px;">3. Нормальная система расширений. </span></strong><br /><span style="font-size:16px;">Для этого:</span>
</p>

<ol><li>
		Полностью выбросить на свалку истории vqmod и ocmod, как причину огромного к-ва конфликтов
	</li>
	<li>
		Сделать нормальную систему Событий. Писал об этом выше как можно расширить движок при наличии конструктора форм и SQL запросов. Это далеко не все, что нужно для полноценной системы Событий, просто показывает на примере как можно достаточно просто создать огромные возможности для правильного! изменения движка через События.
	</li>
	<li>
		Добавить другие инструменты такие как валидаторы, хелперы для например создания хлебных крошек, пагинации и десятков других вещей, для которых в движке нужно дублировать кучу кода в каждом модуле. 
	</li>
</ol><p>
	 
</p>

<p>
	Конечно, добавить еще можно много всего, но если хотя бы реализовать те 3 пункта что я описал выше мы уже бы получили качественно! другой движок. <br />
	Потому что извините, но в 21 году писать вручную SQL запросы, HTML формы и дублировать тысячи строк кода это.. мне даже слова сложно подобрать, чтобы это описать и никого не обидеть.. одним словом - сюр какой-то.<br />
	 
</p>

<p>
	<span style="font-size:16px;">И еще один важный вопрос - усложнят ли все эти нововведения движок? </span>
</p>

<p>
	<br />
	На первый взгляд может показаться что - "да", так как нужно будет выучить новые инструменты. Но с другой стороны сколько времени это займет? Несколько дней? А сколько времени потом будет сэкономлено? В разы, десятки раз больше? Во сколько раз уменьшиться количество конфликтов в движке? В разы, десятки раз? На сколько нам всем будет приятнее работать с таким движком, в котором ты можешь писать код модуля и он после этого будет работать, даже если в движке кроме него установлено еще пару десятков других модулей? А со сменой версии движка не нужно будет вручную переписывать гору HTML кода под новую модную версию бутстрапа? Во сколько раз такой движок, в котором модули работают без конфликтов, а хороших и функциональных модулей будет больше, будет более привлекательным для пользователей?<br />
	Неужели все эти преимущества не стоят этих изменений?<br />
	 
</p>]]></description><guid isPermaLink="false">411</guid><pubDate>Tue, 15 Jun 2021 12:19:10 +0000</pubDate></item><item><title>&#x427;&#x442;&#x43E; &#x43D;&#x430;&#x441; &#x436;&#x434;&#x435;&#x442; &#x432; OpenCart 4?</title><link>https://opencartforum.com/blogs/entry/406-chto-nas-zhdet-v-opencart-4/</link><description><![CDATA[<div>
	На данный момент продолжается работа над 4 версией движка. На сегодня для тестирования доступна версия 4.0.0.0_b. Сроков выхода новой версии пока нету, но уже можно посмотреть какие там запланированы изменения. 
</div>

<div>
	 
</div>

<div>
	<span style="font-size:20px;">Из основного</span>
</div>

<div>
	<strong>- минимальная версия PHP - 8</strong>

	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">"Warning: You need to use PHP8 or above for OpenCart to work!"</span></pre>

	<p>
		 
	</p>
</div>

<div>
	<strong>- убрали модификаторы (ocmod)</strong><br />
	Вот только не понятно как можно убирать модификаторы, если с помощью событий еще можно сделать очень мало? И как при этом писать дополнения? Или будет как в версии 1.5 движка - отдельно OpenCart и отдельно все скачивали vQmod? 
</div>

<div>
	<br /><strong>- добавлена схема для базы данных</strong>

	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">system/helper/db_schema.php </span></pre>
	Опять таки, зачем она нужна если запросы к базе все еще пишутся в одну строчку?<br />
	 
</div>

<div>
	<strong>- для товара добавлены варианты</strong><br />
	Можно указать главный товар и его варианты, например один товар с различными вариантами цветов, теперь это будут разные товары для каждого цвета со своими наборами опций, ценой, остатками и другими полями
</div>

<div>
	 
</div>

<div>
	<strong>- папка дополнений переехала </strong>
</div>

<div>
	из
	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">/catalog и /admin</span></pre>
	в

	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">/extension/opencart/catalog
/extension/opencart/admin</span></pre>
	Свои же дополнения будут храниться в 

	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">/extension/username/catalog
/extension/username/admin</span></pre>
	спасибо <a contenteditable="false" data-ipshover="" data-ipshover-target="https://opencartforum.com/profile/675243-chukcha/?do=hovercard" data-mentionid="675243" href="https://opencartforum.com/profile/675243-chukcha/" rel="">@chukcha</a> за уточнение<br /><br />
	Суть это не меняет, но структуру файлов всех дополнений придется переделывать.<br /><br /><strong>- неймспейсы теперь везде</strong><br />
	было
	<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">ModelCatalogProduct</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{</span></pre>
	стало

	<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="kwd">namespace</span><span class="pln"> </span><span class="typ">Opencart</span><span class="pln">\Catalog\Model\Catalog</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Product</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> \Opencart\System\Engine\Model </span><span class="pun">{</span></pre>
	<br /><strong>- и строгая типизация</strong><br />
	было
	<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> getProducts</span><span class="pun">(</span><span class="pln">$data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>
	стало

	<pre class="ipsCode prettyprint lang-php prettyprinted">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> getProducts</span><span class="pun">(</span><span class="pln">array $data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]):</span><span class="pln"> array </span><span class="pun">{</span></pre>

	<p>
		 
	</p>
</div>

<div>
	<span style="font-size:20px;">Шаблон</span>
</div>

<div>
	<strong>- Bootstrap обновлен до 5 версии </strong><br />
	при этом поддержку font-awesome убрали, видимо иконки уже есть в Bootstrap
</div>

<div>
	<br /><strong>- jQuery 3.6 вместо 2.1 </strong>
</div>

<div>
	<br /><strong>- возможно, в движок будет добавлен React или Vue</strong><br />
	Разговоры об этом идут, <a href="https://opencartforum.com/topic/176462-v-opencart-budet-react-ili-vue/?tab=comments#comment-1723997" rel="">я уже писал об этом на форуме</a>, <a href="https://opencartforum.com/topic/176462-v-opencart-budet-react-ili-vue/?do=findComment&amp;comment=1724007" rel="">также писал о том, насколько маловероятно</a> что это будет реализовано  <br />
	 
</div>

<div>
	<strong>- появилась новый шаблон </strong>
</div>

<div>
	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">product/thumb.twig </span></pre>

	<p>
		 
	</p>
</div>

<div>
	для блока товара в категории, поиске, производителе итд. <a href="https://opencartforum.com/topic/176502-opencart-4-nabljudenie-dlja-reliza-ocstore-4/?do=findComment&amp;comment=1726201" rel="">Более подробно тут</a>
</div>

<div>
	 
</div>

<div>
	<strong>- появился новый шаблон </strong>
</div>

<div>
	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">common/pagination.twig</span></pre>
	для пагинации
</div>

<div>
	 
</div>

<div>
	<span style="font-size:20px;">Админка</span><br /><strong>- появился новый тип дополнений - Startup</strong><br />
	предположительно для добавления своих скриптов, которые будут выполняться при загрузке магазина<br /><br /><strong>- появились задания крона</strong>

	<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">wget "http://localhost/opencart/4.0b/admin/index.php?route=common/cron" --read-timeout=5400</span></pre>

	<p>
		<br /><strong>- добавлено <a href="https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%89%D0%B8%D0%B9_%D1%80%D0%B5%D0%B3%D0%BB%D0%B0%D0%BC%D0%B5%D0%BD%D1%82_%D0%BF%D0%BE_%D0%B7%D0%B0%D1%89%D0%B8%D1%82%D0%B5_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85" rel="external nofollow">GDPR Approvals</a> для пользователей</strong>
	</p>

	<p>
		<br /><strong>- возле логотипа пользователя появился колокольчик</strong>
	</p>

	<p>
		для уведомлений о новостях, новых версиях и обновлениях от OpenCart но по идее это могут использовать и сами модули для создания своих уведомлений. <br /><br /><br /><span style="font-size:20px;">Общие впечатления</span>
	</p>
</div>

<div>
	К сожалению, вот уже несколько новых мажорных версий, начиная со второй, вместо того, чтобы решать глобальные проблемы движка, такие как отсутствие нормальной системы расширений, отсутствие нормальных инструментов работы с базой данных, валидаторов, дублирование кода, устаревшее ядро движка, которое уже больше 10 лет как почти не изменяется, а также многие другие, OpenCart идет по пути "сделаем все красиво" и в каждой новой версии тратится куча времени для обновления дизайна, сначала добавили Bootstrap, потом в каждой новой версии его обновляют, добавили twig, обновили jQuery.. <br />
	Каких-то кардинальных изменений я совсем не заметил, на мажорную версию это никак не тянет, максимум на 3.1. <br />
	Хотя, работа над 4 версией еще не закончена, есть слабая надежда что еще что-то добавят. <br /><br />
	Если что-то пропустил  - дополняйте или поправляйте в комментариях. 
</div>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://opencartforum.com/storage/attachment/monthly_2021_06/90659119_Products(1).png.481da4592ac96d0c43a81e9552df1566.png" data-fileid="651986" data-fileext="png" rel=""><img alt="Products (1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="651986" data-ratio="52,8" style="height:auto;" width="1000" data-src="https://opencartforum.com/storage/attachment/monthly_2021_06/1704325494_Products(1).thumb.png.3baf19053806921bd4d28617dab22c75.png" src="https://opencartforum.com/applications/core/interface/js/spacer.png" /></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://opencartforum.com/storage/attachment/monthly_2021_06/Products.png.14ebe5b64ee84b0dde2c4b2129882794.png" data-fileid="651987" data-fileext="png" rel=""><img alt="Products.png" class="ipsImage ipsImage_thumbnailed" data-fileid="651987" data-ratio="55,31" style="height:auto;" width="980" data-src="https://opencartforum.com/storage/attachment/monthly_2021_06/Products.png.14ebe5b64ee84b0dde2c4b2129882794.png" src="https://opencartforum.com/applications/core/interface/js/spacer.png" /></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://opencartforum.com/storage/attachment/monthly_2021_06/Dashboard.png.de75c8c41ea227358b5333895dbc259b.png" data-fileid="651988" data-fileext="png" rel=""><img alt="Dashboard.png" class="ipsImage ipsImage_thumbnailed" data-fileid="651988" data-ratio="55,31" style="height:auto;" width="980" data-src="https://opencartforum.com/storage/attachment/monthly_2021_06/Dashboard.png.de75c8c41ea227358b5333895dbc259b.png" src="https://opencartforum.com/applications/core/interface/js/spacer.png" /></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://opencartforum.com/storage/attachment/monthly_2021_06/Administration.png.9af9d31353c0db7ab290f38d74374528.png" data-fileid="651989" data-fileext="png" rel=""><img alt="Administration.png" class="ipsImage ipsImage_thumbnailed" data-fileid="651989" data-ratio="54,47" style="height:auto;" width="995" data-src="https://opencartforum.com/storage/attachment/monthly_2021_06/Administration.png.9af9d31353c0db7ab290f38d74374528.png" src="https://opencartforum.com/applications/core/interface/js/spacer.png" /></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://opencartforum.com/storage/attachment/monthly_2021_06/1485594385_YourStore.png.5df4ae19d95c84f94a5565f189a9272e.png" data-fileid="651990" data-fileext="png" rel=""><img alt="Your Store.png" class="ipsImage ipsImage_thumbnailed" data-fileid="651990" data-ratio="51,26" style="height:auto;" width="991" data-src="https://opencartforum.com/storage/attachment/monthly_2021_06/1485594385_YourStore.png.5df4ae19d95c84f94a5565f189a9272e.png" src="https://opencartforum.com/applications/core/interface/js/spacer.png" /></a>
</p>]]></description><guid isPermaLink="false">406</guid><pubDate>Fri, 04 Jun 2021 14:00:00 +0000</pubDate></item></channel></rss>
