I have two database (mysql) with the same structure. I want to:
compare data in two table. Table one - home and the second work,
send email with results,
update data in table work.
My query:
select id, code, quantity from wpx_products
I run this query in table home and work (two databases). And this is output:
"3";"home 005-07";"2"
"63";"home 033-12";"2"
"15";"home 005-19";"2"
and from work:
"1";"work 005-07";"2"
"2";"work 033-12";"5"
"3";"work 005-19";"2"
What I want to do ? What I mean by "compare" ? I want find record with excluding tag work or home in column 'code'. For example I want to find 033-12 and check quantity. If the difference copy value from home to work.
In first second I want to use trigger in mysql. But this is not solution for me because I cant run it by myself and I can't send email with results. What is the best way to achieve this functionality ? Thanks for help.
Kind regards
---------------------edit----------------------------
I check this code below (thanks #AntG). And I have one problem. When I print
foreach ($result_target AS $target) {
$code_target = substr($target['code'], 4);
if ($code_source === $code_target) {
if ($source['quantity'] !== $target['quantity']) {
print $source['quantity'] .' -> ' . $target['quantity']."<br /><br />";
$match[] = array('code' => $source['code'], 'quantity' => $source['quantity'], 'targetid' => $target['id'], 'sourceid' => $source['id']);
}
$found = true;
break;
}
}
I have this results: http://suszek.info/projekt1/ Like You see there is 50 values. When I print $match there is much more, duplicated value and I don't know why ?
$msg = '';
foreach ($match AS $entry) {
$msg .= 'Change identified: Home_ID=' . $entry['sourceid'] . ' code: ' . $entry['code'] . ' quantity:' . $entry['quantity'] . PHP_EOL . '<br />';
print $msg;
/* Perform DB updates using $entry['targetid'] and $entry['quantity'] */
}
I have this results: http://suszek.info/projekt1/index_1.php And all code:
$match = array(); $new = array();
foreach ($result_source AS $source) {
$found = false;
$code_source = substr($source['code'], 4);
foreach ($result_target AS $target) {
$code_target = substr($target['code'], 4);
if ($code_source === $code_target) {
if ($source['quantity'] !== $target['quantity']) {
print $source['quantity'] .' -> ' . $target['quantity']."<br /><br />";
$match[] = array('code' => $source['code'], 'quantity' => $source['quantity'], 'targetid' => $target['id'], 'sourceid' => $source['id']);
}
$found = true;
break;
}
}
if (!$found) {
$new[] = array('code' => $source['code'], 'quantity' => $source['quantity'], 'sourceid' => $source['id']);
} } $msg = ''; foreach ($match AS $entry) {
$msg .= 'Change identified: Home_ID=' . $entry['sourceid'] . ' code: ' . $entry['code'] . ' quantity:' . $entry['quantity'] . PHP_EOL
. '<br />';
print $msg;
/* Perform DB updates using $entry['targetid'] and $entry['quantity'] */ }
foreach ($new AS $entry) {
$msg .= 'New Entry: Home_ID=' . $entry['sourceid'] . ' code: ' . $entry['code'] . ' quantity:' . $entry['quantity'] . PHP_EOL . '<br
/>';
#print $msg;
/* Perform DB inserts using $entry['code'] and $entry['quantity'] if this is desired behaviour */ }
/* Send email with $msg */
If you are capturing both query results in a $results array, then I think substr() is the PHP function that you are after here:
$match=array();
$new=array();
foreach($results_home AS $home)
{
$found=false;
$code=substr($home['code'],5);
foreach($results_work AS $work)
{
if($code===substr($work,5))
{
if($home['quantity']!==$work['quantity'])
{
$match[]=array('code'=>$home['code'],'quantity'=>$home['quantity'],'workid'=>$work['id'],'homeid'=>$home['id']);
}
$found=true;
break;
}
}
if(!$found)
{
$new[]=array('code'=>$home['code'],'quantity'=>$home['quantity'],'homeid'=>$home['id']);
}
}
$msg='';
foreach($match AS $entry)
{
$msg.='Change identified: Home_ID='.$entry['homeid'].' code: '.$entry['code'].' quantity:'.$entry['quantity'].PHP_EOL;
/* Perform DB updates using $entry['workid'] and $entry['quantity'] */
}
foreach($new AS $entry)
{
$msg.='New Entry: Home_ID='.$entry['homeid'].' code: '.$entry['code'].' quantity:'.$entry['quantity'].PHP_EOL;
/* Perform DB inserts using $entry['code'] and $entry['quantity'] if this is desired behaviour */
}
/* Send email with $msg */
Related
I have the following code which works great to do what it is meant to do. It scrapes bodys of all e-mails in the inbox at an e-mail address using IMAP and retrieves the unique code sent inside the body and stores it in a database with the amount paid. I'm hoping to make it so when a user purchases something they can send an Interac e-transfer and then enter the code that both of us receive via e-mail in the website and it will apply the credit of the e-transfer to their account/purchase.
However; after setting it up on a cron job to cycle every few minutes so the content in the database stays fresh it eventually exceeds the bandwidth for the account within a day or so (not positive on how long it took but it didn't take long). Now, like I said the code works it's just very resource intensive apparently.
I do not pipe the script because the e-mail account has already been set up a while ago and we do use the account for other e-transfers which I review manually for other transactions.
Is there anyway to clean it up so it works the same but uses less resources/bandwidth?
Would it be better to run it when a user enters their payment code? Depending on the number of users running it this could also lead to bandwidth troubles.
Is there any improvements or what ideas do you have?
define("MAX_EMAIL_COUNT", $_POST['maxcount']);
/* took from https://gist.github.com/agarzon/3123118 */
function extractEmail($content) {
$regexp = '/([a-z0-9_\.\-])+\#(([a-z0-9\-])+\.)+([a-z0-9]{2,4})+/i';
preg_match_all($regexp, $content, $m);
return isset($m[0]) ? $m[0] : array ();
}
function getAddressText(&$emailList, &$nameList, $addressObject) {
$emailList = '';
$nameList = '';
foreach ($addressObject as $object) {
$emailList .= ';';
if (isset($object->personal)) {
$emailList .= $object->personal;
}
$nameList .= ';';
if (isset($object->mailbox) && isset($object->host)) {
$nameList .= $object->mailbox . "#" . $object->host;
}
}
$emailList = ltrim($emailList, ';');
$nameList = ltrim($nameList, ';');
}
function processMessage($mbox, $messageNumber) {
global $db;
// get imap_fetch header and put single lines into array
$header = imap_rfc822_parse_headers(imap_fetchheader($mbox, $messageNumber));
$timestamp = strtotime($header->Date);
$fromEmailList = '';
$fromNameList = '';
if (isset($header->from)) {
getAddressText($fromEmailList, $fromNameList, $header->from);
}
$toEmailList = '';
$toNameList = '';
if (isset($header->to)) {
getAddressText($toEmailList, $toNameList, $header->to);
}
$body = imap_fetchbody($mbox, $messageNumber, 1);
//echo "<pre>".print_r($body,true)."</pre>";
/* Find Reference Number */
//echo "<pre style='background-color: #A2A2A2; border: 1px solid black'>$body</pre>";
$searchfor = 'Reference Number';
// get the file contents, assuming the file to be readable (and exist)
$contents = $body;
// escape special characters in the query
$pattern = preg_quote($searchfor, '/');
// finalise the regular expression, matching the whole line
$pattern = "/^.*$pattern.*\$/m";
// search, and store all matching occurences in $matches
if(preg_match_all($pattern, $contents, $matches)){
$reference = trim(str_replace('Reference Number : ','',$matches[0][0]));
}
else{
}
/* Find Amount Paid */
//echo "<pre style='background-color: #A2A2A2; border: 1px solid black'>$body</pre>";
$searchfor = 'has sent you a money transfer for the amount of';
// get the file contents, assuming the file to be readable (and exist)
$contents = $body;
// escape special characters in the query
$pattern = preg_quote($searchfor, '/');
// finalise the regular expression, matching the whole line
$pattern = "/^.*$pattern.*\$/m";
// search, and store all matching occurences in $matches
if(preg_match_all($pattern, $contents, $matches)){
$amount = trim(preg_replace("/[^0-9\.]/", "",$matches[0][0]),'.');
}
else{
}
$bodyEmailList = implode(';', extractEmail($body));
// Delete all messages older than one year (31557600 seconds). Divide it by two for six months.
if($timestamp < time()-31557600) {
if(imap_delete($mbox,$messageNumber)) {
/*echo "<strong>";
print_r($messageNumber . ' , ' . date("F j, Y g:i A",$timestamp).' , ' . 'Deleted' . "\n");
echo "</strong>";*/
}
}
else {
if(!empty($reference) && !empty($amount)) {
if($fromNameList == "catch#payments.interac.ca" && $toNameList!='etransfers#example.com') {
$query = "SELECT * FROM `".$db->prefix."payments_etransfer` WHERE `reference_id` = '".$reference."'";
$select = $db->select($query);
if($db->num_rows($select) > 0) {
}
else {
$do = $db->insert_sql("INSERT INTO `".$db->prefix."payments_etransfer` SET
`email_id` = '".$messageNumber."',
`timestamp` = '".$timestamp."',
`reference_id` = '".$reference."',
`amount` = '".$amount."',
`sender` = '".$fromEmailList."'");
if($do) {
}
else {
echo "Error<br><blockquote><pre>";
print_r($messageNumber . ',' . $timestamp. ',' . $reference . ',$' . $amount .
',' . $fromEmailList . ',' . $fromNameList
. ',' . $toEmailList . ',' . $toNameList
. ',' . $bodyEmailList . "\n"
);
echo "</pre></blockquote>";
}
}
}
}
}
}
// imap_timeout(IMAP_OPENTIMEOUT, 300);
// Open pop mailbox
if (!$mbox = imap_open($_POST['mailbox'], $_POST['login'], $_POST['password'])) {
die('Cannot connect/check pop mail! Exiting');
}
if ($hdr = imap_check($mbox)) {
$msgCount = $hdr->Nmsgs;
} else {
echo "Failed to get mail";
exit;
}
/* echo "<pre>";
echo 'emails count=' . $msgCount . "\n\n\n";
echo "record number,from emails list,from names list,to emails list, to names list,extracted from body\n";
*/
/* might improve performance according to
http://www.php.net/manual/en/function.imap-headerinfo.php#98809
imap_headers($mbox);
*/
for ($X = $msgCount; $X > 0; $X--) {
if($X > 0) {
processMessage($mbox, $X);
}
}
/*echo "</pre>";*/
imap_expunge($mbox);
imap_close($mbox);
/*
I'm writing a custom import script for SuiteCRM and I'm getting the error:
Warning: array_combine() expects parameter 2 to be array, boolean
given in /var/www/html/afscmedbv5test/custom/wimporter/newimporter.php
on line 162
My Script is as follows:
<?php
if (!defined('sugarEntry') || !sugarEntry) die ('Not a Valid Entry Point!');
$date = new DateTime();
echo '<H2>Wilderness Import Started</h2>';
echo $date->format('r').'<br>';
echo '-----------------------------------------------------------------------
--------------------------------------------------------------<br>';
require_once("include/utils/sugar_file_utils.php");
WildernessImportJob();
die();
function var_dump_ret($mixed = null) {
ob_start();
var_dump($mixed);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
function time_elapsed()
{
static $first = null;
static $previous = null;
$now = microtime(true);
if ($first == null) $first = $now;
if ($previous != null)
echo '--- Partial ' . round(($now - $previous), 2) . ', Total ' . round(($now
- $first), 2) . ' ---'; // 109s
$ret = round(($now - $previous), 2);
$previous = $now;
return $ret;
}
function myLog ($str2log)
{
file_put_contents('./zlog_'.date("j.n.Y").'.txt', date("H:i:s", time())."
".$str2log.PHP_EOL, FILE_APPEND);
}
function calcDelta($a1, $a2)
{
//combine into a nice associative array:
$delta=Array();
foreach ($a1 as $key=>$value)
{
if ($a1[$key] != $a2->$key)
$delta[] = array($key => ("Was ". $a1[$key]. ", became " . $a2->$key));
}
$num = count($data);
if (empty($a1)) $delta[] = array("a1" => ("Was empty"));
if (empty($a2)) $delta[] = array("a2" => ("Was empty"));
return $delta;
}
require_once("include/utils/sugar_file_utils.php");
function fillPerson($record, &$person)
{
// $record is what is being imported from CSV
// $person is the bean about to be filled and going into the SuitCRM DB. It
may be new or not, depending on whether it exists in the DB previously.
// name: only updates if not existant yet, because it's the key we use for
search, and because names are more complex with parts
if ($person->full_name_c == "") {
$recordname = $record["FULL NAME"]; // != "") ? $record["FULL NAME"] : "
[To-be-filled]");
//echo $prefix;
$recordname = str_replace(" ", " ", $recordname);
echo $recordname;
$parts = explode(" ", $recordname);
$person->last_name = array_pop($parts);
$person->first_name = $parts[0];
$person->name = $person->first_name . " " . $person->last_name;
$person->full_name_c = $record["FULL NAME"]; // custom field created in
Studio
}
//$datanasc = DateTime::createFromFormat('!m/d/Y', $record["PPE"]);
// $datasnasc->setTime(0, 0);
// $person->ppe_date_c = ($datanasc == false) ? "" : $datanasc->format('m-d-
Y');
//$person->ppe_date_c = $record["PPE"];
//print_r($person);
var_dump($person);
}
// finish by making a complete analysis of what changed:
return calcDelta($person->fetched_row, $person);
function GetOrCreateMember ($the_name)
{
//Check if the fullname is null
if ($the_name != "")
{
$person = BeanFactory::getBean("locte_Members");
$person = $person->retrieve_by_string_fields(array('full_name_c' =>
$the_name));
if (is_null($person))
{
//get members bean
$person = BeanFactory::newBean("locte_Members");
//set full_name_c to the_name variable
$person->full_name_c = $the_name;
// $person->lcl_employee_id = $personEmployeeID;
$person_name = str_replace(" ", " ", $the_name);
$parts = explode(" ", $person_name);
$person->last_name = array_pop($parts);
$person->first_name = $parts[0];
//combine first and last name to populate the fullname field
$person->name = $person->first_name . " " . $person->last_name;
$person_id = $person->save();
// add new duespayment to member record
// $rosterDuesPayments = BeanFactory::getBean('Dues Payments')-
>retrieve_by_string_fields(array('name'=> $duesEmployeeID));
// $person->load_relationship('locte_Members_adues_dues'); //confirm
relationship name in cache
// $person->dues_payments->add($rosterDuesPayments->id);
}
return $person;
}
return null;
}
function WildernessImportJob()
{
try
{
time_elapsed();
$GLOBALS['log']->info('Wilderness Import');
$config = new Configurator();
$config->loadConfig();
$xmlDataDir = 'custom/wimporter/ToImport'; //$config->config['WildernessImporter_DataFilePath'];
$GLOBALS['log']->info("Wilderness Import: Scanning XML Data dir $xmlDataDir...");
echo("<h3>Wilderness Import: Scanning XML Data dir $xmlDataDir...<br /></h3>");
$directoryContent = scandir($xmlDataDir);
$GLOBALS['log']->info("Wilderness Import: Scanning XML Data dir $xmlDataDir... [Found " . count($directoryContent) . " files]");
echo("<h3>Wilderness Import: Scanning XML Data dir $xmlDataDir... [Found " . count($directoryContent) . " files]</h3><br />");
foreach ($directoryContent as $itemFile)
{
if (is_dir($xmlDataDir . DIRECTORY_SEPARATOR . $itemFile)) continue;
if (strcasecmp(substr($itemFile, -4), ".csv") != 0) continue;
$GLOBALS['log']->info("Wilderness Import: Processing $itemFile file...");
myLog("---------------------------------------------------");
myLog("Wilderness Import: Processing $itemFile file...");
myLog("----------------------------------------------------");
echo("<h4>---------------------------------------------------------------</h4>");
echo("<h4>Wilderness Import: Processing $itemFile file...</h4>");
echo("<h4>---------------------------------------------------------------</h4>");
$oFile = fopen($xmlDataDir . DIRECTORY_SEPARATOR . $itemFile, 'r');
if ($oFile !== FALSE)
{
// read entire file at once:
// expected separator is ",", expected encoding is UTF-8 without BOM (BOM is 3 weird characters in beginning of file)
while (($data[] = fgetcsv($oFile, 0, ',')) !== FALSE) { }
echo('File opened..... <br /> <br />');
fclose($oFile);
//combine into a nice associative array:
$arow=Array();
echo('Building CSV File Row Array <br /><br />');
$fields = array_shift($data);
echo('Building CSV Header Fields Array as shown below:<strong> <br /><br />');
echo implode(", ", $fields) . "</strong><br /><br />\n";
foreach ($data as $i=>$arow)
{
$GLOBALS['log']->info("Wilderness Import: array_combine " . $i);
$data[$i] = array_combine($fields, $arow);
}
unset($arow); // **********************************************! ! ! !! ! ! ! ! ! !! !
$num = count($data);
echo('Build Full Array of Roster to be Imported Complete. Entries to be imported are shown below <br /><br />');
for ($row=0; $row < $num - 1 ; $row++)
{ // normal bounds: from 0 to $num
//$num is the number of lines including header in csv file
echo "<strong>Filename: $itemFile | Roster Import, Row" . ($row + 1) . ":</strong><br />\n";
$GLOBALS['log']->info("Wilderness Import: Importing " . $data[$row]["FULL NAME"]);
// echo("<strong>Importing Roster Row #: ". ($row + 1) . "<br />" . "Local Number " . $data[$row]["AFFILIATE"] . "<br />" . "Employee: " . $data[$row]["FULL NAME"] . "</strong><br /><br />");
echo "<strong><table>\n";
foreach ($fields as $field) {
//echo "<tr><td>" . $field . "</td><td>" . $data[$row][$field] . "</td><td>" . $data[$row+1][$field] . "</td><td>" . $data[$row+2][$field] . "</td></tr>\n";
}
echo "</table>\n";
echo "File Row Data: ";
echo implode(", ", $data[$row]) . "</strong><br /><br />\n";
$Member = BeanFactory::getBean("locte_Members");
$FullName=$Member->full_name_c;
//$myfield_defs = $Member->getFieldDefinitions(); // just to help while developing
//foreach($myfield_defs as $def) echo $def["name"] . "<br />\n";
$Member=$Member->retrieve_by_string_fields(array('full_name_c' => $data[$row]["FULL NAME"]));
if (is_null($Member)) {
$Member = BeanFactory::newBean("locte_Members");
$delta = fillPerson($data[$row], $Member, ""); //->full_name_c, "FULL NAME");
}
if (count($delta)) {
$Member_id = $Member->save();
}
}
// Records have been saved: from this point on, only work on relationships:
$GLOBALS['log']->info('End: Wilderness Import');
myLog('End: Wilderness Import');
time_elapsed();
return true;
}
}
} catch (Exception $e)
{
$GLOBALS['log']->fatal("Wilderness Import: Exception " . $e->getMessage());
myLog("Wilderness Import: Exception " . $e->getMessage());
echo '\n\nCaught exception: ', $e->getMessage(), "\n";
return false;
}
}
It does return info from both the database and the csv file.
Image of error below.
Error - Capture from browser
Help always appreciated :)
This script is throwing error because the parameter $arow given to array_combine is not an array. So a check should be there to check whether $arow is an array or not.
Try code following:
foreach ($data as $i => $arow) {
$GLOBALS['log']->info("Wilderness Import: array_combine " . $i);
if (is_array($arow)) {
$data[$i] = array_combine($fields, $arow);
}
}
Read more about array_combine
Update
Code you are using to read csv need to be changed. Second parameter in fgetcsv must be greater than the longest line (in characters) to be found in the CSV file. So replace code
while (($data[] = fgetcsv($oFile, 0, ', ')) !== FALSE) {
}
with
while (($data[] = fgetcsv($oFile, 10, ', ')) !== FALSE) {
}
Read more about fgetcsv
This block is doing the saving of records using the beanfactory.... I think :|
$Member = BeanFactory::getBean("locte_Members");
$FullName=$Member->full_name_c;
//$myfield_defs = $Member->getFieldDefinitions(); // just to help while developing
//foreach($myfield_defs as $def) echo $def["name"] . "<br />\n";
$Member=$Member->retrieve_by_string_fields(array('full_name_c' => $data[$row]["FULL NAME"]));
if (is_null($Member)) {
$Member = BeanFactory::newBean("locte_Members");
$delta = fillPerson($data[$row], $Member->full_name_c, "FULL NAME");
var_dump($arow);
}
if (count($delta)) {
$Member_id = $Member->save();
}
}
// Records have been saved: from this point on, only work on relationships:
Here's the output of the script in the browser with field definition dump
Wilderness Import Started
Tue, 19 Jun 2018 02:05:56 -0400
Wilderness Import: Scanning XML Data dir custom/wimporter/ToImport...
Wilderness Import: Scanning XML Data dir custom/wimporter/ToImport... [Found 3 files]
Wilderness Import: Processing L1554v4.csv file...
File opened.....
Building CSV File Row Array
Building CSV Header Fields Array as shown below:
LAST NAME, FIRST NAME, FULL NAME
Build Full Array of Roster to be Imported Complete. Entries to be imported are shown below
Filename: L1554v4.csv | Roster Import, Row1:
LAST NAME BUTLER
FIRST NAME BRIANA
FULL NAME BUTLER BRIANA
File Row Data: BUTLER, BRIANA, BUTLER BRIANA
-id
-name
-date_entered
-date_modified
-modified_user_id
-modified_by_name
-created_by
-created_by_name
-description
-deleted
-securitygroup
-securitygroup_display
-created_by_link
-modified_user_link
-assigned_user_id
-assigned_user_name
-assigned_user_link
-additionalusers
-additionalusers_listview
-salutation
-first_name
-last_name
-full_name
-title
-photo
-department
-do_not_call
-phone_home
-email
-phone_mobile
-phone_work
-phone_other
-phone_fax
-email1
-email2
-invalid_email
-email_opt_out
-primary_address_street
-primary_address_street_2
-primary_address_street_3
-primary_address_city
-primary_address_state
-primary_address_postalcode
-primary_address_country
-alt_address_street
-alt_address_street_2
-alt_address_street_3
-alt_address_city
-alt_address_state
-alt_address_postalcode
-alt_address_country
-assistant
-assistant_phone
-email_addresses_primary
-email_addresses
-email_addresses_non_primary
-lcl_birthdate
-lcl_affiliate_number
-member_signature
-ssn
-staff_rep
-mem_join_date
-class_title
-steward
-olo_code
-enterprise_id
-member_card
-address_map
-member_status
-primary_language
-english_speaking
-annual_salary
-currency_id
-state_hire_date
-dues_frequency
-card_sent_date
-gender
-disabilities
-marital_status
-executive_board
-affiliate_type
-middle_name
-name_suffix
-mailableflag
-no_mailflag
-apt_number
-zip4
-infosrc
-lcl_phone_collected
-lcl_hasmobile
-lcl_hasemail
-lcl_member_status
-backofficeassistants
-backoffice_assistant_phonoe
-backoffice_assistant_email
-lcl_employercontact
-lcl_work_dept
-lcl_work_location
-lcl_jobclasstitle
-lcl_employee_id
-lcl_join_date
-lcl_sig_auth
-lcl_dues_status
-lcl_on_probation
-lcl_prob_end_date
-lcl_prob_term
-afs_signed_by
-afs_region_number
-afemp_employers_id_c
-afs_employer
-primary_address_county
-locte_members_adues_dues
-full_name_c
-locte_members_afcbu_cbu
-locte_members_afcbu_cbu_name
-locte_members_afcbu_cbuafcbu_cbu_idb
-ppe_date_c
--- Partial 0.01, Total 0.01 ---
I'm using the last version of ADOdb PHP (5.18) to make some queries in a SQL Server database.
I select data in this way:
$rS = $localDb->Execute($sql);
if (!$rS) {
echo "Error: " . $localDb->ErrorMsg() . "\n";
}
else {
$tot = $rS->RecordCount();
echo " " . $tot . " record da inserire...\n";
while (!$rS->EOF) {
$id = $rS->fields['id'];
$field1 = $rS->fields['field1'];
$field2 = $rS->fields['field2'];
$rS->MoveNext();
}
}
All works, and I fetch data, but when a field in the database's current row is NULL, the relative element in $rS->fields has the value of the value of the last not-NULL row for the same field.
This is a big problem because I don't have correct data in the current row.
I tried search for this problem but I did not find any solution.
Coud you help me, please?
Look into adodb5/adodb.inc.php and find the GetRowAssoc function. It should be the following defintion:
function GetRowAssoc($upper=ADODB_ASSOC_CASE_UPPER)
{
$record = array();
if (!$this->bind) {
$this->GetAssocKeys($upper);
}
foreach($this->bind as $k => $v) {
if( array_key_exists( $v, $this->fields ) ) {
$record[$k] = $this->fields[$v];
} elseif( array_key_exists( $k, $this->fields ) ) {
$record[$k] = $this->fields[$k];
} else {
# This should not happen... trigger error ?
$record[$k] = null;
}
}
return $record;
}
How can I cache (using ModX's cacheManager), the dynamic placeholders i am generating here:
// recursive function to generate our un-ordered list of menu items
if(!function_exists('GenerateMenu')){
function GenerateMenu($level, $parent = 0, $wc, $wi, $we, $cs, $sc, $cl){
try {
$lvl = ++$level;
global $modx;
// Check for #1, should this be cached, #2 does it already exist in the cache
$cached = $modx->cacheManager->get('Navigator');
if($sc && isset($cached)){
// need to get the placeholders from cache - here somehow!
return $cached;
}else{
// get the site start
$siteStartId = $modx->getOption('site_start');
// Set our initial rows array
$rows = array();
// Run our query to get our menu items
$sql = 'Select `id`, `menutitle`, `uri`, `longtitle`, `parent`, `link_attributes`, `class_key`, `content`, `alias`, `introtext`
From `' . $modx->getOption(xPDO::OPT_TABLE_PREFIX) . 'site_content`
Where `deleted` = 0 AND `hidemenu` = 0 AND `published` = 1 AND `parent` = :parent
Order by `parent`, `menuindex`';
$query = new xPDOCriteria($modx, $sql, array(':parent' => $parent));
if ($query->stmt && $query->stmt->execute()) {
$rows = $query->stmt->fetchAll(PDO::FETCH_ASSOC);
}
// do some cleanup
unset($query, $sql);
// make sure we have some rows, and then build our html for the menu
if($rows){
// grab a count of our results
$rCt = count($rows);
$cls = ($lvl > 1) ? 'sub-item-' . $lvl : 'main-item-' . $lvl;
$ret .= ' <ul class="' . $cls . '" id="' . $cls . '-' . $parent . '">' . "\r\n";
for($i = 0; $i < $rCt; ++$i){
// if this resource is a WebLink, show the content in it, as the URL for the href tag, otherwise, use the resource's URI
$url = ($rows[$i]['class_key'] == 'modWebLink') ? $rows[$i]['content'] : '/' . $rows[$i]['uri'];
// Check for the site's start id, if true, show a "blank" link, otherwise show the $url
$showUrl = ($siteStartId == $rows[$i]['id']) ? '/' : $url;
$la = (strlen($rows[$i]['link_attributes']) > 0) ? ' ' . $rows[$i]['link_attributes'] : null;
// Set some dynamic placeholders, they can only be used ont he pages that contain this snippet
$modx->toPlaceholders(array('Title-' . $rows[$i]['id'] => $rows[$i]['longtitle'],
'MenuTitle-' . $rows[$i]['id'] => $rows[$i]['menutitle'],
'URL-' . $rows[$i]['id'] => $showUrl),
'link');
$ret .= ' <li class="' . $cls . '" id="' . $rows[$i]['alias'] . '">' . "\r\n";
$ret .= ' <a href="' . $showUrl . '" title="' . $rows[$i]['longtitle'] . '"' . $la . '>' . $rows[$i]['menutitle'] . '</a>' . "\r\n";
$ret .= GenerateMenu($lvl, $rows[$i]['id']);
// Check for a snippet, and render it
$it = $rows[$i]['introtext'];
if($cs && IsSnippet($it)){
// if we find a snippet in the Summary field, run it, and attach it to our output
preg_match('/\[\[!?(.*)\]\]/', $it, $sm);
$ret .= $modx->runSnippet($sm[1]);
// clean up
unset($sm);
}
$ret .= ' </li>' . "\r\n";
}
$ret .= ' </ul>' . "\r\n";
}
// clean up
unset($rows);
// Check to see if we should cache it, if so, set it to cache, and apply the length of time it should be cached for: defaults to 2 hours
if($sc){
// NEED TO SET THE PLACEHOLDERS TO CACHE SOMEHOW
$modx->cacheManager->set('Navigator', $ret, $cl);
}
// return the menu
return $ret;
}
} catch(Exception $e) {
// If there was an error, make sure to write it out to the modX Error Log
$modx->log(modX::LOG_LEVEL_ERROR, '[Navigator] Error: ' . $e->getMessage());
return null;
}
}
}
The easiest solution may be pdoTools which allows you to establish caching at run time.
http://www.shawnwilkerson.com/modx/tags/pdotools/
Also, I do not believe resource placeholders are cached which is the best place to have your items cahced:
case '+':
$tagName= substr($tagName, 1 + $tokenOffset);
$element= new modPlaceholderTag($this->modx);
$element->set('name', $tagName);
$element->setTag($outerTag);
$elementOutput= $element->process($tagPropString);
break;
From lines 455-461 of https://github.com/modxcms/revolution/blob/master/core/model/modx/modparser.class.php#L455
You may notice the other tag types have:
$element->setCacheable($cacheable);
I cover the parser in Appendix D of my book. I found some issues in it in 2011 which Jason corrected.
Move toPlaceholders() to the end of your script and instead cache the array of placeholder data:
// attempt to retrieve placeholders from cache
$placeholders = $modx->cacheManager->get('Navigator');
// if not in cache, run your snippet logic and generate the data
if (empty($placeholders))) {
$placeholders = array(
'myplaceholder' => 'placeholder data'
);
$modx->cacheManager->set('Navigator', $placeholders, $cl);
}
// set placeholders for use by MODX
$modx->toPlaceholders($placeholders);
I have asked a couple of questions on here in a rush, and I am getting nowhere fast, I keep changing things and just ending up with a different problem, and no closer to having a clue what is causing it. I am a PHP MYSQL man, and I am having to work with Access via the COM class.
Basically the client has multiple servers, each with an access database, and each with a CMS, the tables should contain the same data and have slipped out of Sync. It is my job to come up with a way of resyncing them.
I have came to bringing the data out into an Array, serializing it and saving it to a file on the main server (the one all should sync to) and then on the other servers, downloading the file, unserializing it and item by item, checking if it is in the DB, and if not inserting it. The insert is failing. I have tried building an sql query for each item and doing $this->conn->Execute(); and that is failing row by row on silly things, so I am now trying this:
function syncCMS()
{
$this->output['msg'] .= "<p><b>The following properties were added to the database on ." . $this->hsite . "</b></p>";
$this->get_field_names();
$this->make_connection(); //assigns connection to $this->conn
$rs = new COM('ADODB.Recordset');
$rs->CursorType = 2;
$rs->CursorLocation = 1;
$rs->LockType = 4;
$rs->Open($this->table_name,$this->conn);
foreach ($this->awayPropertyDetails as $key => $property)
{
$this->check_for_property($property['pname']);
if (!$this->property_exists || $this->mode == "fullSync")
{
unset($values);
$bfields = array("pshow","rent","best", "oda1", "oda2", "oda3", "oda4", "oda5", "oda6", "odap", "topool","tomountain","tofitness","tosauna"); //stores the yes/no values
$q = "INSERT INTO " . $this->table_name . " (" . $this->dbfields . ") VALUES (";
foreach ($property as $k => $value)
{
if ($k == "Kimlik") {
$value = null;
}
if ($k == "tarih")
{
$value = date("d/m/Y");
$value = "'" . $value . "'";
}
if (in_array($k,$bfields))
{
if ($value == "")
{
$value = 'FALSE';
}
else
{
$value = 'TRUE';
}
}
$rs->fields->$k = $value;
$this->output['msg'] .= $property['pname'] . " added";
}
$rs->BatchUpdate();
$rs->Close();
$this->conn->Close();
//$this->download_images($property['OBJECT_NR'],$k);
//$this->output['msg'] .= "<p>Images added</p>";
}
}
$message .= "</ul>";
$this->output['msg'] .= $message;
$this->sendOutput();
//print_r($property);*/
}
And getting this:
Fatal error: Uncaught exception 'com_exception' with message 'Unable to lookup `Kimlik': Unknown name. ' in D:\inetpub...
Kimlik is the name of the first field, the Auto Number field, I took it out and the problem shifted to the second field.
I got there with:
$sql = "SELECT * FROM " . $this->table_name;
if (!$this->property_exists || $this->mode == "fullSync")
{
$this->make_connection();
$rs->Open($sql,$this->conn);
$rs->addnew();
foreach($rs->Fields as $field)
{
if ($field->name != "Kimlik")
{
$rs->Fields[$field->name] = $property[$field->name];
}
}
$rs->Update();
$rs->Close();
$this->conn->Close();
$msg = $this->download_images($property['OBJECT_NR'],$k);
$this->output['msg'] .= $property['pname'] . " added<br/>" . $msg . "<br/><br/>";
}