Cannot load default values in input fields using FormHelper in cakephp 3.x - cakephp-3.0

I'm facing a very wierd situation concerning a quite simple task.
I'm trying to create a very simple edit form in my application using
cakephp 3.x version.
In my ContentsController::edit($contentID) method I'm loading the content entity to be edited like this
$content = $this->Contents->findById($contentID)->first()
and then I'm simply creating the respective view variable using set() method like that:
$this->set('content', $content);
In the view file - named edit.ctp - all I'm doing is to simply create
a new form using FormHelper using the following piece of code:
<h2><?= __('Edit content: ') . $content->title; ?></h2>
<?php
echo $this->Form->create($content);
echo $this->Form->input('title', ['type' => 'text']);
echo $this->Form->input('alias', ['type' => 'text']);
echo $this->Form->input('body', ['type' => 'textarea']);
echo $this->Form->submit();
?>
The following code creates the form correctly but it does not load the default values in each input element from the $content entity. After doing some digging into the source code of the FormHelper I found out that when the FormHelper::create() method is called, it correctly loads the EntityContext interface using the $content entity. But for some reason, which I cannot explain, in each of the FormHelper::input() calls, internally the context interface is switching to NullContext so no data is loaded into the field.
Does anyone have an idea what am I doing wrong with that piece of code?

After some more digging I found the real cause of the issue.
FormHelper works correctly and so does my query.
The issue has to do with the view file and how it is rendered.
The whole picture is this.
My view (edit.ctp) was an extension of a common skeleton I created, namely edit_frm.ctp. So in my view file I was extending by calling $this->extend('/Common/edit_frm');
The structure of the edit_frm.ctp consists of three blocks, as shown below (I removed the html markup)
<?php
// Common/edit_frm.ctp
$this->fetch('formStart');
$this->fetch('formPrimaryOptions');
$this->fetch('formSecondaryOptions');
$this->fetch('formEnd');
?>
Now in my view file (edit.ctp) I was creating the blocks like that:
<?php
// Contents/edit.ctp
$this->extend('Common/edit_frm');
// The "formStart" block contains the opening of the form
$this->start('formStart');
echo $this->Form->create($content);
$this->end('formStart');
// The "formEnd" block contains the submit button and the form closing tag
$this->start('formEnd');
echo $this->Form->submit();
echo $this->Form->end();
$this->end('formEnd');
// "formPrimaryOptions" contains the main input fields
$this->start('formPrimaryOptions');
echo $this->Form->input('title', ['type' => 'text']);
echo $this->Form->input('alias', ['type' => 'text']);
echo $this->Form->input('body', ['type' => 'textarea']);
$this->end('formPrimaryOptions');
?>
As you see in my view file, I was building the formEnd block before the construction of the formPrimaryOptions block. Though in my skeleton the blocks are fetched in a different order.
Apparently in CakePHP when you extend a view combined with blocks of content in the actual view file you must create your blocks in the same order as they are fetched, otherwise you end up in weird situations like the one I was facing.
In any case, I had a very good lesson today!!

Maybe you can do this instead of findById:
$content = $this->Contents->find('all')->where(['id' => $contentID])->first();

Related

CakePHP 3.8. Security Component - FormHelper end() method

