Подзапросы для pdoTools

Добрый день всем! Мне понадобилось сделать сложные запросы в mysql и, так как уже привык к pdoTools, решил доработать его, чтоб с ним делать подзапросы. Извиняюсь, загружен работой и не хватило времени оттестировать все и расписать.
Вкратце под катом.

Нужен был запрос типа такого:
SELECT *
FROM `modx_tsklad_detail_naryad_smena_link` AS `tSkladDetNSLink`
LEFT JOIN `modx_tsklad_order_list` `Detail` ON Detail.id=tSkladDetNSLink.det_id
LEFT JOIN `modx_tsklad_orders` `Order` ON Order.id=Detail.sk_order_id
LEFT JOIN `modx_tsklad_naryad` `Naryad` ON Naryad.id=tSkladDetNSLink.naryad_id
LEFT JOIN `modx_tsklad_smena` `Smena` ON Smena.id=tSkladDetNSLink.smena_id
LEFT JOIN `modx_nomenclature_detail_nom` `DetailNom` ON DetailNom.id=Detail.nom_id
LEFT JOIN `modx_nomenclature_detail_class` `DetailClass` ON DetailClass.id=DetailNom.class_id
LEFT JOIN `modx_nomenclature_type_job` `NomTypeJob` ON NomTypeJob.id=DetailClass.type_job_id
LEFT JOIN (
		#subquery subpdo join 
		SELECT NextDNL.det_id AS next_det_id, NextDNL.naryad_id AS next_naryad_id, NextN.name AS next_naryad_name, NextDNL.smena_id AS next_smena_id, NextS.date AS next_smena_date, NextS.number AS next_smena_number
		FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
		LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
		LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
		ORDER BY NextS.date ASC, NextS.number ASC) `NextDNL1` 

                ON tSkladDetNSLink.det_id = NextDNL1.next_det_id AND 
                 (NextDNL1.next_smena_date > Smena.date OR (NextDNL1.next_smena_date = Smena.date AND NextDNL1.next_smena_number > Smena.number)
) 
 AND NextDNL1.next_smena_id = (
 		#subquery {$subpdo.smena_limit}
		SELECT NextDNL.smena_id AS on_next_smena_id
		FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
		LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
		LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
		WHERE NextS.date > Smena.date OR (NextS.date = Smena.date AND NextS.number > Smena.number)
		ORDER BY NextS.date ASC, NextS.number ASC
		LIMIT 1
)
LEFT JOIN `modx_plazma_list` `PlazmaList` ON PlazmaList.det_id=tSkladDetNSLink.det_id
WHERE (`Detail`.`sech` = 'pryam' AND `Detail`.`name` = 'зонт' AND `DetailNom`.`A` = '2000' AND `DetailNom`.`B` = '1500' AND `DetailNom`.`a_s` = '500' AND `DetailNom`.`b_s` = '500' AND `Detail`.`metall` = '0,7Ц' AND `Detail`.`L` = '0' AND `Detail`.`comment` = 'тип 1, ф355 заузить под наш отвод' AND `tSkladDetNSLink`.`smena_id` = 65 AND `tSkladDetNSLink`.`naryad_id` = 8 AND `NextDNL1`.`next_smena_id` = '66' AND `PlazmaList`.`file_true` = '0')
ORDER BY Detail.sech DESC, Detail.name ASC, DetailNom.A DESC, DetailNom.B DESC, DetailNom.a_s DESC, DetailNom.b_s DESC, Detail.metall DESC, Detail.L DESC, Detail.comment DESC
Сперва исходя из Джоины подзапросов средствами xPDO Сапсибо Fi1osof
сделал инструкцию для джоин подзапроса:
[leftJoin] => Array(

            [NextDNL1] => Array
                (
                    [class] => tSkladDetNSLink
                    [on] => tSkladDetNSLink.det_id = NextDNL1.next_det_id
                    
					[subpdo] => Array
                        (
                            /* Здесь массив обычных инструкций pdoTools для запроса. Функция getSubSelectSQL преобразует его в SQL код.
							https://github.com/touol/pdoTools/blob/61af551759b1d83a2ee5aba21cbaff772a24312b/core/components/pdotools/model/pdotools/pdofetch.class.php#L390
							Затем джоиниться
							https://github.com/touol/pdoTools/blob/61af551759b1d83a2ee5aba21cbaff772a24312b/core/components/pdotools/model/pdotools/pdofetch.class.php#L352
							*/

                        )

                )
	)
Получилось:
LEFT JOIN (
		#subquery subpdo join 
		SELECT NextDNL.det_id AS next_det_id, NextDNL.naryad_id AS next_naryad_id, NextN.name AS next_naryad_name, NextDNL.smena_id AS next_smena_id, NextS.date AS next_smena_date, NextS.number AS next_smena_number
		FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
		LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
		LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
		ORDER BY NextS.date ASC, NextS.number ASC) `NextDNL1` 

                ON tSkladDetNSLink.det_id = NextDNL1.next_det_id AND 
                 (NextDNL1.next_smena_date > Smena.date OR (NextDNL1.next_smena_date = Smena.date AND NextDNL1.next_smena_number > Smena.number)
)
Затем понадобился запрос в on. Сделал так:
Добавил массив инструкцию subpdo в первый уровень массива pdoTools, вида:
[subpdo] => Array
        (
            [smena_limit] => Array
                (
                    /* Здесь массив обычных инструкций pdoTools для запроса. Функция getSubSelectSQL преобразует его в SQL код.
							*/
                )
        )
Преобразуем в SQL. Затем array_walk_recursive github.com/touol/pdoTools/blob/61af551759b1d83a2ee5aba21cbaff772a24312b/core/components/pdotools/model/pdotools/pdofetch.class.php#L214
Проходя по всему массиву инструкций pdoTools и с феном подменяем {$subpdo.smena_limit} на этот SQL.
Было:
[on] => tSkladDetNSLink.det_id = NextDNL1.next_det_id 
        and NextDNL1.next_smena_id = ({$subpdo.smena_limit})
Получилось:
ON tSkladDetNSLink.det_id = NextDNL1.next_det_id AND 
 AND NextDNL1.next_smena_id = (
 		#subquery {$subpdo.smena_limit}
		SELECT NextDNL.smena_id AS on_next_smena_id
		FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
		LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
		LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
		WHERE NextS.date > Smena.date OR (NextS.date = Smena.date AND NextS.number > Smena.number)
		ORDER BY NextS.date ASC, NextS.number ASC
		LIMIT 1
)
Эта возможно с этой правкой Add Fenom soft mode.. Без нее, скорей всего, феном не поймет свою инструкцию в своей инструкции.
Проверка показала, что и без Add Fenom soft mode все прекрасно работает.

