how to add parameter in php callback - php

I struggle to understand how I can add a second parameter ($id) to pass along with this callback in my php class:
($this, 'updateDuplicateAcronym')
The method updateDuplicateAcronym should recieve 2 parameters, one by reference from the form where this code belongs (which works fine), and one more that I need in order to do some checks.
Someone who knows how to do this?

Here is my method to pass parameters :
$callBackFunction = function($p1, $p2) {
...
}
baseFunction($context, $callable, $params)
{
//Main process
call_user_func($callable, $params);
}
// Running
baseFunction($this, $callBackFunction, array(1, 42));

Related

Use identifier in PHP and how does it affect the logic

Use identifier is used when we want to send some outer environment variables inside closures so I have a scenario.
$invoiceList = UserInvoice::where('user_id', $this->user->id)
->where(function ($query) use ($filters) {
$query->where('invoice_number', 'LIKE', "%{$filters['invoiceNumber']}%")
->when($filters['type'], function ($query) use ($filters) {
$query->whereIn('invoice_type', $filters['type']);
});
});
In this Laravel eloquent query I have checked for filter['type'] when it is there then try to filter my invoice_type from filter[type]
But I am now confused here that what if I pass filters inside functions parameters like this
method 1
->when($filters['type'], function ($query,$filters) use () {
$query->whereIn('invoice_type', $filters['type']);
});
Or
method 2
->when($filters['type'], function () use ($query,$filters) {
$query->whereIn('invoice_type', $filters['type']);
});
What impact would it be if I opt these methods
I have also tried both and in method 1 it throws me an error that filters['type'] not available
and when I tried method 2 it works fine so please can any one explain how does it works I mean not theoretically but in practical language what basically happening there.
Also where it is defined that a closure function will accept how many numbers of arguments
The very last thought in your question is actually the key to your misunderstanding:
where it is defined that a closure function will accept how many numbers of arguments
The answer is wherever the function is eventually executed.
In this case, you are passing the function to the when method; that method can decide when to execute it, and what parameters to pass when it does. We can look at the source code directly and see what happens:
public function when($value, callable $callback = null, callable $default = null)
{
// some extra logic skipped as not relevant right now
if ($value) {
return $callback($this, $value) ?? $this;
} elseif ($default) {
return $default($this, $value) ?? $this;
}
return $this;
}
So, if $value is "truthy", $callback will be executed with exactly two parameters: the current object ($this) and the exact value provided ($value). In this case, that will be the query you're building, and the value of $filters['type'].
Think of it like handing over an envelope: you don't have any control of what the when method puts into the envelope, you just get to look at it once it's there.

Pass function and parameters as parameters to intermediary function which then calls named function

I'm trying to construct an intermediary function for my WordPress theme that handles all the checking and returning of transients. I want to call the transient function from a template, passing in the transient name and function to call if the transient doesn't exist. Furthermore, I need to pass parameters to use if the function is actually called.
I can't find anything on passing multiple parameters together to use later. For several uses, I can rely on the default parameters of the eventually called functions and so set the third parameter, $args to false. I looked into using serialize, but that's for one variable at a time, and I need to be able to pass several parameters at once.
Where I call the transient function:
$posts = transitize('transientname', 'functionname', "4, false, array($post->projectsiteid)");
The transient-checking function:
function transitize($transientname, $functionname, $args=false) {
if (false === ($transient_exists = get_site_transient($transientname))) {
$functionresult = ($args) ? $functionname($args) : $functionname();
set_site_transient($transientname, $functionresult, HOUR_IN_SECONDS);
return $functionresult;
}
else {
return $transient_exists;
}
}
How can I prepare the third parameter, containing 3 parameters for later use, such that the later function call works?
Change the third parameter to an array:
$posts = transitize('transientname', 'functionname', array(4, false, array($post->projectsiteid)));
Change this line to use call_user_func_array:
$functionresult = ($args) ? call_user_func_array($functionname, $args) : $functionname();

laravel controller function parameters

