Calling $this->modelname->methodname() with modelname as a variable - php

I am trying to create a generic method that will be able to save all data from different models depending on which "entity" I am handling in the code. As you can see below, I have a variable $entity on which I want decide loading a model and then after that calling a method from it.
The two commented lines in my example are showing what I am trying to achieve, but they are not working. The uncommented (non-dynamic) line $this->companylocation_model->save(...) is working fine.
The commented experiment gives this error: call_user_func() expects parameter 1 to be a valid callback, class '$this->companylocation_model' not found. strange to me, because I am loading that model in the line before it.
I have also tried escaping the > with a backslash but that also doesn't work.
public function submit($entity) // $entity is set to companylocation during method call
{
$filledEntityObject = $this->getEntityDataFromForm($entity);
$this->load->model($entity . '_model');
$this->companylocation_model->save($filledEntityObject, $filledEntityObject->id);
//call_user_func(array('$this->' . $entity . '_model', 'save'), $filledEntityObject, $filledEntityObject->id);
//call_user_func('$this->' . $entity . '_model->save', $filledEntityObject, $filledEntityObject->id);
...
Expected result is simply being able to call the save method from the model with two parameters in a dynamic way.

Rather than using call_user_func you can build the name using the parts directly into the call...
$this->{$entity . '_model'}->save(...)

Related

UnexpectedValueException in Response.php line 403 - Laravel 5.1

I am new to Laravel and am building a small project as my schooling. I have struck the above error and I cannot seem to fix it. Any help is appreciated.
In my controller I make the following call when first loading the page. The getDetails method works perfectly on page load, but fails with above error when I call it with Ajax as the user interacts with the page after load.
On page load the method is called and passed to it resulting values from earlier other method calls ($CSpec[0]->id and $CSize[0]->size_mm, which I can see as values 1 and 0.5) as follows:
$CD = CS::getDetails($CSpec[0]->id, $CSize[0]->size_mm);
Also in the controller I have the following function which triggered via a route used in an Ajax call:
public function itemDetails($ct, $cs)
{
return CS::getDetails($ct, $s);
}
The getDetails method looks like this:
public static function getDetails($ct, $cs)
{
return DB::table('recommend_view')
->where('recommend_view.id', '=', $ct)
->where('recommend_view.size_mm', '=', $cs)
->first();
}
I have this route:
Route::get('vd/cd/{cd}/{cs}',
['uses' => 'Application\VDController#itemDetails', 'as' => 'application.vdcdetails']);
When I use Ajax to call the same method it fails with the above error. The Ajax code produces the following url in the $.getJSON call:
http://my.app/vd/cd/1/0.5
If I dd() inside getDetails for each variable I can see the correct values passed to the method from the url / controller.
If I execute the query in MySQL Workbench, it works as expected:
select *
from `recommender_view`
where `recommender_view`.`ct_id` = 1
and `recommender_view`.`cs_size_mm` = 0.50
limit 1;
So the method works perfectly when called on initial page load with variables fed to it directly from other method calls, but when the variables are passed via the URL / Ajax it fails and I cannot seem to understand what the difference is.
UnexpectedValueException in Response.php line 403:
The Response content must be a string or object implementing __toString(), "object" given.
I believe I know what your issue is, however, please feel free to correct me.
What you're using is the Laravel query builder, which returns a stdClass object type in PHP, assuming it finds a result set for your query. This is effectively a "dumb" object that has no methods to "echo" or return. You can't cast to array, nor json etc.
So when the Laravel response object is trying to handle it, it can't use the __toString() method to deconstruct an appropriate response.
What you'd be better off doing is calling the query against a Model that extends the Illuminate Eloquent Model class.
In this instance, it COULD be something like this
CableRecommenderView::where('recommend_view.id', $ct)
->where('recommend_view.size_mm', $cs)
->first();
Eloquent is able to respond accordingly when being passed to the response object.
As an FYI, when using equals ('=') as the comparison operator in queries Eloquent (and possibly the query builder, although you'd have to check on that), you can forego explicitly defining it in the ->where() clause and simply pass the comparison variable as the second argument.
Hope that helps!
The ajax call expects a response to be passed back to it. It is unable to recognize the object you are trying to pass to it.
Look into creating responses http://laravel.com/docs/5.1/responses.
If you return a json response e.g
public function itemDetails($ct, $cs)
{
$item = CS::getDetails($ct, $s);
return response()->json(['data' => $item]);
}
The ajax call should work. Then you can retrieve from the data variable from your ajax.

How to access values of multiple parameters passed to Laravel controller

I am trying to figure out how to access two (or more) parameters passed to a Laravel controller. I know how to create the route, and the URL is created correctly, but then I can only access the first passed parameter in my controller.
Route:
Route::get('managers/{id}/{parameter2}', array('as'=>'dosomething', 'uses'=> 'ManagersController#dosomething'));
where the first parameter is obviously the $id for managers, and the second parameters is to be processed by the controller.
View:
Do Something
generates the URL:
http://domain/managers/1/2
where 1 is easily accessed as the $id for managers, but when I try to access the 2nd parameter "2" using $parameter2, e.g. using a simple return: "id=$id and parameter2=$parameter2" statement, I get an "unidentified variable: $parameter2" error.
What am I doing wrong?
Is there a better way to pass multiple parameters? I'm especially asking the "better way?" question because what I want to do is use the 2nd parameter to change a value in a database table, and using a 'get' method, somebody could change the parameter value in the URL and therefore cause mischief. Must I use a 'post' method? I'd love to be able to use a link, since that works much better with the design of my application.
Thanks!
I was asked to include the controller, which I'm happy to do. Initially, just for testing, as I mentioned, my controller was a simple return to display the values of the two passed parameters. But here is what I want to be able to do, including the actual name of the function ("update_group" rather than "dosomething") --
ManagersController:
public function update_group($id)
{
DB::table('groups')->where('id','=',$parameter2)->update(array('manager_id'=>$id));
return Redirect::route('managers.show', array('id'=>$id));
}
The update table works perfectly if I replace $parameter2 with an actual value, so that syntax is fine. The issue is that Laravel says that $parameter2 is an undefined variable, despite the fact that the URL contains the value of $parameter2 as you can see above.
And since it occurs to me that the answer to this may involve adding a function to the Manager model, here is the current
Manager.php
class Manager extends Eloquent {
protected $table = 'managers'; ... (mutator and error functions)
}
Just change
public function update_group($id)
to
public function update_group($id, $parameter2)
All looks ok in your route. Seeing the controller code would help, but likely, you may not have a second parameter in your controller's dosomething() method.
public function dosomething($id, $parameter2){
var_dump($id).'<br />';
var_dump($paremter2);
}
If that isn't the case, you can try dumping it from the route's callback to further diagnose.
Route::get('managers/{id}/{parameter2}', function($id, $parameter2)
{
var_dump($id).'<br />';
var_dump($paremter2);
});
Depending on your use case, you can pass them in a query string like so: but it isn't really the 'best way', unless you're doing something like building an API that won't use the same variables in the same order all the time.
/managers?id=1&paramter2=secondParameter
var_dump(Request::query('id')).'<br />';
var_dump(Request::query('paramter2'));

Unable to route to second edit resource Laravel-4

I have a resource controller for member data. All of the usual resource functions, including edit, are working perfectly. I am trying to add additional edit functions within this controller so that I can create views that only are for specific subsets of the Member model data, since the data set is rather large. So, I've set up the extra routes and functions. But when I attempt to link to the edit2 resource, Laravel will not create the proper link. I don't know what I'm doing wrong. Code:
Route:
Route::get('members.edit2', array('as'=>'edit2', 'uses'=> 'MembersController#edit2'));
Route::resource('members','MembersController');
MembersController:
// Regular edit function -- works just fine:
public function edit($id)
{
$member = $this->member->find($id);
return View::make('members.edit', array(
'member'=>$member, ...
));
}
// Extra edit2 function -- should work if I could successfully route to it:
public function edit2($id)
{
$member = $this->member->find($id);
return View::make('members.edit2', array(
'member'=>$member, ...
));
}
show.blade.php:
// normal edit link (works fine, see source code below):
edit
// additional edit2 link (creates a bad link, see source code below):
edit
source code:
// normal link that uses edit for member id=27:
edit
// link that attempts to use edit2 for same member:
edit
I'm sure there is a way of doing this. It doesn't matter whether I use the named route 'edit2' rather than 'members.edit2', the exact same bad link is created. I've tried every combination I can think of. Laravel docs are not at all helpful for this. Thanks!
Your don't declare your edit2 route as you should do. Your first mistake is that the member's id you want to edit is not passed as a parameter and the second one that by calling this {{route('edit2')}} Laravel expects a url like /members.edit2 which is never going to appear. You should better use sth like /members/{id}/edit2.
Try using this:
Route::get('members/{id}/edit2', array('as'=>'edit2', 'uses'=> 'MembersController#edit2'));
and call it like:
{{ route('edit2', [$id]) }}
Also be careful, whenever you call Url::route() or simply route() you should pass their parameters in an array like:
{{route('myRoute', ['par1', 'par2', 'par3', ...]}}

call a controller function from another controller

I have 2 controllers, let's call them c1 and c2. Now I want to call a function in c2, Let's say actionC2, from a function in c1.
I tried something like this:
$c2_instance = new c2();
$c2_instance->actionC2();
but it won't work. I get this error: Missing argument 1 for CController::__construct().
What am I doing wrong?
EDIT: maybe its important to say that it falls on the first line
You should not call a controller from another controller . You should redirect using this
$this->redirect(array('controller/action'));
And if you do not have exactly no way other that than , reconsider your design . Solve the problem , do not try to hide it. It will bite back you anyway.
As #user488074 said, your controller must have an argument that it is looking for when you create an instance of it. Go to that controller and look at what it is looking for in the contstruct function. If you don't want to pass an argument all the time for this controller then add something like this to the construct function argument
public function foo($argument = NULL){
}
so it has a default value if you don't want to pass something.

set models based on condition in cakephp queries

This is probably very easy to do, but I can't seem to get my head around it right now. Let's say in a component in a cakephp application, I have a variable my_model, which contains the model of the corresponding controller that is currently using the component like:
function TestComponent extend Object
{
var $my_model; // can be either User, or Person
function test()
{
$myModelTemp = $this->my_model;
$model = $myModelTemp != 'User' ? $myModelTemp.'->User' : 'User';
$this->$model->find('all');
}
}
As you can see above in my function test() what I'm trying to do is call the correct model based on the value of my_model. So based on the condition, my query will be either:
$this->Person->User->find('all');
Or
$this->User->find('all');
When I do it like I did above, I get an error saying Fatal error: Call to a member function find() on a non-object. In order words, that error means Person->User is not an object (so, it is considered as a string).
What you're saying could be true, however, it can refer to any part of the call.
So either Person or User could be invalid, or together they causes the error. Hard to say.
Try dumping the individual objects using var_dump();
So try:
<?php
echo "<pre>";
var_dump(is_object($this->Person));
var_dump(is_object($this->User));
echo "</pre>";
?>
to determine where you're code goes wrong.
To be clear, that return value needs to be true for it to be an object.
The one that returns false is the likely culprit.
Should your question refer to the correct way to reference an object, an object is basically an array. For example:
<?php
$obj = (object) array("this", "my_function");
?>
The above example casts the array as an object. However, using multiple layers might prove to be more difficult than you'd expect.
Generally, it looks like you might be going about this all wrong. Obviously you want the models to be dynamic, but then you're hard-coding things which defeats the whole point of it being dynamic in the first place.
It also seems like you might be violating the principals of CakePHP and MVC by doing all this in a component. I'm not sure this component should really be manipulating models or assuming which models are currently in use.
However, if you want to evaluate a string as an actual object, you can wrap it in { ... } (this is valid standard PHP syntax, not Cake-specific code).
Try this:
$modelName = $this->my_model;
$model = ($modelName != 'User') ? $this->{$modelName}->User : $this->User;
$model->find('all');
Now, if this doesn't work or you get an error saying it can't find the model(s) you need to ensure the models are actually loaded and initialised in the current scope.

Categories