Drupal 8/9 module no refresh form data after post - forms

I have a D8 module that works well. But I have a problem.
Sensors data are stored in a database. In the D8 website, the cache is disabled, but the selected data are not updated. If I use the "drush cr" then ok, but the next selected data are not updated.
What may be the problem?
The code shortly:
#
# form for SQL SELECT
#
function buildForm()
//...
$form['date_from'] = [ '#type' => 'datetime', ... ];
$form['date_to'] = ...
$form['#cache'] = ['max-age' => 0];
/// ...
So, I select a date_from and date_to and post it then it is ok. I go back and change the date_from, date_to and post it then it still stay the previous date!
After "drush cr" it works once again... and so on
It has no effect (settings.php): $settings['rebuild_access'] = TRUE;
Thanks,
G.

I found it: How to clear cache programmatically in Drupal 8?
Both work. :)
in function buildForm():
drupal_flush_all_caches();
// or
\Drupal::service("router.builder")->rebuild();

Related

Odoo 12: How to disable past dates with datepicker?

How can I use datepicker in a Date field?
I try to disable past dates like that:
<field class="delivery_date" name="delivery_date" options="{'datepicker':{'minDate': 0}}"/>
But past dates are shown nevertheless.
It seems as if the options-tag is not parsed at all. I used the debugger to get an overview what happens in addons/web/static/src/js/fields/basic_fields.js (where datepicker is initialized) but there are no options declared.
Thanks in advance!
UPDATE:
That's my field definition
delivery_date = fields.Date(string='Delivery Date', help="Date on which sales order is delivered.", default=_get_default_delivery_date)
The default-method sets the date to the day after tomorrow.
My view declaration is above. That's all I have.
I expected that the datepicker is invoked as soon as I use it in "options"-attribute.
When I enter my website the datepicker is shown, when I click on that date-field, but the past dates are not disabled..
I tried multiple modules, but nothing works for me in js Odoo 14
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(AccountInvoice, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
if view_type == 'form':
doc = etree.XML(res['arch'])
for node in doc.xpath("//field[#name='date_invoice']"):
node.set('options', "{'datepicker': {'minDate': '%sT23:59:59'}}" % fields.Date.today().strftime(DEFAULT_SERVER_DATE_FORMAT))
res['arch'] = etree.tostring(doc)
return res
Try this, This may help you

MailChimp Campaign Content Update

MailChimp campaign content docs - https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/content
I'm trying to replace some placeholders in a campaign content with actual values via the API. At first, I thought there might be some syntax errors or internal logic errors like non-unique mc:edits into a mc:repeatable that would get the HTML refused/declined by MailChimp, hence the update not taking place, however, that was not the case.
Tried replacing html with a simple <p>test</p> and it was still not working.
Here are a couple of local logs, I'll use xyz as my campaign id:
2018-02-26 16:26:13 [::1][9804][-][warning][application] calling GET /campaigns/xyz/content []
2018-02-26 16:26:13 [::1][9804][-][warning][application] got both plain_text and html versions of content
2018-02-26 16:26:13 [::1][9804][-][warning][application] calling PUT /campaigns/xyz/content {"html":"<p>test</p>"}
2018-02-26 16:26:14 [::1][9804][-][warning][application] got response [
'plain_text' => 'test' + other MailChimp stuff such as footer, that were appended automatically by MailChimp,
'html' => '<p>test</p>'
]
// calling GET immediately after PUT in order to see if any update occurred
2018-02-26 16:26:14 [::1][9804][-][warning][application] calling GET /campaigns/xyz/content []
2018-02-26 16:26:14 [::1][9804][-][warning][application] got updated html (my "test" paragraph + auto footer from MailChimp) and proper plain_text
Everything looks fine according to these, that means both versions updated as they were supposed to. However, on the next API/MailChimp dashboard request, it displays the old HTML content, preserving the update I've just made in the plain text version only.
No errors, nothing to look into. It could be any internal MailChimp behaviour.
PS: I know about Setting Mailchimp campaign content html not working or MailChimp API v3 campaign content template sections, but none of the answers provided to those are helpful.
PS2: I know I should contact MailChimp, but according to
Our MailChimp Support Team isn't trained at in-depth API troubleshooting. If you need a developer to help you configure something using the API, check out our great Experts Directory, which lists third-party MailChimp experts who can be hired to help out.
they don't provide support for API troubleshooting.
MailChimp doesn't allow updating the campaign's HTML content because the campaign type is based on a template.
In order to update the HTML content, the campaign has to be set to custom HTML instead of a template. You can check the type by sending a GET API request to /campaigns or /campaigns/{campaign_id} and finding the content_type attribute in the response (documentation).
Alternatively, in the dashboard, the type can be determined by editing the design of the email. Anything under 'Code your own' is HTML and templates are of course templates.
I'm not entirely sure why the first response to a PUT request on a template campaign shows the updated content, but changing the content type should let you update as you want to.
Hope this helps!
If anyone's still looking for an answer to this.
I managed to solve the issue several weeks ago without creating the campaign via API, but actually updating it.
I used placeholders like [product_card id=123], 3 cards per block/row, all repeatable, which are wrapped in a class that I named product-card. In the MailChimp dashboard, you may still see the placeholders, but on preview and any form of preview like thumbnail, it will display correctly.
On the server, I crawl through the campaign's content, "detect" section names based on how they seemed to me in MailChimp and update each section with the content that I want.
PHP snippet below, some Yii2 stuff, but mostly plain PHP. I use $preview to display a preview of how the template would look, I know it's not visible in the function.
/**
* #param $id - Id of the campaign
* #param $s - Whether to save or just preview
*
* #return bool
*/
function changeContent($id, $s = false)
{
$mcCampaign = new McCampaign();
$mcCampaign::$itemId = $id;
$content = $this->api->get("/campaigns/{$id}/content");
if (!isset($content['html'])) return false;
$template = $content['html'];
$forgedDom = new \DOMDocument();
$forgedDom->loadHTML($template);
$mcSections = [];
$finder = new \DOMXPath($forgedDom);
$nodes = $finder->query('//td[contains(#class, "product-card")]');
// disabling this shit in order to avoid strict errors
libxml_use_internal_errors(true);
$mcEditId = 1;
$mcEditIndex = 0;
foreach ($nodes as $key => $node) {
/** #var \DOMElement $node */
$textContent = $node->textContent;
if (!preg_match("#\[product_card id=\d+\]#", $textContent)) continue;
$productId = filter_var($textContent, FILTER_SANITIZE_NUMBER_INT);
$node->textContent = false;
$product = Product::findOne($productId);
$productDetails = $product ? $this->renderPartial('/partials/_mc-product', [
'product' => $product
]) : 'Product not found.';
if ($key != 0) {
if ($key % 3 == 0) {
$mcEditId = 1;
$mcEditIndex++;
} else {
$mcEditId++;
}
}
$mcSections["repeat_1:{$mcEditIndex}:product_card_{$mcEditId}"] = $productDetails;
$fragment = $forgedDom->createDocumentFragment();
$fragment->appendXML($productDetails);
$node->appendChild($fragment);
}
libxml_use_internal_errors(false);
$preview = $forgedDom->saveHTML();
// just in case
/* $preview = str_replace(["\n", "\t", "\r"], "", $preview); */
if ($s) {
if (!empty($mcSections)) {
$res = $this->api->put("/campaigns/{$id}/content", [
'template' => [
'id' => *template_id_here*,
'sections' => $mcSections
],
]);
// forcing Mc to rebuild cache
$this->api->get("/campaigns/{$id}/content");
Yii::$app->session->setFlash('success', 'Done.');
return $this->redirect(['campaign/index']);
} else {
Yii::$app->session->setFlash('error', 'Something went wrong.');
}
}
}

SugarCRM Adding Additional Details Info icon in Detail View

in SugarCRM some modules like "Calls" has an "i" (Additional Details) icon in List view which shows some additional details about that record.
I want to display same kind for other modules like customer visits with some custom details of the records.
Any hints or guidance will be helpful.
1) Create a file in your metadata folder {MODULENAME}/metadata/additionalDetails.php. You have to find correct place of your module.
custom/modules/MODULENAME/metadata/
custom/modulebuilder/packages/PACKAGENAME/modules/MODULENAME/metadata/
etc...
2) and create a function something like this. replace {MODULENAME} and {MODULE_BEAN_NAME} with actual module name in all places.
function additionalDetails{MODULE_BEAN_NAME}($fields) {
static $mod_strings;
if(empty($mod_strings)) {
global $current_language;
$mod_strings = return_module_language($current_language, '{MODULENAME}');
}
$overlib_string = '';
if(!empty($fields['NAME']))
$overlib_string .= '<b>'. $mod_strings['LBL_NAME'] . '</b> ' . $fields['NAME'] . ' <br>';
//Add whatever info you want to show up to $overlib_string
$editLink = "index.php?action=EditView&module={MODULENAME}&record={$fields['ID']}";
$viewLink = "index.php?action=DetailView&module={MODULENAME}&record={$fields['ID']}";
return array(
'fieldToAddTo' => 'NAME',
'string' => $overlib_string,
'editLink' => $editLink,
'viewLink' => $viewLink
);
}
you have to create $overlib_string with your data (in html). If you need edit and view links on your modal box you have to return them as well. $fields is an associative array that contains db record.
3) The i icon should appear on the module list view.