I'm trying to call a function inside one of my controller from the action() helper function. I need to pass a paramter to my function.
Here is the funciton I'm trying to call :
public function my_function($clef = 'title')
{
$songs = Song::orderBy($clef)->get();
return View::make('my_view', compact('songs'));
}
Here is the way I call it :
Author
The function is always running with the default value, even if I put anything else in my call. From what I can see in my address bar, the paramter seems to be sent along with the call :
http://www.example.com/my_view?clef=author
From the little I know, it seems correct to me, but since it doesn't work, I must come to the evidence that it isn't. What would be the cleanest way to call my function with the right parameter?
The reason why it's not working is because query strings aren't passed as arguments to your controller method. Instead, you need to grab them from the request like this:
public function my_function(Request $request)
{
$songs = Song::orderBy($request->query('clef'))->get();
return View::make('my_view', compact('songs'));
}
Extra tidbit: Because Laravel uses magic methods, you can actually grab the query parameter by just doing $request->clef.
Laravel URL Parameters
I think assigning parameters need not be in key value pair. I got it to work without names.
If your route is like /post/{param} you can pass parameter as shown below. Your URL will replace as /post/100
URL::action('PostsController#show', ['100'])
For multiple parameters say /post/{param1}/attachment/{param2} parameter can be passed as shown below. Similarly your url will be replaced as /post/100/attachment/10
URL::action('PostsController#show', ['100', '10'])
Here show is a method in PostsController
In PostsController
public function show($param1 = false, $param2 = false)
{
$returnData = Post::where(['column1' => $param1, 'column2' => $param2 ])->get();
return View::make('posts.show', compact('returnData'));
}
In View
Read More
In Routes
Route::get('/post/{param1}/attachment/{param2}', [ 'as' => 'show', 'uses' => 'PostsController#show' ] );
URL Should be: http://www.example.com/post/100/attachment/10
Hope this is helpful.

get count controller args from router?

ok im learning on how to make my own custom mvc system, so far i have created things like router and the controller.
example i have a controller profile class and an url www.helloworld.com/args1/args2/args3
class Profiles
{
function index($args1,$args2)
{
echo var_dump($args1,$args2);
}
}
heres are part of my router class that execute the method and the parms
if (is_callable(array($controller,$method))) {
call_user_func_array(array($controller, $method), $this->params);
}
so far no error but somehow i need to give a 404. if the $this->params is different then the count(params) in the method that i call at call_user_func_array(array($controller, $method),
$this->params);
ok what im thinking is if count get params not same as count params at the called class then 404,
lets say i can count my $this->params it gave me a 3. but how about the params in the called class ?
how can we count params in a called class by call_user_func_array?
Thanks for looking in
Adam Ramadhan
From what I know, there is no way of getting the parameter count for a method without using reflection. However, it's pretty simple and would look something like this:
$reflector = new ReflectionClass('Profiles');
$method = $reflector->getMethod('index');
$parameters = $method->getParameters();
printf('%s expects %d parameters', $method->name, count($parameters));
Will yield
index expects 2 parameter
Note that reflection always comes with a cost. However, the performance implications of this should not be noticable.
You could use reflection:
$refclass = new ReflectionClass($controller);
$param_count = $refclass->getMethod($method)->getNumberOfRequiredParameters();
if ($param_count <= count($this->params)) {
$refclass->invokeArgs($controller, $this->params);
} else {
// 404
}
Can be made stricter by checking if there are too many parameters.
count params in a called class by call_user_func_array
Rather simple, actually. You can determine the amount of parameters by fetching them into an array using func_get_args, and then count them. Example:
<?php
function foo( ) {
echo "I have received " . count( func_get_args( ) ) . " parameters.";
}
foo( ); // I have received 0 parameters.
foo( 1, 2, 3, 4, 5 ); // I have received 5 parameters.

How can I get PHPUnit MockObjects to return different values based on a parameter?

