Cron.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. <?php
  2. /**
  3. *
  4. * PHP Pro Bid $Id$ c/WhzHP7QQGgz+1n75/63kwUxwZIVLB4JrDdh2v4hRs=
  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.10 [rev.7.10.02]
  11. */
  12. /**
  13. * cron jobs service class
  14. */
  15. namespace Ppb\Service;
  16. use Cube\Db\Adapter\AbstractAdapter,
  17. Cube\Controller\Front,
  18. Cube\Cache\Adapter\AbstractAdapter as CacheAdapter,
  19. Cube\Db\Expr,
  20. Ppb\Db\Table,
  21. Cube\Config,
  22. Cube\Db\Table\AbstractTable,
  23. Ppb\Service\Table\SalesListings as SalesListingsService;
  24. class Cron extends AbstractService
  25. {
  26. /**
  27. * maximum number of rows to be selected in a transaction
  28. */
  29. const SELECT_TRANSACTION_LIMIT = 50;
  30. /**
  31. * unused files from the uploads folder are to be removed after 6 hours
  32. */
  33. const UNUSED_FILES_REMOVAL_TIME_LIMIT = 21600;
  34. /**
  35. * default number of days after which unused autocomplete tags are removed
  36. */
  37. const AUTOCOMPLETE_TAGS_PURGE_DAYS = 60;
  38. /**
  39. * default number of days when the subscription expiration emails are to be sent
  40. */
  41. const DEFAULT_EXPIRATION_DAYS = 3;
  42. /**
  43. * number of minutes after which data is purged from the users statistics table for online users.
  44. */
  45. const ONLINE_USERS_STATS_PURGE = 5;
  46. /**
  47. *
  48. * listings service
  49. *
  50. * @var \Ppb\Service\Listings
  51. */
  52. protected $_listings;
  53. /**
  54. *
  55. * users service
  56. *
  57. * @var \Ppb\Service\Users
  58. */
  59. protected $_users;
  60. /**
  61. *
  62. * sales service
  63. *
  64. * @var \Ppb\Service\Sales
  65. */
  66. protected $_sales;
  67. /**
  68. *
  69. * sales listings service
  70. *
  71. * @var \Ppb\Service\Table\SalesListings
  72. */
  73. protected $_salesListings;
  74. /**
  75. *
  76. * get listings service
  77. *
  78. * @return \Ppb\Service\Listings
  79. */
  80. public function getListings()
  81. {
  82. if (!$this->_listings instanceof Listings) {
  83. $this->setListings(
  84. new Listings());
  85. }
  86. return $this->_listings;
  87. }
  88. /**
  89. *
  90. * set listings service
  91. *
  92. * @param \Ppb\Service\Listings $listings
  93. *
  94. * @return $this
  95. */
  96. public function setListings(Listings $listings)
  97. {
  98. $this->_listings = $listings;
  99. return $this;
  100. }
  101. /**
  102. *
  103. * get users service
  104. *
  105. * @return \Ppb\Service\Users
  106. */
  107. public function getUsers()
  108. {
  109. if (!$this->_users instanceof Users) {
  110. $this->setUsers(
  111. new Users());
  112. }
  113. return $this->_users;
  114. }
  115. /**
  116. *
  117. * set users service
  118. *
  119. * @param \Ppb\Service\Users $users
  120. *
  121. * @return $this
  122. */
  123. public function setUsers(Users $users)
  124. {
  125. $this->_users = $users;
  126. return $this;
  127. }
  128. /**
  129. *
  130. * get sales service
  131. *
  132. * @return \Ppb\Service\Sales
  133. */
  134. public function getSales()
  135. {
  136. if (!$this->_sales instanceof Sales) {
  137. $this->setSales(
  138. new Sales());
  139. }
  140. return $this->_sales;
  141. }
  142. /**
  143. *
  144. * set sales service
  145. *
  146. * @param \Ppb\Service\Sales $sales
  147. *
  148. * @return $this
  149. */
  150. public function setSales(Sales $sales)
  151. {
  152. $this->_sales = $sales;
  153. return $this;
  154. }
  155. /**
  156. *
  157. * get sales listings service
  158. *
  159. * @return \Ppb\Service\Table\SalesListings
  160. */
  161. public function getSalesListings()
  162. {
  163. if (!$this->_salesListings instanceof SalesListingsService) {
  164. $this->setSalesListings(
  165. new SalesListingsService());
  166. }
  167. return $this->_salesListings;
  168. }
  169. /**
  170. *
  171. * set sales listings service
  172. *
  173. * @param \Ppb\Service\Table\SalesListings $salesListings
  174. *
  175. * @return $this
  176. */
  177. public function setSalesListings(SalesListingsService $salesListings)
  178. {
  179. $this->_salesListings = $salesListings;
  180. return $this;
  181. }
  182. /**
  183. *
  184. * close expired listings and assign winners
  185. * limit to 50 per transaction
  186. * forUpdate means that the rows will be locked until the transaction is complete
  187. *
  188. * @return $this
  189. */
  190. public function closeExpiredListings()
  191. {
  192. $listingsService = $this->getListings();
  193. $usersService = $this->getUsers();
  194. srand();
  195. $rand = mt_rand(1000, 9999);
  196. usleep($rand);
  197. $select = $listingsService->getTable()->select()
  198. ->forUpdate()
  199. ->where('closed = ?', 0)
  200. ->where('deleted = ?', 0)
  201. ->where('draft = ?', 0)
  202. ->where('start_time < ?', new Expr('now()'))
  203. ->where('end_time < ?', new Expr('now()'))
  204. ->where('end_time is not null')
  205. ->limit(self::SELECT_TRANSACTION_LIMIT);
  206. $expiredListings = $listingsService->fetchAll($select)
  207. ->setAutomatic(true)
  208. ->close();
  209. $noSale = array();
  210. $noSaleReserve = array();
  211. /** @var \Ppb\Db\Table\Row\Listing $listing */
  212. foreach ($expiredListings as $listing) {
  213. if ($listing->getClosedFlag() === true) {
  214. if ($listing->getData('quantity') > 0) {
  215. $saleId = $listing->assignWinner();
  216. if ($saleId === false) {
  217. if ($listing->countDependentRowset('\Ppb\Db\Table\Bids')) {
  218. $noSaleReserve[$listing['user_id']][] = $listing;
  219. }
  220. else {
  221. $noSale[$listing['user_id']][] = $listing;
  222. }
  223. }
  224. }
  225. }
  226. }
  227. // send email notifications to listings owners
  228. $mail = new \Listings\Model\Mail\OwnerNotification();
  229. foreach ($noSale as $userId => $listings) {
  230. $user = $usersService->findBy('id', $userId);
  231. $mail->setUser($user)
  232. ->setListings($listings)
  233. ->noSale()
  234. ->send();
  235. }
  236. foreach ($noSaleReserve as $userId => $listings) {
  237. $user = $usersService->findBy('id', $userId);
  238. $mail->setUser($user)
  239. ->setListings($listings)
  240. ->noSaleReserve()
  241. ->send();
  242. }
  243. $expiredListings->relist();
  244. return $this;
  245. }
  246. /**
  247. *
  248. * start scheduled listings
  249. *
  250. * @return $this
  251. */
  252. public function startScheduledListings()
  253. {
  254. $listingsService = $this->getListings();
  255. $adapter = $listingsService->getTable()->getAdapter();
  256. $where = array(
  257. $adapter->quoteInto('closed = ?', 1),
  258. $adapter->quoteInto('deleted = ?', 0),
  259. $adapter->quoteInto('draft = ?', 0),
  260. $adapter->quoteInto('start_time < ?', new Expr('now()')),
  261. 'end_time > ' . new Expr('now()') . ' OR end_time is null',
  262. );
  263. $listingsService->getTable()->update(array('closed' => 0, 'updated_at' => new Expr('now()')), $where);
  264. return $this;
  265. }
  266. /**
  267. *
  268. * method that purges cache routes and metadata
  269. * normally is run from the cron daily
  270. *
  271. * @return $this
  272. */
  273. public function purgeCacheData()
  274. {
  275. /** @var \Cube\Cache $cache */
  276. $cache = Front::getInstance()->getBootstrap()->getResource('cache');
  277. $cache->getAdapter()->purge(CacheAdapter::ROUTES);
  278. $cache->getAdapter()->purge(CacheAdapter::METADATA);
  279. return $this;
  280. }
  281. public function purgeCacheQueries()
  282. {
  283. /** @var \Cube\Cache $cache */
  284. $cache = Front::getInstance()->getBootstrap()->getResource('cache');
  285. $expires = $cache->getAdapter()->getExpires();
  286. $cache->getAdapter()
  287. ->setExpires(AbstractTable::QUERIES_CACHE_EXPIRES)
  288. ->purge(CacheAdapter::QUERIES);
  289. $cache->getAdapter()
  290. ->setExpires($expires);
  291. return $this;
  292. }
  293. /**
  294. *
  295. * delete expired rows from the sales listings table for which the
  296. * corresponding sale is marked as pending
  297. *
  298. * @return $this
  299. */
  300. public function deletePendingSalesListings()
  301. {
  302. $settings = $this->getSettings();
  303. $salesListingsService = $this->getSalesListings();
  304. $select = $salesListingsService->getTable()->getAdapter()
  305. ->select()
  306. ->from(array('sl' => 'sales_listings'), 'sl.id')
  307. ->joinLeft(array('s' => 'sales'), 's.id = sl.sale_id', '')
  308. ->where('sl.created_at < ?',
  309. new Expr('(now() - interval ' . intval($settings['pending_sales_listings_expire_hours']) . ' minute)'))
  310. ->where('s.pending = ?', 1);
  311. $rows = $salesListingsService->fetchAll($select);
  312. $ids = array();
  313. foreach ($rows as $row) {
  314. $ids[] = $row['id'];
  315. }
  316. $salesListingsService->delete($ids);
  317. return $this;
  318. }
  319. /**
  320. *
  321. * suspend users for which the debit balance date has been exceeded
  322. *
  323. * @return $this
  324. */
  325. public function suspendUsersDebitExceededDate()
  326. {
  327. $usersService = $this->getUsers();
  328. $settings = $this->getSettings();
  329. if ($settings['user_account_type'] == 'personal' || $settings['payment_mode'] == 'account') {
  330. $select = $usersService->getTable()->select()
  331. ->where('active = ?', 1)
  332. ->where('role NOT IN (?)', array_keys(Users::getAdminRoles()))
  333. ->where('balance > max_debit')
  334. ->where('debit_exceeded_date is not null')
  335. ->where('debit_exceeded_date < ?',
  336. new Expr('(now() - interval ' . intval($settings['suspension_days']) . ' day)'))
  337. ->limit(self::SELECT_TRANSACTION_LIMIT);
  338. if ($settings['user_account_type'] == 'personal') {
  339. $select->where('account_mode = ?', 'account');
  340. }
  341. $users = $usersService->fetchAll($select);
  342. $mail = new \Members\Model\Mail\User();
  343. /** @var \Ppb\Db\Table\Row\User $user */
  344. foreach ($users as $user) {
  345. $user->updateActive(0);
  346. $mail->accountBalanceExceeded($user)->send();
  347. }
  348. }
  349. return $this;
  350. }
  351. public function sendNewsletters()
  352. {
  353. $newslettersRecipientsService = new NewslettersRecipients();
  354. $newslettersService = new Newsletters();
  355. $recipients = $newslettersRecipientsService->fetchAll(
  356. $newslettersRecipientsService->getTable()->getAdapter()->select()
  357. ->from(array('nr' => 'newsletters_recipients'))
  358. ->joinLeft(array('n' => 'newsletters'), 'n.id = nr.newsletter_id', array('title', 'content'))
  359. // ->joinLeft(array('u' => 'users'), 'u.id = nr.user_id', array('username', 'email'))
  360. ->limit(200));
  361. $mail = new \Members\Model\Mail\User();
  362. $ids = array();
  363. $newslettersIds = array();
  364. /** @var \Cube\Db\Table\Row $data */
  365. foreach ($recipients as $data) {
  366. $ids[] = $data['id'];
  367. $newslettersIds[] = $data['newsletter_id'];
  368. $mail->newsletter($data['title'], $data['content'], $data['email'])->send();
  369. }
  370. if (count($ids)) {
  371. $newslettersRecipientsService->delete($ids);
  372. $adapter = $newslettersService->getTable()->getAdapter();
  373. $newslettersService->getTable()->update(array(
  374. 'updated_at' => new Expr('now()')
  375. ),
  376. $adapter->quoteInto('id IN (?)', array_unique($newslettersIds)));
  377. }
  378. }
  379. /**
  380. *
  381. * remove marked deleted listings from the database
  382. *
  383. * @return $this
  384. */
  385. public function removeMarkedDeletedListings()
  386. {
  387. $listingsService = $this->getListings();
  388. $select = $listingsService->getTable()->select()
  389. ->where('deleted = ?', 1)
  390. ->limit(self::SELECT_TRANSACTION_LIMIT);
  391. $listingsService->fetchAll($select)->setAdmin(true)->delete();
  392. return $this;
  393. }
  394. /**
  395. *
  396. * mark as deleted closed listings
  397. *
  398. * @return $this
  399. */
  400. public function markDeletedClosedListings()
  401. {
  402. $listingsService = $this->getListings();
  403. $settings = $this->getSettings();
  404. $adapter = $listingsService->getTable()->getAdapter();
  405. $where = array(
  406. 'end_time is not null',
  407. $adapter->quoteInto('deleted = ?', 0),
  408. $adapter->quoteInto('closed = ?', 1),
  409. $adapter->quoteInto('end_time < ?',
  410. new Expr('(now() - interval ' . intval($settings['closed_listings_deletion_days']) . ' day)'))
  411. );
  412. $listingsService->getTable()->update(array(
  413. 'deleted' => 1,
  414. ), $where);
  415. return $this;
  416. }
  417. /**
  418. *
  419. * notify users on subscriptions that are about to expire
  420. * only notify users for which the "re-bill if in account mode" setting doesnt apply
  421. *
  422. * @param array $subscription
  423. *
  424. * @return $this
  425. */
  426. public function notifyUsersOnSubscriptionsAboutToExpire(array $subscription)
  427. {
  428. $usersService = $this->getUsers();
  429. $settings = $this->getSettings();
  430. $select = $usersService->getTable()->select()
  431. ->where("{$subscription['active']} = ?", 1)
  432. ->where("{$subscription['expirationDate']} < ?",
  433. new Expr('(now() + interval ' . self::DEFAULT_EXPIRATION_DAYS . ' day)'))
  434. ->where("{$subscription['expirationDate']} > ?", 0)
  435. ->where("{$subscription['emailFlag']} = ?", 0)
  436. ->limit(self::SELECT_TRANSACTION_LIMIT);
  437. $runQuery = true;
  438. if ($settings['rebill_expired_subscriptions']) {
  439. if ($settings['user_account_type'] == 'personal') {
  440. $select->where('account_mode = ?', 'live');
  441. }
  442. else if ($settings['user_account_type'] == 'global' && $settings['payment_mode'] == 'account') {
  443. $runQuery = false;
  444. }
  445. }
  446. if ($runQuery) {
  447. $users = $usersService->fetchAll($select);
  448. /** @var \Ppb\Db\Table\Row\User $user */
  449. $mail = new \Members\Model\Mail\User();
  450. foreach ($users as $user) {
  451. $mail->subscriptionExpirationNotification($subscription, $user, self::DEFAULT_EXPIRATION_DAYS)->send();
  452. $user->save(array(
  453. "{$subscription['emailFlag']}" => 1,
  454. ));
  455. }
  456. }
  457. return $this;
  458. }
  459. /**
  460. *
  461. * process expired user subscriptions
  462. * notify users of the expired subscription
  463. * re-bill if in account mode, and activate automatically
  464. *
  465. * @param array $subscription subscription type
  466. *
  467. * @return $this
  468. */
  469. public function processExpiredSubscriptions(array $subscription)
  470. {
  471. $usersService = $this->getUsers();
  472. $accountingService = new Accounting();
  473. $settings = $this->getSettings();
  474. $select = $usersService->getTable()->select()
  475. ->where("{$subscription['active']} = ?", 1)
  476. ->where("{$subscription['expirationDate']} < ?", new Expr('now()'))
  477. ->where("{$subscription['expirationDate']} > ?", 0)
  478. ->limit(self::SELECT_TRANSACTION_LIMIT);
  479. $users = $usersService->fetchAll($select);
  480. $mail = new \Members\Model\Mail\User();
  481. /** @var \Ppb\Db\Table\Row\User $user */
  482. foreach ($users as $user) {
  483. $user->save(array(
  484. "{$subscription['active']}" => 0
  485. ));
  486. if ($settings['rebill_expired_subscriptions'] && $user->userPaymentMode() == 'account') {
  487. // bill subscription in account mode
  488. /** @var \Ppb\Service\Fees $feesService */
  489. $feesService = new $subscription['feesService']($user);
  490. $totalAmount = $feesService->getTotalAmount();
  491. $user->save(array(
  492. 'balance' => ($user['balance'] + $totalAmount)
  493. ));
  494. $accountingService->save(array(
  495. 'name' => array(
  496. 'string' => 'Automatic Renewal - %s',
  497. 'args' => array($subscription['name']),
  498. ),
  499. 'amount' => $totalAmount,
  500. 'user_id' => $user['id'],
  501. 'currency' => $settings['currency'],
  502. ));
  503. // activate subscription
  504. $user->$subscription['updateMethod'](1);
  505. $mail->subscriptionRenewed($subscription, $user)->send();
  506. }
  507. else {
  508. $mail->subscriptionExpired($subscription, $user)->send();
  509. }
  510. }
  511. return $this;
  512. }
  513. /**
  514. *
  515. * delete sales for which the payment due time limit has expired
  516. * (ref: force payment module)
  517. *
  518. * return $this
  519. */
  520. public function deleteExpiredSalesForcePayment()
  521. {
  522. $salesService = $this->getSales();
  523. $select = $salesService->getTable()->select()
  524. ->where('expires_at is not null')
  525. ->where('expires_at < ?', new Expr('now()'))
  526. ->limit(self::SELECT_TRANSACTION_LIMIT);
  527. $sales = $salesService->fetchAll($select);
  528. /** @var \Ppb\Db\Table\Row\Sale $sale */
  529. foreach ($sales as $sale) {
  530. $sale->revert();
  531. }
  532. return $this;
  533. }
  534. /**
  535. *
  536. * count listings that were not counted since their creation / last update
  537. *
  538. * return $this
  539. */
  540. public function countListings()
  541. {
  542. $listingsService = $this->getListings();
  543. $select = $listingsService->getTable()->select()
  544. ->where('counted_at is null OR counted_at < IF(updated_at is null, created_at, updated_at)')
  545. ->limit(100);
  546. $listings = $listingsService->fetchAll($select);
  547. /** @var \Ppb\Db\Table\Row\Listing $listing */
  548. foreach ($listings as $listing) {
  549. $listing->processCategoryCounter();
  550. }
  551. return $this;
  552. }
  553. /**
  554. *
  555. * remove search phrases that haven't been searched for within the last 6 months
  556. *
  557. * @return $this
  558. */
  559. public function purgeAutocompleteTags()
  560. {
  561. $autocompleteTagsService = new AutocompleteTags();
  562. $adapter = $autocompleteTagsService->getTable()->getAdapter();
  563. $where = array(
  564. $adapter->quoteInto('created_at < ?', new Expr('now() - interval 6 month')),
  565. $adapter->quoteInto('updated_at < ?', new Expr('now() - interval 6 month')),
  566. );
  567. $autocompleteTagsService->getTable()->delete($where);
  568. return $this;
  569. }
  570. /**
  571. *
  572. * remove expired rows from the users statistics table
  573. *
  574. * @return $this
  575. */
  576. public function purgeUsersStatistics()
  577. {
  578. $usersStatisticsService = new UsersStatistics();
  579. $adapter = $usersStatisticsService->getTable()->getAdapter();
  580. $where = array(
  581. $adapter->quoteInto('updated_at < ?', new Expr('now() - interval ' . self::ONLINE_USERS_STATS_PURGE . ' minute')),
  582. );
  583. $usersStatisticsService->getTable()->delete($where);
  584. return $this;
  585. }
  586. /**
  587. *
  588. * remove expired rows from the recently viewed listings table
  589. *
  590. * @return $this
  591. */
  592. public function purgeRecentlyViewedListings()
  593. {
  594. $settings = $this->getSettings();
  595. $recentlyViewedListingsService = new RecentlyViewedListings();
  596. $adapter = $recentlyViewedListingsService->getTable()->getAdapter();
  597. $where = array(
  598. $adapter->quoteInto('IF(updated_at is null, created_at, updated_at) < ?',
  599. new Expr('now() - interval ' . intval($settings['enable_recently_viewed_listings_expiration']) . ' hour')),
  600. );
  601. $recentlyViewedListingsService->getTable()->delete($where);
  602. return $this;
  603. }
  604. /**
  605. *
  606. * method that deletes all unused uploaded files that are older than UNUSED_FILES_REMOVAL_TIME_LIMIT
  607. * this is to be called by a separate cron call to avoid server load
  608. * currently it processes 200 images per call
  609. *
  610. * @return $this
  611. */
  612. public function purgeUnusedUploadedFiles()
  613. {
  614. $counter = null;
  615. $uploadsFolder = \Ppb\Utility::getPath('uploads');
  616. // we have sorted all files by modified date
  617. $files = glob($uploadsFolder . '/*.*');
  618. usort($files, function ($a, $b) {
  619. return filemtime($a) > filemtime($b);
  620. });
  621. $files = array_filter($files);
  622. $files = array_slice($files, 0, 200);
  623. $prefix = $this->getListings()->getTable()->getPrefix();
  624. $adapter = $this->getListings()->getTable()->getAdapter();
  625. foreach ($files as $filePath) {
  626. $file = str_replace($uploadsFolder . DIRECTORY_SEPARATOR, '', $filePath);
  627. $stat = stat($filePath);
  628. if (($stat['mtime'] + self::UNUSED_FILES_REMOVAL_TIME_LIMIT) < time()) {
  629. if ($this->_isUsedFile($file, $adapter, $prefix) !== true) {
  630. @unlink($filePath);
  631. }
  632. else {
  633. @touch($filePath);
  634. }
  635. }
  636. }
  637. clearstatcache();
  638. return $this;
  639. }
  640. /**
  641. *
  642. * gets live currency exchange rates and updates the currencies table
  643. * always gets based on the site's default currency
  644. *
  645. * @return $this
  646. */
  647. public function updateCurrencyExchangeRates()
  648. {
  649. $settings = $this->getSettings();
  650. $feed = 'http://www.floatrates.com/daily/' . strtolower($settings['currency']) . '.xml';
  651. $xml = simplexml_load_file($feed);
  652. $object = new Config\Xml($xml);
  653. $currencies = $object->getData('item');
  654. $data = array();
  655. foreach ($currencies as $currency) {
  656. $isoCode = $currency['targetCurrency'];
  657. $conversionRate = number_format($currency['exchangeRate'], 6, '.', '');
  658. if ($isoCode && $conversionRate > 0) {
  659. $data[] = array(
  660. 'data' => array(
  661. 'conversion_rate' => $conversionRate,
  662. ),
  663. 'where' => array(
  664. "iso_code = '" . $isoCode . "'",
  665. )
  666. );
  667. }
  668. }
  669. $currenciesService = new Table\Currencies();
  670. foreach ($data as $row) {
  671. $currenciesService->update($row['data'], $row['where']);
  672. }
  673. // reset default currency exchange rate to 1
  674. $currenciesService->update(array("conversion_rate" => 1), "iso_code = '" . $settings['currency'] . "'");
  675. return $this;
  676. }
  677. /**
  678. *
  679. * check if a file from the /uploads/ folder is used by the software
  680. * the following tables will be checked:
  681. *
  682. * listings_media [value]
  683. * categories [logo_path]
  684. * advertising [content]
  685. * settings [value : site_logo_path]
  686. * users [store_settings : PREG : s:15:"store_logo_path";s:(d+):"FILENAME"]
  687. *
  688. * @param string $file
  689. * @param \Cube\Db\Adapter\AbstractAdapter $adapter
  690. * @param string $prefix
  691. *
  692. * @return bool
  693. */
  694. protected function _isUsedFile($file, AbstractAdapter $adapter, $prefix)
  695. {
  696. $statement = $adapter->query("SELECT `value` as `file_path` FROM `" . $prefix . "listings_media` WHERE `value` = '" . $file . "'
  697. UNION
  698. SELECT `logo_path` as `file_path` FROM `" . $prefix . "categories` WHERE `logo_path` = '" . $file . "'
  699. UNION
  700. SELECT `content` as `file_path` FROM `" . $prefix . "advertising` WHERE `content` = '" . $file . "' AND `type` = 'image'
  701. UNION
  702. SELECT `value` as `file_path` FROM `" . $prefix . "settings` WHERE `value` = '" . $file . "' AND `name` = 'site_logo_path'
  703. UNION
  704. SELECT `store_settings` as `file_path` FROM `" . $prefix . "users` WHERE `store_settings` LIKE '%" . $file . "%'");
  705. return ($statement->rowCount() > 0) ? true : false;
  706. }
  707. /**
  708. *
  709. * the method that will run all/specified cron jobs
  710. *
  711. * @param string|null $command
  712. *
  713. * @return $this
  714. */
  715. public function run($command = null)
  716. {
  717. $settings = $this->getSettings();
  718. $usersService = $this->getUsers();
  719. switch ($command) {
  720. case 'purge-unused-uploaded-files':
  721. $this->purgeUnusedUploadedFiles();
  722. break;
  723. case 'purge-cache-data':
  724. $this->purgeCacheData();
  725. break;
  726. case 'update-currency-exchange-rates':
  727. $this->updateCurrencyExchangeRates();
  728. break;
  729. default:
  730. $this->closeExpiredListings();
  731. $this->startScheduledListings();
  732. $this->suspendUsersDebitExceededDate();
  733. if ($settings['pending_sales_listings_expire_hours']) {
  734. $this->deletePendingSalesListings();
  735. }
  736. if ($settings['marked_deleted_listings_removal']) {
  737. $this->removeMarkedDeletedListings();
  738. }
  739. if ($settings['closed_listings_deletion_days'] > 0) {
  740. $this->markDeletedClosedListings();
  741. }
  742. $subscriptionTypes = $usersService->getSubscriptionTypes();
  743. foreach ($subscriptionTypes as $subscription) {
  744. $this->notifyUsersOnSubscriptionsAboutToExpire($subscription);
  745. $this->processExpiredSubscriptions($subscription);
  746. }
  747. $this->sendNewsletters();
  748. $this->deleteExpiredSalesForcePayment();
  749. $this->countListings();
  750. $this->purgeAutocompleteTags();
  751. $this->purgeUsersStatistics();
  752. $this->purgeRecentlyViewedListings();
  753. $this->purgeCacheQueries();
  754. break;
  755. }
  756. return $this;
  757. }
  758. }