-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathclass-post-factory.php
More file actions
272 lines (244 loc) · 7.07 KB
/
class-post-factory.php
File metadata and controls
272 lines (244 loc) · 7.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
<?php
/**
* Post_Factory class file.
*
* @package Mantle
*/
namespace Mantle\Database\Factory;
use Carbon\Carbon;
use Closure;
use Faker\Generator;
use Mantle\Database\Model\Attachment;
use Mantle\Database\Model\Post;
use WP_Post;
use function Mantle\Support\Helpers\collect;
use function Mantle\Support\Helpers\get_post_object;
use function Mantle\Support\Helpers\tap;
/**
* Post Factory
*
* @template TModel of \Mantle\Database\Model\Post
* @template TObject
* @template TReturnValue
*
* @extends Factory<TModel, TObject, TReturnValue>
*/
class Post_Factory extends Factory {
use Concerns\With_Byline_Manager_Profiles;
use Concerns\With_Guest_Authors;
use Concerns\With_Meta;
/**
* Model to use when creating objects.
*
* @var class-string<TModel>
*/
protected string $model = Post::class;
/**
* Flag to create terms by default.
*/
protected bool $create_terms = true;
/**
* Flag to append terms by default.
*/
protected bool $append_terms = true;
/**
* Constructor.
*
* @param Generator $faker Faker generator.
* @param string $post_type Post type to use.
*/
public function __construct( Generator $faker, public string $post_type = 'post' ) {
parent::__construct( $faker );
}
/**
* Change the default creation of terms with the post factory.
*
* @param bool $value Value to set.
*/
public function create_terms( bool $value = true ): void {
$this->create_terms = $value;
}
/**
* Change the default appending of terms with the post factory.
*
* @param bool $value Value to set.
*/
public function append_terms( bool $value = true ): void {
$this->append_terms = $value;
}
/**
* Create a new factory instance to create posts with a set of terms.
*
* Any slugs passed that are not found will be created. If you want to
* only use existing terms, use `with_terms_only_existing()`.
*
* @param array<int|string, \WP_Term|int|string|array<string, mixed>>|\WP_Term|int|string ...$terms Terms to assign to the post.
*/
public function with_terms( ...$terms ): static {
// Handle an array in the first argument.
if ( 1 === count( $terms ) && isset( $terms[0] ) && is_array( $terms[0] ) ) {
$terms = $terms[0];
}
$terms = collect( $terms )->all();
return $this->with_middleware(
fn ( array $args, Closure $next ) => $next( $args )->set_terms(
terms: $terms,
append: $this->append_terms,
create: $this->create_terms,
),
);
}
/**
* Create a new factory instance to create posts with a set of terms without creating
* any unknown terms.
*
* @param array<int|string, \WP_Term|int|string|array<string, mixed>>|\WP_Term|int|string ...$terms Terms to assign to the post.
*/
public function with_terms_only_existing( ...$terms ): static {
// Handle an array in the first argument.
if ( 1 === count( $terms ) && isset( $terms[0] ) && is_array( $terms[0] ) ) {
$terms = $terms[0];
}
$terms = collect( $terms )->all();
return $this->with_middleware(
fn ( array $args, Closure $next ) => $next( $args )->set_terms( $terms, append: $this->append_terms, create: false ),
);
}
/**
* Attach a post thumbnail to the post.
*
* Note: the underlying attachment does not actually exist for performance.
* You can use `with_real_thumbnail()` to create a real underlying attachment
* for the post thumbnail.
*/
public function with_thumbnail(): static {
return $this->with_meta(
[
'_thumbnail_id' => ( new Attachment_Factory( $this->faker ) )->create(),
]
);
}
/**
* Attach a thumbnail to the post with an underlying file attachment.
*
* @param string $file The file name to create attachment object from.
* @param int $width The width of the image.
* @param int $height The height of the image.
* @param bool $recycle Whether to recycle the image file.
*/
public function with_real_thumbnail( ?string $file = null, int $width = 640, int $height = 480, bool $recycle = true ): static {
return $this->with_middleware(
function ( array $args, Closure $next ) use ( $file, $width, $height, $recycle ) {
$post = $next( $args );
update_post_meta(
$post->ID,
'_thumbnail_id',
Attachment::factory()->with_image(
file: $file,
width: $width,
parent: $post->ID,
height: $height,
recycle: $recycle
)->create(),
);
return $post;
}
);
}
/**
* Create a new factory instance to create posts for a specific post type.
*
* @param string $post_type Post type to use.
*/
public function with_post_type( string $post_type ): static {
return tap(
clone $this,
fn ( Post_Factory $factory ) => $factory->post_type = $post_type,
);
}
/**
* Alias for {@see Post_Factory::with_post_type()}.
*
* @param string $post_type Post type to use.
*/
public function for( string $post_type ): static {
return $this->with_post_type( $post_type );
}
/**
* Definition of the factory.
*
* @return array<string, mixed>
*/
public function definition(): array {
return [
'post_content' => trim( (string) $this->faker->paragraph_blocks( 3 ) ),
'post_excerpt' => trim( $this->faker->paragraph( 2 ) ),
'post_status' => 'publish',
'post_title' => $this->faker->sentence(),
'post_type' => $this->post_type,
];
}
/**
* Create a post with a thumbnail.
*
* @deprecated Use {@see Post_Factory::with_thumbnail()} instead.
*
* @param array $args The arguments.
*/
public function create_with_thumbnail( array $args = [] ): ?int {
return $this->with_thumbnail()->create( $args );
}
/**
* Create an ordered set of posts.
*
* Useful to create posts in a specific order for testing. Creates posts in
* chronological order separated by a defined number of seconds, the
* default of which is equal to 1 hour.
*
* @param int $count The number of posts to create.
* @param array<mixed> $args The arguments.
* @param Carbon|string $starting_date The starting date for the posts, defaults to
* a month ago.
* @param int $separation The number of seconds between each post.
* @return array<int, int>
*/
public function create_ordered_set(
int $count = 10,
array $args = [],
Carbon|string|null $starting_date = null,
int $separation = 3600
): array {
if ( ! ( $starting_date instanceof Carbon ) ) {
$starting_date = $starting_date
? Carbon::parse( $starting_date )
: Carbon::now()->subSeconds( $separation * $count )->startOfMinute();
}
// Set the date for the first post (seconds added before each run).
$starting_date->subSeconds( $separation );
return collect()
->pad( $count, null )
->map(
fn () => $this->create(
array_merge(
$args,
[
'date' => $starting_date->addSeconds( $separation )->format( 'Y-m-d H:i:s' ),
]
)
)
)
->to_array();
}
/**
* Retrieves an object by ID.
*
* @param int $object_id The object ID.
* @return Post|WP_Post|null
* @phpstan-return TModel|TObject|null
*/
public function get_object_by_id( int $object_id ) {
return $this->as_models
? $this->model::find( $object_id )
: get_post_object( $object_id );
}
}