PageRenderTime 31ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/framework/classes/plants/ElementPlant.php

https://gitlab.com/x33n/platform
PHP | 784 lines | 668 code | 35 blank | 81 comment | 87 complexity | 0c7b70b2d865cd6999ecdd8c4360155b MD5 | raw file
  1. <?php
  2. /**
  3. * ElementPlant Takes an element ID finds it's settings, returns either raw data
  4. * or markup ready to be used in the requesting app.
  5. *
  6. * @package platform.org.cashmusic
  7. * @author CASH Music
  8. * @link http://cashmusic.org/
  9. *
  10. * Copyright (c) 2013, CASH Music
  11. * Licensed under the GNU Lesser General Public License version 3.
  12. * See http://www.gnu.org/licenses/lgpl-3.0.html
  13. *
  14. *
  15. * This file is generously sponsored by John 'Warthog9' Hawley
  16. *
  17. **/
  18. class ElementPlant extends PlantBase {
  19. protected $elements_array=array();
  20. protected $typenames_array=array();
  21. public function __construct($request_type,$request) {
  22. $this->request_type = 'element';
  23. $this->routing_table = array(
  24. // alphabetical for ease of reading
  25. // first value = target method to call
  26. // second value = allowed request methods (string or array of strings)
  27. 'addelementtocampaign' => array('addElementToCampaign','direct'),
  28. 'addcampaign' => array('addCampaign','direct'),
  29. 'addelement' => array('addElement','direct'),
  30. 'addlockcode' => array('addLockCode','direct'),
  31. 'checkuserrequirements' => array('checkUserRequirements','direct'),
  32. 'deletecampaign' => array('deleteCampaign','direct'),
  33. 'deleteelement' => array('deleteElement','direct'),
  34. 'editelement' => array('editElement','direct'),
  35. 'editcampaign' => array('editCampaign','direct'),
  36. 'getanalytics' => array('getAnalytics','direct'),
  37. 'getanalyticsforcampaign' => array('getAnalyticsForCampaign','direct'),
  38. 'getcampaign' => array('getCampaign','direct'),
  39. 'getelement' => array('getElement','direct'),
  40. 'getcampaignsforuser' => array('getCampaignsForUser','direct'),
  41. 'getcampaignforelement' => array('getCampaignForElement','direct'),
  42. 'getelementsforcampaign' => array('getElementsForCampaign','direct'),
  43. 'getelementsforuser' => array('getElementsForUser','direct'),
  44. 'getelementtemplate' => array('getElementTemplate','direct'),
  45. //'getmarkup' => array('getElementMarkup',array('direct','get','post','api_public','api_key','api_fullauth')),
  46. // closing up the above -> security risk allowing people to simply request markup and pass a status UID via
  47. // API or GET. we'll need to require signed status codes and reopen...
  48. 'getmarkup' => array('getElementMarkup','direct'),
  49. 'getsupportedtypes' => array('getSupportedTypes','direct'),
  50. 'redeemcode' => array('redeemLockCode',array('direct','get','post')),
  51. 'removeelementfromcampaign' => array('removeElementFromCampaign','direct'),
  52. 'setelementtemplate' => array('setElementTemplate','direct')
  53. );
  54. $this->buildElementsArray();
  55. $this->plantPrep($request_type,$request);
  56. }
  57. /**
  58. * Builds an associative array of all Element class files in /elements/
  59. * stored as $this->elements_array and used to include proper markup in getElementMarkup()
  60. *
  61. * @return void
  62. */protected function buildElementsArray() {
  63. $all_element_files = scandir(CASH_PLATFORM_ROOT.'/elements/',0);
  64. foreach ($all_element_files as $file) {
  65. if (substr($file,0,1) != "." && substr($file,-4) == '.php') {
  66. $tmpKey = strtolower(substr_replace($file, '', -4));
  67. $this->elements_array["$tmpKey"] = $file;
  68. }
  69. }
  70. }
  71. protected function buildTypeNamesArray() {
  72. if ($elements_dir = opendir(CASH_PLATFORM_ROOT.'/elements/')) {
  73. while (false !== ($file = readdir($elements_dir))) {
  74. if (substr($file,0,1) != "." && !is_dir($file)) {
  75. $element_object_type = substr_replace($file, '', -4);
  76. $tmpKey = strtolower($element_object_type);
  77. include(CASH_PLATFORM_ROOT.'/elements/'.$file);
  78. // Would rather do this with $element_object_type::type but that requires 5.3.0+
  79. // Any ideas?
  80. $this->typenames_array["$tmpKey"] = constant($element_object_type . '::name');
  81. }
  82. }
  83. closedir($elements_dir);
  84. }
  85. }
  86. /**
  87. * Feed in a user id and element type (string) and this function returns either
  88. * true, meaning the user has defined all the required bits needed to set up an
  89. * element of the type; or an array containing codes for what's missing.
  90. *
  91. * A boolean return of false means there was an error reading the JSON
  92. *
  93. * @param {int} $user_id - the user
  94. * @param {string} $element_type - element type name
  95. * @return true|false|array
  96. */ protected function checkUserRequirements($user_id,$element_type) {
  97. $json_location = CASH_PLATFORM_ROOT.'/elements/' . $element_type . '/app.json';
  98. $app_json = false;
  99. if (file_exists($json_location)) {
  100. $app_json = json_decode(file_get_contents($json_location),true);
  101. }
  102. if ($app_json) {
  103. $failures = array();
  104. foreach ($app_json['options'] as $section_name => $details) {
  105. foreach ($details['data'] as $data => $values) {
  106. if ($values['type'] == 'select') {
  107. if (is_string($values['values'])) {
  108. if (substr($values['values'],0,7) == 'connect') {
  109. $scope = explode('/',$values['values']);
  110. // get system settings:
  111. $data_object = new CASHConnection($user_id);
  112. if (!$data_object->getConnectionsByScope($scope[1])) {
  113. $failures[] = $values['values'];
  114. }
  115. } else {
  116. $action_name = false;
  117. switch ($values['values']) {
  118. case 'assets':
  119. $plant_name = 'asset';
  120. $action_name = 'getassetsforuser';
  121. break;
  122. case 'people/lists':
  123. $plant_name = 'people';
  124. $action_name = 'getlistsforuser';
  125. break;
  126. case 'items':
  127. case 'commerce/items':
  128. $plant_name = 'commerce';
  129. $action_name = 'getitemsforuser';
  130. break;
  131. }
  132. if ($action_name) {
  133. $requirements_request = new CASHRequest(
  134. array(
  135. 'cash_request_type' => $plant_name,
  136. 'cash_action' => $action_name,
  137. 'user_id' => $user_id,
  138. 'parent_id' => 0
  139. )
  140. );
  141. if (!$requirements_request->response['payload']) {
  142. $failures[] = $values['values'];
  143. }
  144. }
  145. }
  146. }
  147. }
  148. }
  149. }
  150. if (count($failures) == 0) {
  151. return true;
  152. } else {
  153. return $failures;
  154. }
  155. } else {
  156. return false;
  157. }
  158. }
  159. protected function getElement($id,$user_id=false) {
  160. $condition = array(
  161. "id" => array(
  162. "condition" => "=",
  163. "value" => $id
  164. )
  165. );
  166. if ($user_id) {
  167. $condition['user_id'] = array(
  168. "condition" => "=",
  169. "value" => $user_id
  170. );
  171. }
  172. $result = $this->db->getData(
  173. 'elements',
  174. 'id,name,type,user_id,template_id,options',
  175. $condition
  176. );
  177. if ($result) {
  178. $the_element = array(
  179. 'id' => $result[0]['id'],
  180. 'name' => $result[0]['name'],
  181. 'type' => $result[0]['type'],
  182. 'user_id' => $result[0]['user_id'],
  183. 'template_id' => $result[0]['template_id'],
  184. 'options' => json_decode($result[0]['options'],true)
  185. );
  186. return $the_element;
  187. } else {
  188. return false;
  189. }
  190. }
  191. protected function getElementTemplate($element_id,$return_template=false) {
  192. $element = $this->getElement($element_id);
  193. if ($element) {
  194. if (!$return_template) {
  195. return $element['template_id'];
  196. } else {
  197. if ($element['template_id']) {
  198. $template_request = new CASHRequest(
  199. array(
  200. 'cash_request_type' => 'system',
  201. 'cash_action' => 'gettemplate',
  202. 'template_id' => $element['template_id'],
  203. 'all_details' => 1
  204. )
  205. );
  206. if ($template_request->response['payload']) {
  207. $template = $template_request->response['payload']['template'];
  208. } else {
  209. $template = @file_get_contents(dirname(CASH_PLATFORM_PATH) . '/settings/defaults/embed.mustache');
  210. }
  211. } else {
  212. $template = @file_get_contents(dirname(CASH_PLATFORM_PATH) . '/settings/defaults/embed.mustache');
  213. }
  214. // zero or less means use our standard template, less than zero selects options
  215. if ($element['template_id'] == '-1') {
  216. $template = str_replace(array('!--light','light--'), '', $template);
  217. $template = str_replace('<body', '<body class="light"', $template);
  218. } else if ($element['template_id'] == '-2') {
  219. $template = str_replace(array('!--dark','dark--'), '', $template);
  220. $template = str_replace('<body', '<body class="dark"', $template);
  221. }
  222. return $template;
  223. }
  224. } else {
  225. return false;
  226. }
  227. }
  228. protected function setElementTemplate($element_id,$template_id,$user_id=false) {
  229. $condition = array(
  230. "id" => array(
  231. "condition" => "=",
  232. "value" => $element_id
  233. )
  234. );
  235. if ($user_id) {
  236. $condition['user_id'] = array(
  237. "condition" => "=",
  238. "value" => $user_id
  239. );
  240. }
  241. $result = $this->db->setData(
  242. 'elements',
  243. array(
  244. 'template_id' => $template_id
  245. ),
  246. $condition
  247. );
  248. return $result;
  249. }
  250. protected function getElementsForUser($user_id) {
  251. $result = $this->db->getData(
  252. 'elements',
  253. '*',
  254. array(
  255. "user_id" => array(
  256. "condition" => "=",
  257. "value" => $user_id
  258. )
  259. )
  260. );
  261. return $result;
  262. }
  263. protected function getSupportedTypes($force_all=false) {
  264. $return_array = array_keys($this->elements_array);
  265. $filter_array = json_decode(file_get_contents(CASH_PLATFORM_ROOT.'/elements/supported.json'));
  266. if (is_array($filter_array) && !$force_all) {
  267. $return_array = array_intersect($return_array,$filter_array);
  268. }
  269. return $return_array;
  270. }
  271. /**
  272. * Records the basic access data to the elements analytics table
  273. *
  274. * @return boolean
  275. */protected function recordAnalytics($id,$access_method,$access_action='getmarkup',$location=false,$access_data='') {
  276. // check settings first as they're already loaded in the environment
  277. $record_type = CASHSystem::getSystemSettings('analytics');
  278. if ($record_type == 'off') {
  279. return true;
  280. }
  281. if (!$location) {
  282. $location = CASHSystem::getCurrentURL();
  283. }
  284. // only count one asset + situation per session
  285. $recorded_elements = $this->sessionGet('recorded_elements');
  286. if (is_array($recorded_elements)) {
  287. if (in_array($id . $access_method . $location, $recorded_elements)) {
  288. // already recorded for this session. just return true.
  289. return true;
  290. } else {
  291. // didn't find a record of this asset. record it and move forward
  292. $recorded_elements[] = $id . $access_method . $location;
  293. $this->sessionSet('recorded_elements',$recorded_elements);
  294. }
  295. } else {
  296. $this->sessionSet('recorded_elements',array($id . $access_method . $location));
  297. }
  298. // first the big record if needed
  299. if ($record_type == 'full' || !$record_type) {
  300. $ip_and_proxy = CASHSystem::getRemoteIP();
  301. $result = $this->db->setData(
  302. 'elements_analytics',
  303. array(
  304. 'element_id' => $id,
  305. 'access_method' => $access_method,
  306. 'access_location' => $location,
  307. 'access_action' => $access_action,
  308. 'access_data' => $access_data,
  309. 'access_time' => time(),
  310. 'client_ip' => $ip_and_proxy['ip'],
  311. 'client_proxy' => $ip_and_proxy['proxy'],
  312. 'cash_session_id' => $this->getSessionID()
  313. )
  314. );
  315. }
  316. // basic logging happens for full or basic
  317. if ($record_type == 'full' || $record_type == 'basic') {
  318. $condition = array(
  319. "element_id" => array(
  320. "condition" => "=",
  321. "value" => $id
  322. )
  323. );
  324. $current_result = $this->db->getData(
  325. 'elements_analytics_basic',
  326. '*',
  327. $condition
  328. );
  329. if (is_array($current_result)) {
  330. $new_total = $current_result[0]['total'] +1;
  331. $data = json_decode($current_result[0]['data'],true);
  332. if (isset($data['locations'][$location])) {
  333. $data['locations'][$location] = $data['locations'][$location] + 1;
  334. } else {
  335. $data['locations'][$location] = 1;
  336. }
  337. if (isset($data['methods'][$access_method])) {
  338. $data['methods'][$access_method] = $data['methods'][$access_method] + 1;
  339. } else {
  340. $data['methods'][$access_method] = 1;
  341. }
  342. } else {
  343. $new_total = 1;
  344. $data = array(
  345. 'locations' => array(
  346. $location => 1
  347. ),
  348. 'methods' => array(
  349. $access_method => 1
  350. )
  351. );
  352. $condition = false;
  353. }
  354. $result = $this->db->setData(
  355. 'elements_analytics_basic',
  356. array(
  357. 'element_id' => $id,
  358. 'data' => json_encode($data),
  359. 'total' => $new_total
  360. ),
  361. $condition
  362. );
  363. }
  364. return $result;
  365. }
  366. /**
  367. * Pulls analytics queries in a few different formats
  368. *
  369. * @return array
  370. */protected function getAnalytics($analtyics_type,$user_id,$element_id=0) {
  371. switch (strtolower($analtyics_type)) {
  372. case 'mostactive':
  373. $result = $this->db->getData(
  374. 'ElementPlant_getAnalytics_mostactive',
  375. false,
  376. array(
  377. "user_id" => array(
  378. "condition" => "=",
  379. "value" => $user_id
  380. )
  381. )
  382. );
  383. return $result;
  384. break;
  385. case 'elementbasics':
  386. $result = $this->db->getData(
  387. 'elements_analytics_basic',
  388. '*',
  389. array(
  390. "element_id" => array(
  391. "condition" => "=",
  392. "value" => $element_id
  393. )
  394. )
  395. );
  396. if ($result) {
  397. $data = json_decode($result[0]['data'],true);
  398. $data['total'] = $result[0]['total'];
  399. return $data;
  400. } else {
  401. return false;
  402. }
  403. break;
  404. case 'recentlyadded':
  405. $result = $this->db->getData(
  406. 'elements',
  407. '*',
  408. array(
  409. "user_id" => array(
  410. "condition" => "=",
  411. "value" => $user_id
  412. )
  413. ),
  414. false,
  415. 'creation_date DESC'
  416. );
  417. return $result;
  418. break;
  419. }
  420. }
  421. protected function getElementMarkup($id,$status_uid,$original_request=false,$original_response=false,$access_method='direct',$location=false) {
  422. $element = $this->getElement($id);
  423. $element_type = $element['type'];
  424. $element_options = $element['options'];
  425. if ($element_type) {
  426. $for_include = CASH_PLATFORM_ROOT.'/elements/'.$this->elements_array[$element_type];
  427. if (file_exists($for_include)) {
  428. include_once($for_include);
  429. $element_object_type = substr_replace($this->elements_array[$element_type], '', -4);
  430. $element_object = new $element_object_type($id,$element,$status_uid,$original_request,$original_response);
  431. $this->recordAnalytics($id,$access_method,'getmarkup',$location);
  432. $markup = $element_object->getMarkup();
  433. $markup = '<div class="cashmusic element ' . $element_type . ' id-' . $id . '">' . $markup . '</div>';
  434. return $markup;
  435. }
  436. } else {
  437. return false;
  438. }
  439. }
  440. protected function addElement($name,$type,$options_data,$user_id) {
  441. $options_data = json_encode($options_data);
  442. $result = $this->db->setData(
  443. 'elements',
  444. array(
  445. 'name' => $name,
  446. 'type' => $type,
  447. 'options' => $options_data,
  448. 'user_id' => $user_id
  449. )
  450. );
  451. return $result;
  452. }
  453. protected function editElement($id,$name,$options_data,$user_id=false) {
  454. $options_data = json_encode($options_data);
  455. $condition = array(
  456. "id" => array(
  457. "condition" => "=",
  458. "value" => $id
  459. )
  460. );
  461. if ($user_id) {
  462. $condition['user_id'] = array(
  463. "condition" => "=",
  464. "value" => $user_id
  465. );
  466. }
  467. $result = $this->db->setData(
  468. 'elements',
  469. array(
  470. 'name' => $name,
  471. 'options' => $options_data,
  472. ),
  473. $condition
  474. );
  475. return $result;
  476. }
  477. protected function deleteElement($id,$user_id=false) {
  478. $condition = array(
  479. "id" => array(
  480. "condition" => "=",
  481. "value" => $id
  482. )
  483. );
  484. if ($user_id) {
  485. $condition['user_id'] = array(
  486. "condition" => "=",
  487. "value" => $user_id
  488. );
  489. }
  490. $result = $this->db->deleteData(
  491. 'elements',
  492. $condition
  493. );
  494. return $result;
  495. }
  496. /**
  497. * Wrapper for system lock code call
  498. *
  499. * @param {integer} $element_id - the element for which you're adding the lock code
  500. * @return string|false
  501. */protected function addLockCode($element_id){
  502. $add_request = new CASHRequest(
  503. array(
  504. 'cash_request_type' => 'system',
  505. 'cash_action' => 'addlockcode',
  506. 'scope_table_alias' => 'elements',
  507. 'scope_table_id' => $element_id
  508. )
  509. );
  510. return $add_request->response['payload'];
  511. }
  512. /**
  513. * Wrapper for system lock code call
  514. *
  515. * @param {string} $code - the code
  516. * @param {integer} $element_id - the element for which you're adding the lock code
  517. * @return bool
  518. */protected function redeemLockCode($code,$element_id) {
  519. $redeem_request = new CASHRequest(
  520. array(
  521. 'cash_request_type' => 'system',
  522. 'cash_action' => 'redeemlockcode',
  523. 'code' => $code,
  524. 'scope_table_alias' => 'elements',
  525. 'scope_table_id' => $element_id
  526. )
  527. );
  528. return $redeem_request->response['payload'];
  529. }
  530. /*
  531. *
  532. *
  533. * CAMPAIGNS
  534. *
  535. *
  536. */
  537. protected function addCampaign($title,$description,$user_id,$elements='[]',$metadata='{}') {
  538. $final_options = array(
  539. 'title' => $title,
  540. 'description' => $description,
  541. 'elements' => $elements,
  542. 'metadata' => $metadata,
  543. 'user_id' => $user_id
  544. );
  545. if (is_array($metadata)) {
  546. $final_options['metadata'] = json_encode($metadata);
  547. }
  548. if (is_array($elements)) {
  549. // array_values ensures a non-associative array. which we want.
  550. $final_options['elements'] = json_encode(array_values($elements));
  551. }
  552. $result = $this->db->setData(
  553. 'elements_campaigns',
  554. $final_options
  555. );
  556. return $result;
  557. }
  558. protected function editCampaign($id,$user_id=false,$title=false,$description=false,$elements=false,$metadata=false,$template_id=false) {
  559. $final_edits = array_filter(
  560. array(
  561. 'title' => $title,
  562. 'description' => $description,
  563. 'template_id' => $template_id
  564. ),
  565. 'CASHSystem::notExplicitFalse'
  566. );
  567. if (is_array($metadata)) {
  568. $final_edits['metadata'] = json_encode($metadata);
  569. }
  570. if (is_array($elements)) {
  571. // array_values ensures a non-associative array. which we want.
  572. $final_edits['elements'] = json_encode(array_values($elements));
  573. }
  574. $condition = array(
  575. "id" => array(
  576. "condition" => "=",
  577. "value" => $id
  578. )
  579. );
  580. if ($user_id) {
  581. $condition['user_id'] = array(
  582. "condition" => "=",
  583. "value" => $user_id
  584. );
  585. }
  586. $result = $this->db->setData(
  587. 'elements_campaigns',
  588. $final_edits,
  589. $condition
  590. );
  591. return $result;
  592. }
  593. protected function deleteCampaign($id,$user_id=false) {
  594. $condition = array(
  595. "id" => array(
  596. "condition" => "=",
  597. "value" => $id
  598. )
  599. );
  600. if ($user_id) {
  601. $condition['user_id'] = array(
  602. "condition" => "=",
  603. "value" => $user_id
  604. );
  605. }
  606. $result = $this->db->deleteData(
  607. 'elements_campaigns',
  608. $condition
  609. );
  610. return $result;
  611. }
  612. protected function getCampaign($id,$user_id=false) {
  613. $condition = array(
  614. "id" => array(
  615. "condition" => "=",
  616. "value" => $id
  617. )
  618. );
  619. if ($user_id) {
  620. $condition['user_id'] = array(
  621. "condition" => "=",
  622. "value" => $user_id
  623. );
  624. }
  625. $result = $this->db->getData(
  626. 'elements_campaigns',
  627. '*',
  628. $condition
  629. );
  630. if ($result) {
  631. $result[0]['metadata'] = json_decode($result[0]['metadata'],true);
  632. $result[0]['elements'] = json_decode($result[0]['elements'],true);
  633. return $result[0];
  634. } else {
  635. return false;
  636. }
  637. }
  638. protected function getCampaignsForUser($user_id) {
  639. $result = $this->db->getData(
  640. 'elements_campaigns',
  641. '*',
  642. array(
  643. "user_id" => array(
  644. "condition" => "=",
  645. "value" => $user_id
  646. )
  647. )
  648. );
  649. return $result;
  650. }
  651. protected function getElementsForCampaign($id) {
  652. $campaign = $this->getCampaign($id);
  653. $result = $this->db->getData(
  654. 'elements',
  655. '*',
  656. array(
  657. "id" => array(
  658. "condition" => "IN",
  659. "value" => $campaign['elements']
  660. )
  661. )
  662. );
  663. foreach ($result as $key => &$val) {
  664. $val['options'] = json_decode($val['options'],true);
  665. }
  666. return $result;
  667. }
  668. protected function getAnalyticsForCampaign($id) {
  669. $campaign = $this->getCampaign($id);
  670. $result = $this->db->getData(
  671. 'elements_analytics_basic',
  672. 'MAX(total)',
  673. array(
  674. "element_id" => array(
  675. "condition" => "IN",
  676. "value" => $campaign['elements']
  677. )
  678. )
  679. );
  680. $returnarray = array(
  681. 'total_views' => 0
  682. );
  683. if ($result) {
  684. $returnarray['total_views'] = $result[0]['MAX(total)'];
  685. return $returnarray;
  686. } else {
  687. return false;
  688. }
  689. return $result;
  690. }
  691. protected function getCampaignForElement($id) {
  692. $result = $this->db->getData(
  693. 'ElementPlant_getCampaignForElement',
  694. false,
  695. array(
  696. "elements1" => array(
  697. "condition" => "LIKE",
  698. "value" => '["'.$id.'",%'
  699. ),
  700. "elements2" => array(
  701. "condition" => "LIKE",
  702. "value" => '%,"'.$id.'",%'
  703. ),
  704. "elements3" => array(
  705. "condition" => "LIKE",
  706. "value" => '%,"'.$id.'"]'
  707. ),
  708. "elements4" => array(
  709. "condition" => "LIKE",
  710. "value" => '['.$id.',%'
  711. ),
  712. "elements5" => array(
  713. "condition" => "LIKE",
  714. "value" => '%,'.$id.',%'
  715. ),
  716. "elements6" => array(
  717. "condition" => "LIKE",
  718. "value" => '%,'.$id.']'
  719. )
  720. )
  721. );
  722. // 6 conditions is overkill, but wanted to make sure this would work if PHP treats the
  723. // json_encode variables as strings OR ints (have only seen string handling)
  724. //
  725. // i swear i'll never take regex for granted
  726. // PS: pattern matching across sqlite and mysql is hard. like stupid hard.
  727. // like no thank you. No REGEXP, no GLOB, and CONCAT versus || issues.
  728. if ($result) {
  729. return $result[0];
  730. } else {
  731. return false;
  732. }
  733. }
  734. protected function addElementToCampaign($element_id,$campaign_id) {
  735. $campaign = $this->getCampaign($campaign_id);
  736. if(($key = array_search($element_id, $campaign['elements'])) === false) {
  737. $campaign['elements'][] = $element_id;
  738. }
  739. return $this->editCampaign($campaign_id,false,false,false,$campaign['elements']);
  740. }
  741. protected function removeElementFromCampaign($element_id,$campaign_id) {
  742. $campaign = $this->getCampaign($campaign_id);
  743. if(($key = array_search($element_id, $campaign['elements'])) !== false) {
  744. unset($campaign['elements'][$key]);
  745. }
  746. return $this->editCampaign($campaign_id,false,false,false,$campaign['elements']);
  747. }
  748. } // END class
  749. ?>