Вот полная распечатка массив нужного запроса:
Array
(
    [class] => tSkladDetNSLink
    [limit] => 0
    [sortby] => Array
        (
            [Detail.sech] => DESC
            [Detail.name] => ASC
            [DetailNom.A] => DESC
            [DetailNom.B] => DESC
            [DetailNom.a_s] => DESC
            [DetailNom.b_s] => DESC
            [Detail.metall] => DESC
            [Detail.L] => DESC
            [Detail.comment] => DESC
        )

    [sortdir] => 
    [groupby] => 
    [totalVar] => total
    [setTotal] => 
    [tpl] => Smena.Naryad.Plazma.row
    [return] => data
    [select] => Array
        (
            [tSkladDetNSLink] => `tSkladDetNSLink`.`id`, `tSkladDetNSLink`.`name`, `tSkladDetNSLink`.`det_id`, `tSkladDetNSLink`.`naryad_id`, `tSkladDetNSLink`.`smena_id`, `tSkladDetNSLink`.`det_count`, `tSkladDetNSLink`.`smena_count`, `tSkladDetNSLink`.`flanec_con`, `tSkladDetNSLink`.`done`
            [Detail] => `Detail`.`sk_order_id` AS `d_sk_order_id`, `Detail`.`excel_id` AS `d_excel_id`, `Detail`.`nom_id` AS `d_nom_id`, `Detail`.`detail_nom_id` AS `d_detail_nom_id`, `Detail`.`systema` AS `d_systema`, `Detail`.`sys_number` AS `d_sys_number`, `Detail`.`sech` AS `d_sech`, `Detail`.`name` AS `d_name`, `Detail`.`articul` AS `d_articul`, `Detail`.`mark` AS `d_mark`, `Detail`.`A` AS `d_A`, `Detail`.`B` AS `d_B`, `Detail`.`a_s` AS `d_a_s`, `Detail`.`b_s` AS `d_b_s`, `Detail`.`L` AS `d_L`, `Detail`.`number_shina` AS `d_number_shina`, `Detail`.`metall` AS `d_metall`, `Detail`.`detType` AS `d_detType`, `Detail`.`comment` AS `d_comment`, `Detail`.`count` AS `d_count`, `Detail`.`pro_count` AS `d_pro_count`, `Detail`.`sklad_count` AS `d_sklad_count`, `Detail`.`otgr_count` AS `d_otgr_count`, `Detail`.`SN` AS `d_SN`, `Detail`.`price_metall` AS `d_price_metall`, `Detail`.`price_job` AS `d_price_job`, `Detail`.`price` AS `d_price`, `Detail`.`status_id` AS `d_status_id`, `Detail`.`flanec` AS `d_flanec`, `Detail`.`add_job` AS `d_add_job`, `Detail`.`add_mat` AS `d_add_mat`, `Detail`.`price_svarka` AS `d_price_svarka`, `Detail`.`price_pokraska` AS `d_price_pokraska`, `Detail`.`price_office` AS `d_price_office`, `Detail`.`price_ceh` AS `d_price_ceh`, `Detail`.`price_zp` AS `d_price_zp`, `Detail`.`sektor_upravleniya` AS `d_sektor_upravleniya`, `Detail`.`fas_krug` AS `d_fas_krug`, `Detail`.`fas_pryam` AS `d_fas_pryam`, `Detail`.`vozd_krug` AS `d_vozd_krug`, `Detail`.`vozd_pryam` AS `d_vozd_pryam`, `Detail`.`fanec_count0` AS `d_fanec_count0`, `Detail`.`plazma` AS `d_plazma`
            [Order] => `Order`.`period_id` AS `o_period_id`, `Order`.`order_id` AS `o_order_id`, `Order`.`excel_id` AS `o_excel_id`, `Order`.`org_id` AS `o_org_id`, `Order`.`loc_org_id` AS `o_loc_org_id`, `Order`.`type` AS `o_type`, `Order`.`kontragent` AS `o_kontragent`, `Order`.`automobile` AS `o_automobile`, `Order`.`sentdate` AS `o_sentdate`, `Order`.`plan_makedate` AS `o_plan_makedate`, `Order`.`makedate` AS `o_makedate`, `Order`.`sklad_date` AS `o_sklad_date`, `Order`.`otgr_date` AS `o_otgr_date`, `Order`.`createby_user_id` AS `o_createby_user_id`, `Order`.`status_id` AS `o_status_id`, `Order`.`comment` AS `o_comment`, `Order`.`price` AS `o_price`, `Order`.`beznal` AS `o_beznal`, `Order`.`sum_closed` AS `o_sum_closed`, `Order`.`order_date` AS `o_order_date`, `Order`.`koef_zhuk` AS `o_koef_zhuk`
            [Naryad] => `Naryad`.`name` AS `n_name`
            [Smena] => `Smena`.`date` AS `s_date`, `Smena`.`number` AS `s_number`, `Smena`.`hour` AS `s_hour`
            [DetailNom] => `DetailNom`.`class_id` AS `dn_class_id`, `DetailNom`.`sech` AS `dn_sech`, `DetailNom`.`name2` AS `dn_name2`, `DetailNom`.`articul` AS `dn_articul`, `DetailNom`.`articul2` AS `dn_articul2`, `DetailNom`.`A` AS `dn_A`, `DetailNom`.`B` AS `dn_B`, `DetailNom`.`a_s` AS `dn_a_s`, `DetailNom`.`b_s` AS `dn_b_s`, `DetailNom`.`L` AS `dn_L`, `DetailNom`.`number_shina` AS `dn_number_shina`, `DetailNom`.`metall` AS `dn_metall`, `DetailNom`.`gauge` AS `dn_gauge`, `DetailNom`.`detType` AS `dn_detType`, `DetailNom`.`S` AS `dn_S`
            [NomTypeJob] => `NomTypeJob`.`name` AS `tj_name`, `NomTypeJob`.`description` AS `tj_description`
            [NextDNL1] => NextDNL1.next_naryad_id, NextDNL1.next_naryad_name,
        NextDNL1.next_smena_id, NextDNL1.next_smena_date, NextDNL1.next_smena_number
            [0] => tSkladDetNSLink.smena_count as sum_smena_count
            [1] => Detail.SN/tSkladDetNSLink.det_count*tSkladDetNSLink.smena_count as sum_naryad_s
        )

    [leftJoin] => Array
        (
            [Detail] => Array
                (
                    [class] => tSkladOrderList
                    [on] => Detail.id=tSkladDetNSLink.det_id
                )

            [Order] => Array
                (
                    [class] => tSkladOrders
                    [on] => Order.id=Detail.sk_order_id
                )

            [Naryad] => Array
                (
                    [class] => tSkladNaryad
                    [on] => Naryad.id=tSkladDetNSLink.naryad_id
                )

            [Smena] => Array
                (
                    [class] => tSkladSmena
                    [on] => Smena.id=tSkladDetNSLink.smena_id
                )

            [DetailNom] => Array
                (
                    [class] => DetailNom
                    [on] => DetailNom.id=Detail.nom_id
                )

            [DetailClass] => Array
                (
                    [class] => DetailClass
                    [on] => DetailClass.id=DetailNom.class_id
                )

            [NomTypeJob] => Array
                (
                    [class] => NomTypeJob
                    [on] => NomTypeJob.id=DetailClass.type_job_id
                )

            [NextDNL1] => Array
                (
                    [class] => tSkladDetNSLink
                    [on] => tSkladDetNSLink.det_id = NextDNL1.next_det_id and 
        (NextDNL1.next_smena_date > Smena.date OR (NextDNL1.next_smena_date = Smena.date AND  NextDNL1.next_smena_number > Smena.number))
        
        and NextDNL1.next_smena_id = ({$subpdo.smena_limit})
                    [subpdo] => Array
                        (
                            [class] => tSkladDetNSLink
                            [alias] => NextDNL
                            [select] => Array
                                (
                                    [NextDNL] => NextDNL.det_id as next_det_id, NextDNL.naryad_id AS next_naryad_id, NextN.name AS next_naryad_name,
                NextDNL.smena_id AS next_smena_id, NextS.date AS next_smena_date, NextS.number AS next_smena_number
                                )

                            [leftJoin] => Array
                                (
                                    [NextS] => Array
                                        (
                                            [class] => tSkladSmena
                                            [on] => NextS.id=NextDNL.smena_id
                                        )

                                    [NextN] => Array
                                        (
                                            [class] => tSkladNaryad
                                            [on] => NextN.id=NextDNL.naryad_id
                                        )

                                )

                            [sortby] => Array
                                (
                                    [NextS.date] => ASC
                                    [NextS.number] => ASC
                                )

                        )

                )

            [PlazmaList] => Array
                (
                    [class] => PlazmaList
                    [on] => PlazmaList.det_id=tSkladDetNSLink.det_id
                )

        )

    [where] => Array
        (
            [Detail.sech] => pryam
            [Detail.name] => зонт
            [DetailNom.A] => 2000
            [DetailNom.B] => 1500
            [DetailNom.a_s] => 500
            [DetailNom.b_s] => 500
            [Detail.metall] => 0,7Ц
            [Detail.L] => 0
            [Detail.comment] => тип 1, ф355 заузить под наш отвод
            [tSkladDetNSLink.smena_id] => 65
            [tSkladDetNSLink.naryad_id] => 8
            [NextDNL1.next_smena_id] => 66
            [PlazmaList.file_true] => 0
        )

    [tplWrapper] => Smena.Naryad.Plazma.Outer
    [tpl_sort_sum] => Smena.Naryad.Plazma.row_sort_sum
    [subpdo] => Array
        (
            [smena_limit] => Array
                (
                    [class] => tSkladDetNSLink
                    [alias] => NextDNL
                    [select] => Array
                        (
                            [NextDNL] => NextDNL.smena_id AS on_next_smena_id
                        )

                    [leftJoin] => Array
                        (
                            [NextS] => Array
                                (
                                    [class] => tSkladSmena
                                    [on] => NextS.id=NextDNL.smena_id
                                )

                            [NextN] => Array
                                (
                                    [class] => tSkladNaryad
                                    [on] => NextN.id=NextDNL.naryad_id
                                )

                        )

                    [where] => Array
                        (
                            [0] => NextS.date > Smena.date OR (NextS.date = Smena.date AND  NextS.number > Smena.number)
                        )

                    [sortby] => Array
                        (
                            [NextS.date] => ASC
                            [NextS.number] => ASC
                        )

                    [limit] => 1
                )

        )

)
Надеюсь подзапросы в pdoTools вам пригодятся :-). Вот ссылки
github
Установочный пакет

