18e0e1b25SGreg Roach<?php 28e0e1b25SGreg Roach 38e0e1b25SGreg Roach/** 48e0e1b25SGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 webtrees development team 68e0e1b25SGreg Roach * This program is free software: you can redistribute it and/or modify 78e0e1b25SGreg Roach * it under the terms of the GNU General Public License as published by 88e0e1b25SGreg Roach * the Free Software Foundation, either version 3 of the License, or 98e0e1b25SGreg Roach * (at your option) any later version. 108e0e1b25SGreg Roach * This program is distributed in the hope that it will be useful, 118e0e1b25SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 128e0e1b25SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138e0e1b25SGreg Roach * GNU General Public License for more details. 148e0e1b25SGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 168e0e1b25SGreg Roach */ 178e0e1b25SGreg Roach 188e0e1b25SGreg Roachdeclare(strict_types=1); 198e0e1b25SGreg Roach 208e0e1b25SGreg Roachnamespace Fisharebest\Webtrees\Services; 218e0e1b25SGreg Roach 228e0e1b25SGreg Roachuse Fisharebest\Webtrees\Auth; 238e0e1b25SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 24*81b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpNotFoundException; 258e0e1b25SGreg Roachuse Fisharebest\Webtrees\Module\ModuleBlockInterface; 268e0e1b25SGreg Roachuse Fisharebest\Webtrees\Module\ModuleInterface; 278e0e1b25SGreg Roachuse Fisharebest\Webtrees\Tree; 288e0e1b25SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 298e0e1b25SGreg Roachuse Illuminate\Support\Collection; 308e0e1b25SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 318e0e1b25SGreg Roachuse stdClass; 328e0e1b25SGreg Roach 338e0e1b25SGreg Roachuse function assert; 348e0e1b25SGreg Roachuse function is_numeric; 358e0e1b25SGreg Roach 368e0e1b25SGreg Roach/** 378e0e1b25SGreg Roach * Logic and content for the home-page blocks. 388e0e1b25SGreg Roach */ 398e0e1b25SGreg Roachclass HomePageService 408e0e1b25SGreg Roach{ 41c4943cffSGreg Roach private ModuleService $module_service; 428e0e1b25SGreg Roach 438e0e1b25SGreg Roach /** 448e0e1b25SGreg Roach * HomePageController constructor. 458e0e1b25SGreg Roach * 468e0e1b25SGreg Roach * @param ModuleService $module_service 478e0e1b25SGreg Roach */ 488e0e1b25SGreg Roach public function __construct(ModuleService $module_service) 498e0e1b25SGreg Roach { 508e0e1b25SGreg Roach $this->module_service = $module_service; 518e0e1b25SGreg Roach } 528e0e1b25SGreg Roach 538e0e1b25SGreg Roach /** 5424c0163eSGreg Roach * Load a tree block. 558e0e1b25SGreg Roach * 568e0e1b25SGreg Roach * @param ServerRequestInterface $request 578e0e1b25SGreg Roach * 588e0e1b25SGreg Roach * @return ModuleBlockInterface 598e0e1b25SGreg Roach */ 6024c0163eSGreg Roach public function treeBlock(ServerRequestInterface $request): ModuleBlockInterface 618e0e1b25SGreg Roach { 628e0e1b25SGreg Roach $tree = $request->getAttribute('tree'); 638e0e1b25SGreg Roach assert($tree instanceof Tree); 648e0e1b25SGreg Roach 658e0e1b25SGreg Roach $block_id = (int) $request->getQueryParams()['block_id']; 668e0e1b25SGreg Roach 678e0e1b25SGreg Roach $block = DB::table('block') 688e0e1b25SGreg Roach ->where('block_id', '=', $block_id) 698e0e1b25SGreg Roach ->where('gedcom_id', '=', $tree->id()) 708e0e1b25SGreg Roach ->whereNull('user_id') 718e0e1b25SGreg Roach ->first(); 728e0e1b25SGreg Roach 7324c0163eSGreg Roach if ($block instanceof stdClass) { 748e0e1b25SGreg Roach $module = $this->module_service->findByName($block->module_name); 758e0e1b25SGreg Roach 7624c0163eSGreg Roach if ($module instanceof ModuleBlockInterface) { 778e0e1b25SGreg Roach return $module; 788e0e1b25SGreg Roach } 7924c0163eSGreg Roach } 8024c0163eSGreg Roach 8124c0163eSGreg Roach throw new HttpNotFoundException(); 8224c0163eSGreg Roach } 838e0e1b25SGreg Roach 848e0e1b25SGreg Roach /** 8524c0163eSGreg Roach * Load a user block. 868e0e1b25SGreg Roach * 878e0e1b25SGreg Roach * @param ServerRequestInterface $request 888e0e1b25SGreg Roach * @param UserInterface $user 898e0e1b25SGreg Roach * 908e0e1b25SGreg Roach * @return ModuleBlockInterface 918e0e1b25SGreg Roach */ 928e0e1b25SGreg Roach public function userBlock(ServerRequestInterface $request, UserInterface $user): ModuleBlockInterface 938e0e1b25SGreg Roach { 948e0e1b25SGreg Roach $block_id = (int) $request->getQueryParams()['block_id']; 958e0e1b25SGreg Roach 968e0e1b25SGreg Roach $block = DB::table('block') 978e0e1b25SGreg Roach ->where('block_id', '=', $block_id) 988e0e1b25SGreg Roach ->where('user_id', '=', $user->id()) 998e0e1b25SGreg Roach ->whereNull('gedcom_id') 1008e0e1b25SGreg Roach ->first(); 1018e0e1b25SGreg Roach 10224c0163eSGreg Roach if ($block instanceof stdClass) { 1038e0e1b25SGreg Roach $module = $this->module_service->findByName($block->module_name); 1048e0e1b25SGreg Roach 10524c0163eSGreg Roach if ($module instanceof ModuleBlockInterface) { 1068e0e1b25SGreg Roach return $module; 1078e0e1b25SGreg Roach } 10824c0163eSGreg Roach } 10924c0163eSGreg Roach 11024c0163eSGreg Roach throw new HttpNotFoundException(); 11124c0163eSGreg Roach } 1128e0e1b25SGreg Roach 1138e0e1b25SGreg Roach /** 1148e0e1b25SGreg Roach * Get a specific block. 1158e0e1b25SGreg Roach * 1168e0e1b25SGreg Roach * @param Tree $tree 1178e0e1b25SGreg Roach * @param int $block_id 1188e0e1b25SGreg Roach * 1198e0e1b25SGreg Roach * @return ModuleBlockInterface 1208e0e1b25SGreg Roach */ 1218e0e1b25SGreg Roach public function getBlockModule(Tree $tree, int $block_id): ModuleBlockInterface 1228e0e1b25SGreg Roach { 1238e0e1b25SGreg Roach $active_blocks = $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, Auth::user()); 1248e0e1b25SGreg Roach 1258e0e1b25SGreg Roach $module_name = DB::table('block') 1268e0e1b25SGreg Roach ->where('block_id', '=', $block_id) 1278e0e1b25SGreg Roach ->value('module_name'); 1288e0e1b25SGreg Roach 1298e0e1b25SGreg Roach $block = $active_blocks->first(static function (ModuleInterface $module) use ($module_name): bool { 1308e0e1b25SGreg Roach return $module->name() === $module_name; 1318e0e1b25SGreg Roach }); 1328e0e1b25SGreg Roach 1338e0e1b25SGreg Roach if ($block instanceof ModuleBlockInterface) { 1348e0e1b25SGreg Roach return $block; 1358e0e1b25SGreg Roach } 1368e0e1b25SGreg Roach 1378e0e1b25SGreg Roach throw new HttpNotFoundException('Block not found'); 1388e0e1b25SGreg Roach } 1398e0e1b25SGreg Roach 1408e0e1b25SGreg Roach /** 1418e0e1b25SGreg Roach * Get all the available blocks for a tree page. 1428e0e1b25SGreg Roach * 143f6924bc8SGreg Roach * @param Tree $tree 144f6924bc8SGreg Roach * @param UserInterface $user 145f6924bc8SGreg Roach * 1468e0e1b25SGreg Roach * @return Collection<string,ModuleBlockInterface> 1478e0e1b25SGreg Roach */ 148f6924bc8SGreg Roach public function availableTreeBlocks(Tree $tree, UserInterface $user): Collection 1498e0e1b25SGreg Roach { 150f6924bc8SGreg Roach return $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, $user) 1518e0e1b25SGreg Roach ->filter(static function (ModuleBlockInterface $block): bool { 1528e0e1b25SGreg Roach return $block->isTreeBlock(); 1538e0e1b25SGreg Roach }) 1548e0e1b25SGreg Roach ->mapWithKeys(static function (ModuleBlockInterface $block): array { 1558e0e1b25SGreg Roach return [$block->name() => $block]; 1568e0e1b25SGreg Roach }); 1578e0e1b25SGreg Roach } 1588e0e1b25SGreg Roach 1598e0e1b25SGreg Roach /** 1608e0e1b25SGreg Roach * Get all the available blocks for a user page. 1618e0e1b25SGreg Roach * 162f6924bc8SGreg Roach * @param Tree $tree 163f6924bc8SGreg Roach * @param UserInterface $user 164f6924bc8SGreg Roach * 1658e0e1b25SGreg Roach * @return Collection<string,ModuleBlockInterface> 1668e0e1b25SGreg Roach */ 167f6924bc8SGreg Roach public function availableUserBlocks(Tree $tree, UserInterface $user): Collection 1688e0e1b25SGreg Roach { 169f6924bc8SGreg Roach return $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, $user) 1708e0e1b25SGreg Roach ->filter(static function (ModuleBlockInterface $block): bool { 1718e0e1b25SGreg Roach return $block->isUserBlock(); 1728e0e1b25SGreg Roach }) 1738e0e1b25SGreg Roach ->mapWithKeys(static function (ModuleBlockInterface $block): array { 1748e0e1b25SGreg Roach return [$block->name() => $block]; 1758e0e1b25SGreg Roach }); 1768e0e1b25SGreg Roach } 1778e0e1b25SGreg Roach 1788e0e1b25SGreg Roach /** 1798e0e1b25SGreg Roach * Get the blocks for a specified tree. 1808e0e1b25SGreg Roach * 181f6924bc8SGreg Roach * @param Tree $tree 182f6924bc8SGreg Roach * @param UserInterface $user 1838e0e1b25SGreg Roach * @param string $location "main" or "side" 1848e0e1b25SGreg Roach * 1857c2c99faSGreg Roach * @return Collection<int,ModuleBlockInterface> 1868e0e1b25SGreg Roach */ 187f6924bc8SGreg Roach public function treeBlocks(Tree $tree, UserInterface $user, string $location): Collection 1888e0e1b25SGreg Roach { 1898e0e1b25SGreg Roach $rows = DB::table('block') 190f6924bc8SGreg Roach ->where('gedcom_id', '=', $tree->id()) 1918e0e1b25SGreg Roach ->where('location', '=', $location) 1928e0e1b25SGreg Roach ->orderBy('block_order') 1938e0e1b25SGreg Roach ->pluck('module_name', 'block_id'); 1948e0e1b25SGreg Roach 195f6924bc8SGreg Roach return $this->filterActiveBlocks($rows, $this->availableTreeBlocks($tree, $user)); 1968e0e1b25SGreg Roach } 1978e0e1b25SGreg Roach 1988e0e1b25SGreg Roach /** 1998e0e1b25SGreg Roach * Make sure that default blocks exist for a tree. 2008e0e1b25SGreg Roach * 2018e0e1b25SGreg Roach * @return void 2028e0e1b25SGreg Roach */ 2038e0e1b25SGreg Roach public function checkDefaultTreeBlocksExist(): void 2048e0e1b25SGreg Roach { 2058e0e1b25SGreg Roach $has_blocks = DB::table('block') 2068e0e1b25SGreg Roach ->where('gedcom_id', '=', -1) 2078e0e1b25SGreg Roach ->exists(); 2088e0e1b25SGreg Roach 2098e0e1b25SGreg Roach // No default settings? Create them. 2108e0e1b25SGreg Roach if (!$has_blocks) { 2118e0e1b25SGreg Roach foreach ([ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS] as $location) { 2128e0e1b25SGreg Roach foreach (ModuleBlockInterface::DEFAULT_TREE_PAGE_BLOCKS[$location] as $block_order => $class) { 2133cf189cfSGreg Roach $module = $this->module_service->findByInterface($class)->first(); 2148e0e1b25SGreg Roach 2153cf189cfSGreg Roach if ($module instanceof ModuleInterface) { 2168e0e1b25SGreg Roach DB::table('block')->insert([ 2178e0e1b25SGreg Roach 'gedcom_id' => -1, 2188e0e1b25SGreg Roach 'location' => $location, 2198e0e1b25SGreg Roach 'block_order' => $block_order, 2203cf189cfSGreg Roach 'module_name' => $module->name(), 2218e0e1b25SGreg Roach ]); 2228e0e1b25SGreg Roach } 2238e0e1b25SGreg Roach } 2248e0e1b25SGreg Roach } 2258e0e1b25SGreg Roach } 2263cf189cfSGreg Roach } 2278e0e1b25SGreg Roach 2288e0e1b25SGreg Roach /** 2298e0e1b25SGreg Roach * Get the blocks for a specified user. 2308e0e1b25SGreg Roach * 231f6924bc8SGreg Roach * @param Tree $tree 232f6924bc8SGreg Roach * @param UserInterface $user 2338e0e1b25SGreg Roach * @param string $location "main" or "side" 2348e0e1b25SGreg Roach * 2357c2c99faSGreg Roach * @return Collection<int,ModuleBlockInterface> 2368e0e1b25SGreg Roach */ 237f6924bc8SGreg Roach public function userBlocks(Tree $tree, UserInterface $user, string $location): Collection 2388e0e1b25SGreg Roach { 2398e0e1b25SGreg Roach $rows = DB::table('block') 240f6924bc8SGreg Roach ->where('user_id', '=', $user->id()) 2418e0e1b25SGreg Roach ->where('location', '=', $location) 2428e0e1b25SGreg Roach ->orderBy('block_order') 2438e0e1b25SGreg Roach ->pluck('module_name', 'block_id'); 2448e0e1b25SGreg Roach 245f6924bc8SGreg Roach return $this->filterActiveBlocks($rows, $this->availableUserBlocks($tree, $user)); 2468e0e1b25SGreg Roach } 2478e0e1b25SGreg Roach 2488e0e1b25SGreg Roach /** 2498e0e1b25SGreg Roach * Make sure that default blocks exist for a user. 2508e0e1b25SGreg Roach * 2518e0e1b25SGreg Roach * @return void 2528e0e1b25SGreg Roach */ 2538e0e1b25SGreg Roach public function checkDefaultUserBlocksExist(): void 2548e0e1b25SGreg Roach { 2558e0e1b25SGreg Roach $has_blocks = DB::table('block') 2568e0e1b25SGreg Roach ->where('user_id', '=', -1) 2578e0e1b25SGreg Roach ->exists(); 2588e0e1b25SGreg Roach 2598e0e1b25SGreg Roach // No default settings? Create them. 2608e0e1b25SGreg Roach if (!$has_blocks) { 2618e0e1b25SGreg Roach foreach ([ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS] as $location) { 2628e0e1b25SGreg Roach foreach (ModuleBlockInterface::DEFAULT_USER_PAGE_BLOCKS[$location] as $block_order => $class) { 26323b84b22SGreg Roach $module = $this->module_service->findByInterface($class)->first(); 2648e0e1b25SGreg Roach 26523b84b22SGreg Roach if ($module instanceof ModuleBlockInterface) { 2668e0e1b25SGreg Roach DB::table('block')->insert([ 2678e0e1b25SGreg Roach 'user_id' => -1, 2688e0e1b25SGreg Roach 'location' => $location, 2698e0e1b25SGreg Roach 'block_order' => $block_order, 27023b84b22SGreg Roach 'module_name' => $module->name(), 2718e0e1b25SGreg Roach ]); 2728e0e1b25SGreg Roach } 2738e0e1b25SGreg Roach } 2748e0e1b25SGreg Roach } 2758e0e1b25SGreg Roach } 27623b84b22SGreg Roach } 2778e0e1b25SGreg Roach 2788e0e1b25SGreg Roach /** 2798e0e1b25SGreg Roach * Save the updated blocks for a user. 2808e0e1b25SGreg Roach * 2818e0e1b25SGreg Roach * @param int $user_id 2828e0e1b25SGreg Roach * @param Collection<string> $main_block_ids 2838e0e1b25SGreg Roach * @param Collection<string> $side_block_ids 2848e0e1b25SGreg Roach * 2858e0e1b25SGreg Roach * @return void 2868e0e1b25SGreg Roach */ 2878e0e1b25SGreg Roach public function updateUserBlocks(int $user_id, Collection $main_block_ids, Collection $side_block_ids): void 2888e0e1b25SGreg Roach { 2898e0e1b25SGreg Roach $existing_block_ids = DB::table('block') 2908e0e1b25SGreg Roach ->where('user_id', '=', $user_id) 29178144954SGreg Roach ->whereIn('location', [ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS]) 2928e0e1b25SGreg Roach ->pluck('block_id'); 2938e0e1b25SGreg Roach 2948e0e1b25SGreg Roach // Deleted blocks 2958e0e1b25SGreg Roach foreach ($existing_block_ids as $existing_block_id) { 2968e0e1b25SGreg Roach if (!$main_block_ids->contains($existing_block_id) && !$side_block_ids->contains($existing_block_id)) { 2978e0e1b25SGreg Roach DB::table('block_setting') 2988e0e1b25SGreg Roach ->where('block_id', '=', $existing_block_id) 2998e0e1b25SGreg Roach ->delete(); 3008e0e1b25SGreg Roach 3018e0e1b25SGreg Roach DB::table('block') 3028e0e1b25SGreg Roach ->where('block_id', '=', $existing_block_id) 3038e0e1b25SGreg Roach ->delete(); 3048e0e1b25SGreg Roach } 3058e0e1b25SGreg Roach } 3068e0e1b25SGreg Roach 3078e0e1b25SGreg Roach $updates = [ 3088e0e1b25SGreg Roach ModuleBlockInterface::MAIN_BLOCKS => $main_block_ids, 3098e0e1b25SGreg Roach ModuleBlockInterface::SIDE_BLOCKS => $side_block_ids, 3108e0e1b25SGreg Roach ]; 3118e0e1b25SGreg Roach 3128e0e1b25SGreg Roach foreach ($updates as $location => $updated_blocks) { 3138e0e1b25SGreg Roach foreach ($updated_blocks as $block_order => $block_id) { 3148e0e1b25SGreg Roach if (is_numeric($block_id)) { 3158e0e1b25SGreg Roach // Updated block 3168e0e1b25SGreg Roach DB::table('block') 3178e0e1b25SGreg Roach ->where('block_id', '=', $block_id) 3188e0e1b25SGreg Roach ->update([ 3198e0e1b25SGreg Roach 'block_order' => $block_order, 3208e0e1b25SGreg Roach 'location' => $location, 3218e0e1b25SGreg Roach ]); 3228e0e1b25SGreg Roach } else { 3238e0e1b25SGreg Roach // New block 3248e0e1b25SGreg Roach DB::table('block')->insert([ 3258e0e1b25SGreg Roach 'user_id' => $user_id, 3268e0e1b25SGreg Roach 'location' => $location, 3278e0e1b25SGreg Roach 'block_order' => $block_order, 3288e0e1b25SGreg Roach 'module_name' => $block_id, 3298e0e1b25SGreg Roach ]); 3308e0e1b25SGreg Roach } 3318e0e1b25SGreg Roach } 3328e0e1b25SGreg Roach } 3338e0e1b25SGreg Roach } 3348e0e1b25SGreg Roach 3358e0e1b25SGreg Roach /** 3368e0e1b25SGreg Roach * Save the updated blocks for a tree. 3378e0e1b25SGreg Roach * 3388e0e1b25SGreg Roach * @param int $tree_id 3398e0e1b25SGreg Roach * @param Collection<string> $main_block_ids 3408e0e1b25SGreg Roach * @param Collection<string> $side_block_ids 3418e0e1b25SGreg Roach * 3428e0e1b25SGreg Roach * @return void 3438e0e1b25SGreg Roach */ 3448e0e1b25SGreg Roach public function updateTreeBlocks(int $tree_id, Collection $main_block_ids, Collection $side_block_ids): void 3458e0e1b25SGreg Roach { 3468e0e1b25SGreg Roach $existing_block_ids = DB::table('block') 3478e0e1b25SGreg Roach ->where('gedcom_id', '=', $tree_id) 34878144954SGreg Roach ->whereIn('location', [ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS]) 3498e0e1b25SGreg Roach ->pluck('block_id'); 3508e0e1b25SGreg Roach 3518e0e1b25SGreg Roach // Deleted blocks 3528e0e1b25SGreg Roach foreach ($existing_block_ids as $existing_block_id) { 3538e0e1b25SGreg Roach if (!$main_block_ids->contains($existing_block_id) && !$side_block_ids->contains($existing_block_id)) { 3548e0e1b25SGreg Roach DB::table('block_setting') 3558e0e1b25SGreg Roach ->where('block_id', '=', $existing_block_id) 3568e0e1b25SGreg Roach ->delete(); 3578e0e1b25SGreg Roach 3588e0e1b25SGreg Roach DB::table('block') 3598e0e1b25SGreg Roach ->where('block_id', '=', $existing_block_id) 3608e0e1b25SGreg Roach ->delete(); 3618e0e1b25SGreg Roach } 3628e0e1b25SGreg Roach } 3638e0e1b25SGreg Roach 3648e0e1b25SGreg Roach $updates = [ 3658e0e1b25SGreg Roach ModuleBlockInterface::MAIN_BLOCKS => $main_block_ids, 3668e0e1b25SGreg Roach ModuleBlockInterface::SIDE_BLOCKS => $side_block_ids, 3678e0e1b25SGreg Roach ]; 3688e0e1b25SGreg Roach 3698e0e1b25SGreg Roach foreach ($updates as $location => $updated_blocks) { 3708e0e1b25SGreg Roach foreach ($updated_blocks as $block_order => $block_id) { 3718e0e1b25SGreg Roach if (is_numeric($block_id)) { 3728e0e1b25SGreg Roach // Updated block 3738e0e1b25SGreg Roach DB::table('block') 3748e0e1b25SGreg Roach ->where('block_id', '=', $block_id) 3758e0e1b25SGreg Roach ->update([ 3768e0e1b25SGreg Roach 'block_order' => $block_order, 3778e0e1b25SGreg Roach 'location' => $location, 3788e0e1b25SGreg Roach ]); 3798e0e1b25SGreg Roach } else { 3808e0e1b25SGreg Roach // New block 3818e0e1b25SGreg Roach DB::table('block')->insert([ 3828e0e1b25SGreg Roach 'gedcom_id' => $tree_id, 3838e0e1b25SGreg Roach 'location' => $location, 3848e0e1b25SGreg Roach 'block_order' => $block_order, 3858e0e1b25SGreg Roach 'module_name' => $block_id, 3868e0e1b25SGreg Roach ]); 3878e0e1b25SGreg Roach } 3888e0e1b25SGreg Roach } 3898e0e1b25SGreg Roach } 3908e0e1b25SGreg Roach } 3918e0e1b25SGreg Roach 3928e0e1b25SGreg Roach /** 3938e0e1b25SGreg Roach * Take a list of block names, and return block (module) objects. 3948e0e1b25SGreg Roach * 3958e0e1b25SGreg Roach * @param Collection<string> $blocks 3967c2c99faSGreg Roach * @param Collection<int,ModuleBlockInterface> $active_blocks 3978e0e1b25SGreg Roach * 3987c2c99faSGreg Roach * @return Collection<int,ModuleBlockInterface> 3998e0e1b25SGreg Roach */ 4008e0e1b25SGreg Roach private function filterActiveBlocks(Collection $blocks, Collection $active_blocks): Collection 4018e0e1b25SGreg Roach { 4028e0e1b25SGreg Roach return $blocks->map(static function (string $block_name) use ($active_blocks): ?ModuleBlockInterface { 4038e0e1b25SGreg Roach return $active_blocks->filter(static function (ModuleInterface $block) use ($block_name): bool { 4048e0e1b25SGreg Roach return $block->name() === $block_name; 4058e0e1b25SGreg Roach })->first(); 4068e0e1b25SGreg Roach })->filter(); 4078e0e1b25SGreg Roach } 4088e0e1b25SGreg Roach} 409