ID => [fixture file, layout type, global]. */ public const ITEMS = [ 1054 => ['library--layout-ganze-seite.html', 'layout', false], 1055 => ['library--library-abschnitt.html', 'section', false], 1056 => ['library--library-zeile.html', 'row', false], 1057 => ['library--library-modul.html', 'module', false], 1058 => ['library-global--globaler-abschnitt.html', 'section', true], 1059 => ['library-global--globales-modul.html', 'module', true], ]; /** @param array $fields */ public static function item(int $id, array $fields = []): WP_Post { return new WP_Post(array_merge([ 'ID' => $id, 'post_type' => DiviLibraryStore::POST_TYPE, 'post_status' => 'publish', 'post_title' => '[Fixture] ' . $id, 'post_content' => DiviFixtures::markup('stage3/' . self::ITEMS[$id][0]), ], $fields)); } /** @param array $fields */ public static function page(string $content, array $fields = []): WP_Post { return new WP_Post(array_merge([ 'ID' => self::PAGE, 'post_type' => 'page', 'post_status' => 'draft', 'post_title' => 'Start', 'post_content' => $content, ], $fields)); } /** * WordPress stubs for $posts (get_post by ID) and a user with every capability but $denied. * * @param list $posts * @param list $denied */ public static function given(array $posts, array $denied = []): void { $byId = []; foreach ($posts as $post) { $byId[(int) $post->ID] = $post; } Functions\when('get_post')->alias( static fn (mixed $id): ?WP_Post => $byId[(int) ($id instanceof WP_Post ? $id->ID : $id)] ?? null ); Functions\when('current_user_can')->alias( static fn (string $cap, mixed ...$args): bool => ! in_array($cap, $denied, true) ); Functions\when('get_post_type_object')->justReturn(null); Functions\when('get_permalink')->justReturn('https://kunde.test/?page_id=7'); Functions\when('get_edit_post_link')->alias(static fn (mixed $post): string => sprintf( 'https://kunde.test/wp-admin/post.php?post=%d&action=edit', $post instanceof WP_Post ? $post->ID : (int) $post )); Functions\when('add_query_arg')->alias( static fn (string $key, string $value, string $url): string => $url . '&' . $key . '=' . $value ); Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true'); } /** A store that answers isGlobal()/layoutType() from ITEMS (no database). */ public static function store(): DiviLibraryStore { $store = Mockery::mock(DiviLibraryStore::class)->makePartial(); $store->allows('isGlobal')->andReturnUsing(static fn (int $id): bool => self::ITEMS[$id][2] ?? false); $store->allows('layoutType')->andReturnUsing(static fn (int $id): ?string => self::ITEMS[$id][1] ?? null); return $store; } /** @param list $deniedRoles Divi role options the user lacks. */ public static function roles(array $deniedRoles = []): DiviRoles { return new DiviRoles(static fn (string $cap): bool => ! in_array($cap, $deniedRoles, true)); } /** @param list $deniedRoles */ public static function access( array $deniedRoles = [], bool $writable = true, ?DiviLibraryStore $store = null ): LibraryAccess { return new LibraryAccess($store ?? self::store(), self::roles($deniedRoles), static fn (): bool => $writable); } /** * GlobalUsages whose query answers $rows (a closure gets the entry ID on every call); the rights checks * are the real ones, with the post-cache functions stubbed. * * @param list|\Closure(int): list $rows */ public static function usages(array|\Closure $rows, ?DiviRoles $roles = null): GlobalUsages { Functions\when('_get_non_cached_ids')->returnArg(1); Functions\when('_prime_post_caches')->justReturn(null); Functions\when('wp_cache_delete')->justReturn(true); $usages = Mockery::mock(GlobalUsages::class, [null, $roles ?? self::roles()])->makePartial(); $usages->allows('rows')->andReturnUsing(static fn (int $id): array => is_array($rows) ? $rows : $rows($id)); return $usages; } /** @return list One row per ID. */ public static function rows(array $ids, string $status = 'publish', string $type = 'page'): array { return array_map(static fn (int $id): array => ['id' => $id, 'status' => $status, 'type' => $type], $ids); } public static function loader(?LibraryAccess $access = null): DiviPageLoader { return new DiviPageLoader(DiviFixtures::schema(), new Parser(), $access ?? self::access()); } }