PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Search.php

https://github.com/icz/OpenPNE3
PHP | 287 lines | 164 code | 48 blank | 75 comment | 8 complexity | 9d5bb95607ff1d85fcb7b821c1de63db MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1
  1. <?php
  2. /*
  3. * $Id$
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information, see
  19. * <http://www.phpdoctrine.org>.
  20. */
  21. /**
  22. * Doctrine_Search
  23. *
  24. * @package Doctrine
  25. * @subpackage Search
  26. * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
  27. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  28. * @version $Revision$
  29. * @link www.phpdoctrine.org
  30. * @since 1.0
  31. */
  32. class Doctrine_Search extends Doctrine_Record_Generator
  33. {
  34. const INDEX_FILES = 0;
  35. const INDEX_TABLES = 1;
  36. protected $_options = array('generateFiles' => false,
  37. 'type' => self::INDEX_TABLES,
  38. 'className' => '%CLASS%Index',
  39. 'generatePath' => false,
  40. 'table' => null,
  41. 'batchUpdates' => false,
  42. 'pluginTable' => false,
  43. 'fields' => array(),
  44. 'connection' => null,
  45. 'children' => array());
  46. /**
  47. * __construct
  48. *
  49. * @param array $options
  50. * @return void
  51. */
  52. public function __construct(array $options)
  53. {
  54. $this->_options = Doctrine_Lib::arrayDeepMerge($this->_options, $options);
  55. if ( ! isset($this->_options['analyzer'])) {
  56. $this->_options['analyzer'] = 'Doctrine_Search_Analyzer_Standard';
  57. }
  58. $this->_options['analyzer'] = new $this->_options['analyzer'];
  59. if ( ! isset($this->_options['connection'])) {
  60. $this->_options['connection'] = Doctrine_Manager::connection();
  61. }
  62. }
  63. /**
  64. * Searchable keyword search
  65. *
  66. * @param string $string Keyword string to search for
  67. * @param Doctrine_Query $query Query object to alter. Adds where condition to limit the results using the search index
  68. * @return mixed The Doctrine_Collection or array of ids and relevancy
  69. */
  70. public function search($string, $query = null)
  71. {
  72. $q = new Doctrine_Search_Query($this->_table);
  73. if ($query instanceof Doctrine_Query) {
  74. $q->query($string, false);
  75. $newQuery = $query->copy();
  76. $query->getSql();
  77. $key = (array) $this->getOption('table')->getIdentifier();
  78. $newQuery->addWhere($query->getRootAlias() . '.'.current($key).' IN (SQL:' . $q->getSql() . ')', $q->getParams());
  79. return $newQuery;
  80. } else {
  81. $q->query($string);
  82. return $this->_options['connection']->fetchAll($q->getSql(), $q->getParams());
  83. }
  84. }
  85. /**
  86. * analyze
  87. *
  88. * @param string $text
  89. * @return void
  90. */
  91. public function analyze($text)
  92. {
  93. return $this->_options['analyzer']->analyze($text);
  94. }
  95. /**
  96. * updateIndex
  97. * updates the index
  98. *
  99. * @param Doctrine_Record $record
  100. * @return integer
  101. */
  102. public function updateIndex(array $data)
  103. {
  104. $this->initialize($this->_options['table']);
  105. $fields = $this->getOption('fields');
  106. $class = $this->getOption('className');
  107. $name = $this->getOption('table')->getComponentName();
  108. $conn = $this->getOption('table')->getConnection();
  109. $identifier = $this->_options['table']->getIdentifier();
  110. $q = Doctrine_Query::create()->delete()
  111. ->from($class);
  112. foreach ((array) $identifier as $id) {
  113. $q->addWhere($id . ' = ?', array($data[$id]));
  114. }
  115. $q->execute();
  116. if ($this->_options['batchUpdates'] === true) {
  117. $index = new $class();
  118. foreach ((array) $this->_options['table']->getIdentifier() as $id) {
  119. $index->$id = $data[$id];
  120. }
  121. $index->save();
  122. } else {
  123. foreach ($fields as $field) {
  124. $value = isset($data[$field]) ? $data[$field] : null;
  125. $terms = $this->analyze($value);
  126. foreach ($terms as $pos => $term) {
  127. $index = new $class();
  128. $index->keyword = $term;
  129. $index->position = $pos;
  130. $index->field = $field;
  131. foreach ((array) $this->_options['table']->getIdentifier() as $id) {
  132. $index->$id = $data[$id];
  133. }
  134. $index->save();
  135. }
  136. }
  137. }
  138. }
  139. /**
  140. * readTableData
  141. *
  142. * @param mixed $limit
  143. * @param mixed $offset
  144. * @return Doctrine_Collection The collection of results
  145. */
  146. public function readTableData($limit = null, $offset = null)
  147. {
  148. $this->initialize($this->_options['table']);
  149. $conn = $this->_options['table']->getConnection();
  150. $tableName = $this->_options['table']->getTableName();
  151. $id = $this->_options['table']->getIdentifier();
  152. $query = 'SELECT * FROM ' . $conn->quoteIdentifier($tableName)
  153. . ' WHERE ' . $conn->quoteIdentifier($id)
  154. . ' IN (SELECT ' . $conn->quoteIdentifier($id)
  155. . ' FROM ' . $conn->quoteIdentifier($this->_table->getTableName())
  156. . ' WHERE keyword IS NULL) OR ' . $conn->quoteIdentifier($id)
  157. . ' NOT IN (SELECT ' . $conn->quoteIdentifier($id)
  158. . ' FROM ' . $conn->quoteIdentifier($this->_table->getTableName()) . ')';
  159. $query = $conn->modifyLimitQuery($query, $limit, $offset);
  160. return $conn->fetchAll($query);
  161. }
  162. /**
  163. * batchUpdateIndex
  164. *
  165. * @param mixed $limit
  166. * @param mixed $offset
  167. * @return void
  168. */
  169. public function batchUpdateIndex($limit = null, $offset = null)
  170. {
  171. $this->initialize($this->_options['table']);
  172. $id = $this->_options['table']->getIdentifier();
  173. $class = $this->_options['className'];
  174. $fields = $this->_options['fields'];
  175. $conn = $this->_options['connection'];
  176. try {
  177. $conn->beginTransaction();
  178. $rows = $this->readTableData($limit, $offset);
  179. $ids = array();
  180. foreach ($rows as $row) {
  181. $ids[] = $row[$id];
  182. }
  183. $placeholders = str_repeat('?, ', count($ids));
  184. $placeholders = substr($placeholders, 0, strlen($placeholders) - 2);
  185. $sql = 'DELETE FROM '
  186. . $conn->quoteIdentifier($this->_table->getTableName())
  187. . ' WHERE ' . $conn->quoteIdentifier($id) . ' IN (' . substr($placeholders, 0) . ')';
  188. $conn->exec($sql, $ids);
  189. foreach ($rows as $row) {
  190. foreach ($fields as $field) {
  191. $data = $row[$field];
  192. $terms = $this->analyze($data);
  193. foreach ($terms as $pos => $term) {
  194. $index = new $class();
  195. $index->keyword = $term;
  196. $index->position = $pos;
  197. $index->field = $field;
  198. foreach ((array) $id as $identifier) {
  199. $index->$identifier = $row[$identifier];
  200. }
  201. $index->save();
  202. }
  203. }
  204. }
  205. $conn->commit();
  206. } catch (Doctrine_Exception $e) {
  207. $conn->rollback();
  208. }
  209. }
  210. /**
  211. * buildDefinition
  212. *
  213. * @return void
  214. */
  215. public function setTableDefinition()
  216. {
  217. if ( ! isset($this->_options['table'])) {
  218. throw new Doctrine_Record_Exception("Unknown option 'table'.");
  219. }
  220. $componentName = $this->_options['table']->getComponentName();
  221. $className = $this->getOption('className');
  222. $autoLoad = (bool) ($this->_options['generateFiles']);
  223. if (class_exists($className, $autoLoad)) {
  224. return false;
  225. }
  226. $columns = array('keyword' => array('type' => 'string',
  227. 'length' => 200,
  228. 'primary' => true,
  229. ),
  230. 'field' => array('type' => 'string',
  231. 'length' => 50,
  232. 'primary' => true),
  233. 'position' => array('type' => 'integer',
  234. 'length' => 8,
  235. 'primary' => true,
  236. ));
  237. $this->hasColumns($columns);
  238. }
  239. }