I create an array within which 2 elements. These elements, in turn, are also arrays; they contain the result of a sample ::find from two different models. The problem is in sorting the data by keys.
Here is the code that does the selection and combines it:
$mergedArray = array_merge( //выборка из таблицы thisDay ThisDay::find() ->where( new Expression( "day = :dateDay" . " AND id_region = :id_region" . " AND month = :month", [":dateDay" => $dateDay, ":month" => $currentMoth, ":id_region" => REGION_ID])) // ->orderBy("news_date DESC") ->all(), //поиск по таблице News с лимитом 4 - (минус) кол-во новостей в ThisDay News::find() ->alias("n") ->select() ->where( //выборка по дню new Expression("EXTRACT(DAY FROM cdate) = :userDay " // выборка по региону, . "AND id_region = :id_region " // выборка по месяцу, . "AND EXTRACT(MONTH FROM cdate) = :userMonth " // выборка по году, . "AND EXTRACT(YEAR FROM cdate) " // выборка по статусу, . "AND status > :stat AND n.id NOT IN" //и чтобы id не совпадало с id из таблицы this_day . " (SELECT id_news FROM this_day)", //агрументы для бандинга [":userDay" => $dateDay, ":userMonth" => $currentMoth, ":id_region" => REGION_ID, ":stat" => 1])) //новости с самым высоким рейтингом ->joinWith("rating nr") ->orderBy("nr.rate DESC") ->limit(4 - ThisDay::find() ->where( new Expression( "day = :dateDay" . " AND id_region = :id_region", [":dateDay" => $dateDay, ":id_region" => REGION_ID])) ->count()) //группировка и сортировка по дате ->orderBy("cdate_int DESC") ->groupBy("EXTRACT(YEAR FROM cdate)") ->all()); At the exit ( var_dump($mergedArray)); ) the structure is as follows:
array(4) { [0]=> object(***\***\***\***\ThisDay)#244 (8) {(тут пошел массив для нулевого элемента массива и первого для ThisDay за 2017 год)} [1]=> object(***\***\***\***\ThisDay)#244 (8) {(тут пошел массив для первого элемента массива и второго для ThisDay за 2016 год)} [2]=> object(***\***\***\***\News)#244 (8) {(тут пошел массив для второго элемента массива и первый для News за 2017 год)} [3]=> object(***\***\***\***\News)#244 (8) {(тут пошел массив для третьего элемента массива и второй для News за 2016 год)} Important: depending on the results of the sampling, some of the array may be empty at all and this will work correctly. Each array is sorted separately from each other in the correct order from the largest to the smallest, that is, without each other, they look correct. But as soon as arrays of two and year elements of the sample do NOT go in perfect order, for example, "2017 2016 2015 2014" , but contain, for example, the following order: "2017 2016 2016 2017" then they are sorted separately from each other, like this: "2017 2016 2017 2016"
I'm trying to solve this problem by re-indexing arrays separately from each other:
//индексирую, если ThisDay $indexedThisDay = ArrayHelper::index($mergedArray, function ($element) { if ($element instanceof ThisDay) { return (int) \Yii::$app->formatter->asDate($element['news_date'], 'yyyy'); // return $element['news_date']; } }); //индексирую, если News $indexedNews = ArrayHelper::index($mergedArray, function ($element) { if ($element instanceof News) { return (int) \Yii::$app->formatter->asDate($element['cdate_int'], 'yyyy'); // return $element['cdate_int']; } }); ['news_date'] and ['cdate_int'] store data in the same timeStamp format, but because of the law, the field names are different. Now here in each variable by array, their structure ( var_export($indexedThisDay); ) is approximately as follows:
array ( 2017 => ****\****\****\****\ThisDay::__set_state(array((тут пошел элемент массива для 2017 года ThisDay и т.д)) 2016 => ****\****\****\****\ThisDay::__set_state(array((тут пошел элемент массива для 2017 года ThisDay и т.д)) (var_export($indexedNews);) 2017 => ****\****\***\***\News::__set_state(array((тут пошел элемент массива для 2017 года ThisDay и т.д)) 2016 => ***\***\***\***\News::__set_state(array((тут пошел элемент массива для 2017 года ThisDay и т.д)) Great, now separately from each other I can sort them by key (year). But I need to send all 4 items to the view. Therefore, I do the following:
$model = array_merge($indexedThisDay, $indexedNews); Ie, I merge two arrays in order to merge them into one and sort it already, but this is what var_dump($model); produces var_dump($model);
array(4) { [0]=> object(***\***\***\***\ThisDay)#244 (8) {(тут пошел массив для нулевого элемента массива и первого для ThisDay за 2017 год)} And so all 4 elements.
Ie, I again come back to the fact that I have an incorrectly sorted array of 4 values, the keys are lost.
Question: how can I sort my sample result as if it were a single array, how to correctly combine them for sorting? I will be glad to criticism and advice on how to solve the problem with sorting by key or by field values ['news_date'] and ['cdate_int']
UPD: I tried to sort like this:
$arrOut = array(); foreach ($result as $subArr) { // разберем подмассив на ключи и значения foreach ($subArr as $key => $val) { // если значение с таким ключом существует, и оно больше текущего, то ничего не делаем if (isset($arrOut[$key]) && $arrOut[$key] > $val) continue; // добавляем значение во внешний массив $arrOut[$key] = $val; } } and so:
function sortBy($array) { usort($array, function ($item1, $item2) { if ($item1 instanceof News) { if ($item1['cdate_int']) { $newsArr = $item1['cdate_int']; } } if ($item2 instanceof ThisDay) { if ($item2['news_date']) { $thisDayArr = $item2['news_date']; } } if ($thisDayArr == $newsArr) return 0; return ($thisDayArr < $newsArr) ? -1 : 1; }); return true; } $this->sortBy($model); But this gave no results, the arrays are still sorted separately from each other.
$value->getImgUrl()- Evgeny Shalaev