Source.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\data;
  9. use lithium\core\NetworkException;
  10. /**
  11. * This is the base class for Lithium's data abstraction layer.
  12. *
  13. * In addition to utility methods and standardized properties, it defines the implementation tasks
  14. * for all Lithium classes that work with external data, such as connections to remote resources
  15. * (`connect()` and `disconnect()`), introspecting available data objects (`sources()` and
  16. * `describe()`), and a standard read/write interface (`create()`, `read()`, `update()` and
  17. * `delete()`).
  18. *
  19. * Subclasses may implement any other non-standard functionality, but the above methods define the
  20. * requirements for interacting with `Model` objects, and other classes within `lithium\data`.
  21. */
  22. abstract class Source extends \lithium\core\Object {
  23. /**
  24. * The list of object properties to be automatically assigned from configuration passed to
  25. * `__construct()`.
  26. *
  27. * @var array
  28. */
  29. protected $_autoConfig = array('classes' => 'merge');
  30. /**
  31. * Default entity and set classes used by subclasses of `Source`.
  32. *
  33. * @var array
  34. */
  35. protected $_classes = array(
  36. 'entity' => 'lithium\data\Entity',
  37. 'set' => 'lithium\data\Collection',
  38. 'relationship' => 'lithium\data\model\Relationship'
  39. );
  40. /**
  41. * Stores a connection to a remote resource. Usually a database connection (`resource` type),
  42. * or an HTTP connection object ('object' type).
  43. *
  44. * @var mixed
  45. */
  46. public $connection = null;
  47. /**
  48. * Stores the status of this object's connection. Updated when `connect()` or `disconnect()` are
  49. * called, or if an error occurs that closes the object's connection.
  50. *
  51. * @var boolean
  52. */
  53. protected $_isConnected = false;
  54. /**
  55. * Constructor. Sets defaults and returns object.
  56. *
  57. * Options defined:
  58. * - 'autoConnect' `boolean` If true, a connection is made on initialization. Defaults to true.
  59. *
  60. * @param array $config
  61. * @return Source object
  62. */
  63. public function __construct(array $config = array()) {
  64. $defaults = array('autoConnect' => true);
  65. parent::__construct($config + $defaults);
  66. }
  67. /**
  68. * Ensures the connection is closed, before the object is destroyed.
  69. *
  70. * @return void
  71. */
  72. public function __destruct() {
  73. if ($this->isConnected()) {
  74. $this->disconnect();
  75. }
  76. }
  77. protected function _init() {
  78. parent::_init();
  79. if ($this->_config['autoConnect']) {
  80. $this->connect();
  81. }
  82. }
  83. /**
  84. * Checks the connection status of this data source. If the `'autoConnect'` option is set to
  85. * true and the source connection is not currently active, a connection attempt will be made
  86. * before returning the result of the connection status.
  87. *
  88. * @param array $options The options available for this method:
  89. * - 'autoConnect': If true, and the connection is not currently active, calls
  90. * `connect()` on this object. Defaults to `false`.
  91. * @return boolean Returns the current value of `$_isConnected`, indicating whether or not
  92. * the object's connection is currently active. This value may not always be accurate,
  93. * as the connection could have timed out or otherwise been dropped by the remote
  94. * resource during the course of the request.
  95. */
  96. public function isConnected(array $options = array()) {
  97. $defaults = array('autoConnect' => false);
  98. $options += $defaults;
  99. if (!$this->_isConnected && $options['autoConnect']) {
  100. try {
  101. $this->connect();
  102. } catch (NetworkException $e) {
  103. $this->_isConnected = false;
  104. }
  105. }
  106. return $this->_isConnected;
  107. }
  108. /**
  109. * Quotes data-source-native identifiers, where applicable.
  110. *
  111. * @param string $name Identifier name.
  112. * @return string Returns `$name`, quoted if applicable.
  113. */
  114. public function name($name) {
  115. return $name;
  116. }
  117. /**
  118. * Abstract. Must be defined by child classes.
  119. */
  120. abstract public function connect();
  121. /**
  122. * Abstract. Must be defined by child classes.
  123. */
  124. abstract public function disconnect();
  125. /**
  126. * Returns a list of objects (sources) that models can bind to, i.e. a list of tables in the
  127. * case of a database, or REST collections, in the case of a web service.
  128. *
  129. * @param string $class The fully-name-spaced class name of the object making the request.
  130. * @return array Returns an array of objects to which models can connect.
  131. */
  132. abstract public function sources($class = null);
  133. /**
  134. * Gets the column schema for a given entity (such as a database table).
  135. *
  136. * @param mixed $entity Specifies the table name for which the schema should be returned, or
  137. * the class name of the model object requesting the schema, in which case the model
  138. * class will be queried for the correct table name.
  139. * @param array $schema
  140. * @param array $meta The meta-information for the model class, which this method may use in
  141. * introspecting the schema.
  142. * @return array Returns a `Schema` object describing the given model's schema, where the
  143. * array keys are the available fields, and the values are arrays describing each
  144. * field, containing the following keys:
  145. * - `'type'`: The field type name
  146. */
  147. abstract public function describe($entity, $schema = array(), array $meta = array());
  148. /**
  149. * Defines or modifies the default settings of a relationship between two models.
  150. *
  151. * @param $class the primary model of the relationship
  152. * @param $type the type of the relationship (hasMany, hasOne, belongsTo)
  153. * @param $name the name of the relationship
  154. * @param array $options relationship options
  155. * @return array Returns an array containing the configuration for a model relationship.
  156. */
  157. abstract public function relationship($class, $type, $name, array $options = array());
  158. /**
  159. * Create a record. This is the abstract method that is implemented by specific data sources.
  160. * This method should take a query object and use it to create a record in the data source.
  161. *
  162. * @param mixed $query An object which defines the update operation(s) that should be performed
  163. * against the data store. This can be a `Query`, a `RecordSet`, a `Record`, or a
  164. * subclass of one of the three. Alternatively, `$query` can be an adapter-specific
  165. * query string.
  166. * @param array $options The options from Model include,
  167. * - `validate` _boolean_ default: true
  168. * - `events` _string_ default: create
  169. * - `whitelist` _array_ default: null
  170. * - `callbacks` _boolean_ default: true
  171. * - `locked` _boolean_ default: true
  172. * @return boolean Returns true if the operation was a success, otherwise false.
  173. */
  174. abstract public function create($query, array $options = array());
  175. /**
  176. * Abstract. Must be defined by child classes.
  177. *
  178. * @param mixed $query
  179. * @param array $options
  180. * @return boolean Returns true if the operation was a success, otherwise false.
  181. */
  182. abstract public function read($query, array $options = array());
  183. /**
  184. * Updates a set of records in a concrete data store.
  185. *
  186. * @param mixed $query An object which defines the update operation(s) that should be performed
  187. * against the data store. This can be a `Query`, a `RecordSet`, a `Record`, or a
  188. * subclass of one of the three. Alternatively, `$query` can be an adapter-specific
  189. * query string.
  190. * @param array $options Options to execute, which are defined by the concrete implementation.
  191. * @return boolean Returns true if the update operation was a success, otherwise false.
  192. */
  193. abstract public function update($query, array $options = array());
  194. /**
  195. * Abstract. Must be defined by child classes.
  196. *
  197. * @param mixed $query
  198. * @param array $options
  199. * @return boolean Returns true if the operation was a success, otherwise false.
  200. */
  201. abstract public function delete($query, array $options = array());
  202. /**
  203. * Casts data into proper format when added to a collection or entity object.
  204. *
  205. * @param mixed $entity The entity or collection for which data is being cast, or the name of
  206. * the model class to which the entity/collection is bound.
  207. * @param array $data An array of data being assigned.
  208. * @param array $options Any associated options with, for example, instantiating new objects in
  209. * which to wrap the data. Options implemented by `cast()` itself:
  210. * - `first` _boolean_: Used when only one value is passed to `cast()`. Even though
  211. * that value must be wrapped in an array, setting the `'first'` option to `true`
  212. * causes only that one value to be returned.
  213. * @return mixed Returns the value of `$data`, cast to the proper format according to the schema
  214. * definition of the model class specified by `$model`.
  215. */
  216. public function cast($entity, array $data, array $options = array()) {
  217. $defaults = array('first' => false);
  218. $options += $defaults;
  219. return $options['first'] ? reset($data) : $data;
  220. }
  221. /**
  222. * Returns the list of methods which format values imported from `Query` objects. Should be
  223. * overridden in subclasses.
  224. *
  225. * @see lithium\data\model\Query
  226. * @return array
  227. */
  228. public function methods() {
  229. return get_class_methods($this);
  230. }
  231. /**
  232. * A method which can be optionally implemented to configure a model class.
  233. *
  234. * @see lithium\data\Model::$_meta
  235. * @see lithium\data\Model::$_finders
  236. * @see lithium\data\Model::$_classes
  237. * @param string $class The name of the model class to be configured.
  238. * @return array This method should return an array one or more of the following keys: `'meta'`,
  239. * `'classes'` or `'finders'`. These keys maps to the three corresponding properties in
  240. * `lithium\data\Model`, and are used to override the base-level default settings and
  241. * dependencies.
  242. */
  243. public function configureClass($class) {
  244. return array('meta' => array('key' => 'id', 'locked' => true));
  245. }
  246. /**
  247. * This method is responsible for factorying a new instance of a single entity object of correct
  248. * type, matching the current data source class.
  249. *
  250. * @param string $model A fully-namespaced class name representing the model class to which the
  251. * `Entity` object will be bound.
  252. * @param array $data The default data with which the new `Entity` should be populated.
  253. * @param array $options Any additional options to pass to the `Entity`'s constructor
  254. * @return object Returns a new, un-saved `Entity` object bound to the model class specified
  255. * in `$model`.
  256. */
  257. public function item($model, array $data = array(), array $options = array()) {
  258. $defaults = array('class' => 'entity');
  259. $options += $defaults;
  260. $class = $options['class'];
  261. unset($options['class']);
  262. return $this->_instance($class, compact('model', 'data') + $options);
  263. }
  264. /**
  265. * Applying a strategy to a `lithium\data\model\Query` object
  266. *
  267. * @param array $options The option array
  268. * @param object $context A query object to configure
  269. */
  270. public function applyStrategy($options, $context) {}
  271. }
  272. ?>