Exact Problem and the Solution
Upon activating the CakePHP (3) Security Component, when loading a form, you generate three hidden fields in the form. These are '_Token[fields]', '_Token[unlocked]' and '_Token[debug]'. What exactly happens is the Form->end() method calls the secure() method (see FormHelper) when the request data contains a ['Token'] parameter.
The forms that were not working for me were all forms rendered as an Element. For these forms, the '$this->request->params' did not contain the parameter normally generated by the Security Component.
Solution was in manually adding the parameter to the request data..
$this->request->params['_Token'] = ['unlockedFields' => []];
This than runs through the secure() method of FormHelper, as it should, and token parameters are correctly added.
Original Question
I have an issue using the SecurityComponent of CakePHP 3.8.
Everything was working fine, until I loaded Component in my AppController.
If (!$this->request->is('ajax')) {
$this->loadComponent('Security');
}
My forms were working fine, but upon activating the component I get an error message. Apparently using the Security Component checks for an additional token apart from the csrf-token.
'_Token' was not found in request data.
I found a solution in customizing the Form->end() method.
"The end() method closes and completes a form. Often, end() will only
output a closing form tag, but using end() is a good practice as it
enables FormHelper to insert the hidden form elements that
Cake\Controller\Component\SecurityComponent requires."
I customized my end method as suggested in documentation:
echo $this->Form->end(['data-type' => 'hidden']);
But my output in HTML differs from the output in the documentation..
Documentation Output:
<div style="display:none;">
<input type="hidden" name="_Token[fields]" data-type="hidden"
value="2981c38990f3f6ba935e6561dc77277966fabd6d%3AAddresses.id">
<input type="hidden" name="_Token[unlocked]" data-type="hidden"
value="address%7Cfirst_name">
</div>
Example of a non-working form..
echo $this->Form->create($athlete, ['url' => ['controller' => 'Athletesux', 'action' => $action]]);
echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => $userid]);
echo $this->Form->control('first_name');
echo $this->Form->control('last_name');
echo $this->Form->control('threek_time', ['value' => $athlete['3K_time']]);
echo $this->Form->control('fivek_time', ['value' => $athlete['5K_time']]);
echo $this->Form->control('tenk_time', ['value' => $athlete['10K_time']]);
echo $this->Form->select('country', $countryoptions);
echo $this->Form->select('gender', $gender);
echo $this->Form->button('Add Athlete');
echo $this->Form->end();
My output contains only one hidden field, for '_csrfToken'...
Can anyone explain what I can do about this? I don't find much information on this..
Thanks!

How to retrive Custom Post Type Meta Fields in Custom WP_Query

Can some one let me know How I can render the Custom Post Type Meta Fields (Meta-boxes).
I have a Custom Post Type Called "News" and I successfully added a metabox to my Custom Post Type called "News Info" which is suppose to store : A TextField = News Resource A Select option = News Type A check box
I can retrieve the Custom post Type "News"content using a custom Loop as:
<?php
$args = array( 'post_type' => 'news');
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
the_title();
echo '<div class="content">';
the_content();
echo '</div>';
endwhile;
?>
But I have no idea how to get the associated meta fields to "news" posts? trust me I Google this a lot but couldn't find any solution all of them just tried to render the Metabox on the admin page but no sample for presenting on the page!
Can you please let me know how I can get access and render the data on the page using the wp-query loop?
Thanks
To build upon SidGBF's answer, you can use get_post_meta(get_the_ID(),'YOUR_FIELD_NAME',true);
That is a little verbose if you're going to use it again and again, so it might be helpful to add this to your functions.php file:
function get_custom_field($field_name){
return get_post_meta(get_the_ID(),$field_name,true);
}
Then you can just use get_custom_field('YOUR_FIELD_NAME').
If you'd like to print the value of the field, use echo get_custom_field('YOUR_FIELD_NAME')
Your solution may be found in http://codex.wordpress.org/Function_Reference/get_post_meta . To get the post's ID you may use get_the_ID().

Exporting MySQL data to an RTF template creating multiple pages

