PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/dal.php

https://github.com/adnanpri/domain
PHP | 1157 lines | 755 code | 217 blank | 185 comment | 76 complexity | e3894f2640a7770cf060b919e2e8e60b MD5 | raw file
  1. <?php
  2. /**
  3. * Part of the Domain API for Layla.
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this package in the file licence.txt.
  9. * If you did not receive a copy of the license and are unable to
  10. * obtain it through the world-wide-web, please send an email
  11. * to license@getlayla.com so I can send you a copy immediately.
  12. *
  13. * @package Layla Domain
  14. * @version 1.0
  15. * @author Koen Schmeets <koen@getlayla.com>
  16. * @license MIT License
  17. * @link http://getlayla.com
  18. */
  19. namespace Domain\Libraries;
  20. use Laravel\Str;
  21. use Laravel\Database as DB;
  22. use Layla\DBManager;
  23. /**
  24. * This DAL class provides methods for setting up a secured,
  25. * CRUD DB layer over HTTP with very little effort
  26. */
  27. class DAL {
  28. /**
  29. * The model we are working with
  30. *
  31. * @var Database\Eloquent\Model
  32. */
  33. public $model;
  34. /**
  35. * The model's table
  36. *
  37. * @var string
  38. */
  39. public $table;
  40. /**
  41. * The language model
  42. *
  43. * @var Database\Eloquent\Model
  44. */
  45. public $language_model;
  46. /**
  47. * The language table
  48. *
  49. * @var string
  50. */
  51. public $language_table;
  52. /**
  53. * The language table's foreign key
  54. *
  55. * @var string
  56. */
  57. public $language_table_foreign_key;
  58. /**
  59. * The parent
  60. */
  61. public $parent;
  62. /**
  63. * The data
  64. */
  65. public $data = array();
  66. /**
  67. * The input
  68. *
  69. * @var array
  70. */
  71. public $input = array();
  72. /**
  73. * The response code
  74. *
  75. * @var int
  76. */
  77. public $code = 200;
  78. /**
  79. * The settings
  80. *
  81. * @var array
  82. */
  83. public $settings = array(
  84. 'relating' => array(),
  85. 'sortable' => array(),
  86. 'searchable' => array(),
  87. 'filterable' => array()
  88. );
  89. /**
  90. * Options are used for limiting the results on get requests
  91. * And can be used to add custom data to the input on post / put requests
  92. *
  93. * @var array
  94. */
  95. public $options = array(
  96. 'offset' => 0,
  97. 'limit' => 20,
  98. 'sort_by' => 'name',
  99. 'order' => 'ASC',
  100. 'filter' => array(
  101. ),
  102. 'search' => array(
  103. 'string' => '',
  104. 'columns' => array()
  105. )
  106. );
  107. /**
  108. * Indicates if a language table should be joined or included
  109. *
  110. * The table will be joined in case there is no search or order
  111. * on one of the table's columns
  112. * The expected language table name is the model's name
  113. * post-fixed with "_lang". For example, the expected language
  114. * table for "users" is "user_lang"
  115. *
  116. * @var bool
  117. */
  118. public $multilanguage = false;
  119. /**
  120. * Indicates if the main model is versioned
  121. *
  122. * When turned on, upon saving the version will be "increased" and
  123. * upon retrieval only the latest version will be returned
  124. *
  125. * @var bool
  126. */
  127. public $versioned = false;
  128. /**
  129. * Indicates if slug is enabled and from
  130. * what column it should be generated
  131. *
  132. * @var string
  133. */
  134. public $slug;
  135. /**
  136. * The model's id
  137. */
  138. public $id;
  139. /**
  140. * The language_id
  141. */
  142. public $language_id;
  143. /**
  144. * The relationships that have to be synced
  145. *
  146. * @var array
  147. */
  148. public $sync = array();
  149. /**
  150. * Indicates what tables should be joined (only for get_ methods)
  151. *
  152. * <code>
  153. * $this->joins[] = array(
  154. * 'table' => 'mobilenumbers',
  155. * 'join' => array('users.id', '=', 'mobilenumbers.user_id', 'INNER')
  156. * );
  157. * </code>
  158. *
  159. * @var array
  160. */
  161. public $joins = array();
  162. /**
  163. * The columns on joined tables that will be mapped
  164. *
  165. * @var array
  166. */
  167. public $mapped_columns = array();
  168. /**
  169. * The fields that will be retrieved
  170. *
  171. * @var array
  172. */
  173. public $get_columns = array();
  174. public function __construct($model = null)
  175. {
  176. if( ! is_null($model))
  177. {
  178. $this->model = $model;
  179. $this->table = $model->table();
  180. // Initialize the array that will hold the columns we want to fetch
  181. $this->get_columns = array($this->table.'.*');
  182. }
  183. }
  184. /**
  185. * Method for retrieving a DAL instance
  186. *
  187. * @param $model the model to work with
  188. */
  189. public static function model($model)
  190. {
  191. return new DAL($model);
  192. }
  193. /**
  194. * Method for setting the language model
  195. *
  196. * @param $language_model the language model
  197. */
  198. public function language_model($language_model)
  199. {
  200. $this->language_model = $language_model;
  201. return $this;
  202. }
  203. /**
  204. * Method for merging settings
  205. *
  206. * @var array the settings
  207. */
  208. public function settings($settings)
  209. {
  210. $this->settings = array_replace_recursive($this->settings, $settings);
  211. return $this;
  212. }
  213. /**
  214. * Method for merging options
  215. *
  216. * @var array the options
  217. */
  218. public function options($options)
  219. {
  220. $this->options = array_replace_recursive($this->options, $options);
  221. return $this;
  222. }
  223. /**
  224. * Method for merging options
  225. *
  226. * @var array the options
  227. */
  228. public function join($join)
  229. {
  230. $this->joins[] = $join;
  231. return $this;
  232. }
  233. public function filter($filter)
  234. {
  235. $this->options['filter'] = array_replace_recursive($this->options['filter'], $filter);
  236. return $this;
  237. }
  238. /**
  239. * Method for merging input
  240. *
  241. * @var array the input
  242. */
  243. public function input($input)
  244. {
  245. $this->input = array_replace_recursive($this->input, $input);
  246. return $this;
  247. }
  248. public function multilanguage($multilanguage = true)
  249. {
  250. $this->multilanguage = $multilanguage;
  251. if($multilanguage)
  252. {
  253. // Get the lowercase model name, without the namespace
  254. $basename = strtolower(class_basename($this->model));
  255. // Set the language table name
  256. $this->language_table = $basename.'_lang';
  257. // Set the language table's foreign key
  258. $this->language_table_foreign_key = $basename.'_id';
  259. $this->settings['filterable'][$this->language_table][] = 'language_id';
  260. }
  261. return $this;
  262. }
  263. public function versioned($versioned = true)
  264. {
  265. $this->versioned = $versioned;
  266. return $this;
  267. }
  268. public function slug($slug = '')
  269. {
  270. $this->slug = $slug;
  271. return $this;
  272. }
  273. public function parent($parent)
  274. {
  275. $this->parent = $parent;
  276. return $this;
  277. }
  278. public function sync($sync = null)
  279. {
  280. if(is_null($sync))
  281. {
  282. foreach($this->sync as $relationship)
  283. {
  284. $this->model->$relationship()->sync($this->input[$relationship] ? array_flip(array_filter(array_flip($this->input[$relationship]), 'strlen')) : array());
  285. }
  286. return $this;
  287. }
  288. $this->sync = $sync;
  289. return $this;
  290. }
  291. /**
  292. * Method for retrieving multiple records
  293. */
  294. public function read_multiple()
  295. {
  296. if( ! $this->valid_options())
  297. {
  298. return $this;
  299. }
  300. // Multilanguage, lets check if we need to join the records (for search or sort)
  301. if ($this->multilanguage)
  302. {
  303. $filters = $this->get_filters($this->language_table);
  304. // Find out if we need a join
  305. if ($this->needs_join($this->language_table) || $this->versioned)
  306. {
  307. $table = $this->table;
  308. $language_table = $this->language_table;
  309. $language_table_foreign_key = $this->language_table_foreign_key;
  310. // Add a join for the language table
  311. $this->joins[] = array(
  312. 'table' => $language_table,
  313. 'join' => array(function($join) use ($table, $language_table, $language_table_foreign_key, $filters)
  314. {
  315. foreach($filters as $filter)
  316. {
  317. list($table, $column, $value) = $filter;
  318. $join->where($table.'.'.$column, '=', $value);
  319. }
  320. $join->on($table.'.id', '=', $language_table.'.'.$language_table_foreign_key);
  321. $join->on($language_table.'.language_id', '=', 1);
  322. })
  323. );
  324. if($this->versioned)
  325. {
  326. // Add a left outer join to be able to only get
  327. // the language rows at the latest version
  328. $this->joins[] = array(
  329. 'table' => $language_table.' AS max',
  330. 'join' => array(function($join) use ($table, $language_table, $language_table_foreign_key, $filters)
  331. {
  332. foreach($filters as $filter)
  333. {
  334. list($table, $column, $value) = $filter;
  335. $join->where($table.'.'.$column, '=', $value);
  336. }
  337. $join->on($table.'.id', '=', 'max.'.$language_table_foreign_key);
  338. $join->on('max.version', '>', $language_table.'.version');
  339. $join->on('max.language_id', '=', 1);
  340. }, '', '', 'LEFT OUTER')
  341. );
  342. $this->get_columns[] = $language_table.'.version';
  343. $this->model = $this->model->where('max.version', 'IS', DB::raw('NULL'));
  344. }
  345. }
  346. else
  347. {
  348. $this->model->includes[] = array('lang' => function($query) use ($filters)
  349. {
  350. foreach($filters as $filter)
  351. {
  352. list($table, $column, $value) = $filter;
  353. $query = $query->where($table.'.'.$column, '=', $value);
  354. }
  355. });
  356. }
  357. }
  358. elseif($this->versioned)
  359. {
  360. $this->model = $this->model->where('version', '=',
  361. DB::raw('('.
  362. DB::table($this->table.' AS max')
  363. ->select(DB::raw('MAX(version) AS version'))
  364. ->where($this->table.'.id', '=', DB::raw('max.id'))
  365. ->sql().
  366. ')')
  367. );
  368. }
  369. $this->apply_joins();
  370. foreach($this->get_filters($this->table) as $filter)
  371. {
  372. list($table, $column, $value) = $filter;
  373. $this->model = $this->model->where($table.'.'.$column, '=', $value);
  374. }
  375. // Add where's to our query
  376. if ($this->options['search']['string'] !== '')
  377. {
  378. $columns = $this->options['search']['columns'];
  379. $string = $this->options['search']['string'];
  380. $this->model = $this->model->where(function($query) use ($columns, $string)
  381. {
  382. foreach($columns as $column)
  383. {
  384. $query->or_where($column, ' LIKE ', '%'.$string.'%');
  385. }
  386. });
  387. }
  388. $total = (int) $this->model->count();
  389. // Add order_by, skip & take to our results query
  390. $results = $this->model
  391. ->order_by($this->options['sort_by'], $this->options['order'])
  392. ->skip($this->options['offset'])
  393. ->take($this->options['limit'])
  394. ->get($this->get_columns);
  395. $this->data = array(
  396. 'results' => to_array($results),
  397. 'total' => $total,
  398. 'pages' => ceil($total / $this->options['limit'])
  399. );
  400. $this->apply_mappings();
  401. return $this;
  402. }
  403. /**
  404. * Method for retrieving a single record
  405. */
  406. public function read($id)
  407. {
  408. if( ! $this->valid_options())
  409. {
  410. return $this;
  411. }
  412. if( ! $this->find($id))
  413. {
  414. return $this;
  415. }
  416. $version = isset($this->options['filter']['version'])
  417. ?
  418. $this->options['filter']['version']
  419. :
  420. null;
  421. if(is_null($version) && $this->versioned)
  422. {
  423. if($this->multilanguage)
  424. {
  425. $query = DB::table($this->language_table)
  426. ->where($this->language_table_foreign_key, '=', $this->id);
  427. foreach($this->get_filters($this->language_table) as $filter)
  428. {
  429. list($table, $column, $value) = $filter;
  430. $query = $query->where($table.'.'.$column, '=', $value);
  431. }
  432. $version = $query->max('version');
  433. }
  434. else
  435. {
  436. $query = DB::table($this->table)
  437. ->where_id($this->id);
  438. foreach($this->get_filters($this->table) as $filter)
  439. {
  440. list($table, $column, $value) = $filter;
  441. $query = $query->where($table.'.'.$column, '=', $value);
  442. }
  443. $version = $query->max('version');
  444. }
  445. }
  446. if($this->multilanguage)
  447. {
  448. if( ! isset($this->options['filter']['language_id']))
  449. {
  450. $filters = $this->get_filters($this->language_table);
  451. $this->model->model->includes['languages'] = function($query) use ($version, $filters)
  452. {
  453. foreach($filters as $filter)
  454. {
  455. list($table, $column, $value) = $filter;
  456. $query->where($table.'.'.$column, '=', $value);
  457. }
  458. if( ! is_null($version))
  459. {
  460. $query->where_version($version);
  461. }
  462. };
  463. }
  464. else
  465. {
  466. $language_id = $this->options['filter']['language_id'];
  467. $filters = $this->get_filters($this->language_table);
  468. $this->model->model->includes['lang'] = function($query) use ($version, $language_id, $filters)
  469. {
  470. foreach($filters as $filter)
  471. {
  472. list($table, $column, $value) = $filter;
  473. $query->where($table.'.'.$column, '=', $value);
  474. }
  475. $query->where_language_id($language_id);
  476. if( ! is_null($version))
  477. {
  478. $query->where_version($version);
  479. }
  480. };
  481. }
  482. }
  483. if( ! is_null($version))
  484. {
  485. $this->model = $this->model->where($this->table.'.version', '=', $version);
  486. }
  487. foreach($this->get_filters($this->table) as $filter)
  488. {
  489. list($table, $column, $value) = $filter;
  490. $this->model = $this->model->where($table.'.'.$column, '=', $value);
  491. }
  492. $this->data = $this->model->first($this->get_columns)->to_array();
  493. $this->apply_mappings();
  494. return $this;
  495. }
  496. public function create_multiple()
  497. {
  498. foreach($this->input as $input)
  499. {
  500. $dal = clone $this;
  501. $dal->input = $input;
  502. $dal->create();
  503. if($dal->code === 400)
  504. {
  505. $this->code = 400;
  506. $this->data[] = $dal->data;
  507. }
  508. }
  509. return $this;
  510. }
  511. public function create()
  512. {
  513. if( ! $this->multilanguage && ( ! is_null($this->slug) || (isset($this->parent) && ! is_null($this->parent))))
  514. {
  515. $key = isset($this->parent) && ! is_null($this->parent) ?
  516. $this->parent->slug
  517. :
  518. $this->slug;
  519. $this->input['slug'] = Str::slug($this->input[$key]);
  520. }
  521. // Fill the model with data
  522. $this->model->fill($this->input);
  523. // Try to save
  524. if($this->model->save() === false)
  525. {
  526. $this->code = 400;
  527. $this->data = (array) $this->model->errors->messages;
  528. return $this;
  529. }
  530. $this->sync();
  531. if($this->multilanguage)
  532. {
  533. $lang_input = array();
  534. foreach($this->input['lang'] as $id => $input)
  535. {
  536. $input['language_id'] = $id;
  537. $input[$this->language_table_foreign_key] = $this->id;
  538. $lang_input[] = $input;
  539. }
  540. unset($this->input['lang']);
  541. $dal = DAL::model($this->language_model)
  542. ->versioned($this->versioned)
  543. ->input($lang_input)
  544. ->create_multiple();
  545. if( ! $dal->code == 200)
  546. {
  547. $this->data = $dal->data;
  548. $this->code = $dal->code;
  549. return $this;
  550. }
  551. }
  552. // Set the model's id as data
  553. $this->data = $this->model->get_key();
  554. return $this;
  555. }
  556. public function update_multiple()
  557. {
  558. foreach($this->input as $input)
  559. {
  560. $dal = clone $this;
  561. $dal->input = $input;
  562. $id = is_null($this->parent) ? $input['id'] : $input[$this->parent->language_table_foreign_key];
  563. $dal->update($id);
  564. if($dal->code === 400)
  565. {
  566. $this->code = 400;
  567. $this->data[$dal->id] = $dal->data;
  568. }
  569. }
  570. return $this;
  571. }
  572. public function update($id)
  573. {
  574. if( ! $this->find($id))
  575. {
  576. if($this->parent)
  577. {
  578. $this->input[$this->parent->language_table_foreign_key] = $this->parent->model->id;
  579. return DAL::model($this->model->model)
  580. ->parent($this->parent)
  581. ->versioned($this->versioned)
  582. ->input($this->input)
  583. ->create();
  584. }
  585. return $this;
  586. }
  587. $this->model = $this->model->first();
  588. if($this->versioned && ! $this->multilanguage)
  589. {
  590. $latest_version = DB::table($this->table)
  591. ->where_id($this->model->get_key())
  592. ->max('version');
  593. $this->model->version = is_null($latest_version) ? 0 : $latest_version + 1;
  594. $this->model->exists = false;
  595. }
  596. if($this->multilanguage)
  597. {
  598. $lang_input = array();
  599. foreach($this->input['lang'] as $id => $input)
  600. {
  601. $input['language_id'] = $id;
  602. $input[$this->language_table_foreign_key] = $this->id;
  603. $lang_input[] = $input;
  604. }
  605. unset($this->input['lang']);
  606. $dal = DAL::model($this->language_model)
  607. ->parent($this)
  608. ->versioned($this->versioned)
  609. ->input($lang_input)
  610. ->update_multiple();
  611. if( ! $dal->code == 200)
  612. {
  613. $this->data = $dal->data;
  614. $this->code = $dal->code;
  615. return $this;
  616. }
  617. }
  618. elseif( ! is_null($this->slug) || (isset($this->parent) && ! is_null($this->parent)))
  619. {
  620. $key = isset($this->parent) && ! is_null($this->parent) ?
  621. $this->parent->slug
  622. :
  623. $this->slug;
  624. $this->input['slug'] = Str::slug($this->input[$key]);
  625. }
  626. // Fill the model
  627. $this->model->fill($this->input);
  628. // Try to save
  629. if($this->model->save() === false)
  630. {
  631. $this->code = 400;
  632. $this->data = (array) $this->model->errors->messages;
  633. }
  634. $this->sync();
  635. return $this;
  636. }
  637. public function delete_multiple($ids)
  638. {
  639. foreach($ids as $id)
  640. {
  641. $dal = clone $this;
  642. $dal->delete($id);
  643. }
  644. return $this;
  645. }
  646. public function delete($id)
  647. {
  648. if( ! $this->find($id))
  649. {
  650. return $this;
  651. }
  652. $this->model->delete();
  653. return $this;
  654. }
  655. public function get()
  656. {
  657. return $this->data;
  658. }
  659. public function response()
  660. {
  661. return Response::json(is_null($this->data) ? '' : $this->data, $this->code);
  662. }
  663. public function __clone()
  664. {
  665. $this->model = clone $this->model;
  666. if( ! is_null($this->language_model))
  667. {
  668. $this->language_model = clone $this->language_model;
  669. }
  670. }
  671. public function __call($method, $parameters)
  672. {
  673. $this->model = call_user_func_array(array($this->model, $method), $parameters);
  674. return $this;
  675. }
  676. public function __get($key = null)
  677. {
  678. if(is_null($key))
  679. {
  680. return $this->data;
  681. }
  682. return $this->data[$key];
  683. }
  684. public function find($id)
  685. {
  686. $column = 'id';
  687. if( ! is_numeric($id))
  688. {
  689. if(is_null($this->slug))
  690. {
  691. $this->code = 404;
  692. $this->data = 'You are trying to retrieve data with a slug from a resource that is not retrievable via a slug';
  693. return false;
  694. }
  695. if($this->multilanguage)
  696. {
  697. $language_row = DB::table($this->language_table)
  698. ->where_slug($id)
  699. ->first(array($this->language_table_foreign_key, 'language_id'));
  700. if(is_null($language_row))
  701. {
  702. $id = null;
  703. }
  704. else
  705. {
  706. $id = $language_row->{$this->language_table_foreign_key};
  707. $this->options(array(
  708. 'filter' => array(
  709. 'language_id' => $language_row->language_id
  710. )
  711. ));
  712. }
  713. }
  714. else
  715. {
  716. $column = 'slug';
  717. }
  718. }
  719. elseif($this->parent && $this->parent->multilanguage)
  720. {
  721. if( ! $this->input['language_id'])
  722. {
  723. $this->code = 404;
  724. $this->data = 'Please provide the language_id';
  725. return false;
  726. }
  727. $this->language_id = $this->input['language_id'];
  728. $this->model = $this->model->where($this->table.'.language_id', '=', $this->input['language_id']);
  729. $column = $this->parent->language_table_foreign_key;
  730. }
  731. $this->id = $id;
  732. $this->model = $this->model->where($this->table.'.'.$column, '=', $id);
  733. if(is_null($this->model->first()))
  734. {
  735. $this->code = 404;
  736. $this->data = 'The data you are trying to retrieve could not be found';
  737. return false;
  738. }
  739. return true;
  740. }
  741. protected function apply_joins()
  742. {
  743. if(count($this->joins) > 0)
  744. {
  745. foreach($this->joins as $table => $join)
  746. {
  747. extract($join);
  748. $segments = explode(' AS ', $table);
  749. if(count($segments) > 1)
  750. {
  751. list($table_name, $alias_name) = $segments;
  752. }
  753. else
  754. {
  755. $table_name = $table;
  756. $alias_name = $table;
  757. }
  758. if($alias_name !== 'max')
  759. {
  760. if ( ! isset($this->settings['relating'][$table_name]))
  761. {
  762. $this->settings['relating'][$table_name] = $this->get_columns($table_name);
  763. }
  764. foreach($this->settings['relating'][$table_name] as $column)
  765. {
  766. $this->mapped_columns[$alias_name][$column] = 'temp_'.$alias_name.'_'.$column;
  767. $this->get_columns[] = $alias_name.'.'.$column.' AS '. 'temp_'.$alias_name.'_'.$column;
  768. }
  769. }
  770. $defaults = array(
  771. '', '', '', 'INNER'
  772. );
  773. $join = $join + $defaults;
  774. list($column1, $operator, $column2, $type) = $join;
  775. $this->model = $this->model->join($table, $column1, $operator, $column2, $type);
  776. }
  777. }
  778. }
  779. protected function apply_mapping($result)
  780. {
  781. foreach($this->mapped_columns as $table => $columns)
  782. {
  783. foreach($columns as $column => $temp_name)
  784. {
  785. $result[ends_with($table, '_lang') ? 'lang' : $table][$column] = $result[$temp_name];
  786. unset($result[$temp_name]);
  787. }
  788. }
  789. return $result;
  790. }
  791. protected function apply_mappings()
  792. {
  793. if (count($this->joins) > 0)
  794. {
  795. if(array_key_exists('results', $this->data) && array_key_exists('total', $this->data) && array_key_exists('pages', $this->data))
  796. {
  797. foreach($this->data['results'] as &$row)
  798. {
  799. $row = $this->apply_mapping($row);
  800. }
  801. }
  802. else
  803. {
  804. $this->data = $this->apply_mapping($this->data);
  805. }
  806. }
  807. }
  808. protected function get_filters($table)
  809. {
  810. $filters = array();
  811. if(empty($this->settings['filterable'][$table]))
  812. {
  813. return $filters;
  814. }
  815. foreach($this->options['filter'] as $column => $value)
  816. {
  817. if(in_array($column, $this->settings['filterable'][$table]))
  818. {
  819. $filters[] = array($table, $column, $value);
  820. }
  821. }
  822. return $filters;
  823. }
  824. protected function get_columns($table)
  825. {
  826. $table = explode(' AS ', $table);
  827. $table = $table[0];
  828. $table_info = DBManager::table($table)->info();
  829. return array_map(function($column)
  830. {
  831. return $column['name'];
  832. }, $table_info);
  833. }
  834. protected function needs_join($table)
  835. {
  836. $segments = explode('.', $this->options['sort_by']);
  837. $sort_by = end($segments);
  838. if( ! isset($this->settings['sortable'][$table]))
  839. {
  840. $this->settings['sortable'][$table] = array();
  841. }
  842. if( ! isset($this->settings['searchable'][$table]))
  843. {
  844. $this->settings['searchable'][$table] = array();
  845. }
  846. $join = false;
  847. if(in_array($sort_by, $this->settings['sortable'][$table]))
  848. {
  849. $join = true;
  850. }
  851. foreach($this->options['search']['columns'] as $column)
  852. {
  853. if(in_array($column, $this->settings['searchable'][$table]))
  854. {
  855. $join = true;
  856. }
  857. }
  858. return $join;
  859. }
  860. protected function valid_options()
  861. {
  862. $found = false;
  863. foreach($this->settings['sortable'] as $table => $columns)
  864. {
  865. if(in_array($this->options['sort_by'], $columns))
  866. {
  867. $found = true;
  868. $this->options['sort_by'] = $table.'.'.$this->options['sort_by'];
  869. }
  870. }
  871. if( ! $found)
  872. {
  873. $this->data = "The specified sort_by option \"".$this->options['sort_by']."\" is not supported";
  874. $this->code = 400;
  875. return false;
  876. }
  877. // We are looking for something...
  878. if($this->options['search']['string'] !== '')
  879. {
  880. if( ! isset($this->options['search']['columns']))
  881. {
  882. $this->data = "Please specify the column that you want to search through";
  883. $this->code = 400;
  884. return false;
  885. }
  886. $unfound_columns = array();
  887. foreach($this->options['search']['columns'] as $i => $column)
  888. {
  889. $found = false;
  890. foreach($this->settings['searchable'] as $table => $columns)
  891. {
  892. if (in_array($column, $columns))
  893. {
  894. $this->options['search']['columns'][$i] = $table.'.'.$column;
  895. $found = true;
  896. }
  897. }
  898. if( ! $found)
  899. {
  900. $unfound_columns[] = $column;
  901. }
  902. }
  903. $unfound_column_count = count($unfound_columns);
  904. // Make sure we have valid search columns
  905. if ($unfound_column_count > 0)
  906. {
  907. if($unfound_column_count == 1)
  908. {
  909. $this->data = "The specified search column \"".$unfound_columns[0]."\" is not supported";
  910. $this->code = 400;
  911. return false;
  912. }
  913. else
  914. {
  915. $this->data = "The specified search columns \"".implode(', ', $unfound_columns)."\" are not supported";
  916. $this->code = 400;
  917. return false;
  918. }
  919. }
  920. }
  921. foreach($this->options['filter'] as $column => $value)
  922. {
  923. $found = false;
  924. foreach($this->settings['filterable'] as $table => $columns)
  925. {
  926. if(in_array($column, $this->settings['filterable'][$table]))
  927. {
  928. $found = true;
  929. }
  930. }
  931. if( ! $found)
  932. {
  933. $this->data = "The specified filter option \"".$column."\" is not supported";
  934. $this->code = 400;
  935. return false;
  936. }
  937. }
  938. return true;
  939. }
  940. }