How to populate zend form field using session?

I am using sessions to populate a multi select box with options in my Zend application.
The user selects one or more options and fills in other fields on the form and then submits. If the user didn't select all of the options in the multi select then the form is displayed again but the multi select only has the options that the user did not select the last time. This process goes on until there are no more options from the multi select left to process.
Here is the code I use to get rid of the options that have already been processed so that they are not used to populate the multi select box:
if($form_successful){
// TODO remove $post['keyword_names'] (i.e. already processed) from $keyword_names (that come from $_SESSION)
$keyword_names = array_diff($keyword_names, $post['keyword_names']);
print_r($keyword_names);
if(is_array($keyword_names) && !empty($keyword_names)){
// save updated $keyword_names into $_SESSION['workflow1']
$session = new Zend_Session_Namespace('workflow1');
$session->keyword_names = $keyword_names;
// set flag to false so that we display form again
$form_successful = false;
}else{ // all keywords have been assigned
// go to next step
$this->_redirect('/workflow-1/step-'.($step+1).'/');
}
}
print_r($keyword_names); displays the correct options, however when the form is loaded when the user submits, the multi select displays the options that were there from the begining ie the options the user has just selected and submitted are not being taken out of the multi select, it is only when the user submits the form again then the multi select box updates.
Appreciate the help.
Solved the issue by making use of URL parameters. Here is the code (might differ a lot from what I posted first because some big changes were made):
// after successful form submission
if($form_successful){
// remove $post['keyword_names'] (i.e. already processed) from $keyword_names (that come from $_SESSION)
$keyword_names = array_diff($keyword_names, $post['keyword_names']);
// save remaining $keyword_names into $_SESSION['workflow1']
$session = new Zend_Session_Namespace('workflow1');
$session->keyword_names = $keyword_names;
if(is_array($keyword_names) && !empty($keyword_names)){
// redirect to the same step again - to ensure that the form will reflect (in select lists) newly created AdGroup and/or Campaign
// GET parameteres ($params_array) provide a way to remember user's choice
$params_array = array();
if(!empty($post['match_type_id'])){
$params_array['match_type_id'] = $post['match_type_id'];
}
if(!empty($post['with_permutations'])){
$params_array['with_permutations'] = $post['with_permutations'];
}
if(!empty($ad_group_id)){
$params_array['ad_group_id'] = $ad_group_id;
}
$this_step_url = UrlUtils::assemble('', $this->getRequest()->getActionName(), $this->getRequest()->getControllerName(), $this->getRequest()->getModuleName(), $params_array);
$this->_redirect($this_step_url);
}else{ // all keywords have been assigned
// go to next step
$this->_redirect('/workflow-1/step-'.($step+1).'/');
}
}
So you don't have any code about Zend_Form object here. How do you populate the form element? If you post your class code which extends Zend_Form (or any other code dials with your form) then I may help. But in any case you can populate your multiselectbox with setMultiOptions() method or addMultiOption() for each item in multiselectbox.

