xref: /webtrees/app/Services/HomePageService.php (revision 449b311ecf65f677a2595e1e29f712d11ef22f34)
18e0e1b25SGreg Roach<?php
28e0e1b25SGreg Roach
38e0e1b25SGreg Roach/**
48e0e1b25SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 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;
246f4ec3caSGreg Roachuse Fisharebest\Webtrees\DB;
2581b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpNotFoundException;
268e0e1b25SGreg Roachuse Fisharebest\Webtrees\Module\ModuleBlockInterface;
278e0e1b25SGreg Roachuse Fisharebest\Webtrees\Module\ModuleInterface;
288e0e1b25SGreg Roachuse Fisharebest\Webtrees\Tree;
29b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator;
308e0e1b25SGreg Roachuse Illuminate\Support\Collection;
318e0e1b25SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
328e0e1b25SGreg Roach
338e0e1b25SGreg Roachuse function is_numeric;
34f70bcff5SGreg Roachuse function is_object;
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     * @param ModuleService $module_service
458e0e1b25SGreg Roach     */
468e0e1b25SGreg Roach    public function __construct(ModuleService $module_service)
478e0e1b25SGreg Roach    {
488e0e1b25SGreg Roach        $this->module_service = $module_service;
498e0e1b25SGreg Roach    }
508e0e1b25SGreg Roach
518e0e1b25SGreg Roach    /**
5224c0163eSGreg Roach     * Load a tree block.
538e0e1b25SGreg Roach     *
548e0e1b25SGreg Roach     * @param ServerRequestInterface $request
558e0e1b25SGreg Roach     *
568e0e1b25SGreg Roach     * @return ModuleBlockInterface
578e0e1b25SGreg Roach     */
5824c0163eSGreg Roach    public function treeBlock(ServerRequestInterface $request): ModuleBlockInterface
598e0e1b25SGreg Roach    {
60b55cbc6bSGreg Roach        $tree     = Validator::attributes($request)->tree();
61b55cbc6bSGreg Roach        $block_id = Validator::attributes($request)->integer('block_id');
628e0e1b25SGreg Roach
638e0e1b25SGreg Roach        $block = DB::table('block')
648e0e1b25SGreg Roach            ->where('block_id', '=', $block_id)
658e0e1b25SGreg Roach            ->where('gedcom_id', '=', $tree->id())
668e0e1b25SGreg Roach            ->whereNull('user_id')
678e0e1b25SGreg Roach            ->first();
688e0e1b25SGreg Roach
69f70bcff5SGreg Roach        if (is_object($block)) {
708e0e1b25SGreg Roach            $module = $this->module_service->findByName($block->module_name);
718e0e1b25SGreg Roach
7224c0163eSGreg Roach            if ($module instanceof ModuleBlockInterface) {
738e0e1b25SGreg Roach                return $module;
748e0e1b25SGreg Roach            }
7524c0163eSGreg Roach        }
7624c0163eSGreg Roach
7724c0163eSGreg Roach        throw new HttpNotFoundException();
7824c0163eSGreg Roach    }
798e0e1b25SGreg Roach
808e0e1b25SGreg Roach    /**
8124c0163eSGreg Roach     * Load a user block.
828e0e1b25SGreg Roach     *
838e0e1b25SGreg Roach     * @param ServerRequestInterface $request
848e0e1b25SGreg Roach     * @param UserInterface          $user
858e0e1b25SGreg Roach     *
868e0e1b25SGreg Roach     * @return ModuleBlockInterface
878e0e1b25SGreg Roach     */
888e0e1b25SGreg Roach    public function userBlock(ServerRequestInterface $request, UserInterface $user): ModuleBlockInterface
898e0e1b25SGreg Roach    {
90b55cbc6bSGreg Roach        $block_id = Validator::attributes($request)->integer('block_id');
918e0e1b25SGreg Roach
928e0e1b25SGreg Roach        $block = DB::table('block')
938e0e1b25SGreg Roach            ->where('block_id', '=', $block_id)
948e0e1b25SGreg Roach            ->where('user_id', '=', $user->id())
958e0e1b25SGreg Roach            ->whereNull('gedcom_id')
968e0e1b25SGreg Roach            ->first();
978e0e1b25SGreg Roach
98f70bcff5SGreg Roach        if (is_object($block)) {
998e0e1b25SGreg Roach            $module = $this->module_service->findByName($block->module_name);
1008e0e1b25SGreg Roach
10124c0163eSGreg Roach            if ($module instanceof ModuleBlockInterface) {
1028e0e1b25SGreg Roach                return $module;
1038e0e1b25SGreg Roach            }
10424c0163eSGreg Roach        }
10524c0163eSGreg Roach
10624c0163eSGreg Roach        throw new HttpNotFoundException();
10724c0163eSGreg Roach    }
1088e0e1b25SGreg Roach
1098e0e1b25SGreg Roach    /**
1108e0e1b25SGreg Roach     * Get a specific block.
1118e0e1b25SGreg Roach     *
1128e0e1b25SGreg Roach     * @param Tree $tree
1138e0e1b25SGreg Roach     * @param int  $block_id
1148e0e1b25SGreg Roach     *
1158e0e1b25SGreg Roach     * @return ModuleBlockInterface
1168e0e1b25SGreg Roach     */
1178e0e1b25SGreg Roach    public function getBlockModule(Tree $tree, int $block_id): ModuleBlockInterface
1188e0e1b25SGreg Roach    {
1198e0e1b25SGreg Roach        $active_blocks = $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, Auth::user());
1208e0e1b25SGreg Roach
1218e0e1b25SGreg Roach        $module_name = DB::table('block')
1228e0e1b25SGreg Roach            ->where('block_id', '=', $block_id)
1238e0e1b25SGreg Roach            ->value('module_name');
1248e0e1b25SGreg Roach
125f25fc0f9SGreg Roach        $block = $active_blocks->first(static fn (ModuleInterface $module): bool => $module->name() === $module_name);
1268e0e1b25SGreg Roach
1278e0e1b25SGreg Roach        if ($block instanceof ModuleBlockInterface) {
1288e0e1b25SGreg Roach            return $block;
1298e0e1b25SGreg Roach        }
1308e0e1b25SGreg Roach
1318e0e1b25SGreg Roach        throw new HttpNotFoundException('Block not found');
1328e0e1b25SGreg Roach    }
1338e0e1b25SGreg Roach
1348e0e1b25SGreg Roach    /**
1358e0e1b25SGreg Roach     * Get all the available blocks for a tree page.
1368e0e1b25SGreg Roach     *
137f6924bc8SGreg Roach     * @param Tree          $tree
138f6924bc8SGreg Roach     * @param UserInterface $user
139f6924bc8SGreg Roach     *
1408e0e1b25SGreg Roach     * @return Collection<string,ModuleBlockInterface>
1418e0e1b25SGreg Roach     */
142f6924bc8SGreg Roach    public function availableTreeBlocks(Tree $tree, UserInterface $user): Collection
1438e0e1b25SGreg Roach    {
144f6924bc8SGreg Roach        return $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, $user)
145f25fc0f9SGreg Roach            ->filter(static fn (ModuleBlockInterface $block): bool => $block->isTreeBlock())
146f25fc0f9SGreg Roach            ->mapWithKeys(static fn (ModuleBlockInterface $block): array => [$block->name() => $block]);
1478e0e1b25SGreg Roach    }
1488e0e1b25SGreg Roach
1498e0e1b25SGreg Roach    /**
1508e0e1b25SGreg Roach     * Get all the available blocks for a user page.
1518e0e1b25SGreg Roach     *
152f6924bc8SGreg Roach     * @param Tree          $tree
153f6924bc8SGreg Roach     * @param UserInterface $user
154f6924bc8SGreg Roach     *
1558e0e1b25SGreg Roach     * @return Collection<string,ModuleBlockInterface>
1568e0e1b25SGreg Roach     */
157f6924bc8SGreg Roach    public function availableUserBlocks(Tree $tree, UserInterface $user): Collection
1588e0e1b25SGreg Roach    {
159f6924bc8SGreg Roach        return $this->module_service->findByComponent(ModuleBlockInterface::class, $tree, $user)
160f25fc0f9SGreg Roach            ->filter(static fn (ModuleBlockInterface $block): bool => $block->isUserBlock())
161f25fc0f9SGreg Roach            ->mapWithKeys(static fn (ModuleBlockInterface $block): array => [$block->name() => $block]);
1628e0e1b25SGreg Roach    }
1638e0e1b25SGreg Roach
1648e0e1b25SGreg Roach    /**
1658e0e1b25SGreg Roach     * Get the blocks for a specified tree.
1668e0e1b25SGreg Roach     *
167f6924bc8SGreg Roach     * @param Tree          $tree
168f6924bc8SGreg Roach     * @param UserInterface $user
1698e0e1b25SGreg Roach     * @param string        $location "main" or "side"
1708e0e1b25SGreg Roach     *
1717c2c99faSGreg Roach     * @return Collection<int,ModuleBlockInterface>
1728e0e1b25SGreg Roach     */
173f6924bc8SGreg Roach    public function treeBlocks(Tree $tree, UserInterface $user, string $location): Collection
1748e0e1b25SGreg Roach    {
1758e0e1b25SGreg Roach        $rows = DB::table('block')
176f6924bc8SGreg Roach            ->where('gedcom_id', '=', $tree->id())
1778e0e1b25SGreg Roach            ->where('location', '=', $location)
1788e0e1b25SGreg Roach            ->orderBy('block_order')
1798e0e1b25SGreg Roach            ->pluck('module_name', 'block_id');
1808e0e1b25SGreg Roach
181f6924bc8SGreg Roach        return $this->filterActiveBlocks($rows, $this->availableTreeBlocks($tree, $user));
1828e0e1b25SGreg Roach    }
1838e0e1b25SGreg Roach
1848e0e1b25SGreg Roach    /**
1858e0e1b25SGreg Roach     * Make sure that default blocks exist for a tree.
1868e0e1b25SGreg Roach     *
1878e0e1b25SGreg Roach     * @return void
1888e0e1b25SGreg Roach     */
1898e0e1b25SGreg Roach    public function checkDefaultTreeBlocksExist(): void
1908e0e1b25SGreg Roach    {
1918e0e1b25SGreg Roach        $has_blocks = DB::table('block')
1928e0e1b25SGreg Roach            ->where('gedcom_id', '=', -1)
1938e0e1b25SGreg Roach            ->exists();
1948e0e1b25SGreg Roach
1958e0e1b25SGreg Roach        // No default settings?  Create them.
1968e0e1b25SGreg Roach        if (!$has_blocks) {
1978e0e1b25SGreg Roach            foreach ([ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS] as $location) {
1988e0e1b25SGreg Roach                foreach (ModuleBlockInterface::DEFAULT_TREE_PAGE_BLOCKS[$location] as $block_order => $class) {
1993cf189cfSGreg Roach                    $module = $this->module_service->findByInterface($class)->first();
2008e0e1b25SGreg Roach
2013cf189cfSGreg Roach                    if ($module instanceof ModuleInterface) {
2028e0e1b25SGreg Roach                        DB::table('block')->insert([
2038e0e1b25SGreg Roach                            'gedcom_id'   => -1,
2048e0e1b25SGreg Roach                            'location'    => $location,
2058e0e1b25SGreg Roach                            'block_order' => $block_order,
2063cf189cfSGreg Roach                            'module_name' => $module->name(),
2078e0e1b25SGreg Roach                        ]);
2088e0e1b25SGreg Roach                    }
2098e0e1b25SGreg Roach                }
2108e0e1b25SGreg Roach            }
2118e0e1b25SGreg Roach        }
2123cf189cfSGreg Roach    }
2138e0e1b25SGreg Roach
2148e0e1b25SGreg Roach    /**
2158e0e1b25SGreg Roach     * Get the blocks for a specified user.
2168e0e1b25SGreg Roach     *
217f6924bc8SGreg Roach     * @param Tree          $tree
218f6924bc8SGreg Roach     * @param UserInterface $user
2198e0e1b25SGreg Roach     * @param string        $location "main" or "side"
2208e0e1b25SGreg Roach     *
2217c2c99faSGreg Roach     * @return Collection<int,ModuleBlockInterface>
2228e0e1b25SGreg Roach     */
223f6924bc8SGreg Roach    public function userBlocks(Tree $tree, UserInterface $user, string $location): Collection
2248e0e1b25SGreg Roach    {
2258e0e1b25SGreg Roach        $rows = DB::table('block')
226f6924bc8SGreg Roach            ->where('user_id', '=', $user->id())
2278e0e1b25SGreg Roach            ->where('location', '=', $location)
2288e0e1b25SGreg Roach            ->orderBy('block_order')
2298e0e1b25SGreg Roach            ->pluck('module_name', 'block_id');
2308e0e1b25SGreg Roach
231f6924bc8SGreg Roach        return $this->filterActiveBlocks($rows, $this->availableUserBlocks($tree, $user));
2328e0e1b25SGreg Roach    }
2338e0e1b25SGreg Roach
2348e0e1b25SGreg Roach    /**
2358e0e1b25SGreg Roach     * Make sure that default blocks exist for a user.
2368e0e1b25SGreg Roach     *
2378e0e1b25SGreg Roach     * @return void
2388e0e1b25SGreg Roach     */
2398e0e1b25SGreg Roach    public function checkDefaultUserBlocksExist(): void
2408e0e1b25SGreg Roach    {
2418e0e1b25SGreg Roach        $has_blocks = DB::table('block')
2428e0e1b25SGreg Roach            ->where('user_id', '=', -1)
2438e0e1b25SGreg Roach            ->exists();
2448e0e1b25SGreg Roach
2458e0e1b25SGreg Roach        // No default settings?  Create them.
2468e0e1b25SGreg Roach        if (!$has_blocks) {
2478e0e1b25SGreg Roach            foreach ([ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS] as $location) {
2488e0e1b25SGreg Roach                foreach (ModuleBlockInterface::DEFAULT_USER_PAGE_BLOCKS[$location] as $block_order => $class) {
24923b84b22SGreg Roach                    $module = $this->module_service->findByInterface($class)->first();
2508e0e1b25SGreg Roach
25123b84b22SGreg Roach                    if ($module instanceof ModuleBlockInterface) {
2528e0e1b25SGreg Roach                        DB::table('block')->insert([
2538e0e1b25SGreg Roach                            'user_id'     => -1,
2548e0e1b25SGreg Roach                            'location'    => $location,
2558e0e1b25SGreg Roach                            'block_order' => $block_order,
25623b84b22SGreg Roach                            'module_name' => $module->name(),
2578e0e1b25SGreg Roach                        ]);
2588e0e1b25SGreg Roach                    }
2598e0e1b25SGreg Roach                }
2608e0e1b25SGreg Roach            }
2618e0e1b25SGreg Roach        }
26223b84b22SGreg Roach    }
2638e0e1b25SGreg Roach
2648e0e1b25SGreg Roach    /**
2658e0e1b25SGreg Roach     * Save the updated blocks for a user.
2668e0e1b25SGreg Roach     *
2678e0e1b25SGreg Roach     * @param int                    $user_id
26836779af1SGreg Roach     * @param Collection<int,string> $main_block_ids
26936779af1SGreg Roach     * @param Collection<int,string> $side_block_ids
2708e0e1b25SGreg Roach     *
2718e0e1b25SGreg Roach     * @return void
2728e0e1b25SGreg Roach     */
2738e0e1b25SGreg Roach    public function updateUserBlocks(int $user_id, Collection $main_block_ids, Collection $side_block_ids): void
2748e0e1b25SGreg Roach    {
2758e0e1b25SGreg Roach        $existing_block_ids = DB::table('block')
2768e0e1b25SGreg Roach            ->where('user_id', '=', $user_id)
27778144954SGreg Roach            ->whereIn('location', [ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS])
2788e0e1b25SGreg Roach            ->pluck('block_id');
2798e0e1b25SGreg Roach
2808e0e1b25SGreg Roach        // Deleted blocks
2818e0e1b25SGreg Roach        foreach ($existing_block_ids as $existing_block_id) {
2828e0e1b25SGreg Roach            if (!$main_block_ids->contains($existing_block_id) && !$side_block_ids->contains($existing_block_id)) {
2838e0e1b25SGreg Roach                DB::table('block_setting')
2848e0e1b25SGreg Roach                    ->where('block_id', '=', $existing_block_id)
2858e0e1b25SGreg Roach                    ->delete();
2868e0e1b25SGreg Roach
2878e0e1b25SGreg Roach                DB::table('block')
2888e0e1b25SGreg Roach                    ->where('block_id', '=', $existing_block_id)
2898e0e1b25SGreg Roach                    ->delete();
2908e0e1b25SGreg Roach            }
2918e0e1b25SGreg Roach        }
2928e0e1b25SGreg Roach
2938e0e1b25SGreg Roach        $updates = [
2948e0e1b25SGreg Roach            ModuleBlockInterface::MAIN_BLOCKS => $main_block_ids,
2958e0e1b25SGreg Roach            ModuleBlockInterface::SIDE_BLOCKS => $side_block_ids,
2968e0e1b25SGreg Roach        ];
2978e0e1b25SGreg Roach
2988e0e1b25SGreg Roach        foreach ($updates as $location => $updated_blocks) {
2998e0e1b25SGreg Roach            foreach ($updated_blocks as $block_order => $block_id) {
3008e0e1b25SGreg Roach                if (is_numeric($block_id)) {
3018e0e1b25SGreg Roach                    // Updated block
3028e0e1b25SGreg Roach                    DB::table('block')
3038e0e1b25SGreg Roach                        ->where('block_id', '=', $block_id)
3048e0e1b25SGreg Roach                        ->update([
3058e0e1b25SGreg Roach                            'block_order' => $block_order,
3068e0e1b25SGreg Roach                            'location'    => $location,
3078e0e1b25SGreg Roach                        ]);
3088e0e1b25SGreg Roach                } else {
3098e0e1b25SGreg Roach                    // New block
3108e0e1b25SGreg Roach                    DB::table('block')->insert([
3118e0e1b25SGreg Roach                        'user_id'     => $user_id,
3128e0e1b25SGreg Roach                        'location'    => $location,
3138e0e1b25SGreg Roach                        'block_order' => $block_order,
3148e0e1b25SGreg Roach                        'module_name' => $block_id,
3158e0e1b25SGreg Roach                    ]);
3168e0e1b25SGreg Roach                }
3178e0e1b25SGreg Roach            }
3188e0e1b25SGreg Roach        }
3198e0e1b25SGreg Roach    }
3208e0e1b25SGreg Roach
3218e0e1b25SGreg Roach    /**
3228e0e1b25SGreg Roach     * Save the updated blocks for a tree.
3238e0e1b25SGreg Roach     *
3248e0e1b25SGreg Roach     * @param int                    $tree_id
32536779af1SGreg Roach     * @param Collection<int,string> $main_block_ids
32636779af1SGreg Roach     * @param Collection<int,string> $side_block_ids
3278e0e1b25SGreg Roach     *
3288e0e1b25SGreg Roach     * @return void
3298e0e1b25SGreg Roach     */
3308e0e1b25SGreg Roach    public function updateTreeBlocks(int $tree_id, Collection $main_block_ids, Collection $side_block_ids): void
3318e0e1b25SGreg Roach    {
3328e0e1b25SGreg Roach        $existing_block_ids = DB::table('block')
3338e0e1b25SGreg Roach            ->where('gedcom_id', '=', $tree_id)
33478144954SGreg Roach            ->whereIn('location', [ModuleBlockInterface::MAIN_BLOCKS, ModuleBlockInterface::SIDE_BLOCKS])
3358e0e1b25SGreg Roach            ->pluck('block_id');
3368e0e1b25SGreg Roach
3378e0e1b25SGreg Roach        // Deleted blocks
3388e0e1b25SGreg Roach        foreach ($existing_block_ids as $existing_block_id) {
3398e0e1b25SGreg Roach            if (!$main_block_ids->contains($existing_block_id) && !$side_block_ids->contains($existing_block_id)) {
3408e0e1b25SGreg Roach                DB::table('block_setting')
3418e0e1b25SGreg Roach                    ->where('block_id', '=', $existing_block_id)
3428e0e1b25SGreg Roach                    ->delete();
3438e0e1b25SGreg Roach
3448e0e1b25SGreg Roach                DB::table('block')
3458e0e1b25SGreg Roach                    ->where('block_id', '=', $existing_block_id)
3468e0e1b25SGreg Roach                    ->delete();
3478e0e1b25SGreg Roach            }
3488e0e1b25SGreg Roach        }
3498e0e1b25SGreg Roach
3508e0e1b25SGreg Roach        $updates = [
3518e0e1b25SGreg Roach            ModuleBlockInterface::MAIN_BLOCKS => $main_block_ids,
3528e0e1b25SGreg Roach            ModuleBlockInterface::SIDE_BLOCKS => $side_block_ids,
3538e0e1b25SGreg Roach        ];
3548e0e1b25SGreg Roach
3558e0e1b25SGreg Roach        foreach ($updates as $location => $updated_blocks) {
3568e0e1b25SGreg Roach            foreach ($updated_blocks as $block_order => $block_id) {
3578e0e1b25SGreg Roach                if (is_numeric($block_id)) {
3588e0e1b25SGreg Roach                    // Updated block
3598e0e1b25SGreg Roach                    DB::table('block')
3608e0e1b25SGreg Roach                        ->where('block_id', '=', $block_id)
3618e0e1b25SGreg Roach                        ->update([
3628e0e1b25SGreg Roach                            'block_order' => $block_order,
3638e0e1b25SGreg Roach                            'location'    => $location,
3648e0e1b25SGreg Roach                        ]);
3658e0e1b25SGreg Roach                } else {
3668e0e1b25SGreg Roach                    // New block
3678e0e1b25SGreg Roach                    DB::table('block')->insert([
3688e0e1b25SGreg Roach                        'gedcom_id'   => $tree_id,
3698e0e1b25SGreg Roach                        'location'    => $location,
3708e0e1b25SGreg Roach                        'block_order' => $block_order,
3718e0e1b25SGreg Roach                        'module_name' => $block_id,
3728e0e1b25SGreg Roach                    ]);
3738e0e1b25SGreg Roach                }
3748e0e1b25SGreg Roach            }
3758e0e1b25SGreg Roach        }
3768e0e1b25SGreg Roach    }
3778e0e1b25SGreg Roach
3788e0e1b25SGreg Roach    /**
3798e0e1b25SGreg Roach     * Take a list of block names, and return block (module) objects.
3808e0e1b25SGreg Roach     *
38136779af1SGreg Roach     * @param Collection<int,string>               $blocks
3827c2c99faSGreg Roach     * @param Collection<int,ModuleBlockInterface> $active_blocks
3838e0e1b25SGreg Roach     *
3847c2c99faSGreg Roach     * @return Collection<int,ModuleBlockInterface>
3858e0e1b25SGreg Roach     */
3868e0e1b25SGreg Roach    private function filterActiveBlocks(Collection $blocks, Collection $active_blocks): Collection
3878e0e1b25SGreg Roach    {
388*1ff45046SGreg Roach        return $blocks->map(static fn (string $block_name): ModuleBlockInterface|null => $active_blocks->filter(static fn (ModuleInterface $block): bool => $block->name() === $block_name)->first())
389*1ff45046SGreg Roach            ->filter();
3908e0e1b25SGreg Roach    }
3918e0e1b25SGreg Roach}
392