YII2 mock web Request class in controller - yii2

In my yii2 controller I am running this:
$address = \Yii::$app->request->post('address');
How can I mock this request in PHPUnit? I've tried using mockery but cannot figure out how to mock the \Yii::$app part?

to mock a request in Yii2 try this
use yii\web\Request;
use Codeception\Stub;
private function mockRequest($attributes){
// mock a request
$_SERVER['REQUEST_URI'] = 'http://localhost';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
\Yii::$app->requestedAction = new Action('fake', $this->model);
\Yii::$app->setHomeUrl('http://localhost');
return Stub::make(Request::class, [
'getUserIP' =>'127.0.0.1',
'enableCookieValidation' => false,
'getUserAgent' => 'Dummy User Agent',
'getBodyParams' => [
'MyModel' => $attributes
],
]);
}

I struggled quite a bit with this one last week. I'm using Codeception, but I believe this will also work for PHPUnit, only needing minor adjustments.
Create a partial mock of the Request class and set it as active request inside your test:
$request = $this->createPartialMock('\yii\web\Request', ['getUserIP', 'getUserAgent', 'getBodyParams', 'getIsAjax']);
$request->expects($this->any())
->method('getIsAjax')
->will($this->returnValue(true));
$request->expects($this->any())
->method('getUserIP')
->will($this->returnValue('127.0.0.1'));
$request->expects($this->any())
->method('getUserAgent')
->will($this->returnValue('Dummy User Agent'));
\Yii::$app->set('request', $request);
Source

Related

Create dynamic request object in Laravel

I was looking for help creating an object of the type Illuminate\Http\Request. This article helped me understand the mechanism of the class, but I did not get the desired result.
Create a Laravel Request object on the fly
I'm editing the development code passed to me by the customer. The code has a function that gets a request parameter from vue and translates it to JSON:
$json = $request->json()->get('data');
$json['some_key'];
This code returned an empty array of data:
$json = $request->request->add([some data]);
or
$json = $request->request->replace([some data]);
this one returned an error for missing the add parameter
$json = $request->json->replace([some data]);
A variant was found by trying and errors. Maybe, it help someone save time:
public function index() {
$myRequest = new \Illuminate\Http\Request();
$myRequest->json()->replace(['data' => ['some_key' => $some_data]]);
$data = MyClass::getData($myRequest);
}
..
class MyClass extends ...
{
public static function getData(Request $request) {
$json = $request->json()->get('data');
$json['some_key'];
In addition, there are other fields in the class that you can also slip data into so that you can pass everything you want via Request
$myRequest->json()->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->request->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->attributes->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->query->replace(['data' => ['some_key' => $some_data]]);
$myRequest = new \Illuminate\Http\Request();
$myRequest->setMethod('POST');
$myRequest->request->add(['foo' => 'bar']);
dd($request->foo);
This from the link you shared works, give it a try. Thanks for sharing that link!

Execute stored procedure in directus headless cms

I just find directus headless cms
Looks awesome. It resolve many uses cases for me.
But I am concerned about how to achieve transactions, aggregate functions or complex queries. I understand that maybe is out scope.
If a custom endpoint or graphql allow me execute a stored procedure i will have all my needs achieved.
Is it possible?
Hi finally I find how to use custom endpoints to do plain querys, including stored procedures.
Maybe is possible implement a module for add admin gui option for that, I try work in that, for the moment this is the example for a select:
use Directus\Application\Http\Request;
use Directus\Application\Http\Response;
return [
'' => [
'method' => 'GET',
'handler' => function (Request $request, Response $response) {
$container = \Directus\Application\Application::getInstance()->getContainer();
$dbConnection = $container->get('database');
$tableGateway = new \Zend\Db\TableGateway\TableGateway('directus_users', $dbConnection);
$query = $tableGateway->getAdapter()->query("select * from productos where 1=1");
$result = $query->execute();
if ($result->count() > 0) {
$returnArr = array();
while ($result->valid()) {
$returnArr[] = $result->current();
$result->next();
}
if (count($returnArr) > 0) {
return $response->withJson([
'data' => [
$returnArr,
],
]);
}
}
return "{}";
},
],
];
Sorry for my bad English.

Retrieve specific data using JSON decode Laravel

I'm new to Laravel. I need to retrieve specific data from the database using the JSON decode. I am currently using $casts to my model to handle the JSON encode and decode.
This is my insert query with json encode:
$request->validate([
'subject' => 'required|max:255',
'concern' => 'required'
]);
$issue = new Issue;
$issue->subject = $request->subject;
$issue->url = $request->url;
$issue->details = $request->concern;
$issue->created_by = $request->userid;
$issue->user_data = $request->user_data; //field that use json encode
$issue->status = 2; // 1 means draft
$issue->email = $request->email;
$issue->data = '';
$issue->save();
The user_data contains {"id":37,"first_name":"Brian","middle_name":"","last_name":"Belen","email":"arcega52#gmail.com","username":"BLB-Student1","avatar":"avatars\/20170623133042-49.png"}
This is my output:
{{$issue->user_data}}
What I need to retrieve is only the first_name, middle_name, and last_name. How am I supposed to achieve that? Thank you in ADVANCE!!!!!
As per the above code shown by you it will only insert data into the database.For retrieving data you can make use of Query Builder as i have written below and also you can check the docs
$users = DB::table('name of table')->select('first_name', 'middle_name', 'last_name')->get();
I will recommend using Resources. It really very helpful laravel feature. Check it out. It is a reusable class. You call anywhere and anytime.
php artisan make:resource UserResource
Go to your the newly created class App/Http/Resources/UserResource.php and drfine the column you want to have in your response.
public function toArray($request) {
return [
"first_name" => $this->first_name,
"middle_name" => $this->middle_name,
"last_name" => $this->last_name
]
}
Now is your controller you can use the UserResource like folow:
public function index()
{
return UserResource::collection(User::all());
}
Or after inserting data you can return the newly added data(f_name, l_name...)
$user = new User;
$user->first_name= $request->first_name;
$user->middle_name= $request->middle_name;
$user->last_name= $request->last_name;
$user->save();
$user_data= new UserResource($user);
return $user_data;

Laravel's Maximum function nesting level of '256' reached

I'm calling an API which gives a nested mixture of JSON, STDClass, and Arrays. One of my main concerns was trying to take out specific data out of it which has been solved. The point is that the code worked until I tried to use Laravel blade. After creating a layout called master.layout.php, and creating a section called 'content' which takes the codes inside the tag, It stopped working and kept giving me "Maximum function nesting level of '256' reached" error.
There were some solutions in Stackoverflow that I tried and some tricks to even bypass it by changing the xdebug config in PHP.ini file. but unfortunately, none of them worked for me. One the members said "it's better to take a look at the structure of your code instead of trying to bypass it so I did. From what I figured out, I feel like json_decode() function keep recursing since its a recursive function. I tried to set the depth for it but it didn't work as well. I'd be glad if someone guides me about the ways to fix this issue.
Here is the code:
price.blade.php:
#extends('layouts.master')
#section('content')
#php
$btc = new \App\Http\Controllers\CoinsController();
$parameters = [
'start' => '1',
'limit' => '1',
];
$query = http_build_query($parameters);
$result = $btc->apiGet('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest'."?".$query);
$price = json_decode($result['response'])->data[0]->quote->USD->price;
#endphp
<h1>Bitcoin Price Live</h1>
<h2>{{"Current Price of Bitcoin: ". $price}}</h2>
#stop
CoinsController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CoinsController extends Controller
{
function apiGet($url)
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_TIMEOUT => 30000,
CURLOPT_POST => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
// Set Here Your Requesred Headers
'Content-Type: application/json',
'Accept-Encoding: deflate, gzip',
'X-CMC_PRO_API_KEY: xxxxxxxxxxxxxxxxxxx',
),
)
);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
json_decode($response);
}
return view('index.price', compact('response'));
}
}
You shouldn't really be instantiating the controller within the blade template.
The issue is that you are essentially causing infinite loop.
Within your controller you are loading your blade view. Then within your blade view you are creating a new instance of the controller and running the method again. That method then returns the same view and so the process starts again. This will then keep going on and on and on until PHP eventually hit's a limit - and that is the issue here.
Instead you should have one controller that returns the view. You could then have a separate class that you instantiate which just returns you the value you are after as a string. That way you are not reloading the controller and getting caught in an infinite loop.