Zend_Db - Building a Delete Query

I'm trying to recreate the following in Zend Framework and am not sure how to do it:
DELETE FROM mytablename WHERE date( `time_cre` ) < curdate( ) - INTERVAL 4 DAY
I was thinking something like:
$table = $this->getTable();
$db = Zend_Registry::get('dbAdapter');
$db->delete($table, array(
'date(`time_cre`) < curdate() - interval 4'
));
Does that seem correct?
What is the best way to handle something like this?
EDIT: Ack! Sorry, I was adapting this from a SELECT I was using to test and didn't change the syntax properly when I pasted it in. I've edited the example to fix it.
Figured it out...
public function pruneOld($days) {
$table = $this->getTable();
$db = Zend_Registry::get('dbAdapter');
$where = $db->quoteInto("DATE(`time_cre`) < CURDATE() - INTERVAL ? DAY", $days);
return $table->delete($where);
}
$table gets an reference of the table I want to edit...
$db grabs an instance of the database adapter so I can use quoteInto()...
$where builds the main part of the query accepting $days to make things a bit more flexible.
Create an action to call this method... something like:
public function pruneoldAction() {
// Disable the view/layout stuff as I don't need it for this action
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
// Get the data model with a convenience method
$data = $this->_getDataModel();
// Prune the old entries, passing in the number of days I want to be older than
$data->pruneOld(2);
}
And now hitting: http://myhost/thiscontroller/pruneold/ will delete the entries. Of course, anyone hitting that url will delete the entries but I've taken steps not included in my example to deal with this. Hope this helps someone.
I usually do this to delete a row
$table = new yourDB;
$row = $table->fetchRow($table->select()->where(some where params));
$row->delete();
try:
$db->delete($table, array(
'date(time_cre) < ?' => new Zend_Db_Expr('curdate() - interval 4')
));