I've got a PHPUnit mock object that returns 'return value' no matter what its arguments:
// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
->method('methodToMock')
->will($this->returnValue('return value'));
What I want to be able to do is return a different value based on the arguments passed to the mock method. I've tried something like:
$mock = $this->getMock('myObject', 'methodToMock');
// methodToMock('one')
$mock->expects($this->any))
->method('methodToMock')
->with($this->equalTo('one'))
->will($this->returnValue('method called with argument "one"'));
// methodToMock('two')
$mock->expects($this->any))
->method('methodToMock')
->with($this->equalTo('two'))
->will($this->returnValue('method called with argument "two"'));
But this causes PHPUnit to complain if the mock isn't called with the argument 'two', so I assume that the definition of methodToMock('two') overwrites the definition of the first.
So my question is: Is there any way to get a PHPUnit mock object to return a different value based on its arguments? And if so, how?
Use a callback. e.g. (straight from PHPUnit documentation):
<?php
class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnCallbackStub()
{
$stub = $this->getMock(
'SomeClass', array('doSomething')
);
$stub->expects($this->any())
->method('doSomething')
->will($this->returnCallback('callback'));
// $stub->doSomething() returns callback(...)
}
}
function callback() {
$args = func_get_args();
// ...
}
?>
Do whatever processing you want in the callback() and return the result based on your $args as appropriate.
From the latest phpUnit docs: "Sometimes a stubbed method should return different values depending on a predefined list of arguments. You can use returnValueMap() to create a map that associates arguments with corresponding return values."
$mock->expects($this->any())
->method('getConfigValue')
->will(
$this->returnValueMap(
array(
array('firstparam', 'secondparam', 'retval'),
array('modes', 'foo', array('Array', 'of', 'modes'))
)
)
);
I had a similar problem (although slightly different... I didn't need different return value based on arguments, but had to test to ensure 2 sets of arguments were being passed to the same function). I stumbled upon using something like this:
$mock = $this->getMock();
$mock->expects($this->at(0))
->method('foo')
->with(...)
->will($this->returnValue(...));
$mock->expects($this->at(1))
->method('foo')
->with(...)
->will($this->returnValue(...));
It's not perfect, since it requires that the order of the 2 calls to foo() is known, but in practice this probably isn't too bad.
You would probably want to do a callback in a OOP fashion:
<?php
class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnAction()
{
$object = $this->getMock('class_name', array('method_to_mock'));
$object->expects($this->any())
->method('method_to_mock')
->will($this->returnCallback(array($this, 'returnTestDataCallback')));
$object->returnAction('param1');
// assert what param1 should return here
$object->returnAction('param2');
// assert what param2 should return here
}
public function returnTestDataCallback()
{
$args = func_get_args();
// process $args[0] here and return the data you want to mock
return 'The parameter was ' . $args[0];
}
}
?>
It is not exactly what you ask, but in some cases it can help:
$mock->expects( $this->any() ) )
->method( 'methodToMock' )
->will( $this->onConsecutiveCalls( 'one', 'two' ) );
onConsecutiveCalls - returns a list of values in the specified order
Pass two level array, where each element is an array of:
first are method parameters, and last is return value.
example:
->willReturnMap([
['firstArg', 'secondArg', 'returnValue']
])
You also can return the argument as follows:
$stub = $this->getMock(
'SomeClass', array('doSomething')
);
$stub->expects($this->any())
->method('doSomething')
->will($this->returnArgument(0));
As you can see in the Mocking documentation, the method returnValue($index) allows to return the given argument.
Do you mean something like this?
public function TestSomeCondition($condition){
$mockObj = $this->getMockObject();
$mockObj->setReturnValue('yourMethod',$condition);
}
I had a similar problem which I couldn't work out as well (there's surprisingly little information about for PHPUnit). In my case, I just made each test separate test - known input and known output. I realised that I didn't need to make a jack-of-all-trades mock object, I only needed a specific one for a specific test, and thus I separated the tests out and can test individual aspects of my code as a separate unit. I'm not sure if this might be applicable to you or not, but that's down to what you need to test.
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');
public function testBusiness()
{
/*
onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
*/
$this->BusinessMock ->method('getEmployees')
->will($this->onConsecutiveCalls(
$this->returnArgument(0),
$this->returnValue('employee')
)
);
// first call
$this->assertInstanceOf( //$this->returnArgument(0),
'argument',
$this->BusinessMock->getEmployees()
);
// second call
$this->assertEquals('employee',$this->BusinessMock->getEmployees())
//$this->returnValue('employee'),
}
Try :
->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));

Categories