The data pulled from the database inserts into an RTF template without a problem as long as I only have 1 row. If I put my header("Content-type: text/rtf") inside the loop, however, I receive a headers already sent error. When removing the headers from the code, the raw data prints properly in the browser window.
How do I combine data from multiple records in the database to create multiple documents (or 1 document with page breaks)?
Code here:
$document='../docs/letter.rtf';
$qry="Select * from table";
$result=mysql_query($qry);
$num_row=mysql_num_rows($result);
while($row=mysql_fetch_assoc($result)){
$account_id=$row['pk_account];
$name=$row['first_name'];
$file_doc='01-'.$pk_account.'.rtf';
....
$body=file_get_contents($document);
$body=str_replace("NAME", $name, $body);
....
for($i=0; $i<$num_rows; $i++){
}
header("Content-type: text/rtf");
header("Content-Disposition:attachment; filename={$file_doc}");
echo $body;
}
You need to concatenate your $body. So instead of this:
$body=file_get_contents($document);
$body=str_replace("NAME", $name, $body);
try this:
$body.=str_replace("NAME", $name, file_get_contents($document));
Then place this outside your while loop:
header("Content-type: text/rtf");
header("Content-Disposition:attachment; filename={$file_doc}");
echo $body;

Generate HTML web form from XML configuration file with Perl and vice versa

I am in need of assistance with the following problem. There is an application that I co-wrote and currently manage that is written in a combination C and Haskell. The application can be customized and configured via a single XML file. It is a back-end application with no user interface. We have been asked to provide a graphical interface to this application via a web interface. Each configuration option is a form field in the html form like this
configuration1 string1
configuration2 string2
etc
etc
The graphical front end must be a web form that converts the data the user has entered to an XML file that contains the application settings. When the user saves the form, the changes are written to the XML file. When the user opens the form, the configuration from the XML file is displayed in the HTML form fields.
Our team deals with purely back-end stuff and we know nothing of GUIs and the like. The restriction we have is that the front end must be written in Perl and use the LibXML module to conform with company standards. Our team is purely C and Haskell and this is the first request we have ever received for something like that. I would appreciate any help you can provide. If you can include code examples as elaborate as possible it would be a significant help. We know very little Perl but with a clear enough example we can do it. The team that would normally handle this type of stuff is being restructured and we can't wait as we need to get this interface up as quickly as possible.
Thank you.
Don't do this yourself. You don't know Perl or web-apps and the restrictions you mention regarding libxml are probably only one of several. Every tiny configuration and typing mistake will take you hours or days to figure out. You'll end up miserable and stressed, and so will the users.
Someone from your web team could produce a simple form with supporting tests and documentation in a day. You can then extend and bug-fix secure in the knowledge you start from a working app.
If you can't get someone in-house, you cold hire a coder, but do everything you can to get it done in-house first. Don't do this yourself.
To the OP: you did not describe the configuration format properly, an XML fragment would have helped us. As it is you will probably have to modify the solution below to match your format.
I assumed a the following format:
<conf>
<option><name>configuration1</name><value>string1 modified</value></option>
<option><name>configuration2</name><value>string2 re-modded</value></option>
<option><name>configuration3</name><value>string3</value></option>
</conf>
Code that would process this format would be:
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw( -nosticky -utf8 :standard form );
use XML::LibXML;
my $CONF="/web/data/conf.xml"; # or wherever your XML is located
# dispatch table, action => code to process it
my $dispatch= { display => \&display_conf,
edit => \&display_edit_form,
save => \&save_edits,
};
# action is "what to do"
my $action= param( 'action') || 'display';
$dispatch->{$action}->() || exit_error( "wrong action");
exit;
# load the XML and build a table to display it
sub display_conf
{ my $conf= XML::LibXML->load_xml( location => $CONF);
my $content;
foreach my $option ($conf->findnodes( '/conf/option'))
{ $content .= Tr( td( $option->findvalue( './name')),
td( $option->findvalue( './value'))
);
}
$content= table( $content);
# add a link to the edit form
$content .= p( a({ href => url() . '?action=edit' }, 'edit'));
output( $content);
}
# load the XML and build a form that will let you edit it
sub display_edit_form
{ my $conf= XML::LibXML->load_xml( location => $CONF);
my $content;
foreach my $option ($conf->findnodes( '/conf/option'))
{ $content .= Tr( td( $option->findvalue( './name')),
td( input( { type => "text", size => 40,
name => $option->findvalue( 'name'),
value => $option->findvalue( './value')}
)
)
);
}
$content= table( $content);
$content= form( { action => url() },
hidden( { name => 'action', value => 'save', override => 1 }),
$content,
submit( 'Save'),
);
output( $content);
}
# load the XML, go through all options, update the value from the form,
# save the XML, display it value, from the form
sub save_edits
{ my $conf= XML::LibXML->load_xml( location => $CONF);
foreach my $option ($conf->findnodes( '/conf/option'))
{ my $new_value= param( $option->findvalue( './name'));
my( $value_node)= $option->findnodes( './value');
$value_node->removeChildNodes();
$value_node->appendText( $new_value);
}
$conf->toFile( $CONF);
display_conf();
}
# placeholder,
sub exit_error
{ my $message= shift;
print header(), p($message);
}
# output subs, load the template, inject the content and output (with header)
sub output
{ my $content= shift;
print header(), fill_in_string( template(), content => $content );
}
sub fill_in_string
{ my( $template, %param)= #_;
$template=~ s{<<(\w+)>>}{$param{$1}}g;
return $template;
}
sub template
{ return join '', <DATA>; }
# template, very simple
__DATA__
<html>
<head>
<title>Configuration Editor</title>
</head>
<body>
<h1>Configuration Editor</h1>
<h2>Configuration</h2>
<<content>>
</h2>
</body>
</html>
Deployement: put the code somewhere it can be run as CGI, and make sure conf.xml can be read and written by the web server. It's probably better to put it outside of the web tree.
This is in a way prehistorical Perl. CGI is widely considered archaic and there are more modern and fancy options available in Perl. If your configuration is more complex than a key/value list, if you want to have custom help for each field or if you need to use a more complex template to conform to your company's look'n feel, then web Frameworks like Dancer or Mojolicious would be better suited than the simple solution above.
OTOH it works, and I this is still how I write a lot of small tools, that have a few internal users and don't need much in terms of UI.
To the people who suggested that this is too complex to do for people not familiar with Perl, way to go guys! This is not rocket science. It's the kind of code that gets people to start with Perl, why wouldn't we help with writing it? This is in fact a perfect illustration of The Reluctant Perl Programmer.

How to use node_load()?

Hi m a bit confused that how to retrieve node title by using this code
node_load($nid);
$title=$nid->title;
i have done this coding in block and i wants to retrieve from node id for displaying image.that images are normally uploaded at the site by using filezilla and it has same name as the node title.i have tried many forms of node_load(),but i m failure.so please tell me right option for this.
Thanks all.-Pranoti
Here is the reference for node_load
http://api.drupal.org/api/function/node_load
It returns an object which is the node.
$node = node_load($nid); // $nid contains the node id
$title = $node->title;
Please get a good book on Drupal Module development to learn the fundamentals.
Your question is a little confusing. Could you clean it up and explain better what you are trying to accomplish? In all events:
Node load takes either an numeric argument or an array of parameters to query, and returns a single node object. (As already mentioned, here's the API documentation: http://api.drupal.org/api/function/node_load).
Load with a numeric node id:
$nid = 55;
$node = node_load($nid);
$title = $node->title;
Load by querying on title:
$title = 'How to serve man';
$node = node_load(array('title' => $title));
$body = $node->body;
you can also load multiple node load efficiently by using the following code
<?php
$type = "product_type";
$nodes = node_load_multiple(array(), array('type' => $type));
foreach($nodes as $products):
?>
<?php print $products->nid; ?>
<?php print $products->title; ?>
<?php endforeach; ?>
also you can query any thing in the node load for example we have used type in query but we can also use title as mentioned in the above post by
"David Eads"
NODE LOAD BEST PRACTICES
If you are loading a lot of nodes with node_load(), make sure to use the $reset parameter so that every node isn't kept in the function's static cache (and increasing memory usage):
$nid = 55;
$node = node_load($nid, NULL, TRUE);