zend framework 2, return the rendered contents of a view inside a JSON Model

I am trying to create a JsonModel with an item in the variables 'html' containing the current rendered view. I would like to add this code to an event:
rather than this method: How to render ZF2 view within JSON response? which is in the controller, I would like to automate the process by moving it to an Event
I have the strategy in my module.config.php:
'strategies' => array(
'ViewJsonStrategy',
)
I have set up a setEventManager in the controller:
$events->attach(MvcEvent::EVENT_RENDER, function ($e) use ($controller) {
$controller->setRenderFormat($e);
}, -20);
Is this the best event to attach it to? would the RENDER_EVENT be better?
Now I would like to change the render of the page based on !$this->getRequest()->isXmlHttpRequest(), (commented out for debug)
public function setRenderFormat($e)
{
//if(!$this->getRequest()->isXmlHttpRequest())
//{
$controller = $e->getTarget();
$controllerClass = get_class($controller);
//Get routing info
$controllerArr = explode('\\', $controllerClass);
$currentRoute = array(
'module' => strtolower($controllerArr[0]),
'controller' => strtolower(str_replace("Controller", "", $controllerArr[2])),
'action' => strtolower($controller->getEvent()->getRouteMatch()->getParam('action'))
);
$view_template = implode('/',$currentRoute);
$viewmodel = new \Zend\View\Model\ViewModel();
$viewmodel->setTemplate($view_template);
$htmlOutput = $this->getServiceLocator()->get('viewrenderer')->render($viewmodel, $viewmodel);
$jsonModel = new JsonModel();
$jsonModel->setVariables(array(
'html' => $htmlOutput,
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1,2,3,4,5,6)
));
return $jsonModel;
//}
}
Strangely, (or not) this code works and produces the $jsonModel, however is doesn't overwite the normal HTML view with the json, but the same code (without the event) in a controller method, overwrites perfectly.
p.s Is there a better method to do the whole concept?
p.p.s how can I obtain the current View Template from within the controller, without resorting to 8 lines of code?
Thanks in advance!
Aborgrove
you are returning the view model from an event I thinks this doesn't have any effect in current viewmanager view model, fetch the current viewmodel from viewmanager and call setTerminal(true). or replace the created jsonmodel using the viewmanager