Сделал пул. Может сейчас @Василий Наумкин примет.
ЗЫ. Наверно можно сделать кучу вложенных подзапросов. Сделано так, что подзапросы обрабатываются рекурсивно. Но не тестировал.

Upd 04.03.2020
Хотелки к следующей версии:
  1. Обработка JSON и JS. Хотелось бы, чтоб, если обнаружился JSON или JS, чтоб ошибки вообще не возникало. Для JSON при парсинге кода можно проверить является ли строка JSON. Как проверить, является ли строка JSON'ом на PHP. Для JS отследить открытие тега script.
  2. Обработка ошибок феном. Если у юзера есть разрешение fenom_debuger, то на страницу, где возникла ошибка, и в лог и на почту выводить описание ошибки вида:
    • Error: Описание ошибки, как сейчас в логе.
    • call stack pdoTools: страница ошибки(id, pagetitle, ссылка в менеджер, № строки)->Шаблон, если ошибка не в контенте страницы(id, name, ссылка в менеджер, № строки)->Чанк (id, name или имя файла, ссылка в менеджер, № строки). (Еще бы сниппет, где возникло если сниппеты вызываются парсером феном это может возможно???). (В классе ввести pdoTools ввести массив call_stack и записывать в него все вызовы чанков)

    • call stack Femon: У него стандартная для PHP обработка ошибок и полный call stack можно вывести.
    И предусмотреть уровень вывода ошибок наверно.
  3. Конфигурация модификаторов феном в системных параметрах MODX.Тут которые.. Только по безопасности продумывать надо. Или не надо??
  4. Псевдокод. Мне нужно предоставить юзерам возможность вводить и править формулы. С нуля писать интерпретатор псевдокода — это жесть. Тем более в феном уже практически все есть. То есть, ограничение вызываемых функций php. Можно сделать отдельный компонент от pdoTools, но пока не понятно, может лучше конфигуратор параметров pdoTools сделать.
  5. femonSyntax вывести из $this->config или разделить $this->config на массив параметров pdoTools и массив конфига запроса pdoTools
  6. Проверять на присутствие инструкций фенома перед вызовом getChunk. В walkFunc точно надо.
Александр Туниеков
03 марта 2020, 20:02
modx.pro
2
1 894
-1
Поблагодарить автора Отправить деньги

Комментарии: 64

Yurij Finiv
03 марта 2020, 20:30
+3
А при чём здесь pdoTools, зачем править исходник? Почему не использовать pdoFetch, или pdoResources или чем то другом построеном на pdoFetch? Они умеет работать с любими таблицами так что не нужно и костылей лепить. И можно спокойно делать leftJoin.

