PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/SLMerge/SLMerge.php

https://bitbucket.org/southsidehealth/southsidehealth
PHP | 727 lines | 484 code | 145 blank | 98 comment | 109 complexity | 7ef27f8f003b5529288b8110734fe69d MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0, LGPL-2.1
  1. <?php
  2. //Note: when this script is run, there should be a table called tmp_locations
  3. // to store the new locations as they are made. Afterwards we can rename
  4. // the old locations table.
  5. // This script should be placed in cake's bin/SLMerge directory in order for the path names
  6. // to work properly
  7. //
  8. // The log file will record every tmp_site, tmp_location, and services_tmp_sites entry
  9. // that was added to the database.
  10. // The error log file will record the number of orphaned users, the number of orphaned
  11. // services, and the number of tmp_sites without any services, as well as
  12. // recording the name and id of each such orphaned user, etc.
  13. // It will also record every tmp_site that is created with no location info
  14. // and every failed attempt to update services_tmp_sites.
  15. define ('LOG_ERROR', dirname(dirname(dirname(__FILE__))) . "/tmp/SLMerge_errors.log");
  16. define ('LOG_SUCCESS', dirname(dirname(dirname(__FILE__))) . "/tmp/SLMerge.log");
  17. define('DATE_FORMAT', "Y-m-d H:i:s");
  18. class SLMerge
  19. {
  20. var $id_translations = array('sites'=>array(), 'locations'=>array());
  21. #var $max_tmp_loc_id = 0;
  22. var $max_agency_id = 0;
  23. var $conflict = false;
  24. var $limit = null;
  25. var $debug = false;
  26. var $agencies_services = array();
  27. var $dummy_id = null;
  28. var $Mptt;
  29. var $lang_regexp;
  30. var $langTok;
  31. function __construct($limit = null, $clear = false, $debug = false) {
  32. require_once("mptt.php");
  33. require_once("database.php");
  34. require_once("LangTokenizer.php");
  35. $this->limit = $limit;
  36. $this->debug = $debug;
  37. if ($clear) {
  38. mysql_query("DELETE FROM tmp_sites;");
  39. mysql_query("DELETE FROM services_tmp_sites;");
  40. mysql_query("DELETE FROM languages_tmp_sites;");
  41. mysql_query("UPDATE languages SET site_count = 0;");
  42. if (file_exists(LOG_SUCCESS))
  43. unlink(LOG_SUCCESS);
  44. if (file_exists(LOG_ERROR))
  45. unlink(LOG_ERROR);
  46. }
  47. /* set max agency id */
  48. $max_agency_id = mysql_query("SELECT MAX(id) FROM tmp_sites;");
  49. if (!$max_agency_id)
  50. die(__CLASS__ ."::" .__FUNCTION__ . " failed on line " . __LINE__. "\n" . mysql_error());
  51. $max = mysql_fetch_array($max_agency_id);
  52. if ($max['MAX(id)'])
  53. $this->max_agency_id = $max['MAX(id)'];
  54. else
  55. $this->max_agency_id = 0;
  56. /* set max tmp_location id */
  57. #$max_tmp_loc_id = mysql_query("SELECT MAX(id) FROM tmp_locations;");
  58. #if (!$max_tmp_loc_id)
  59. #die(__CLASS__ . "::" . __FUNCTION__ . " failed on line " . __LINE__ . "\n" . mysql_error());
  60. #$max = mysql_fetch_array($max_tmp_loc_id);
  61. #if ($max['MAX(id)'])
  62. #$this->max_tmp_loc_id = $max['MAX(id)'];
  63. #else
  64. #$this->max_tmp_loc_id = 0;
  65. /* build array of services_tmp_sites */
  66. $agencies_services = mysql_query("SELECT * FROM services_tmp_sites;");
  67. while ($as = mysql_fetch_array($agencies_services))
  68. $this->agencies_services[$as['tmp_site_id']] = $as['service_id'];
  69. /* create a dummy location for any sites that do not have good location info on file */
  70. #$dummy_id = mysql_query("SELECT id FROM tmp_locations WHERE name LIKE \"Dummy\";");
  71. #if (!($dummy_id = mysql_fetch_array($dummy_id))) {
  72. #mysql_query("INSERT INTO tmp_locations(id, name, lat, lng, location)
  73. #VALUES (". ++$this->max_tmp_loc_id .", \"Dummy\", 0, 0, GeomFromText('POINT (0 0)'));");
  74. #$this->dummy_id = $this->max_tmp_loc_id;
  75. #} else {
  76. #$this->dummy_id = $dummy_id['id'];
  77. #}
  78. /* initialize an MPTT object for inserting into the tmp_sites table */
  79. $this->Mptt = new Mptt("tmp_sites");
  80. $this->langTok = new LangTokenizer;
  81. require_once("languages.php");
  82. if (isset($languages)) {
  83. $this->lang_regexp = "/(" . strtolower(implode("|", $languages)) . ")/";
  84. }
  85. }
  86. function merge() {
  87. /* lock tables */
  88. $lock_query = "LOCK TABLES tmp_sites WRITE, users WRITE, languages_tmp_sites WRITE,"
  89. . " languages WRITE, services_tmp_sites WRITE, sites READ, "
  90. . "locations_services READ, draft_services WRITE, contacts WRITE, "
  91. . "express_carts WRITE, libraries WRITE, location_versions WRITE, "
  92. . "locations WRITE, service_versions WRITE, services WRITE;";
  93. if (!mysql_query($lock_query))
  94. die("failed to lock tables");
  95. /* Make tmp_locations and tmp_sites from old sites table */
  96. $query = "SELECT * FROM sites";
  97. if ($this->limit)
  98. $query .= " LIMIT $this->limit";
  99. $sites = mysql_query($query . ";");
  100. if (!$sites)
  101. die(__CLASS__."::".__FUNCTION__." failed on line " . __LINE__ .
  102. " with the following MySQL error:\n" . mysql_error());
  103. while ($site = mysql_fetch_array($sites)) {
  104. echo "Migrating site " . $site['id'] . "\n";
  105. #$tmp_loc_id = $this->makeLocation($site);
  106. $agency_id = $this->makeAgency($site);
  107. $this->id_translations['sites'][$site['id']] = $agency_id; #array('tmp_loc_id'=>$tmp_loc_id, 'agency_id'=>$agency_id);
  108. $this->makeAgenciesServices('services', $site, $agency_id);
  109. if (!mysql_query("UPDATE draft_services SET parent_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  110. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  111. if (!mysql_query("UPDATE express_carts SET tmp_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  112. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  113. if (!mysql_query("UPDATE libraries SET tmp_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  114. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  115. if (!mysql_query("UPDATE location_versions SET tmp_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  116. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  117. if (!mysql_query("UPDATE locations SET tmp_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  118. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  119. if (!mysql_query("UPDATE service_versions SET tmp_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  120. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  121. if (!mysql_query("UPDATE services SET parent_site_id = $agency_id WHERE site_id = " . $site['id'] .";"))
  122. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  123. }
  124. /* Make locations and agencies from old locations table */
  125. $old_locations = mysql_query("SELECT * FROM locations" . ($this->limit ? " LIMIT $this->limit;" : ";"));
  126. if (!$old_locations)
  127. die(__CLASS__."::".__FUNCTION__." failed on line " . __LINE__ .
  128. " with the following MySQL error:\n" . mysql_error());
  129. while ($old_location = mysql_fetch_array($old_locations)) {
  130. echo "Migrating location " . $old_location['id'] . "\n";
  131. # $tmp_loc_id = $this->makeLocation($old_location);
  132. if (isset($this->id_translations['sites'][$old_location['site_id']])) {
  133. $parent_id = $this->id_translations['sites'][$old_location['site_id']];
  134. # $parent_loc = $this->id_translations['sites'][$old_location['site_id']]['tmp_loc_id'];
  135. } else {
  136. $parent_id = null;
  137. # $parent_loc = null;
  138. }
  139. $agency_id = $this->makeAgency($old_location, $parent_id);
  140. $this->id_translations['locations'][$old_location['id']] = $agency_id;
  141. /* set users.tmp_site_id to match the newly made agency */
  142. if (!mysql_query("UPDATE users SET tmp_site_id=$agency_id WHERE location_id=".$old_location['id'].";"))
  143. trigger_error(__CLASS__."::".__FUNCTION__." failed to set users.tmp_site_id on line " .__LINE__. "\n" . mysql_error());
  144. if ($affected = mysql_affected_rows()) {
  145. if (!mysql_query("UPDATE tmp_sites SET user_count = user_count + $affected WHERE id = $agency_id;"))
  146. trigger_error(__CLASS__."::".__FUNCTION__." failed to set users.tmp_site_id on line " .__LINE__. "\n" . mysql_error());
  147. }
  148. /* if we are just using the parent and did not make a separate agency, no need to update services_tmp_sites.
  149. * just go to the next iteration of the loop */
  150. #if ($parent_id == $agency_id)
  151. #continue;
  152. // else
  153. /* populate agencies_services table */
  154. $this->makeAgenciesServices("locations_services", $old_location, $agency_id);
  155. if (!mysql_query("UPDATE contacts SET tmp_site_id = $agency_id WHERE location_id = " . $old_location['id'] .";"))
  156. die(__METHOD__." error on line ".__LINE__ ."\n". mysql_error() ."\n");
  157. }
  158. /* set agency_id for all users who have not received an agency yet */
  159. if (! $users = mysql_query("SELECT id, site_id FROM users WHERE tmp_site_id = 0;"))
  160. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  161. while ($user = mysql_fetch_array($users)) {
  162. if (isset($this->id_translations['sites'][$user['site_id']]) &&
  163. $this->id_translations['sites'][$user['site_id']['agency_id']] != null) {
  164. $agency_id = $this->id_translations['sites'][$user['site_id']]['agency_id'];
  165. if (! mysql_query("UPDATE users SET tmp_site_id = $agency_id WHERE id = " . $user['id'] . ";"))
  166. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  167. if (!mysql_query("UPDATE tmp_sites SET user_count = user_count + 1 WHERE id = $agency_id;"))
  168. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  169. }
  170. }
  171. /* log info */
  172. /* tmp_sites without services */
  173. if (! $no_services = mysql_query("SELECT id, name FROM tmp_sites WHERE id NOT IN (SELECT tmp_site_id FROM services_tmp_sites);"))
  174. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  175. /* tmp_sites without a location */
  176. if (! $no_locs = mysql_query("SELECT id, name FROM tmp_sites WHERE Equals(location, GeomFromText('POINT(0 0)'));"))
  177. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  178. /* services without tmp_sites */
  179. if (! $no_agencies = mysql_query("SELECT id, name FROM services WHERE id NOT IN (SELECT service_id FROM services_tmp_sites);"))
  180. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  181. /* users without tmp_sites */
  182. if (! $users = mysql_query("SELECT id, firstname, lastname FROM users WHERE tmp_site_id NOT IN (SELECT id FROM tmp_sites);"))
  183. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__."\n".mysql_error()."\n");
  184. if ($nrows = mysql_num_rows($no_services))
  185. error_log("$nrows tmp_sites created with no services attached to them.\n", 3, LOG_ERROR);
  186. if ($nrows = mysql_num_rows($no_locs))
  187. error_log("$nrows tmp_sites created with no location.\n", 3, LOG_ERROR);
  188. if ($nrows = mysql_num_rows($no_agencies))
  189. error_log("$nrows services are not associated with any tmp_site.\n", 3, LOG_ERROR);
  190. if ($nrows = mysql_num_rows($users))
  191. error_log("$nrows users are not associated with any tmp_site.\n", 3, LOG_ERROR);
  192. while ($no_service = mysql_fetch_array($no_services)) {
  193. error_log("TmpSite ". $no_service['name'] . " (id " .$no_service['id'] . ") has no services associated with it.\n", 3, LOG_ERROR);
  194. }
  195. while ($no_loc = mysql_fetch_array($no_locs)) {
  196. error_log("TmpSite ". $no_loc['name'] . " (id " .$no_loc['id'] . ") has no location.\n", 3, LOG_ERROR);
  197. }
  198. while ($no_agency = mysql_fetch_array($no_agencies)) {
  199. error_log("Service " . $no_agency['name'] . " (id " . $no_agency['id'] . ") is not associated with any tmp_sites.\n", 3, LOG_ERROR);
  200. }
  201. while ($user = mysql_fetch_array($users)) {
  202. error_log("User " . $user['firstname'] ." ". $user['lastname'] .
  203. " (id " . $user['id'] . ") not associated with any tmp_site.\n", 3, LOG_ERROR);
  204. }
  205. if (! mysql_query("UNLOCK TABLES;"))
  206. die("Failed to unlock tables");
  207. }
  208. /* note: this function can be called on sites and locations */
  209. private function makeLocation($site) {
  210. /* if lat and lng are not set use dummy location */
  211. if (!isset($site['lat'])) {
  212. error_log("Site ". $site['name'] . " has no lat set.\n", 3, LOG_ERROR);
  213. return $this->dummy_id;
  214. }
  215. if (!isset($site['lng'])) {
  216. error_log("Site ". $site['name'] . " has no lng set.\n", 3, LOG_ERROR);
  217. return $this->dummy_id;
  218. }
  219. $lat = $site['lat'];
  220. $lng = $site['lng'];
  221. if ($lat == 0 || $lng == 0) {
  222. return $this->dummy_id;
  223. }
  224. /* if lat and lng match a location already in the db, ask user before making a new entry */
  225. $point = "GeomFromText(\"POINT($lat $lng)\")";
  226. if (!$duplicates = mysql_query("SELECT * FROM tmp_locations WHERE Equals(location, $point);"))
  227. die(__CLASS__."::".__FUNCTION__." failed on line ".__LINE__."\n".mysql_error()."\n");
  228. if (mysql_num_rows($duplicates)) {
  229. if ($old_id = $this->keep($site, $duplicates, 'tmp_locations'))
  230. return $old_id;
  231. }
  232. // Else go ahead and build the new location
  233. /* build new tmp_location */
  234. $fields = array('id');
  235. $values = array(++$this->max_tmp_loc_id);
  236. $this->_make_helper('name', $site, &$fields, &$values);
  237. $this->_make_helper('address1', $site, &$fields, &$values);
  238. $this->_make_helper('address2', $site, &$fields, &$values);
  239. $this->_make_helper('city', $site, &$fields, &$values);
  240. $this->_make_helper('state', $site, &$fields, &$values);
  241. $this->_make_helper('zipcode', $site, &$fields, &$values);
  242. $fields[] = 'lat';
  243. $values[] = $lat;
  244. $fields[] = 'lng';
  245. $values[] = $lng;
  246. $fields[] = 'location';
  247. $values[] = "GeomFromText(\"POINT($lat $lng)\")";
  248. $query = "INSERT INTO tmp_locations(" . implode(", ", $fields) . ") VALUES(" . implode(", ", $values) . ");";
  249. if (! mysql_query($query))
  250. trigger_error("Inset on tmp_locations failed using query $query\n" . mysql_error());
  251. else
  252. error_log(date(DATE_FORMAT) ." new location \"" . $site['name'] . "\" with id "
  253. . $this->max_tmp_loc_id . " made from " . (isset($site['site_id']) ? 'location ' : 'site ') . $site['id']. "\n", 3, LOG_SUCCESS);
  254. return $this->max_tmp_loc_id;
  255. }
  256. /**
  257. * If parent_id is not set, go ahead and make the agency. If parent_id
  258. * is set, then compare all fields against the parent agency. If they are
  259. * identical, don't bother to make the new agency. If only a few fields
  260. * differ, ask the user whether or not to make the new agency.
  261. */
  262. private function makeAgency($site, $parent_id = null) {
  263. /* if there is a parent agency, make sure the proposed new agency is not identical */
  264. if ($parent_id) {
  265. if (! $parent = mysql_query("SELECT * FROM tmp_sites where id = $parent_id;"))
  266. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__.":\n" . mysql_error() . "\n");
  267. if (! mysql_num_rows($parent))
  268. die("TmpSite id $parent_id was stored in the id_translations table, but not found in the database.\n");
  269. /* if we are going to keep the site, we may need to update languages */
  270. if ($this->keep($site, $parent, 'tmp_sites')) {
  271. if (isset($site['languages']) && $site['languages'] != null)
  272. $this->addLangs($parent_id, $site['languages']);
  273. return $parent_id;
  274. }
  275. }
  276. /* build the fields to insert into the agencies table */
  277. $fields = array('id');
  278. $values = array(++$this->max_agency_id);
  279. $this->_make_helper('name', $site, &$fields, &$values);
  280. $this->_make_helper('website', $site, &$fields, &$values);
  281. $this->_make_helper('phone', $site, &$fields, &$values, 'main_phone');
  282. $this->_make_helper('email', $site, &$fields, &$values, 'main_email');
  283. $this->_make_helper('fax', $site, &$fields, &$values, 'main_fax');
  284. $this->_make_helper('file_image', $site, &$fields, &$values);
  285. $this->_make_helper('main_contact', $site, &$fields, &$values);
  286. $this->_make_helper('neighborhood_served', $site, &$fields, &$values);
  287. $this->_make_helper('address1', $site, &$fields, &$values);
  288. $this->_make_helper('address2', $site, &$fields, &$values);
  289. $this->_make_helper('city', $site, &$fields, &$values);
  290. $this->_make_helper('state', $site, &$fields, &$values);
  291. $this->_make_helper('zipcode', $site, &$fields, &$values);
  292. $lat = $site['lat'];
  293. $lng = $site['lng'];
  294. $fields[] = 'lat';
  295. $values[] = $lat;
  296. $fields[] = 'lng';
  297. $values[] = $lng;
  298. $fields[] = 'location';
  299. $values[] = "GeomFromText(\"POINT($lat $lng)\")";
  300. $fields[] = 'created';
  301. if (isset($site['created']) && $site['created'] != 0 && $site['created'] != '0')
  302. $values[] = '"' . $site['created'] . '"' ;
  303. else
  304. $values[] = '"' .date(DATE_FORMAT) . '"';
  305. $fields[] = 'modified';
  306. if (isset($site['modified']) && $site['modified'] != 0 && $site['modified'] != '0')
  307. $values[] = '"' . $site['modified'] . '"';
  308. else
  309. $values[] = '"' . date(DATE_FORMAT) . '"';
  310. /* insert the new tmp_site */
  311. if ($this->Mptt->insert($parent_id, $fields, $values)) {
  312. error_log(date(DATE_FORMAT) . " new tmp_site " . $values[1] . " with id " . $values[0] .
  313. " made from " . (isset($site['site_id']) ? 'location ' : 'site ') . $site['id'] . "\n", 3, LOG_SUCCESS);
  314. /* on successful creation of a new TmpSite, add the language associations for it */
  315. if (isset($site['languages']) && $site['languages'] != '')
  316. $this->addLangs($this->max_agency_id, $site['languages']);
  317. return $this->max_agency_id;
  318. }
  319. else {
  320. error_log(date(DATE_FORMAT) . "failed to insert agency\"" . $values[1] . "\" with id " . $values[0] . "\n", 3, LOG_ERROR);
  321. return null;
  322. }
  323. }
  324. private function addLangs($tmp_site_id, $languages) {
  325. $languages = strtolower($languages);
  326. $matches = array();
  327. preg_match_all($this->lang_regexp, $languages, &$matches);
  328. foreach ($matches[0] as $language) {
  329. /* if this site has already been associated with this language, continue */
  330. if (! $old = mysql_query("SELECT * FROM languages_tmp_sites WHERE language_id =
  331. (SELECT id FROM languages WHERE language = \"$language\")
  332. AND tmp_site_id = $tmp_site_id;"))
  333. die(__METHOD__." MySQL error on line ".__LINE__.": " . mysql_error() . "\n");
  334. if (mysql_num_rows($old) != 0)
  335. continue;
  336. /* if not, create the new association */
  337. if (! mysql_query("INSERT INTO languages_tmp_sites(language_id, tmp_site_id)
  338. VALUES((SELECT id FROM languages WHERE language = \"$language\"), $tmp_site_id);"))
  339. die(__METHOD__." MySQL error on line ".__LINE__.": " . mysql_error() . "\n");
  340. if (! mysql_query("UPDATE languages SET site_count = site_count + 1 WHERE language = \"$language\";"))
  341. die(__METHOD__." MySQL error on line ".__LINE__.": " . mysql_error() . "\n");
  342. }
  343. }
  344. private function makeAgenciesServices($table, $old, $agency_id) {
  345. /* get the appropriate service ids out of the database */
  346. if ($table == "locations_services")
  347. $query = "SELECT service_id AS id FROM $table WHERE location_id = " . $old['id'];
  348. #" UNION SELECT id FROM services WHERE site_id = " . $old['site_id'] . ";";
  349. else if ($table == "services")
  350. $query = "SELECT id FROM $table WHERE site_id = " . $old['id'] . ";";
  351. else
  352. die(__CLASS__."::".__FUNCTION__." received bad table value on line ".__LINE__.": $table\n");
  353. if (! $service_ids = mysql_query($query))
  354. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__.":\n" . mysql_error() . "\n");
  355. /* create new services_tmp_locations */
  356. while ($service_id = mysql_fetch_array($service_ids)) {
  357. if (isset($this->agencies_services[$agency_id]) && in_array($service_id, $this->agencies_services[$agency_id])) {
  358. continue;
  359. }
  360. if (! mysql_query("INSERT INTO services_tmp_sites(tmp_site_id, service_id)
  361. VALUES ($agency_id, ".$service_id['id'].");"))
  362. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__.":\n" . mysql_error() . "\n");
  363. $this->agencies_services[$agency_id][] = $service_id;
  364. if (!mysql_query("UPDATE tmp_sites SET service_count = service_count + 1 WHERE id = $agency_id;"))
  365. die(__CLASS__."::".__FUNCTION__." received sql error on line ".__LINE__.":\n" . mysql_error() . "\n");
  366. error_log(date(DATE_FORMAT)." new services_tmp_site: service id=". $service_id['id'] .", tmp_site id = $agency_id\n", 3, LOG_SUCCESS);
  367. }
  368. }
  369. /**
  370. * this function returns true if we SHOULD keep the new entry
  371. * and false if we should not
  372. * note: $olds should only contain one entry, if we are checking an agency
  373. */
  374. private function keep($new, $olds, $table) {
  375. $old = null;
  376. while ($tmp = mysql_fetch_array($olds)) {
  377. $diff = array();
  378. $add = array();
  379. $old = $tmp;
  380. #if ($old['lat'] != $new['lat'] || $old['lng'] != $new['lng'])
  381. #return null;
  382. $this->_keep_helper('name', $new, $old, &$diff, &$add);
  383. $this->_keep_helper('address1', $new, $old, &$diff, &$add);
  384. $this->_keep_helper('address2', $new, $old, &$diff, &$add);
  385. $this->_keep_helper('city', $new, $old, &$diff, &$add);
  386. $this->_keep_helper('state', $new, $old, &$diff, &$add);
  387. $this->_keep_helper('zipcode', $new, $old, &$diff, &$add);
  388. $this->_keep_helper('website', $new, $old, &$diff, &$add);
  389. $this->_keep_helper('phone', $new, $old, &$diff, &$add, 'main_phone');
  390. $this->_keep_helper('email', $new, $old, &$diff, &$add, 'main_email');
  391. $this->_keep_helper('main_contact', $new, $old, &$diff, &$add);
  392. $this->_keep_helper('neighborhood_served', $new, $old, &$diff, &$add);
  393. /* if all fields are identical, just use the old location without asking the user */
  394. if (empty($diff) && empty($add))
  395. return $old['id'];
  396. /* all mutual fields are identical, some to be added */
  397. if (empty($diff) && !empty($add)) {
  398. if (!mysql_query("UPDATE $table set " . implode(", ", $add) . " WHERE id = " . $old['id'] . ";"))
  399. die(__CLASS__."::".__FUNCTION__." failed on line ".__LINE__."\n".mysql_error()."\n");
  400. return $old['id'];
  401. }
  402. } // end WHILE loop. note: this means that if the user is being prompted for input, we are comparing
  403. // against the last of the matching entries
  404. /* nothing to add, some differences in existing fields */
  405. if (!empty($diff) && empty($add)) {
  406. /* if more than two fields differ and this is an agency,
  407. * go ahead and make a new agency */
  408. if (count($diff) > 2 && $table == 'tmp_sites')
  409. return null;
  410. /* if we are looking at a location and the only difference is the name, don't make a duplicate */
  411. #if ($diff === array('name') && $table == 'tmp_locations')
  412. #return $old['id'];
  413. /* else prompt the user */
  414. }
  415. /* at this point we know that !empty($diff) AND !empty($add) */
  416. if ($diff === array('zipcode')) {
  417. if (!mysql_query("UPDATE $table set " . implode(", ", $add) . " WHERE id = " . $old['id'] . ";"))
  418. die(__CLASS__."::".__FUNCTION__." failed on line ".__LINE__."\n".mysql_error()."\n");
  419. return $old['id'];
  420. }
  421. /* if there are too many differences, just go ahead and make a new agency */
  422. #$keep = $this->promptUser($new, $old, $diff, $table);
  423. #if ($keep)
  424. return null;
  425. // else update the existing agency, if we have any new information about it
  426. if (!empty($add)) {
  427. if (!mysql_query("UPDATE $table set " . implode(", ", $add) . " WHERE id = " . $old['id'] . ";"))
  428. die(__CLASS__."::".__FUNCTION__." failed on line ".__LINE__."\n".mysql_error()."\n");
  429. }
  430. return $old['id'];
  431. }
  432. private function promptUser($site, $duplicate, $diff, $table) {
  433. print("\n**************************************************************************************************\n");
  434. print("Working on " . (isset($site['site_id']) ? 'location' : 'site') . " " . $site['id'] . "\n");
  435. print("Comparing with " . (isset($site['site_id']) ? 'tmp_location' : 'tmp_site') . " " .$duplicate['id'] . "\n\n");
  436. print("There is a proposed new $table that closely matches an existing $table\n");
  437. print("Here are the differences:\n\n");
  438. printf("%40s\n", "EXISTING $table");
  439. foreach ($diff as $key) {
  440. printf("%20s: %s\n", $key, (isset($duplicate[$key]) ? $duplicate[$key] : "NULL" ));
  441. }
  442. printf("%20s: %s\n", "lat", $site['lat']);
  443. printf("%20s: %s\n", "lng", $site['lng']);
  444. printf("\n%40s\n", "PROPOSED NEW $table");
  445. foreach ($diff as $key) {
  446. printf("%20s: %s\n", $key, (isset($site[$key]) ? $site[$key] : "NULL"));
  447. }
  448. printf("%20s: %s\n", "lat", $duplicate['lat']);
  449. printf("%20s: %s\n", "lng", $duplicate['lng']);
  450. return $this->getResponse($table);
  451. }
  452. private function getResponse($table) {
  453. print("\nWould you like to add the proposed new $table to the database?\n");
  454. print("(y)es or (n)o\n");
  455. print("[y] ");
  456. $input = strtolower(trim(fgets(STDIN, 200)));
  457. switch ($input) {
  458. case 'n':
  459. case 'no':
  460. return false;
  461. case '':
  462. case 'y':
  463. case 'yes':
  464. return true;
  465. default:
  466. echo "\nSorry, I didn't understand your answer.\n\n";
  467. return $this->getResponse($table);
  468. }
  469. }
  470. private function _keep_helper ($field, $new, $old, $diff, $add, $alt_field_name = null) {
  471. if (isset($new[$field]) && trim($new[$field]) != '') {
  472. $this->_check_fields($field, $field, $new, $old, &$diff, &$add);
  473. }
  474. else if ($alt_field_name != null && isset($new[$alt_field_name]) && trim($new[$alt_field_name]) != '') {
  475. $this->_check_fields($alt_field_name, $field, $new, $old, &$diff, &$add);
  476. }
  477. }
  478. private function _check_fields ($newfield, $oldfield, $new, $old, $diff, $add) {
  479. $new_val = $this->_sanitize($new[$newfield]);
  480. if (! isset($old[$oldfield]) || $old[$oldfield] == '') {
  481. $add[] = "$oldfield = $new_val";
  482. }
  483. else if ($oldfield == 'zipcode' && isset($old[$oldfield]) && $old[$oldfield] == '0') {
  484. $add[] = "$oldfield = $new_val";
  485. }
  486. else if ($oldfield == 'phone') {
  487. if ($this->_normalize($new_val) != $this->_normalize($old[$oldfield])) {
  488. $new_val = $this->_sanitize($old[$oldfield] . ", " . $new_val);
  489. $add[] = "phone = $new_val";
  490. }
  491. }
  492. else if ($this->_normalize($new_val) != $this->_normalize($old[$oldfield])) {
  493. // check if one is a substring of the other
  494. if (strpos(' '.$this->_normalize($new_val), $this->_normalize($old[$oldfield]))) {
  495. $add[] = "$oldfield = $new_val";
  496. }
  497. else if (strpos(' '.$this->_normalize($old[$oldfield]), $this->_normalize($new_val)))
  498. ; //do nothing
  499. else $diff[] = $newfield;
  500. }
  501. }
  502. private function _make_helper($name, $site, $fields, $values, $altname = null) {
  503. if ($altname != null)
  504. $site_name = $altname;
  505. else
  506. $site_name = $name;
  507. if (isset($site[$site_name]) && trim($site[$site_name]) != '') {
  508. $fields[] = $name;
  509. $new_val = $this->_sanitize($site[$site_name]);
  510. $values[] = $new_val;
  511. }
  512. }
  513. private function _sanitize ($val) {
  514. if (is_string($val)) {
  515. $val = trim($val);
  516. $val = preg_replace("/\"/", "", $val);
  517. $val = '"' . $val . '"';
  518. }
  519. return $val;
  520. }
  521. function _normalize ($val) {
  522. if (is_string($val)) {
  523. /* normalize phone numbers */
  524. $val = preg_replace("/(1\-|1 )?\(?(\d\d\d)(\)? ?|-|\.)(\d\d\d)(-?|\.)(\d\d\d\d)/", "$2 $4 $6", $val);
  525. $val = strtolower($val);
  526. $val = preg_replace("/[\.\",\-\/]/", "", $val);
  527. $stopWords = array('st', 'street', 'ave', 'avenue',
  528. 'dr', 'drive', 'pl', 'place', 'rd',
  529. 'road', 'usa'
  530. );
  531. $replacements = array('w'=>'west',
  532. 'n'=>'north',
  533. 'e'=>'east',
  534. 's'=>'south',
  535. '1st'=>'first',
  536. '2nd'=>'second'
  537. );
  538. $val = preg_replace("/[ ]+/", " ", $val);
  539. $val = $this->_replace($replacements, $val);
  540. $val = $this->_delStopWords($stopWords, $val);
  541. }
  542. return trim($val);
  543. }
  544. private function _delStopWords($stopWords, $val) {
  545. foreach ($stopWords as $word) {
  546. $val = preg_replace("/ $word( |$)/", " ", $val);
  547. }
  548. return $val;
  549. }
  550. private function _replace($replacements, $val) {
  551. foreach ($replacements as $key => $replacement) {
  552. $val = preg_replace("/ $key( |$)/", " $replacement$1", $val);
  553. }
  554. return $val;
  555. }
  556. }
  557. $slMerge = new SLMerge(null, true, true);
  558. $slMerge->merge();