Please see my question in the template section below:
Form (showSuccess):
<?php echo form_tag('job/salarySubmit') ?>
<input type="hidden" name="job_id" value="<?php echo $job->getId(); ?>">
<input type="submit" value="View Salary">
</form>
Action:
public function executeSalarySubmit(sfWebRequest $request)
{
$this->forward404Unless($request->isMethod('post'));
$param = array('job_id' => $request->getParameter('job_id'), );
$this->redirect('job/salary?'.http_build_query($param));
}
public function executeSalary(sfWebRequest $request)
{
$this->object_id = $request->getParameter('job_id');
$this->salary = $this->getRoute()->getObject();
}
Template (salarySuccess.php):
<?php echo $object_id; ?> // returns correct job_id: 6100, but when I try to access the object's other getters (example: echo $object_id->getName(), I get "Fatal error: Call to a member function getName() on a non-object"
<?php echo $salary->getName(); ?> //works, but it gets the wrong name. It's returning the first job in my DB with an ID of "1" which is not correct... it needs to be 6100
Routing:
job_salary:
url: /job/salary/:job_id
param: { module: job, action: salary }
class: sfDoctrineRoute
options: { model: Job, type: object }
requirements:
id: \d+
sf_method: [GET]
use var_dump() on your template variables.
You'll see that $object_id is not an object (it is a non-object, like the error message says). $object_id is most likely a string or an integer and its value must be "6100".
$salary is not the object you're looking for, because sfDoctrineRoute looks for a parameter called id, and you named it job_id in your routing.yml (which is strange, because you name it id in this route's requirements.
Related
Am creating a custom page using Opencart. Here am using foreach for displaying customer details.
But customer details not showing.
Following codes:
.tpl
<?php foreach($dealerData as $invoice){ ?>
<label> <b>Dealer Name:</b> <?php echo $invoice['name']; ?></label><br>
<label><b>Dealer TIN Number:</b> <?php echo $invoice['tin_number'];?></label><br>
<?php } ?>
Controller
$query13 = $this->db->query("select concat(firstname, ' ', lastname) as name, tin_number from ".DB_PREFIX."customer where customer_id='".$customer_id."'");
$dataDelar = $query13->rows;
foreach ($dataDelar as $dealer) {
$data['dealerData'][] = array(
'name' => $dealer['name'],
'tin_number' => $dealer['tin_number']
);
}
Why are you putting queries in your controller? You have models van database related functions. An foreach on the variable $invoiceData1 should work, you can see in the print_r that there is 1 array in the array. Did you put the print_r in your controller? So yes, look bellow that, maybe you are overriding $invoiceData1.
EDIT
You are not creating an empty array to put your values in:
$query13 = $this->db->query("select concat(firstname, ' ', lastname) as name, tin_number from ".DB_PREFIX."customer where customer_id='".$customer_id."'");
$dataDelar = $query13->rows;
$data['dealerData'] = [];
foreach ($dataDelar as $dealer) {
$data['dealerData'][] = array(
'name' => $dealer['name'],
'tin_number' => $dealer['tin_number']
);
}
In my app, people can comment on pets' images. I am using the react example from here, although I changed quite a few stuff.
Right now, it is successful in displaying the existing comments. Now, when a user is creating a comment, I have to pass the comment body, user id, and pet id. I was trying to do the following:
var CommentForm = React.createClass({
handleSubmit:function()
{
var user=this.refs.user_id.getDOMNode().value.trim();
var comment=this.refs.body.getDOMNode().value.trim();
var pet_id=this.refs.pet_id.getDOMNode().value.trim();
this.props.onCommentSubmit({comment:comment, user:user, pet:pet_id});
if(!user||!comment||!pet_id)
return false;
var formData = $( this.refs.form.getDOMNode() ).serialize();
this.props.onCommentSubmit( formData, this.props.form.action );
// reset form
this.refs.body.getDOMNode().value = "";
},
render: function () {
return (
<form ref="form" className="comment-form" action={ this.props.form.action } accept-charset="UTF-8" method="post" onSubmit={ this.handleSubmit }>
<p><input type="hidden" name={ this.props.form.csrf_param } value={ this.props.form.csrf_token } /></p>
<p><input type="hidden" ref="user" value={ this.props.user_id } /></p>
<p><input type="hidden" ref="pet_id" value={ this.props.pet_id } /></p>
<p><textarea ref="body" name="comment[text]" placeholder="Say something..." /></p>
<p><button type="submit">Post comment</button></p>
</form>
)
}
});
And apparently, it doesn't look like it is passing the pet_id correctly, because I am getting the error message
ActiveRecord::RecordNotFound in CommentsController#create
Couldn't find Pet with 'id'=
My CommentsController looks like
def create
#pet = Pet.find(params[:pet_id])
#comment = #pet.comments.new(comment_params)
#comment.user = current_user
For further clarification, I have three models, Pets, Users and Comments, and when users make comments, the comment gets the user_id, and pet_id as its parameters.
edit:
My react component looks like
<%= react_component('CommentBox',
{:presenter => #presenter.to_json},
{:prerender => true}) %>
and my PetController looks like
def show
#comments = #pet.comments
#user = current_user
#presenter = {
:comments => #comments,
:user => current_user,
:pet_id => #pet,
:form => {
:action => comments_path,
:csrf_param => request_forgery_protection_token,
:csrf_token => form_authenticity_token
}
So there are a few issues I can see. Firstly your using ref where you should be name.
<input type="hidden" ref="pet_id" value={ this.props.pet_id } />
should be
<input type="hidden" name="pet_id" value={ this.props.pet_id } />
Your setting both an action and an onSubmit. Is there a reason to do this? Why not just read it from the props when you perform the ajax request? This is most likely causing your form to be submitted and the browser to load another page. The form submitting has nothing to do with what is on the server. The issue is in your client side code.
I would also consider putting your model values in to their own array. This is generally what rails expects back from the server. In your case it should be params[:pet][:id] not params[:pet_id]. Many of the rails active record methods such as update attributes can then be directly called giving you less verbose code.
#pet = Pet.find(params[:pet][:id])
#pet.update_attributes(prams[:pet])
#pet.save
I created a form to allow people to register, it worked fine but weeks passed and it is not working anymore.
I have my module Inscription with index function:
public function executeIndex(sfWebRequest $request)
{
$this->form = new InscriptionForm();
}
In indexSuccess.php, I have:
<?php include_partial('form', array('form' => $form)) ?>
My partial form is like:
<form action="<?php echo url_for('Inscription/'.($form->getObject()->isNew() ? 'create' : 'update').(!$form->getObject()->isNew() ? '?id='.$form->getObject()->getId() : '')) ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>>
... // All my input for the inscription Form
</form>
And the create function:
public function executeCreate(sfWebRequest $request)
{
$this->forward404Unless($request->isMethod(sfRequest::POST));
$this->form = new InscriptionForm();
$this->processForm($request, $this->form);
}
My form is displayed properly, but if I submit the form, the create function is not called anymore.
$form->getObject()->isNew()
return true.
The update case works, just the create does not. I have no errors, just in config -> request, I have:
parameterHolder:
action: index
module: Inscription
Seems like my form call the action index instead of create.
I'm searching for hours now and I can't get the reason why.
Edit:
I got this when I submit my form:
options:
path_info_key: PATH_INFO
path_info_array: SERVER
http_port: null
https_port: null
default_format: null
logging: '1'
relative_url_root: null
formats: { txt: text/plain, js: [application/javascript, application/x-javascript, text/javascript], css: text/css, json: [application/json, application/x-json], xml: [text/xml, application/xml, application/x-xml], rdf: application/rdf+xml, atom: application/atom+xml }
no_script_name: false
parameterHolder:
action: index
module: Inscription
sf_guard_user: { id: '', _csrf_token: 2a4bd03a7c7cb1cfd8a41653fddabcc3, username: '', email_address: admin, password: admin, password_confirmation: '', Informations: { sexe_id: '1', date_naissance: { month: '', day: '', year: '' }, id: '', token: '0', etat_id: '2' }, Avatar: { id: '', valide: '0' } }
attributeHolder:
sf_route: 'sfRoute Object()'
This is like create function is not called!
And in my logs I have:
# type message
1 sfPatternRouting Connect sfRoute "sf_guard_signin" (/guard/login)
2 sfPatternRouting Connect sfRoute "sf_guard_signout" (/guard/logout)
3 sfPatternRouting Match route "sf_guard_signin" (/:module) for /Inscription with parameters array ( 'module' => 'Inscription', 'action' => 'index',)
4 sfFilterChain Executing filter "sfRenderingFilter"
5 sfFilterChain Executing filter "sfExecutionFilter"
6 InscriptionActions Call "InscriptionActions->executeIndex()"
7 sfPHPView Set component "sf_twitter_bootstrap_permanent_slot" (/)
8 sfPHPView Render "sf_app_dir\modules/Inscription/templates/indexSuccess.php"
9 sfPartialView Render "sf_app_dir\modules/Inscription/templates/_form.php"
10 sfPHPView Decorate content with "sf_app_dir\templates/layout.php"
11 sfPHPView Render "sf_app_dir\templates/layout.php"
12 sfWebResponse Send status "HTTP/1.1 200 OK"
13 sfWebResponse Send header "Content-Type: text/html; charset=utf-8"
Normally, when I submit my form, it checks for a value from an InscriptionForm, but I can set every value that I want; there is no control anymore and the index function calls the index again.
I have a model that implements NestedSet behaviour:
Page:
actAs:
NestedSet:
hasManyRoots: true
rootColumnName: root_id
columns:
slug: string(255)
name: string(255)
Example fixtures:
Page:
NestedSet: true
Page_1:
slug: slug1
name: name1
Page_2:
slug: slug2
name: name2
children:
Page_3:
slug: page3
name: name3
I am looking for the easiest way to implement breadcrumb navigation (trail). For example, for Page_3 navigation will look like this:
name2 > <a href="page2/page3>name3</a>
Since I hate having any kind of logic in templates (and partials), here's my slightly improved version.
//module/templates/_breadcrumbElement.php
<?php foreach ($node as $child): ?>
<li>
<?php echo $child->getName() ?>
<?php if (count($child->get('__children')) > 0): ?>
<ul>
<?php include_partial('node', array('node' => $child->get('__children'), 'parent' => $child)) ?>
</ul>
<?php endif; ?>
</li>
<?php endforeach; ?>
So, all the logic for building a url is now in Page::getPath() method.
class Page extends BasePage
{
/**
* Full path to node from root
*
*/
protected $path = false;
public function __toString()
{
return $this->getSlug();
}
public function getPath($parent = null)
{
if (!$this->path)
{
$this->path = join('/', null !== $parent ? array($parent->getPath(), $this) : array($this));
}
return $this->path;
}
}
What I don't like it having to pass $parent to Page::getPath(). It just doesn't make any semantical sense.
Almost the same as in the other question, but you have to add a 'parentUrl' variable :
//module/templates/_breadcrumbElement.php
foreach ($node->get('__children') as $child) :
if ($child->isAncestorOf($pageNode)):
$currentNodeUrl = $parentUrl . $child->getSlug() . '/';
echo link_to($child->getName(), $currentNodeUrl) . ' > ' ;
include_partial('module/breadcrumbElement', array('node' => $child, 'pageNode' => $pageNode, 'parentUrl' => $currentNodeUrl));
endif;
endforeach;
Feed it the root of your tree as $node (hydrate it hierarchically), the node of the current page as $pageNode, and '' as $currentNodeUrl and add ' > ' and the link to the current page.
Why does this solution use recursion and not getAncestors()? Because your urls seem to imply recursion.
Another answer, more simple (and perhaps more efficient), with getAncestors() and recursion:
//module/templates/_breadcrumbElement.php
if ($node = array_pop($nodes)) // stop condition
{
$currentNodeUrl = $parentUrl . $node->getSlug() . '/';
echo link_to($node->getName(), $currentNodeUrl) . ' > ' ;
include_partial('module/breadcrumbElement', array(
'nodes' => $nodes, 'parentUrl' => $currentNodeUrl));
}
Call this with an array of ancestor nodes or find a way to pop a Doctrine_Collection if you want to use it with getAncestors() directly.
Again, all your problem comes from the fact that your urls are recursively computed, it would be simpler and faster to display if you had a colum path with the current url (but then you would have to compute, update it), etc... consider doing this if you have more reads than writes (if your tree does not change often).
I have the following macro:
<macro name="InputField" id="string" value="string">
...
<input type="text" id="${id}" name="${id}" value="${value} />
...
</macro>
And the call to the macro:
${InputField( "model.address.address1", 75, "Address", model.Address.Address1 )}
The only problem is that model.Address will be null in some situations
(creating the item instead of editing it), because of this the macro
doesn't run or fails and just outputs the macro call to the view.
How can I pass either "" or the value of model.Address.Address1
depending if Address is null or not? the null operator ($!{}) doesnt
seem to work in this instance.
Solution 1. Write method
public static string HandleNull(Func<object> func)
{
try { return func().ToString(); }
catch (NullReferenceException) { return ""; }
}
and use it instead of Spark macro.
${InputField( "model.address.address1", 75, "Address", HandleNull(() => model.Address.Address1) )}
Solution 2. Use http://www.jmill.net/taxonomy/term/312
Solution 3.
<macro name="InputField" id="string" value="Func<string>">
...
<input type="text" id="${id}" name="${id}" value="$!{value()} />
...
</macro>
${InputField( "model.address.address1", 75, "Address", () => model.Address.Address1 )}
All the solutions depend on deferred execution.