Потом сложно обновлять сайты, и нужно все файлы сверять.
    Александр Туниеков
    03 марта 2020, 20:34
    0
    Подзапросы pdoTools не умеет делать!!! Точнее pdoFetch не умеет.
      Yurij Finiv
      03 марта 2020, 20:37
      +1
      Он умеет, работаю проблем не возникало. Если у Вас проблема можно в сниппете сделать
      запрос
        Александр Туниеков
        03 марта 2020, 20:54
        0
        Напишите с pdoFetch запрос
        SELECT tSkladDetNSLink.id, Smena.id, (SELECT NextDNL.smena_id
        FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
        LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
        WHERE NextS.date > Smena.date
        ORDER BY NextS.date ASC, NextS.number ASC
        LIMIT 1) AS on_next_smena_id
        FROM `modx_tsklad_detail_naryad_smena_link` AS `tSkladDetNSLink`
        LEFT JOIN `modx_tsklad_smena` `Smena` ON Smena.id=tSkladDetNSLink.smena_id
        WHERE Smena.id > 0
        ORDER BY tSkladDetNSLink.id DESC
        LIMIT 10
        так, чтоб в конфиге запроса не было названий таблиц с префиксом базы modx_tsklad_detail_naryad_smena_link, modx_tsklad_smena и не надо лишних сниппетов(Я уже заманался вспоминать какой сниппет для чего нужен). Я проверю у себя :-).
          Александр Туниеков
          03 марта 2020, 22:59
          0
          Решил проверить как сработает и написал простенький код :-):
          {'!pdoResources' | snippet :[
              'loadModels'=>'tSklad',
              'subpdo'=>[
                  'test'=>[
                      'class'=>'tSkladDetNSLink',
                      'alias'=>'NextDNL',
                      'select'=>[
                          'NextDNL'=>'NextDNL.smena_id',
                      ],
                      'leftJoin'=>[
                          'NextS'=>[
                              'class'=>'tSkladSmena',
                              'on'=>'NextS.id=NextDNL.smena_id',
                              'where'=>[
                                  'NextS.date > Smena.date',
                              ],
                          ],
                      ],
                      'where'=>[
                          'NextS.date > Smena.date',
                      ],
                      'sortby'=>[
                          'NextS.date'=>'ASC',
                          'NextS.number'=>'ASC',
                      ],
                      'limit'=>1,
                  ],
              ],
              'class'=>'tSkladDetNSLink',
              'select'=>[
                  'tSkladDetNSLink'=>'tSkladDetNSLink.id,Smena.id as smena_id, ({$subpdo.test}) as on_next_smena_id',
              ],
              'leftJoin'=>[
                  'Smena'=>[
                      'class'=>'tSkladSmena',
                      'on'=>'Smena.id=tSkladDetNSLink.smena_id',
                  ],
              ],
              'where'=>[
                  'Smena.id > 0',
              ],
              'sortby'=>[
                  'tSkladDetNSLink.id'=>'DESC',
              ],
              'limit'=>10,
              'tpl'=>'subpdo_test',
              'showLog'=>1,
          ]}
          И этот код я уже считаю простеньким :-). Есть у меня подобные конфиги и на 571 строку! Жесть.
          Вот вывел:
      Александр Туниеков
      03 марта 2020, 20:38
      0
      Потом сложно обновлять сайты, и нужно все файлы сверять.
      Надеюсь Василий пул реквест примет и будет стандарт. Подзапросы нужны, хотя и не часто.
      iWatchYouFromAfar
      03 марта 2020, 21:23
      +1
      PR отредактируйте, чтобы код был написан красиво и по тому стандарту, который используется в pdoTools.



      P.S.
      В каждой строчке…
      Василий Наумкин
      04 марта 2020, 04:36
      +5
      Я уже не принял предыдущий PR и пропихивать мне его еще раз, под видом необходимого для подзапросов — очень странно.

      Какая связь вообще между генерацией SQL запроса в БД и шаблонизатором?

      Ты вот такое прям серьёзно пишешь, это не прикол?

      Может сейчас Василий Наумкин примет.
      Нет конечно, не примет. Ты меня за дурака держишь, или что?

      Да хоть бы отформатировал в PSR-2 свою писанину, чтобы читать это возможно было.


      Это ты еще и 2 новых версии pdoTools сразу выпустил? Ну вообще орёл.
        Александр Туниеков
        04 марта 2020, 14:10
        0
        под видом необходимого для подзапросов
        Ладно счас протестирую на коде из коммента. Поставил чистый pdoTools 2.11.3-pl. Ответ:
        0.0009770: SQL prepared "SELECT tSkladDetNSLink.id, Smena.id as smena_id, () as on_next_smena_id
        Подзапроса нет. Заменяем pdofetch.class.php.
        Все правильно выведено :-). Add Fenom soft mode не потребовалось.
        Страницы сайта не работают. Ошибка pdotools.class.php: 989) Unexpected tag 'display' in 0b3013274c174a9c5505daeb0e70dfc6 line 27, near '{display:' < — there
        Через modDevTools заменяю все {display на { display. Затем также {font
        Сайт заработал. В getTables тоже все работает :-). Ну я написал, что не все тестировал. Что-то когда-то не запустилось, а с Add Fenom soft mode заработало. И дальше я со стандартным пакетом не работал. И тут
        Эта возможно с этой правкой Add Fenom soft mode… Без нее, скорей всего, феном не поймет
        , тоже оговорился что скорее всего.

        PR Add Fenom soft mode не требуется. Если он вам так не нравиться, подзапросы можно принять без него. Актуальные изменения только в pdofetch.class.php.
        Правок не много и сами можете написать так как вам хочется. Только синтаксис subpdo просьба сохранить, но тоже не обязательно :-). 1 сниппет можно и поправить.
          Василий Наумкин
          04 марта 2020, 15:24
          0
          Саша, ты несёшь такую пургу, что я просто теряюсь.

          Скажи пожалуйста, каким образом у тебя построение запроса через xPDO приводит к ошибке работы Fenom? Это откуда должны расти руки, чтобы так получалось? Ты понимаешь, что Fenom в pdoTools был добавлен лишь в версии 2.0, и как-то до этого запросы прекрасно строились без него?

          Пока ты не ответишь на этот вопрос, я не вижу смысла продолжать общение.
            Александр Туниеков
            04 марта 2020, 15:55
            0
            Саша, ты несёшь такую пургу, что я просто теряюсь.
            Для меня вроде все логично что я пишу, но я могу ошибаться и у людей с разным опытом разные мнения. И не супер писатель я. Не всегда понятно пишу. Надо общаться и писать просто больше…
            Скажи пожалуйста, каким образом у тебя построение запроса через xPDO приводит к ошибке работы Fenom?
            Что-то я совсем не понял с честь чего у вас такой вопрос?? «построение запроса через xPDO приводит к ошибке работы Fenom» — вроде нигде такого не говорил. Василий, пожалуйста, поясните, что вы имеете в виду.
              Василий Наумкин
              04 марта 2020, 18:55
              0
              Что-то я совсем не понял с честь чего у вас такой вопрос?? «построение запроса через xPDO приводит к ошибке работы Fenom» — вроде нигде такого не говорил.
              У тебя с памятью беда, или с логикой?



              Вот это вот — оно про что?

              Почему у тебя какие-то ошибки в парсинге именно после выполнения запроса? Какие ты там display и font меняешь, зачем? Какое оно имеет отношение к запросам или подзапросам в БД?

              Или ты (я только сейчас об этом подумал) проверяешь свой новый придуманный синтаксис на pdoFetch с твоими изменениями, и без них? И приводишь как доказательство, что твой синтаксис без твоих изменений в pdoFetch не работает?

              Если это и правда так, то я вообще уже не знаю, куда в скорую звонить, в какой регион.
                Александр Туниеков
                04 марта 2020, 19:31
                0
                проверяешь свой новый придуманный синтаксис на pdoFetch с твоими изменениями, и без них? И приводишь как доказательство, что твой синтаксис без твоих изменений в pdoFetch не работает?
                1) Сперва проверил синтаксис на чистом pdoTools. Понятно дело ошибка.
                2) Проверил синтаксис только с заменой pdoFetch. Заработало. То есть
                Я уже не принял предыдущий PR

                принимать этот PR Не требуется..
                3) Ну и на всякий случай проверил как весь сайт без предыдущего PR будет работать. Нормально работает. (Только в стилях пробелов понаставил).

                Сейчас подготовлю PR чисто для подзапросов. Еще через минут 20 будет.
                  Василий Наумкин
                  04 марта 2020, 19:33
                  +1
                  принимать этот PR Не требуется..
                  А нафига ж ты его прислал с своём PR?

                  Еще через минут 20 будет.
                  Не надо.
                    Александр Туниеков
                    04 марта 2020, 19:40
                    -2
                    А нафига ж ты его прислал с своём PR?
                    Торопился не проверил. И мне он нравиться :-).
                    Не надо.
                    Подсадили всех на pdoTools, а теперь нужные правки отказываетесь принять? :-) Проявите ответственность :-)
                      Василий Наумкин
                      04 марта 2020, 19:43
                      +1
                      И мне он нравиться :-).
                      Ну не может быть хороший программист неграмотным. tsya.ru

                      Проявите ответственность :-)
                      Я и так много времени на тебя потратил. Иди, просвещайся.
        Сергей Шлоков
        04 марта 2020, 07:34
        +7
        Зачем стучаться в закрытую дверь? Просто сделай отдельный пакет. Кому надо поставит. Не нужно лезть в исходники!!!
        Я, например, когда начинал свой путь в MODX и мне надо было добавить функционал в Tickets, сделал отдельный TicketMessages, расширяющий исходный компонент, в который добавил всё, что мне надо. Я не мучал автора своими пулами.
          Александр Туниеков
          04 марта 2020, 13:02
          0
          Не нужно лезть в исходники!!!
          Думал расширить феном, но там все функции оказались privite и protected. И меня это так разочаровало, что функции pdoTools я и не думал расширять, а тупо писал что мне нужно в исходники. Иногда нужно исходники править, чтоб не усложнять код и, если исходники обновились, чтобы компонент смог работать.
          Я не мучал автора своими пулами.
          Зря :-). Авторы бывают ленивыми и зазнайками. Их надо мучать, чтоб прогресс был. Подзапросы вроде вещь актуальная. Разве нет?
          И не стоит плодить кучу разных компонентов. В wordpress, взяв сделанный кем-то сайт, приходиться изучать десяток новых плагинов. Такой компонент как pdoTools лучше, чтоб один был и со стандартным синтаксисом.
            Василий Наумкин
            04 марта 2020, 15:30
            +3
            Авторы бывают ленивыми и зазнайками. Их надо мучать, чтоб прогресс был.
            А еще авторы бывают опытными, и понимающими, что нужно их дополнениям, а что нет.

            Пиши свои допы, развивай — Сергей верно говорит.

            Подзапросы вроде вещь актуальная. Разве нет?
            Внезапно, нет.

            pdoTools появился в 2013 году и целых 7 лет эти подзапросы никого не волновали. И сейчас не волнуют, увы.
              Александр Туниеков
              04 марта 2020, 16:01
              0
              Меня волновали. Года 3 :-). Просто обходился чистым sql. Думаю, далеко не всем, но нужны. Может просто никто не говорил. Вообще интересно опрос устроить. Правда на modx.pro опросов нет :-(.
                Александр Туниеков
                04 марта 2020, 16:14
                0
                Пиши свои допы, развивай — Сергей верно говорит.
                Ниже пример с подзапросом. Нужно для одного этапа производства детали получить на когда запланирован следующий этап. С измененным pdoTool, это можно получить через pdoResources. Не надо писать никаких сниппетов. Их уже и так целая куча.
                Как можно сделать доп, чтобы можно было так же через pdoResources вывести нужную информацию, не меняя pdoTools?
                {'!pdoResources' | snippet :[
                    'loadModels'=>'tSklad',
                    'subpdo'=>[
                        'test'=>[
                            'class'=>'tSkladDetNSLink',
                            'alias'=>'NextDNL',
                            'select'=>[
                                'NextDNL'=>'NextDNL.smena_id',
                            ],
                            'leftJoin'=>[
                                'NextS'=>[
                                    'class'=>'tSkladSmena',
                                    'on'=>'NextS.id=NextDNL.smena_id',
                                    'where'=>[
                                        'NextS.date > Smena.date',
                                    ],
                                ],
                            ],
                            'where'=>[
                                'NextS.date > Smena.date',
                            ],
                            'sortby'=>[
                                'NextS.date'=>'ASC',
                                'NextS.number'=>'ASC',
                            ],
                            'limit'=>1,
                        ],
                    ],
                    'class'=>'tSkladDetNSLink',
                    'select'=>[
                        'tSkladDetNSLink'=>'tSkladDetNSLink.id,Smena.id as smena_id, ({$subpdo.test}) as on_next_smena_id',
                    ],
                    'leftJoin'=>[
                        'Smena'=>[
                            'class'=>'tSkladSmena',
                            'on'=>'Smena.id=tSkladDetNSLink.smena_id',
                        ],
                    ],
                    'where'=>[
                        'Smena.id > 0',
                    ],
                    'sortby'=>[
                        'tSkladDetNSLink.id'=>'DESC',
                    ],
                    'limit'=>10,
                    'tpl'=>'subpdo_test',
                    'showLog'=>1,
                ]}
            Александр Туниеков
            04 марта 2020, 14:22
            0
            А авторы Tikkets вообще собираются редактор сообщений обновлять?
            Офтопик (скрытый раскрывающейся блок) вроде уже давно стандарт. Километры кодов, логов и запросов нагружают восприятие текста, а вырезать лишнее замучишся. В офтопик проще засунуть и восприятие не нагружает и кому надо может все полностью посмотреть.
            Еще выделение цветом блока в блоке кода тоже хорошо было бы. И загрузка файлов без перехода в Файлохранилище тоже не помешает.
              Василий Наумкин
              04 марта 2020, 15:21
              +3
              А авторы Tikkets вообще собираются редактор сообщений обновлять?
              Нет, не собираются.

              Авторам Tickets (обрати внимание на правильное написание) есть много чем другим заняться. Судя по твоему энтузиазму, ты легко запилишь прекрасный форк, на который все пользователи Tickets легко перейдут без потери данных.

              И будешь его потом поддерживать бесплатно, годами.
                Александр Туниеков
                04 марта 2020, 16:20
                -1
                ты легко запилишь прекрасный форк
                Запилю :-). Надо для работы. Не легко :-(.
                И будешь его потом поддерживать бесплатно, годами.
                Не буду :-). Наверно передам кому-нибудь, если будут желающие. Но пока такой ситуации нет, так что вопрос открытый. Проблемы решаю по мере поступления.
              vectorserver
              04 марта 2020, 14:55
              +1
              Полная хрень! Зачем изобретать велосипед и влезать в ядро pdoTools ради 1-3 вложенных запросов, если есть xPDO.getCollection!?
              Вполне логично написать свой сниппет или плагин!
                Александр Туниеков
                04 марта 2020, 15:06
                0
                Уф… Пример напишите запроса с xPDO.getCollection раз. Два pdoTools удобнее.
                Вполне логично написать свой сниппет или плагин!
                Лишние сниппеты не нужны!!! А, кстати, плагин тут причем?
                Короче не морочте мне голову :-)
                  Михаил
                  04 марта 2020, 17:19
                  0
                  Что то странно, то не подходит, это тоже. )))
                    vectorserver
                    05 марта 2020, 09:00
                    0
                    $query = $xpdo->newQuery('Box');
                    $query->select($xpdo->getSelectColumns('Box'));
                    $query->select(array(
                      'Owner.name'
                    ));
                    $query->leftJoin('Owner','Owner');
                    $boxes = $xpdo->getCollection('Box',$query);
                    Ответ про плагин: плагином можно сформировать ответ после сохранения ресурса к примеру или наоборот подгрузить.
                  Василий Наумкин
                  04 марта 2020, 19:36
                  +2
                  Нужен был запрос типа такого:
                  Александр не знает, что xPDO и следовательно, pdoTools, прекрасно понимают сырые запросы, если засунуть их в строку внутри массива.

                  И тогда вполне возможно написать даже то, что он приводит в начале заметки:
                  {'!pdoResources' | snippet :[
                      'class' => 'tSkladDetNSLink',
                      'select' => ['*
                          FROM `modx_tsklad_detail_naryad_smena_link` AS `tSkladDetNSLink`
                          LEFT JOIN `modx_tsklad_order_list` `Detail` ON Detail.id=tSkladDetNSLink.det_id
                          LEFT JOIN `modx_tsklad_orders` `Order` ON Order.id=Detail.sk_order_id
                          LEFT JOIN `modx_tsklad_naryad` `Naryad` ON Naryad.id=tSkladDetNSLink.naryad_id
                          LEFT JOIN `modx_tsklad_smena` `Smena` ON Smena.id=tSkladDetNSLink.smena_id
                          LEFT JOIN `modx_nomenclature_detail_nom` `DetailNom` ON DetailNom.id=Detail.nom_id
                          LEFT JOIN `modx_nomenclature_detail_class` `DetailClass` ON DetailClass.id=DetailNom.class_id
                          LEFT JOIN `modx_nomenclature_type_job` `NomTypeJob` ON NomTypeJob.id=DetailClass.type_job_id
                          LEFT JOIN (
                              SELECT NextDNL.det_id AS next_det_id, NextDNL.naryad_id AS next_naryad_id, NextN.name AS next_naryad_name, NextDNL.smena_id AS next_smena_id, NextS.date AS next_smena_date, NextS.number AS next_smena_number
                              FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
                              LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
                              LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
                              ORDER BY NextS.date ASC, NextS.number ASC) `NextDNL1` 
                                  ON tSkladDetNSLink.det_id = NextDNL1.next_det_id AND 
                                  (NextDNL1.next_smena_date > Smena.date OR (NextDNL1.next_smena_date = Smena.date AND NextDNL1.next_smena_number > Smena.number)
                          ) 
                          AND NextDNL1.next_smena_id = (
                              SELECT NextDNL.smena_id AS on_next_smena_id
                              FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
                              LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
                              LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
                              WHERE NextS.date > Smena.date OR (NextS.date = Smena.date AND NextS.number > Smena.number)
                              ORDER BY NextS.date ASC, NextS.number ASC
                              LIMIT 1
                          )
                          LEFT JOIN `modx_plazma_list` `PlazmaList` ON PlazmaList.det_id=tSkladDetNSLink.det_id
                      '],
                      'where' => [
                          "(`Detail`.`sech` = 'pryam' AND `Detail`.`name` = 'зонт' AND `DetailNom`.`A` = '2000' AND `DetailNom`.`B` = '1500' AND `DetailNom`.`a_s` = '500' AND `DetailNom`.`b_s` = '500' AND `Detail`.`metall` = '0,7Ц' AND `Detail`.`L` = '0' AND `Detail`.`comment` = 'тип 1, ф355 заузить под наш отвод' AND `tSkladDetNSLink`.`smena_id` = 65 AND `tSkladDetNSLink`.`naryad_id` = 8 AND `NextDNL1`.`next_smena_id` = '66' AND `PlazmaList`.`file_true` = '0')"
                      ],
                      'sortby' => 'Detail.sech DESC, Detail.name ASC, DetailNom.A DESC, DetailNom.B DESC, DetailNom.a_s DESC, DetailNom.b_s DESC, Detail.metall DESC, Detail.L DESC, Detail.comment',
                      'sortdir' => 'DESC'
                      'limit' => 0,
                      'showLog' => 1,
                  ]}

                  Запрос, вполне себе, подготавливается

                  У меня он не может быть выполнен просто потому, что таких таблиц в системе нет.

                  Но можно сравнить исходные параметры и конечный код — они идентичны, за исключением FROM из несуществующей таблицы (что при наличии модели tSkladDetNSLink будет заменено на FROM `modx_tsklad_detail_naryad_smena_link` AS `tSkladDetNSLink`) и экранирования сортировки (которой xPDO закрывает старую уязвимость).


                  Так что, кому уж прям очень нужны подзапросы в pdoTools — они уже там есть, с самого начала.
                    Александр Туниеков
                    04 марта 2020, 19:56
                    0
                    Блин. Мне не нужны сырые запросы. Мне надо, чтоб запрос был подготовлен. Вдруг я префикс базы захочу изменить, а в куче запросов он будет указан.
                      Василий Наумкин
                      04 марта 2020, 20:07
                      +5
                      Вдруг я префикс базы захочу изменить, а в куче запросов он будет указан.
                      Ну ты же любишь использовать плейсхолдеры в запросах, вот тебе еще один: {'table_prefix' | option}

                      А если серьёзно, то ты пишешь очень сложный запрос, который не понадобится 99% пользователей pdoTools, а может и вообще MODX.
                      Он не станет менее сложным, если засунуть его в массив Fenom, никто ничего от этого не выиграет.

                      Усилия по добавлению этого функционала не просто ничего не стоят, они отрицательные не длинной дистанции, потому что нужно будет отвечать на вопросы по конвертации этих твоих вложенных массивов в SQL.

                      Периодически будут находиться люди, пытающиеся наворотить какую-нибудь фигню с этими параметрами. Как сейчас это делают с долбаным tvFilters.

                      Рейтинг этой заметки на данный момент составляет 0 при 34 комментариях, что уже намекает на её полезность.

                      Я этот PR гарантированно не приму, удачи в развитии своих дополнений.
                        Александр Туниеков
                        04 марта 2020, 22:16
                        -2
                        А если серьёзно, то ты пишешь очень сложный запрос, который не понадобится 99% пользователей pdoTools, а может и вообще MODX
                        Если 1% понадобится, то уже неплохо. 99% не понадобиться — это не слишком хороший критерий. Взлетит не взлетит 100% не угадаешь. То есть, это критерий на способности предсказывать будущие. А оно не слишком предсказуемо.
                        Он не станет менее сложным, если засунуть его в массив Fenom, никто ничего от этого не выиграет.
                        А, кстати, тогда зачем вообще запросы описывать массивом феном? Можно же вообще писать чисто SQL.
                        XPDO это типа ORM. В нем получил объект и сразу можно что-то записать в базу. В pdoTools только чисто вывод.
                        Мне просто удобнее сам синтаксис pdoTools писать. И, так как запрос массив, есть возможность на лету его поменять. Приготовил массив запроса, а потом where добавляешь или удаляешь когда надо. На чисто sql менять where жуть. Код 5 лет назад :-). Ни pdoTools ни strftime еще не знал.
                        if(isset($_GET['date1'])){
                            $modx->setPlaceholder('date1',$_GET['date1']);
                            if(isset($_GET['date2'])){
                                $modx->setPlaceholder('date2',$_GET['date2']);
                            }
                            if($_GET['date1']!='' and $_GET['date2']==''){
                               $where = "where o.makedate >='".$_GET['date1']." 00:00:00' and l.status_id=1"; 
                            }elseif($_GET['date2']!=''){
                                $where = "where o.makedate >='".$_GET['date1']." 00:00:00' and o.makedate <='".$_GET['date2']." 23:59:59' and l.status_id=1";
                            }
                        }else{
                            $where = "where l.status_id=1";
                        }
                        Тоже для XPDO и pdoTools
                        $where = [ 'l.status_id'=>1];
                        if($_GET['date1']){
                            $modx->setPlaceholder('date1',$_GET['date1']);
                            $where['o.makedate:>='] = '".$_GET['date1']." 00:00:00'";
                        }
                        if($_GET['date2']){
                            $modx->setPlaceholder('date2',$_GET['date2']);
                            $where['o.makedate:<='] = '".$_GET['date2']." 23:59:59'";
                        }
                        Явно проще. Особенно когда фильтр больше на параметров 6.
                        А вот пример уже с феном.
                        {set $where = [
                                'Detail.flanec:NOT IN'=>[1,3],
                                'Detail.sech'=>'pryam',
                                ]}
                            {if $.get.sk_order_id}{set $where['Detail.sk_order_id']=$.get.sk_order_id}{/if}
                            {if $.get.smena_id}{set $where['tSkladDetNSLink.smena_id']=$.get.smena_id}{/if}
                            {if $.get.type_job_id}{set $where['DetailClass.type_job_id']=$.get.type_job_id}{/if}
                        Так что запрос в массиве штука полезная.
                        А вот подзапросов в массиве у меня не было. Поиграюсь, посмотрю, что можно с ними сделать. Хотя, конечно, их на каждом шагу внедрять не стоит.
                        Усилия по добавлению этого функционала не просто ничего не стоят, они отрицательные не длинной дистанции, потому что нужно будет отвечать на вопросы по конвертации этих твоих вложенных массивов в SQL.
                        Это аргумент. Отвечать на вопросы кучи начинающих прогеров не самая приятная перспектива. Но тормозить из-за этого компоненты или проекты?? Это раз. И два. Отвечать имеет смысл, если развивать свою команду. С которой можно делать очень большие проекты. Такие как linux, например. Думаю сеньор не предел развития программиста. Можно как-бы основать свою школу и стать что-то вроде академика.
                        Периодически будут находиться люди, пытающиеся наворотить какую-нибудь фигню в этими параметрами. Как сейчас это делают с долбаным tvFilters.
                        Будут явно. Люди пытаются решить свои задачи. Изучаем их задачи и пишем код, чтобы у них был инструмент для их задач :-). Прикалываюсь, если что :-). Но в каждой шутке доля шутки…

                        Резюме.
                        Я этот PR не приму, удачи в развитии своих дополнений.

                        Ну как хотите. Я то надеялся, что вот крутая фишка пользуйтесь. Но, возможно, это и не так круто как мне кажется. Подзапросы, когда они мне понадобятся буду писать в своей версии синтаксиса pdoTools. Просто потому, что мне так удобнее. Сейчас, практические преимущества этой версии не понятны :-(.

                        PS. Сюда $fields массивом иногда приходят.
                        $fields = 'SQL_CALC_FOUND_ROWS ' . $fields;
                        В итоге запрос выглядит так:
                        SELECT SQL_CALC_FOUND_ROWSArray FROM
                        Где $fields массивом становиться не нашел. Просто implode сделал. Может разберетесь?
                          Артем
                          04 марта 2020, 22:36
                          +4
                          Дико извиняюсь, не удержался

                          $where['o.makedate:>='] = '".$_GET['date1']." 00:00:00'";
                          $where['Detail.sk_order_id']=$.get.sk_order_id
                          Сергей Шлоков
                          05 марта 2020, 07:35
                          +3
                          Если бы ты принял этот PR, пришлось бы pdoTools удалять.

                          Магистр кода 99 уровня
                          $modx->setPlaceholder('date1',$_GET['date1']);
                          $where['o.makedate:>='] = '".$_GET['date1']." 00:00:00'";
                          Ну нахер. Штопать таки дыры, искать в коде display и fonts. И ещё Бог знает чего.
                            Александр Туниеков
                            05 марта 2020, 11:39
                            0
                            Ну если вы магистр напишите внятную инструкцию как делать санацию параметров.
                            $where['id'] = (int)$_POST['id'];
                            (int) это понятно. Для даты strftime можно использовать. А остальное? string, decimal, float. Хотя тоже все понятно. Только писать такие преобразования во все сниппеты долго. Плагин или что-то такое посмотрю. Ну здесь на интранет хакеров лет 10 не предвидеться. А если и предвидятся, то взлом внутреннего сайта это уже мелочь.
                              Сергей Шлоков
                              05 марта 2020, 12:22
                              +1
                              Давно уже написано. Да и в инете полно такой информации.
                                Александр Туниеков
                                05 марта 2020, 12:32
                                0
                                Читал год назад. (int) использую, а с санацией строки проблема вышла. В поле название города кавычки писались и его никто найти не мог. Так что, санация это работа надолго :-(.
                              Александр Туниеков
                              05 марта 2020, 12:05
                              0
                              Если бы ты принял этот PR, пришлось бы pdoTools удалять.
                              Дыры много где есть. И никто вам не мешает взять и переписать PR или что-то еще без дыр, если они там есть. Вроде ничего такого не должно быть. Все стандартные дыры MODX только.
                        Павел Бигель
                        04 марта 2020, 21:03
                        0
                        Я в целом не понимаю, зачем все это.
                        Такие сложные запросы я выполню с помощью $modx->query

                        Сколько будет выполнятся такой вопрос, если сверху на него навесить абстракцию в виде pdoTools? Сорок лет?
                          Александр Туниеков
                          04 марта 2020, 22:44
                          0
                          Сколько будет выполнятся такой вопрос, если сверху на него навесить абстракцию в виде pdoTools? Сорок лет?
                          Преобразовать массив на 10-40 ключей в строку 100-600 символов? Явно миллисекунды :-).

                          После последней правки, подзапрос добавил плюс 7 мс к общему выполнению запроса. getChunk операция затратная. Целых 5 мс :-).
                          Андрей Степаненко
                          05 марта 2020, 09:14
                          1
                          +1
                          'select' => ['*
                                  FROM `modx_tsklad_detail_naryad_smena_link` AS `tSkladDetNSLink`
                                  LEFT JOIN `modx_tsklad_order_list` `Detail` ON Detail.id=tSkladDetNSLink.det_id
                                  LEFT JOIN `modx_tsklad_orders` `Order` ON Order.id=Detail.sk_order_id
                                  LEFT JOIN `modx_tsklad_naryad` `Naryad` ON Naryad.id=tSkladDetNSLink.naryad_id
                                  LEFT JOIN `modx_tsklad_smena` `Smena` ON Smena.id=tSkladDetNSLink.smena_id
                                  LEFT JOIN `modx_nomenclature_detail_nom` `DetailNom` ON DetailNom.id=Detail.nom_id
                                  LEFT JOIN `modx_nomenclature_detail_class` `DetailClass` ON DetailClass.id=DetailNom.class_id
                                  LEFT JOIN `modx_nomenclature_type_job` `NomTypeJob` ON NomTypeJob.id=DetailClass.type_job_id
                                  LEFT JOIN (
                                      SELECT NextDNL.det_id AS next_det_id, NextDNL.naryad_id AS next_naryad_id, NextN.name AS next_naryad_name, NextDNL.smena_id AS next_smena_id, NextS.date AS next_smena_date, NextS.number AS next_smena_number
                                      FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
                                      LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
                                      LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
                                      ORDER BY NextS.date ASC, NextS.number ASC) `NextDNL1` 
                                          ON tSkladDetNSLink.det_id = NextDNL1.next_det_id AND 
                                          (NextDNL1.next_smena_date > Smena.date OR (NextDNL1.next_smena_date = Smena.date AND NextDNL1.next_smena_number > Smena.number)
                                  ) 
                                  AND NextDNL1.next_smena_id = (
                                      SELECT NextDNL.smena_id AS on_next_smena_id
                                      FROM `modx_tsklad_detail_naryad_smena_link` AS `NextDNL`
                                      LEFT JOIN `modx_tsklad_smena` `NextS` ON NextS.id=NextDNL.smena_id
                                      LEFT JOIN `modx_tsklad_naryad` `NextN` ON NextN.id=NextDNL.naryad_id
                                      WHERE NextS.date > Smena.date OR (NextS.date = Smena.date AND NextS.number > Smena.number)
                                      ORDER BY NextS.date ASC, NextS.number ASC
                                      LIMIT 1
                                  )
                                  LEFT JOIN `modx_plazma_list` `PlazmaList` ON PlazmaList.det_id=tSkladDetNSLink.det_id
                              '],
                          Никогда не понимал зачем такие мега запросы писать. Бесполезных join-нов куча. Этаж сколько выборка этого всего идти будет. А потом еще сидеть постоянно разбирать что там написано.

                          Для таких запросов проще временную таблицу сделать куда будут данные сливаться на бэкенде, и потом уже готовые данные забирать на фронте.
                          Такими запросами, только фронт напрягать.

                          Почему то всегда охота все в один запрос запихать, но по опыту еще больше времени тратишь на всякие такие выборки.
                          Еще как вариант делать несколько запросов и получать id которые уже потом идут where в виде product_id IN (тут список id из какой то таблицы)

                          На примере получения товаров:
                          Этот код будет делать выборку в десятки раз быстрее:
                          $ids = [];
                          $q = $modx->newQuery('modResource');
                          $q->select('id');
                          $q->where(array(
                              'published' => 1,
                              'class_key' => 'msProduct',
                          ));
                          if ($q->prepare() && $q->stmt->execute()){
                              while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
                                  $ids[] = $row['id'];
                              }
                          }
                          
                          
                          /* @var msProductData $object*/
                          $q = $modx->newQuery('msProductData');
                          $q->where(array(
                              'id:IN' => $ids
                          ));
                          if($objectList = $modx->getCollection('msProductData', $q)) {
                              foreach ($objectList as $object) {
                                 echo '<pre>';
                                 print_r( $object->toArray()); die;
                              }
                          }


                          Чем
                          /* @var msProduct $object*/
                          $q = $modx->newQuery('msProductData');
                          $q->where(array(
                              'Product.published' => 1,
                              'Product.class_key' => 'msProduct',
                          ));
                          $q->innerJoin('msProduct','Product','Product.id = msProductData.id');
                          if($objectList = $modx->getCollection('msProductData', $q)) {
                              foreach ($objectList as $object) {
                                  echo '<pre>';
                                  print_r( $object->toArray()); die;
                              }
                          }
                          join — зло еще то))
                            Александр Туниеков
                            05 марта 2020, 11:50
                            0
                            Никогда не понимал зачем такие мега запросы писать. Бесполезных join-нов куча. Этаж сколько выборка этого всего идти будет. А потом еще сидеть постоянно разбирать что там написано.
                            Выборка достаточно быстро идет. Какие-то тормоза не заметны. И в каком таком случае не приходиться разбирать что написано? Что в сниппете что в запросе одинаково приятно.
                            Для таких запросов проще временную таблицу сделать куда будут данные сливаться на бэкенде, и потом уже готовые данные забирать на фронте.
                            И еще за актуальность временных таблиц следить. Причем разных нужных данных может быть много вариантов. Вроде кол-во перестановок пропорционально n! Если 2 таблицы по 5 колонок, то кол-во возможных выборок 10! = 3628800 вариантов :-).
                              Андрей Степаненко
                              05 марта 2020, 12:06
                              0
                              И еще за актуальность временных таблиц следить. Причем разных нужных данных может быть много вариантов. Вроде кол-во перестановок пропорционально n! Если 2 таблицы по 5 колонок, то кол-во возможных выборок 10! = 3628800 вариантов :-).
                              Временная таблица!
                              Актуальность в одну минут, вообще не принципиально)))
                                Александр Туниеков
                                05 марта 2020, 12:20
                                0
                                Актуальность в одну минут, вообще не принципиально)))
                                В смысле, крон настраивать запросы для этих таблиц писать. На 80 базовых таблиц — это офигенное кол-во временных. Сайт только висеть будет их генерировать.
                              vectorserver
                              06 марта 2020, 10:01
                              0
                              +1
                                Артем
                                06 марта 2020, 19:41
                                +1
                                Справедливости ради, я бы поспорил про join.
                                IN — еще большее зло, если в нем указана целая простыня (тысячи или десятки тысяч) id.
                                Вот ради интереса копипастнул себе на один из проектов оба варианта и, как я и ожидал, второй существенно быстрее.
                                На проекте 29705 товаров.
                                Ну и я заменил getCollection на getCount, потому что получать 30к объектов — самоубийство, даже через более оптимальный getIterator.

                                Вариант с IN:
                                Total time: 0.7136 s
                                Вариант с join:
                                Total time: 0.4630 s
                                Но вариант с IN может оказаться действительно быстрее там, где небольшой перечень id, тут согласен.
                                  Андрей Степаненко
                                  06 марта 2020, 20:05
                                  0
                                  Наверное поле куда делался IN, без индекс, и это обычное текстов поле.
                                    Артем
                                    06 марта 2020, 20:09
                                    0
                                    Не, это же таблица ms2_products, где id — PK и, естественно, с индексом.
                                    Дело в количестве указанных id, их слишком много, поэтому join работает быстрее.
                                      Андрей Степаненко
                                      06 марта 2020, 20:11
                                      0
                                      Как)) Мне просто интересно?
                                      getCollection — дергает все поля как с site_content так и c ms2_products
                                      Как он может быть быстрее даже с этого ракурса?
                                      Обращение к msProduct?
                                    Андрей Степаненко
                                    06 марта 2020, 20:07
                                    0
                                    Покажите код? Один и другой
                                      Артем
                                      06 марта 2020, 20:31
                                      0
                                      Да я прям копипастнул, только getCollection на getCount заменил

                                      Вариант с IN:
                                      $ids = [];
                                      $q = $modx->newQuery('modResource');
                                      $q->select('id');
                                      $q->where(array(
                                          'published' => 1,
                                          'class_key' => 'msProduct',
                                      ));
                                      if ($q->prepare() && $q->stmt->execute()){
                                          while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
                                              $ids[] = $row['id'];
                                          }
                                      }
                                      
                                      
                                      /* @var msProductData $object*/
                                      $q = $modx->newQuery('msProductData');
                                      $q->where(array(
                                          'id:IN' => $ids
                                      ));
                                      if($objectCount = $modx->getCount('msProductData', $q)) {
                                          return $objectCount;
                                      }
                                      Total time: 0.4705 s
                                      Вариант с join:
                                      /* @var msProduct $object*/
                                      $q = $modx->newQuery('msProductData');
                                      $q->where(array(
                                          'Product.published' => 1,
                                          'Product.class_key' => 'msProduct',
                                      ));
                                      $q->innerJoin('msProduct','Product','Product.id = msProductData.id');
                                      if($objectCount = $modx->getCount('msProductData', $q)) {
                                          return $objectCount;
                                      }
                                      Total time: 0.4096 s
                                      Сейчас разница уже не такая большая, но она все еще в пользу join'а.
                                        Андрей Степаненко
                                        06 марта 2020, 20:34
                                        0
                                        ну это интересно)) Запомню на будущие.
                                        А теперь тоже самое только к примеру с получением pagetitle и price)
                                        Вот тут явно увидите разницу
                                          Артем
                                          06 марта 2020, 21:10
                                          0
                                          pagetitle и price не самый удачный пример, способом с IN их не очень удобно доставать)
                                          я бы тут из-за удобства выбрал join, хоть он действительно будет немного медленнее

                                          Вариант с IN:
                                          $data = [];
                                          $c = $modx->newQuery('msProduct', ['class_key' => 'msProduct', 'published' => 1]);
                                          $c->select(['id', 'pagetitle']);
                                          if ($c->prepare() && $c->stmt->execute()) {
                                              $data = $c->stmt->fetchAll(PDO::FETCH_KEY_PAIR);
                                          }
                                          
                                          
                                          $c = $modx->newQuery('msProductData', ['id:IN' => array_keys($data)]);
                                          $c->select(['id', 'price']);
                                          if ($c->prepare() && $c->stmt->execute()) {
                                              while ($item = $c->stmt->fetch(PDO::FETCH_ASSOC)) {
                                                  $data[$item['id']] = ['pagetitle' => $data[$item['id']], 'price' => $item['price']];
                                              }
                                          }
                                          print_r($data);
                                          return; 
                                          Total time: 0.4112 s
                                          Memory: 22 MB
                                          Можно было еще сделать через ASSOC и array_column, но это медленнее, как мне показалось

                                          Вариант с join:
                                          $c = $modx->newQuery('msProduct', ['msProduct.class_key' => 'msProduct', 'msProduct.published' => 1]);
                                          $c->select(['msProduct.pagetitle', 'Data.price']);
                                          $c->innerJoin('msProductData', 'Data', 'msProduct.id = Data.id');
                                          if ($c->prepare() && $c->stmt->execute()) {
                                              print_r($c->stmt->fetchAll(PDO::FETCH_ASSOC));
                                          }
                                          return;
                                          Total time: 0.4927 s
                                          Memory: 18 MB
                                            Андрей Степаненко
                                            06 марта 2020, 21:23
                                            0
                                            При учете что мне к примеру не нежно ничего получать из site_content а только id, оно еще быстрее будет.
                                            Ноооооо если мы используем getCollection) То innerJoin не позволит сделать select!
                                            Так что скорость ощутим упадет))
                                            Кстати, твой код, исключает getCollection. О чем я писал когда говорил о IN.
                                            Так что если по играть, с кодом, то явно увидишь разницу.
                                              Сергей Шлоков
                                              07 марта 2020, 05:28
                                              0
                                              При учете что мне к примеру не нежно ничего получать из site_content а только id, оно еще быстрее будет.
                                              Не будет. Только если ты поле контент гнать не будешь. Даже 3G не заметит разницы в несколько небольших полей. Простыня айдишников весит больше, чем price и pagetitle вместе взятые.
                                                Сергей Шлоков
                                                07 марта 2020, 05:42
                                                0
                                                Хотя эти айдишники будут внутри сетки гоняться.
                                          Андрей Степаненко
                                          06 марта 2020, 20:37
                                          0
                                          if($objectCount = $modx->getCount('msProductData', $q)) {
                                          return $objectCount;
                                          }
                                          в $objectCount запишется 0
                                          Приходилось встречаться что в итоге 0 это тоже true, скорей всего это в старом каком то php
                                          по этому лучше так
                                          if($count = (boolean)$modx->getCount('modResource', array())){
                                              
                                          }
                                            Артем
                                            06 марта 2020, 21:14
                                            0
                                            На самом деле getCount всегда возвращает число, поэтому проверка по сути не нужна)
                                            Можно было прям сразу
                                            return $modx->getCount('modResource', $q));
                                            Сергей Шлоков
                                            07 марта 2020, 05:39
                                            0
                                            В варианте с join нет селекта. Т.е. условия теста не равнозначны.
                                        Сергей Шлоков
                                        07 марта 2020, 05:23
                                        0
                                        Этот код будет делать выборку в десятки раз быстрее:
                                        На практике или в теории? Уверен, если замерить, то join выиграет. Ибо один подготовленный запрос отработает быстрее, чем 2 запроса. Тем более со вторым запросом нужно гнать тонны айдишников по сетке.

                                        join — зло еще то))
                                        Только, если ты не умеешь его готовить )) Молотком можно и гвозди забивать и шурупы.
                                        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                                        64