i'm trying to call a frontend action from console like
php yii cron/test
console action is like:
public function actionTest(){
yii::$app->controllerNamespace = "frontend\controllers";
$test = Yii::$app->runAction('web-service/test', [
]);
echo $test;
}
frontend action is like:
public function beforeAction($action)
{
if ($action->id == 'test') {
$this->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}
function actionTest(){
$x="hi ";
echo $x;
return $x;
}
in command prmpot i get result like this
hi 0 // i have really tested this codes
"hi" is because of echo in actionTest but i can't understand why printed $test in console is 0?
it seems "return $x" won't work and $x is not returned to console action.
if i move frontend action to somewhere like component (of course with changes like removing beforeaction() and calling component instead of runaction()), i get expected result "hi hi".
In Yii2 Console, the \Yii:$app::runAction() doesn't return data from action.
The runAction() returns an exit code from Console Application, so you get the 0 which means normal:
The result of the action. This can be either an exit code or Response object. Exit code 0 means normal, and other values mean abnormal. Exit code of null is treaded as 0 as well.
yii-console-application#runAction()
Return response object Demo
frontend action:
public function actionTest($value='')
{
return (object)['title'=>'Empty Object'];
}
console action:
public function actionTest($message = 'hello world')
{
yii::$app->controllerNamespace = "frontend\controllers";
$test = Yii::$app->runAction('web-service/test');
echo $test->title;
}
Related
I am trying to test an ajax request with a basic install of Yii2. I am just using the SiteController::actionAbout() method to try this out.
public function actionAbout()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'message' => 'hello world',
'code' => 100,
];
}
And in the test:
public function sendAjax(\FunctionalTester $I)
{
$I->sendAjaxGetRequest('site/about');
$r = $I->grabResponse();
die(var_dump($r));
}
The grab response method is one I wrote myself in a \Helper\Functional.php file:
public function grabResponse()
{
return $this->getModule('Yii2')->_getResponseContent();
}
When I dump out the response, I just see the html from the site/index page.
This happens for any route except the site default. If I try to do the same thing using site/index then it returns:
string(36) "{"message":"hello world","code":100}"
What am I missing / doing wrong?
Note the difference between a Yii route and the actual URL.
The argument to sendAjaxGetRequest() is the URL, not the route (at least if you pass it as a string, see below).
Dependent on your UrlManager config you might have URLs like /index.php?r=site/about, where the route is site/about. You can use the Url helper of Yii to create the URL:
$I->sendAjaxGetRequest(\yii\helpers\Url::to(['site/about']));
I am not sure about this but if you have the Codeception Yii2 module installed you should also be able to pass the route like this:
$I->sendAjaxGetRequest(['site/about']);
I created an API client for my company to fetch orders from our distributors. I need to acknowledge download of orders back to them with a PUT. The PUT is working properly but I get an error on their confirmation of my acknowledgement.
Using Postman, I get a JSON body message back.
When I PUT a acknowledgement back, I get the following error:
Type error: Argument 1 passed to GuzzleHttp\Client::send() must
implement interface Psr\Http\Message\RequestInterface, instance of
GuzzleHttp\Psr7\Response given, called in
/var/www/orders/app/Http/Controllers/edi/OrderController.php on line 86
This is line 86:
$response = $client->send($apirequest);
The relevant code:
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Psr7\Stream;
use Illuminate\Support\Facades\Input;
use Response;
use XmlParser;
use Psr\Http\Message\RequestInterface;
public function orderConfirm()
{
$uri = config('services.orders.orderack');
$formdata = Input::all();
$orders = Input::get('orders');
try {
$client = new GuzzleHttpClient([
'headers'=> [
'Authorization' => '$user',
'ContractID' => '$contract',
'Content-Type' => 'application/json']
]);
$apirequest = $client->request('PUT', $uri,
['body' => json_encode(
[
$orders
]
)]
);
$response = $client->send($apirequest);
$contents = (string) $response->getBody();
return $contents;
}
catch (RequestException $ex) {
//Exception Handling
echo $ex;
}
Output from Postman was:
"Number of Orders Acknowledged: 1"
from other posts on SO, this:
$contents = (string) $response->getBody();
is the way to get the body and other people fixed their problems, but it's not working for me.
Obviously I'm still missing something here!
Calling $client->request() actually does the request (which is why it's returning an instance of GuzzleHttp\Psr7\Response) instead of building a request object to send later. You don't need to tell the client to send anything because it's already been sent; you just need to set the $response variable to the value of the call to $client->request().
This can be seen in the Body example in their PSR7 documentation.
$response = $client->request('GET', 'http://httpbin.org/get');
To build a request object manually, you will have to create an instance of GuzzleHttp\Psr7\Request using its constructor, as documented under Requests.
// Create a request using a completely custom HTTP method
$request = new \GuzzleHttp\Psr7\Request('MOVE', 'http://httpbin.org/move');
echo $request->getMethod();
// MOVE
I an trying to return json from a cakephp 3.1 controller function. My problem is that no matter what I do with the _serialize flag, the response is always that there is a missing view template file.
In the cake docs it says to set the _serialize flag if you do not need to use a template to format the response. Cake Docs on View _serialize
Below is the Javascript on the client side that initializes the process
function save_activity( mod, act, resp ) {
$.ajax({
method: 'POST',
url: '/activities/saveActivity',
data: {
'module' : "example1",
'activity_name' : "example2",
'response' : "example3"
},
dataType: 'json',
error: function( xhr, status, error ){
alert( status + error );
},
success: function( data, status, xhr ){
alert( status + data.success );
}
});
}
The Controller code that handles the json from the client.
public function saveActivity()
{
$user = $this->Auth->user();
//This line does not seem to do anything
//$this->request->input('json_decode', 'true');
//Debugger::log($this->request->data);
$activityTable = TableRegistry::get('Activities');
$activity = $activityTable->newEntity();
$activity->user_id = $user['id'];
$activity->module = $this->request->data('module');
$activity->activity_name = $this->request->data('activity_name');
$activity->response = $this->request->data('response');
//These lines do not have any effect
//$this->RequestHandler->renderAs($this, 'json');
//$this->response->type('application/json');
//$this->viewBuilder()->layout(null);
//$this->render(false);
$msg = '';
if ($activityTable->save($activity)) {
$msg = 'Activity Stored';
} else {
$msg = 'Activity Not Stored';
}
$this->set(['response' => $msg]);
//comment or uncomment this line and it makes no difference
//as it still returns a json response about a missing template.
$this->set('_serialize', true);
}
The error message I get when I include or remove the _serialize flag.
"Template file "Pages\json\module1\activity4.ctp" is missing."
Anyone have any insight into this mechanims? The workaround I have found is to include the template file... but this means I will have to generate a few dozen essentially empty template files to handle all the places this call is generated from.
Any help please?
Problem cause:- Violation of assumption.
My assumption was that the saveActivity method was being executed. While the reality was that AuthComponent was failing to allow access to that method and the default handler was being run instead, then the default view template was being looked for... and failing.
I found this by looking at the stack track attached to the error message in the returned page via devTools. I should also have verified this assumption with some simple trace logging calls. I already had the clue when I commented out the "$this->set('_serialize', true);" and nothing changed.
Then the simple solution was to authorise the method in the controllers beforeFilter:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('saveActivity');
$this->Auth->allow('getActivity');
$this->eventManager()->off($this->Csrf);
}
Thanks for the assist ndm.
Hello I am currently trying to use POSTMAN to test an early API that is based of of this post
http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api/
I am having an error when trying to either submit variables via POST in php url style or even sending an object. The response from the API comes back 200 and it creates a new entry into the database, but unfortunately it will not take any info from the post variables or jason object, it just comes up null. It seems now that that code is just looking through $_POST variables to and trying to match them to a model variable and if so, it should update it save it, However when i try to send through url parameters in POSTMAN or even change content type json and send raw json object I seem to have no luck with it.
Also I really only need it to decode a jason object and not post parameters so maybe that is where I will start by removing the $post loop and working on retrieving a JSON object instead. Thanks for any help!
public function actionCreate()
{
switch($_GET['model'])
{
// Get an instance of the respective model
case 'event':
$model = new Event;
break;
case 'media':
$model = new Media;
break;
case 'comment':
$model = new Comment;
break;
default:
$this->_sendResponse(501,
sprintf('Mode <b>create</b> is not implemented for model <b>%s</b>',
$_GET['model']) );
Yii::app()->end();
}
// Try to assign POST values to attributes
foreach($_POST as $var=>$value) {
// Does the model have this attribute? If not raise an error
if($model->hasAttribute($var))
$model->$var = $value;
else
$this->_sendResponse(500,
sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>', $var,
$_GET['model']) );
}
// Try to save the model
if($model->save())
$this->_sendResponse(200, CJSON::encode($model));
else {
// Errors occurred
$msg = "<h1>Error</h1>";
$msg .= sprintf("Couldn't create model <b>%s</b>", $_GET['model']);
$msg .= "<ul>";
foreach($model->errors as $attribute=>$attr_errors) {
$msg .= "<li>Attribute: $attribute</li>";
$msg .= "<ul>";
foreach($attr_errors as $attr_error)
$msg .= "<li>$attr_error</li>";
$msg .= "</ul>";
}
$msg .= "</ul>";
$this->_sendResponse(500, $msg );
}
}
Fixed by removing $POST loop and changing to a JSON object scheme only. Here is the code if anyone happens to find themselves in this situation.
//read the post input (use this technique if you have no post variable name):
$post = file_get_contents("php://input");
//decode json post input as php array:
$data = CJSON::decode($post, true);
//load json data into model:
$model->attributes = $data;
Used that instead of the foreach loop through $_POST variables. Now it accepts a json object instead. Happy Coding all!
Honestly, I'm not sure what your problem is. If you can see the values POSTed in $_POST but not assigned to $model, it's probably because you did not specify the validation rules for those fields in the model. If you do not need to validate the fields, simply mark them as 'safe' in the model's rules() function like below.
public function rules() {
return array(
array('fieldName1,fieldName2', 'safe'),
);
}
I'm working on a RESTful application using CodeIgniter and I'm unable to access my POST'd json data in my controller.
I'm posting the json via cURL on my local machine, while the app is being developed on a remote server.
Here is the controller code in question:
class Products extends CI_Controller
{
public function __construct()
{
$this->load->model(products_model);
}
public function index($id = FALSE)
{
if($_SERVER['REQUEST_METHOD'] == 'GET')
{
// fetch product data
$product_data = $this->products_model->get_products($id)
// set appropriate header, output json
$this->output
->set_content_type(application/json)
->set_output(json_encode($product_data));
}
elseif($_SERVER['REQUEST_METHOD'] == 'POST')
{
// debugging for now, just dump the post data
var_dump($this->input->post());
}
}
}
The GET action is working well enough, and returning the appropriate data when requested from a browser, or via a cURL request. However, when attempting to POST json data via cURL I consistently get bool(FALSE) returned from the POST section of the index function. Here is the cURL request I'm making:
curl -X POST -d #product.json mydomain.com/restfulservice/products
Also, here is the contents of the product.json file:
{"id":"240",
"name":"4 x 6 Print",
"cost":"1.5900",
"minResolution":401,
"unitOfMeasure":"in",
"dimX":0,
"dimY":0,
"height":4,
"width":6}
I've made another POST via cURL, excluding the json data and passing something like this:
curl -X POST -d '&this=that' mydomain.com/restfulservice/products
Which returns
array(1) {
["this"]=>
string(4) "that"
}
What gives? Something with the json? It's valid. I've turned off the global CSRF and XSS in application/config/config.php as I understand they require use of CI's form_open() and won't work properly without it. It's my understanding that excluding parameters from $this->input->post() will return ALL the post items yet I continue to get none. I've also tried going around CI's input library and accessing the data via PHP's $_POST variable, it has made no difference.
Your post data is not in query string format so you should skip dealing with $_POST and go straight to the raw post data.
try
var_dump($HTTP_RAW_POST_DATA);
or even better
var_dump(file_get_contents("php://input"));
in codeigniter 2.X, you can override Input class and add necessary functionality.
https://ellislab.com/codeigniter/user-guide/general/core_classes.html
add file MY_Input.php to application/core
add code inside this file:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Input extends CI_Input {
public function raw_post() {
return file_get_contents('php://input');
}
public function post($index = NULL, $xss_clean = FALSE) {
$content_type = $this->get_request_header('Content-type');
if (stripos($content_type, 'application/json') !== FALSE
&& ($postdata = $this->raw_post())
&& in_array($postdata[0], array('{', '['))) {
$decoded_postdata = json_decode($postdata, true);
if ((json_last_error() == JSON_ERROR_NONE))
$_POST = $decoded_postdata;
}
return parent::post($index, $xss_clean);
}
}
that's it..
use it like normal post..