PluginProbe
FV Player 8 / trunk
FV Player 8 vtrunk
trunk 8.0.18 8.0.19 8.0.20 8.0.21 8.0.25 8.0.27 8.1 8.1.3
fv-player / models / db-video-meta.php

db-video-meta.php in FV Player 8 trunk, at models/db-video-meta.php

538 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* FV Player - HTML5 video player
3 Copyright (C) 2013 Foliovision
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 // video meta data instance with options that's stored in a DB
20 class FV_Player_Db_Video_Meta {
21
22 private
23 $id, // automatic ID for the meta data
24 $is_valid = true, // used when loading meta data from DB to determine whether we've found it
25 $id_video, // DB ID of the video to which this meta data belongs
26 $meta_key, // arbitrary meta key
27 $meta_value; // arbitrary meta value
28
29 private static
30 $db_table_name,
31 $DB_Instance = null;
32
33 /**
34 * @return int
35 */
36 public function getId() {
37 return $this->id;
38 }
39
40 /**
41 * @return int
42 */
43 public function getIdVideo() {
44 return $this->id_video;
45 }
46
47 /**
48 * @return string
49 */
50 public function getMetaKey() {
51 return $this->meta_key;
52 }
53
54 /**
55 * @return mixed
56 */
57 public function getMetaValue() {
58 return $this->meta_value;
59 }
60
61 /**
62 * @return bool
63 */
64 public function getIsValid() {
65 return $this->is_valid;
66 }
67
68 /**
69 * Initializes database name, including WP prefix
70 * once WPDB class is initialized.
71 *
72 * @return string Returns the actual table name for this ORM class.
73 */
74 public static function init_db_name() {
75 global $wpdb;
76
77 self::$db_table_name = $wpdb->prefix.'fv_player_videometa';
78 return self::$db_table_name;
79 }
80
81 /**
82 * Returns name of the video DB table.
83 *
84 * @return mixed The name of the video DB table.
85 */
86 public static function get_db_table_name() {
87 if ( !self::$db_table_name ) {
88 self::init_db_name();
89 }
90
91 return self::$db_table_name;
92 }
93
94 /**
95 * Checks for DB tables existence and creates it as necessary.
96 *
97 * @param $force Forces to run dbDelta.
98 */
99 public static function initDB($force = false) {
100 global $wpdb, $fv_fp, $fv_wp_flowplayer_ver;
101
102 self::init_db_name();
103
104 $res = false;
105
106 if( defined('PHPUnitTestMode') || !$fv_fp->_get_option('video_meta_model_db_checked') || $fv_fp->_get_option('video_meta_model_db_checked') != $fv_wp_flowplayer_ver || $force ) {
107 $sql = "
108 CREATE TABLE " . self::$db_table_name . " (
109 id bigint(20) unsigned NOT NULL auto_increment,
110 id_video bigint(20) unsigned NOT NULL default '0',
111 meta_key varchar(255) NOT NULL,
112 meta_value longtext NOT NULL,
113 PRIMARY KEY (id),
114 KEY id_video (id_video),
115 KEY meta_key (meta_key(191))
116 )" . $wpdb->get_charset_collate() . ";";
117 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
118 $res = dbDelta( $sql );
119 $fv_fp->_set_option('video_meta_model_db_checked', $fv_wp_flowplayer_ver);
120 }
121
122 return $res;
123 }
124
125 /**
126 * Makes this meta data object linked to a record in database.
127 * This is used when loading multiple meta data records in the constructor,
128 * so we can return them as objects from the DB and any saving will
129 * not insert their duplicates.
130 *
131 * @param $id The DB ID to which we'll link this meta data record.
132 * @param bool $id_is_video If true, link to an actual video ID will be made.
133 */
134 public function link2db($id, $id_is_video = false) {
135 if (!$id_is_video) {
136 $this->id = (int) $id;
137 } else {
138 $this->id_video = (int) $id;
139 }
140 }
141
142 /**
143 * FV_Player_Db_Video_Meta constructor.
144 *
145 * @param int $id ID of video meta data to load data from the DB for.
146 * @param array $options Options for a newly created video meta data that will be stored in a DB.
147 * @param FV_Player_Db $DB_Cache Instance of the DB shortcode global object that handles caching
148 * of videos, players and their meta data.
149 *
150 * @throws Exception When no valid ID nor options are provided.
151 */
152 function __construct($id, $options = array(), $DB_Cache = null) {
153 global $wpdb;
154
155 if ($DB_Cache) {
156 self::$DB_Instance = $DB_Cache;
157 }
158
159 self::initDB();
160 $multiID = is_array($id);
161
162 // don't load anything, if we've only created this instance
163 // to initialize the database (this comes from list-table.php and unit tests)
164 if ($id === -1) {
165 return;
166 }
167
168 // check whether we're not trying to load data for a single video
169 // rather than meta data by its own ID
170 $load_for_video = false;
171 $force_cache_update = false;
172
173 if (is_array($options) && count($options) && isset($options['id_video']) && is_array($options['id_video'])) {
174 $load_for_video = true;
175 $multiID = true;
176 $id = $options['id_video'];
177 // reset this, so we don't try to create a new record below
178 $options = array();
179 }
180
181 // if we've got options, fill them in instead of querying the DB,
182 // since we're storing new video meta data into the DB in such case
183 if (is_array($options) && count($options)) {
184 foreach ($options as $key => $value) {
185 if (property_exists($this, $key)) {
186 if ($key !== 'id') {
187 $this->$key = FV_Player_Db::sanitize( $value );
188 }
189 } else {
190 // generate warning
191 trigger_error('Unknown property for new DB video meta data item: ' . $key);
192 }
193 }
194 } else if ($multiID || (is_numeric($id) && $id > 0)) {
195 /* @var $cache FV_Player_Db_Video_Meta[] */
196 $cache = ($DB_Cache ? $DB_Cache->getVideoMetaCache() : array());
197 $all_cached = false;
198 $some_meta_exist = false;
199
200 // no options, load data from DB
201 if ($multiID) {
202 $query_ids = array();
203
204 // make sure we have numeric IDs and that they're not cached yet
205 $is_cached = false;
206 foreach ($id as $id_key => $id_value) {
207 if ($load_for_video) {
208 $is_cached = isset($cache[$id_value]);
209 $some_meta_exist = ($is_cached ? count($cache[$id_value]) : false);
210 } else {
211 // run through all the cached data and check
212 // whether our meta data ID was not cached yet
213 foreach ($cache as $video_meta) {
214 if (isset($video_meta[$id_value])) {
215 $is_cached = true;
216 $some_meta_exist = (count($video_meta[$id_value]) ? true : false);
217 }
218 }
219 }
220
221 // select from DB if not cached yet
222 if (!$is_cached) {
223 $query_ids[ $id_key ] = $id_value;
224 }
225
226 $id[$id_key] = (int) $id_value;
227 }
228
229 if (count($query_ids)) {
230 // load multiple video metas via their IDs but a single query and return their values
231 $placeholders = implode( ', ', array_fill( 0, count( $query_ids ), '%d' ) );
232
233 if ( $load_for_video ) {
234 $meta_data = $wpdb->get_results(
235 $wpdb->prepare(
236 // $placeholders is a string of %d created above
237 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
238 "SELECT * FROM `{$wpdb->prefix}fv_player_videometa` WHERE id_video IN( $placeholders )",
239 $query_ids
240 )
241 );
242
243 } else {
244 $meta_data = $wpdb->get_results(
245 $wpdb->prepare(
246 // $placeholders is a string of %d created above
247 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
248 "SELECT * FROM `{$wpdb->prefix}fv_player_videometa` WHERE id IN( $placeholders )",
249 $query_ids
250 )
251 );
252 }
253
254 // run through all of the meta data and
255 // fill the ones that were not found with blank arrays
256 // for cache-filling purposes
257 if ( !is_array( $meta_data ) ) {
258 $meta_data = array();
259 }
260
261 foreach ( $query_ids as $q_id ) {
262 $meta_found = false;
263 foreach ( $meta_data as $m_data ) {
264 if ( ( $load_for_video && $m_data->id_video == $q_id ) || ( ! $load_for_video && $m_data->id == $q_id ) ) {
265 $meta_found = true;
266 break;
267 }
268 }
269
270 // if we have no meta data for the requested ID,
271 // fill it with an empty array
272 if ( ! $meta_found ) {
273 $force_cache_update = true;
274
275 if ( $load_for_video ) {
276 // for video, create an empty array with no meta
277 $cache[ $q_id ] = array();
278 } else {
279 // for a single meta, initialize it with null value
280 // on a 0-id video (which obviously cannot exist,
281 // so we can use it for cache-checking purposes)
282 $cache[0][ $q_id ] = null;
283 }
284 }
285 }
286 } else {
287 $all_cached = true;
288 }
289 } else {
290 $is_cached = false;
291 if ($load_for_video) {
292 $is_cached = isset($cache[$id]);
293 $some_meta_exist = ($is_cached ? count($cache[$id]) : false);
294 } else {
295 // run through all the cached data and check
296 // whether our meta data ID was not cached yet
297 foreach ($cache as $video_id => $video_meta) {
298 if (isset($video_meta[$id])) {
299 $is_cached = true;
300 $some_meta_exist = (count($video_meta[$id]) ? true : false);
301 }
302 }
303 }
304
305 if (!$is_cached) {
306 // load a single video meta data record
307 $meta_data = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM `{$wpdb->prefix}fv_player_videometa` WHERE id = %d', $id ) );
308
309 // run through all of the meta data and
310 // fill the ones that were not found with blank arrays
311 // for cache-filling purposes
312 if (!is_array($meta_data)) {
313 $meta_data = array();
314 }
315
316 $meta_found = false;
317 foreach ($meta_data as $m_data) {
318 if (($load_for_video && $m_data->id_video == $id) || (!$load_for_video && $m_data->id == $id)) {
319 $meta_found = true;
320 break;
321 }
322 }
323
324 // if we have no meta data for the requested ID,
325 // fill it with an empty array
326 if (!$meta_found) {
327 $force_cache_update = true;
328
329 if ($load_for_video) {
330 // for player, create an empty array with no meta
331 $cache[$id] = array();
332 } else {
333 // for a single meta, initialize it with null value
334 // on a 0-id video (which obviously cannot exist,
335 // so we can use it for cache-checking purposes)
336 $cache[0][$id] = null;
337 }
338 }
339 } else {
340 $all_cached = true;
341 }
342 }
343
344 if (isset($meta_data) && $meta_data && count($meta_data)) {
345 // single ID, just populate our own data
346 if (!$multiID) {
347 // fill-in our internal variables, as they have the same name as DB fields (ORM baby!)
348 foreach ( $meta_data as $key => $value ) {
349 $this->$key = FV_Player_Db::sanitize( $value );
350 }
351
352 // cache this meta in DB object
353 if ($DB_Cache) {
354 $cache[$this->id_video][$this->id] = $this;
355 }
356 } else {
357 // multiple IDs, create new video meta objects for each of them except the first one,
358 // for which we'll use this instance
359 $first_done = false;
360 foreach ($meta_data as $db_record) {
361 if (!$first_done) {
362 // fill-in our internal variables
363 foreach ( $db_record as $key => $value ) {
364 $this->$key = FV_Player_Db::sanitize( $value );
365 }
366
367 $first_done = true;
368
369 // cache this meta in DB object
370 if ($DB_Cache) {
371 $cache[$db_record->id_video][$this->id] = $this;
372 }
373 } else {
374 // create a new video object and populate it with DB values
375 $record_id = $db_record->id;
376 // if we don't unset this, we'll get warnings
377 unset($db_record->id);
378
379 if (!self::$DB_Instance->isVideoMetaCached($db_record->id_video, $record_id)) {
380 $video_meta_object = new FV_Player_Db_Video_Meta(null, get_object_vars($db_record), self::$DB_Instance);
381 $video_meta_object->link2db($record_id);
382
383 // cache this meta in DB object
384 if ($DB_Cache) {
385 $cache[$db_record->id_video][$record_id] = $video_meta_object;
386 }
387 }
388 }
389 }
390 }
391 } else if ($all_cached && $some_meta_exist) {
392 // fill the data for this class with data of the cached class
393 if ($multiID) {
394 $cached_meta = reset($id);
395 } else {
396 $cached_meta = $id;
397 }
398
399 // find the meta in cache and reassign $cached_meta
400 foreach ($cache as $video_id => $video) {
401 if ($load_for_video && $video_id == $cached_meta ) {
402 // load first meta for the requested video
403 $cached_meta = reset( $video );
404 break;
405 } else if (!$load_for_video && isset($video[$cached_meta])) {
406 $cached_meta = $video[$cached_meta];
407 break;
408 }
409 }
410
411 // $cached_meta will remain numeric if there are no meta data in the database
412 if ($cached_meta instanceof FV_Player_Db_Video_Meta) {
413 foreach ( $cached_meta->getAllDataValues() as $key => $value ) {
414 $this->$key = FV_Player_Db::sanitize( $value );
415 }
416 }
417 } else {
418 $this->is_valid = false;
419 }
420 } else {
421 throw new Exception('No options nor a valid ID was provided for DB video meta data item.');
422 }
423
424 // update cache, if changed
425 if (isset($cache) && ($force_cache_update || !isset($all_cached) || !$all_cached)) {
426 self::$DB_Instance->setVideoMetaCache($cache);
427 }
428 }
429
430 /**
431 * Returns all options data for this video.
432 *
433 * @return array Returns all options data for this video.
434 */
435 public function getAllDataValues() {
436 $data = array();
437 foreach (get_object_vars($this) as $property => $value) {
438 if ($property != 'is_valid' && $property != 'db_table_name' && $property != 'DB_Instance') {
439 $data[$property] = $value;
440 }
441 }
442
443 return $data;
444 }
445
446 /**
447 * Stores new video meta data item or updates and existing one
448 * in the database.
449 *
450 * @return bool|int Returns record ID if successful, false otherwise.
451 */
452 public function save() {
453 global $wpdb;
454
455 // prepare SQL
456 $is_update = ($this->id ? true : false);
457 $data_values = array();
458
459 foreach (get_object_vars($this) as $property => $value) {
460 if ($property != 'id' && $property != 'is_valid' && $property != 'db_table_name' && $property != 'DB_Instance') {
461 $data_values[ $property ] = $value;
462 }
463 }
464
465 if ($is_update) {
466 $wpdb->update( self::$db_table_name, $data_values, array( 'id' => $this->id ) );
467
468 } else {
469 $wpdb->insert( self::$db_table_name, $data_values );
470 }
471
472 if (!$is_update) {
473 $this->id = $wpdb->insert_id;
474 }
475
476 if (!$wpdb->last_error) {
477 // add this meta into cache
478 $cache = self::$DB_Instance->getVideoMetaCache();
479 $cache[$this->id_video][$this->id] = $this;
480 self::$DB_Instance->setVideoMetaCache($cache);
481
482 return $this->id;
483 } else {
484 /*var_export($wpdb->last_error);
485 var_export($wpdb->last_query);*/
486 return false;
487 }
488 }
489
490 /**
491 * Prepares this class' properties for export
492 * and returns them in an associative array.
493 *
494 * @return array Returns an associative array of this class' properties and their values.
495 */
496 public function export() {
497 $export_data = array();
498 foreach (get_object_vars($this) as $property => $value) {
499 if ($property != 'id' && $property != 'id_video' && $property != 'is_valid' && $property != 'db_table_name' && $property != 'DB_Instance') {
500 $export_data[$property] = $value;
501 }
502 }
503
504 return $export_data;
505 }
506
507 /**
508 * Removes meta data instance from the database.
509 *
510 * @return bool Returns true if the delete was successful, false otherwise.
511 */
512 public function delete() {
513 // not a DB meta? no delete
514 if (!$this->is_valid) {
515 return false;
516 }
517
518 global $wpdb;
519
520 $wpdb->delete(self::$db_table_name, array('id' => $this->id));
521
522 if (!$wpdb->last_error) {
523 // remove this meta from cache
524 $cache = self::$DB_Instance->getVideoMetaCache();
525 if (isset($cache[$this->id_video][$this->id])) {
526 unset($cache[$this->id_video][$this->id]);
527 self::$DB_Instance->setVideoMetaCache($cache);
528 }
529
530 return true;
531 } else {
532 /*var_export($wpdb->last_error);
533 var_export($wpdb->last_query);*/
534 return false;
535 }
536 }
537 }
538