Completed
Push — master ( 5a2e90...9a86e3 )
by Evan
03:43
created

Post::all()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Silk\Models;
4
5
use Silk\Query\Builder;
6
use stdClass;
7
use WP_Post;
8
use Silk\WP_ErrorException;
9
use Silk\Meta\ObjectMeta;
10
use Silk\Models\Exceptions\PostNotFoundException;
11
use Silk\Models\Exceptions\ModelPostTypeMismatchException;
12
use WP_Query;
13
14
class Post
15
{
16
    /**
17
     * The post
18
     * @var WP_Post
19
     */
20
    protected $post;
21
22
    /**
23
     * Post ID
24
     * @var int
25
     */
26
    protected $id;
27
28
    /**
29
     * The post type of the post this model wraps
30
     * @var string
31
     */
32
    const POST_TYPE = 'post';
33
34
35
    /**
36
     * [__construct description]
37
     * @param WP_Post $post [description]
38
     */
39
    public function __construct(WP_Post $post = null)
40
    {
41
        if (! $post) {
42
            $post = new WP_Post(new stdClass);
43
            $post->post_type = static::POST_TYPE;
44
        }
45
46
        $this->post = $post;
47
        $this->id   = $post->ID;
48
    }
49
50
    public static function fromWpPost(WP_Post $post)
51
    {
52
        if ($post->post_type !== static::POST_TYPE) {
53
            throw new ModelPostTypeMismatchException(static::class, $post);
54
        }
55
56
        return new static($post);
57
    }
58
59
    /**
60
     * Make new instance from a Post with the given ID
61
     *
62
     * @param  int|string $id [description]
63
     *
64
     * @return static
65
     */
66
    public static function fromID($id)
67
    {
68
        $post = WP_Post::get_instance($id);
69
70
        if (false === $post) {
71
            throw new PostNotFoundException("No post found with ID {$id}");
72
        }
73
74
        return static::fromWpPost($post);
75
    }
76
77
    /**
78
     * Make new instance from a Post slug
79
     *
80
     * @param  string $slug  the post slug
81
     *
82
     * @return static
83
     */
84
    public static function fromSlug($slug)
85
    {
86
        $posts = (array) get_posts([
87
            'name'           => $slug,
88
            'post_type'      => static::POST_TYPE,
89
            'post_status'    => 'any',
90
            'posts_per_page' => 1
91
        ]);
92
93
        if (! $post = reset($posts)) {
94
            throw new PostNotFoundException("No post found with slug {$slug}");
95
        }
96
97
        return static::fromWpPost($post);
98
    }
99
100
    /**
101
     * Make new instance from the global $post
102
     *
103
     * @return static
104
     */
105
    public static function fromGlobal()
106
    {
107
        $post = get_post();
108
109
        if (! $post instanceof WP_Post) {
1 ignored issue
show
Bug introduced by
The class WP_Post does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
110
            throw new PostNotFoundException('Global $post not an instance of WP_Post');
111
        }
112
113
        return static::fromWpPost($post);
114
    }
115
116
    /**
117
     * Create a new post of the model's type
118
     *
119
     * @param  [type] $attributes [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
120
     * @return [type]             [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
121
     */
122
    public static function create($attributes = [])
123
    {
124
        unset($attributes['ID']);
125
        $attributes['post_type'] = static::POST_TYPE;
126
127
        $post = new WP_Post((object) $attributes);
128
        $model = static::fromWpPost($post);
129
130
        return $model->save();
131
    }
132
133
    /**
134
     * Meta API for this post
135
     *
136
     * @param  string $key [description]
137
     * @return Meta
138
     */
139
    public function meta($key = '')
140
    {
141
        $meta = new ObjectMeta('post', $this->id);
142
143
        if ($key) {
144
            return $meta->get($key);
145
        }
146
147
        return $meta;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $meta; (Silk\Meta\ObjectMeta) is incompatible with the return type documented by Silk\Models\Post::meta of type Silk\Models\Meta.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
148
    }
149
150
    /**
151
     * Send the post to the trash
152
     *
153
     * If trash is disabled, the post or page is permanently deleted.
154
     *
155
     * @return false|array|WP_Post|null Post data array, otherwise false.
156
     */
157
    public function trash()
158
    {
159
        if (wp_trash_post($this->id)) {
160
            $this->refresh();
161
        }
162
163
        return $this;
164
    }
165
166
    /**
167
     * Restore a post or page from the Trash
168
     *
169
     * @return WP_Post|false WP_Post object. False on failure.
170
     */
171
    public function untrash()
172
    {
173
        if (wp_untrash_post($this->id)) {
174
            $this->refresh();
175
        }
176
177
        return $this;
178
    }
179
180
    /**
181
     * Permanently deletes the post and related objects
182
     *
183
     * When the post and page is permanently deleted, everything that is
184
     * tied to it is deleted also. This includes comments, post meta fields,
185
     * and terms associated with the post.
186
     *
187
     * @return [type] [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
188
     */
189
    public function delete()
190
    {
191
        if (wp_delete_post($this->id, true)) {
192
            $this->refresh();
193
        }
194
195
        return $this;
196
    }
197
198
    /**
199
     * Refresh the post object from cache/database
200
     *
201
     * @return static
202
     */
203
    public function refresh()
204
    {
205
        $this->post = WP_Post::get_instance($this->id);
206
207
        return $this;
208
    }
209
210
    /**
211
     * Update the post in the database
212
     *
213
     * @return [type] [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
214
     */
215
    public function save()
216
    {
217
        if (! $this->id) {
218
            $result = wp_insert_post($this->post->to_array(), true);
219
        } else {
220
            $result = wp_update_post($this->post, true);
221
        }
222
223
        if (is_wp_error($result)) {
224
            throw new WP_ErrorException($result);
225
        }
226
227
        $this->id = (int) $result;
228
229
        return $this->refresh();
230
    }
231
232
    public static function all()
233
    {
234
        return static::query()->limit(-1);
235
    }
236
237
    /**
238
     * Get a new query builder for the model.
239
     *
240
     * @return Builder
241
     */
242
    public function newQuery()
243
    {
244
        return (new Builder(new WP_Query))->setModel($this);
245
    }
246
247
    /**
248
     * Create a new query builder instance for this model type.
249
     * @return Builder
250
     */
251
    public static function query()
252
    {
253
        return (new static)->newQuery();
254
    }
255
256
    /**
257
     * Magic getter
258
     * @param  string $property
259
     * @return mixed
260
     */
261
    public function __get($property)
262
    {
263
        if ('id' === $property) {
264
            return $this->id;
265
        }
266
267
        if (isset($this->$property)) {
268
            return $this->$property;
269
        }
270
271
        if (isset($this->post->$property)) {
272
            return $this->post->$property;
273
        }
274
275
        throw new \InvalidArgumentException(static::class . " has no property: {$property}");
276
    }
277
278
    /**
279
     * Magic setter
280
     * @param string $property
281
     * @param mixed $value
282
     */
283
    public function __set($property, $value)
284
    {
285
        if (isset($this->post->$property)) {
286
            $this->post->$property = $value;
287
        }
288
    }
289
290
    /**
291
     * Handle dynamic static method calls on the model class.
292
     *
293
     * Proxies calls to direct method calls on a new instance
294
     *
295
     * @param       $method
296
     * @param array $arguments
297
     *
298
     * @return mixed
299
     */
300
    public static function __callStatic($method, array $arguments)
301
    {
302
        return call_user_func_array([new static, $method], $arguments);
303
    }
304
305
    /**
306
     * Handle dynamic method calls into the model.
307
     *
308
     * @param  string  $method
309
     * @param  array  $arguments
310
     * @return mixed
311
     */
312
    public function __call($method, $arguments)
313
    {
314
        $query = $this->newQuery();
315
316
        return call_user_func_array([$query, $method], $arguments);
317
    }
318
319
}
320