Categories.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. <?php
  2. /**
  3. *
  4. * PHP Pro Bid $Id$ IkuJpeISJMvMSB2o7xC37aFalCA5KBXMHgG9AXBjGos=
  5. *
  6. * @link http://www.phpprobid.com
  7. * @copyright Copyright (c) 2017 Online Ventures Software & CodeCube SRL
  8. * @license http://www.phpprobid.com/license Commercial License
  9. *
  10. * @version 7.9 [rev.7.9.01]
  11. */
  12. /**
  13. * categories table service class
  14. */
  15. namespace Ppb\Service\Table\Relational;
  16. use Ppb\Db\Table\Categories as CategoriesTable,
  17. Cube\Navigation,
  18. Cube\Controller\Front,
  19. Cube\Db\Select,
  20. Cube\Db\Expr,
  21. Cube\View\Helper\Url as UrlViewHelper;
  22. class Categories extends AbstractServiceTableRelational
  23. {
  24. /**
  25. *
  26. * class constructor
  27. */
  28. public function __construct()
  29. {
  30. parent::__construct();
  31. $this->setInsertRows(5)
  32. ->setTable(
  33. new CategoriesTable());
  34. }
  35. /**
  36. *
  37. * set categories table data.
  38. * This data will be used for traversing the categories tree
  39. *
  40. * @param string|\Cube\Db\Select $where SQL where clause, or a select object
  41. * @param array|\Traversable $data Optional. Custom categories data
  42. *
  43. * @return $this
  44. */
  45. public function setData($where = null, array $data = null)
  46. {
  47. if ($data === null) {
  48. if ($where === null) {
  49. $where = $this->_table->select()
  50. ->where("enable_auctions = ?", 1);
  51. }
  52. $categories = $this->_table->fetchAll($where);
  53. $data = array();
  54. foreach ($categories as $row) {
  55. $data[$row['parent_id']][] = array(
  56. 'className' => '\Ppb\Navigation\Page\Category',
  57. 'id' => (int)$row['id'],
  58. 'label' => $row['name'],
  59. 'order' => (int)$row['order_id'],
  60. 'customFees' => $row['custom_fees'],
  61. );
  62. }
  63. reset($data);
  64. $tree = $this->_createTree($data, current($data));
  65. $this->_data = new Navigation($tree);
  66. }
  67. else {
  68. $this->_data = $data;
  69. }
  70. return $this;
  71. }
  72. /**
  73. *
  74. * get all table columns needed to generate the
  75. * categories management table in the admin area
  76. *
  77. * @return array
  78. */
  79. public function getColumns()
  80. {
  81. $columns = array(
  82. array(
  83. 'label' => '',
  84. 'class' => 'size-tiny',
  85. 'element_id' => null,
  86. 'children' => array(
  87. 'key' => 'parent_id',
  88. 'value' => 'id',
  89. ),
  90. ),
  91. array(
  92. 'label' => $this->_('Name'),
  93. 'element_id' => 'name',
  94. 'popup' => array(
  95. 'action' => 'category-options',
  96. ),
  97. 'owner' => null,
  98. ),
  99. array(
  100. 'label' => $this->_('Custom Fees'),
  101. 'class' => 'size-tiny td-sm',
  102. 'element_id' => 'custom_fees',
  103. 'parent_id' => 0,
  104. ),
  105. array(
  106. 'label' => $this->_('Adult Category'),
  107. 'class' => 'size-tiny td-sm',
  108. 'element_id' => 'adult',
  109. 'parent_id' => 0,
  110. ),
  111. array(
  112. 'label' => $this->_('Order ID'),
  113. 'class' => 'size-mini td-sm',
  114. 'element_id' => 'order_id',
  115. ),
  116. array(
  117. 'label' => $this->_('Delete'),
  118. 'class' => 'size-mini td-sm',
  119. 'element_id' => array(
  120. 'id', 'delete'
  121. ),
  122. ),
  123. );
  124. $settings = $this->getSettings();
  125. if (!$settings['enable_adult_categories']) {
  126. foreach ($columns as $key => $column) {
  127. if ($column['element_id'] == 'adult') {
  128. unset($columns[$key]);
  129. }
  130. }
  131. }
  132. if ($this->_parentId) {
  133. foreach ($columns as $key => $column) {
  134. if (array_key_exists('parent_id', $column)) {
  135. if ($column['parent_id'] != $this->_parentId) {
  136. unset($columns[$key]);
  137. }
  138. }
  139. }
  140. }
  141. return $columns;
  142. }
  143. /**
  144. *
  145. * get all form elements that are needed to generate the
  146. * categories management table in the admin area
  147. *
  148. * @return array
  149. */
  150. public function getElements()
  151. {
  152. return array(
  153. array(
  154. 'id' => 'id',
  155. 'element' => 'hidden',
  156. ),
  157. array(
  158. 'id' => 'name',
  159. 'element' => 'text',
  160. 'attributes' => array(
  161. 'class' => 'form-control input-large',
  162. ),
  163. ),
  164. array(
  165. 'id' => 'custom_fees',
  166. 'element' => 'checkbox',
  167. 'multiOptions' => array(
  168. 1 => null,
  169. ),
  170. ),
  171. array(
  172. 'id' => 'adult',
  173. 'element' => 'checkbox',
  174. 'multiOptions' => array(
  175. 1 => null,
  176. ),
  177. ),
  178. array(
  179. 'id' => 'order_id',
  180. 'element' => 'text',
  181. 'attributes' => array(
  182. 'class' => 'form-control input-mini',
  183. ),
  184. ),
  185. array(
  186. 'id' => 'delete',
  187. 'element' => 'checkbox',
  188. 'multiOptions' => array(
  189. 1 => null,
  190. ),
  191. ),
  192. );
  193. }
  194. /**
  195. *
  196. * generate full names and slugs selected categories and save them into the table.
  197. * will be run as a separate function.
  198. *
  199. * @param int $parentId
  200. *
  201. * @return $this
  202. */
  203. protected function _saveSlugs($parentId = null)
  204. {
  205. $data = array();
  206. $select = $this->getTable()->select();
  207. if ($parentId > 0) {
  208. $select->where('parent_id = ?', $parentId);
  209. }
  210. else if ($parentId === null) {
  211. $select->where('parent_id is null');
  212. }
  213. else {
  214. // generate new slugs
  215. $select->where('slug = ""');
  216. }
  217. $categories = $this->fetchAll($select);
  218. $request = Front::getInstance()->getRequest();
  219. /** @var \Ppb\Db\Table\Row\Category $category */
  220. foreach ($categories as $category) {
  221. $fullName = $request->filterInput(
  222. $this->getFullName($category['id']));
  223. $slug = $this->sluggizeCategoryName(str_replace(parent::NAME_SEPARATOR, '_', $fullName), $category['id']);
  224. $data[] = array(
  225. 'currentFullName' => $category['full_name'],
  226. 'currentSlug' => $category['slug'],
  227. 'newFullName' => $fullName,
  228. 'newSlug' => $slug,
  229. );
  230. $category->save(array(
  231. 'full_name' => $fullName,
  232. 'slug' => $slug,
  233. ));
  234. }
  235. $table = $this->getTable();
  236. $adapter = $table->getAdapter();
  237. $tableName = $table->getPrefix() . $table->getName();
  238. foreach ($data as $row) {
  239. $statement = $adapter->query("UPDATE " . $tableName . "
  240. SET
  241. `slug` = REPLACE (`slug`, '" . $row['currentSlug'] . "', '" . $row['newSlug'] . "'),
  242. `full_name` = REPLACE (`full_name`, '" . $row['currentFullName'] . "', '" . $row['newFullName'] . "')
  243. ");
  244. $statement->execute();
  245. }
  246. return $this;
  247. }
  248. /**
  249. *
  250. * save adult categories flags
  251. *
  252. * @return $this
  253. */
  254. protected function _saveAdultCategoriesFlags()
  255. {
  256. $settings = $this->getSettings();
  257. if ($settings['enable_adult_categories']) {
  258. $ids = array();
  259. $table = $this->getTable();
  260. $adultMainCategories = $this->fetchAll(
  261. $table->select()
  262. ->where('parent_id is null')
  263. ->where('adult = ?', 1)
  264. );
  265. foreach ($adultMainCategories as $adultMainCategory) {
  266. $ids[] = $adultMainCategory['id'];
  267. }
  268. $table->update(array(
  269. 'adult' => 0,
  270. ), '');
  271. if (count($ids) > 0) {
  272. $adapter = $table->getAdapter();
  273. $tableName = $table->getPrefix() . $table->getName();
  274. $statement = $adapter->query("SELECT `id`
  275. FROM (SELECT * FROM " . $tableName . " ORDER BY `parent_id`, `id`) `categories_sorted`,
  276. (SELECT @pv := '" . implode(',', $ids) . "') `initialization`
  277. WHERE find_in_set(`parent_id`, @pv) > 0 and @pv := concat(@pv, ',', `id`)");
  278. $ids = array_merge($ids, $statement->fetchAll(\Pdo::FETCH_COLUMN, 0));
  279. $table->update(array(
  280. 'adult' => 1,
  281. ), $adapter->quoteInto('id IN (?)', $ids));
  282. }
  283. }
  284. return $this;
  285. }
  286. /**
  287. *
  288. * save data in the table (update if an id exists or insert otherwise)
  289. * also generate and save the slugs and full names of the inserted/modified categories
  290. *
  291. * @param array $data
  292. *
  293. * @return \Ppb\Service\Table\AbstractServiceTable
  294. * @throws \InvalidArgumentException
  295. */
  296. public function save(array $data)
  297. {
  298. if (!isset($data['id'])) {
  299. throw new \InvalidArgumentException("The form must use an element with the name 'id'.");
  300. }
  301. parent::save($data);
  302. $parentId = (!empty($data['parent_id'])) ? $data['parent_id'] : null;
  303. $this->_saveSlugs($parentId);
  304. $settings = $this->getSettings();
  305. if (!$parentId) {
  306. $this->_saveAdultCategoriesFlags();
  307. }
  308. return $this;
  309. }
  310. /**
  311. *
  312. * return sluggized category name value
  313. * uses the cleanString method from the Url view helper
  314. *
  315. * @param string $categoryName
  316. * @param int $categoryId
  317. *
  318. * @return string
  319. */
  320. public function sluggizeCategoryName($categoryName, $categoryId)
  321. {
  322. $duplicate = true;
  323. do {
  324. $categorySlug = UrlViewHelper::cleanString($categoryName);
  325. $select = $this->getTable()
  326. ->select(array('nb_rows' => new Expr('count(*)')))
  327. ->where('slug = ?', $categorySlug)
  328. ->where('id != ?', $categoryId);
  329. $stmt = $select->query();
  330. $counter = (integer)$stmt->fetchColumn('nb_rows');
  331. if ($counter > 0) {
  332. $categoryName .= '1';
  333. }
  334. else {
  335. $duplicate = false;
  336. }
  337. } while ($duplicate === true);
  338. return $categorySlug;
  339. }
  340. /**
  341. *
  342. * Returns a multidimensional array containing all categories which are in the same level as the selected cats,
  343. * all parents, plus a row with the children of the selected category
  344. *
  345. * @param int $id
  346. * @param \Cube\Db\Select $where select object
  347. *
  348. * @return array
  349. */
  350. public function getCategoriesSelectData($id, Select $where)
  351. {
  352. $result = array();
  353. $breadcrumbs = array_keys($this->getBreadcrumbs($id));
  354. array_unshift($breadcrumbs, 0);
  355. foreach ($breadcrumbs as $key => $id) {
  356. /** @var \Ppb\Db\Table\Rowset\Categories $rowset */
  357. if ($id) {
  358. $where = $this->getTable()->select()
  359. ->where('parent_id = ?', $id);
  360. }
  361. else {
  362. $where->where('parent_id is null');
  363. }
  364. $rowset = $this->fetchAll($where);
  365. $child = (!empty($breadcrumbs[$key + 1])) ? $breadcrumbs[$key + 1] : null;
  366. $values = $this->_formatSelectorData($rowset);
  367. if (count($values) > 0) {
  368. $result[] = array(
  369. 'selected' => $child,
  370. 'values' => $values,
  371. );
  372. }
  373. }
  374. return $result;
  375. }
  376. /**
  377. *
  378. * reset the counter field for all categories
  379. *
  380. * @return $this
  381. */
  382. public function resetCounters()
  383. {
  384. $this->getTable()->update(array(
  385. 'counter' => '',
  386. ), '');
  387. return $this;
  388. }
  389. /**
  390. *
  391. * format category selector row data for display purposes
  392. *
  393. * @param mixed $data
  394. *
  395. * @return array
  396. */
  397. protected function _formatSelectorData($data)
  398. {
  399. $values = array();
  400. $translate = $this->getTranslate();
  401. $select = $this->getTable()
  402. ->select(array('nb_rows' => new Expr('count(*)')));
  403. /** @var mixed $page */
  404. foreach ($data as $page) {
  405. $select->reset(Select::WHERE)
  406. ->where('parent_id = ?', $page['id']);
  407. $stmt = $select->query();
  408. $nbChildren = (integer)$stmt->fetchColumn('nb_rows');
  409. $values[$page['id']] = $translate->_($page['name'])
  410. . (($nbChildren > 0) ? ' > ' : '');
  411. }
  412. return $values;
  413. }
  414. }