Slim v3 PUT method and retrieve POST data - post

I have added route to update emails in a database which uses PUT method
$app->put('/notifications/{email}', 'add_email_address');
and function for it looks like:
function add_email_address($request, $response, $args) {
$email = $args['email'];
$addon_email = $request->getParam('addon_email', null);
echo "ADD/UPDATE $email with $addon_email";
}
UPDATE somehow on testing PUT method with a form input post addon_email = test#null.com retrieved value for $addon_email is empty;
Any tips what I'm doing wrong?

You should use $request->getParams() to get array of all POST/PUT parameters, or you can use $reqeuest->getParam('key', 'defaultValue'), where 'key' is paramter name and 'defaultValue' is... well, default value in case parameter is missing.
So,
function add_email_address($request, $response, $args) {
$email = $args['email'];
$addon_email = $app->request->getParam('addon_email', null);
// some code....
return $response->withJson("ADD/UPDATE $email with $email");
}
EDIT
We both forgot that you should return response object. )
Since add_email_address is route callback, it should return Psr\Http\Message\ResponseInterface response.

I have got it to work by changing
$addon_email = $app->request->getParam('addon_email', null);
to
$allPostPutVars = $request->getParsedBody();
$addon_email = $allPostPutVars['addon_email'];
It looks like getParam works only for GET method. Also content-type must be set as x-www-form-urlencoded

Related

Unable to figure out how to use post method, for a suitescript written in Netsuite

I am trying to do use the post method for a simple suitescript program, i am very new to this.
In Netsuite i have written a suitescript as follows.
function restPost()
{
var i = nlapiLoadRecord('department', 115);
var memo = nlapisetfieldvalue('custrecord225', ' ');// this is a customfield, which i want to populate the memo field, using rest client in firefox
var recordId = nlapiSubmitRecord(i);
}
i have created a script record and uploaded this suitescript and even copied the external URL to paste it in restclient.
In Restclient(firefox plugin), pasted the external URL, i have given the method as post, header authorization given, content-type: application/json, and in body i put in {"memo":"mynamehere"};
In this the error i get is
message": "missing ) after argument list
I even tried it by writting other suitescript programs the errors i get is as follows:
Unexpected token in object literal (null$lib#3) Empty JSON string
Invalid data format. You should return TEXT.
I am kinda new to the programming world, so any help would be really good.
I think you are trying to create a RESTlet for POST method. Following is the sample code for POST method -
function createRecord(datain)
{
var err = new Object();
// Validate if mandatory record type is set in the request
if (!datain.recordtype)
{
err.status = "failed";
err.message= "missing recordtype";
return err;
}
var record = nlapiCreateRecord(datain.recordtype);
for (var fieldname in datain)
{
if (datain.hasOwnProperty(fieldname))
{
if (fieldname != 'recordtype' && fieldname != 'id')
{
var value = datain[fieldname];
if (value && typeof value != 'object') // ignore other type of parameters
{
record.setFieldValue(fieldname, value);
}
}
}
}
var recordId = nlapiSubmitRecord(record);
nlapiLogExecution('DEBUG','id='+recordId);
var nlobj = nlapiLoadRecord(datain.recordtype,recordId);
return nlobj;
}
So after deploying this RESTlet you can call this POST method by passing following sample JSON payload -
{"recordtype":"customer","entityid":"John Doe","companyname":"ABCTools Inc","subsidiary":"1","email":"jdoe#email.com"}
For Authorization you have to pass request headers as follows -
var headers = {
"Authorization": "NLAuth nlauth_account=" + cred.account + ", nlauth_email=" + cred.email +
", nlauth_signature= " + cred.password + ", nlauth_role=" + cred.role,
"Content-Type": "application/json"};
I can understand your requirement and the answer posted by Parsun & NetSuite-Expert is good. You can follow that code. That is a generic code that can accept any master record without child records. For Example Customer Without Contact or Addressbook.
I would like to suggest a small change in the code and i have given it in my solution.
Changes Below
var isExistRec = isExistingRecord(objDataIn);
var record = (isExistRec) ? nlapiLoadRecord(objDataIn.recordtype, objDataIn.internalid, {
recordmode: 'dynamic'
}) : nlapiCreateRecord(objDataIn.recordtype);
//Check for Record is Existing in Netsuite or Not using a custom function
function isExistingRecord(objDataIn) {
if (objDataIn.internalid != null && objDataIn.internalid != '' && objDataIn.internalid.trim().length > 0)
return true;
else
return false;
}
So whenever you pass JSON data to the REStlet, keep in mind you have
to pass the internalid, recordtype as mandatory values.
Thanks
Frederick
I believe you will want to return something from your function. An empty object should do fine, or something like {success : true}.
Welcome to Netsuite Suitescripting #Vin :)
I strongly recommend to go through SuiteScript API Overview & SuiteScript API - Alphabetized Index in NS help Center, which is the only and most obvious place to learn the basics of Suitescripting.
nlapiLoadRecord(type, id, initializeValues)
Loads an existing record from the system and returns an nlobjRecord object containing all the field data for that record. You can then extract the desired information from the loaded record using the methods available on the returned record object. This API is a core API. It is available in both client and server contexts.
function restPost(dataIn) {
var record = nlapiLoadRecord('department', 115); // returns nlobjRecord
record.setFieldValue('custrecord225', dataIn.memo); // set the value in custom field
var recordId = nlapiSubmitRecord(record);
return recordId;
}

Silex Pimple service implementation

Inside my Silex app I need a function which basically does a file_get_contents() my idea was to use something like
$app['funky_service'] = function () {
$content = file_get_contents();
return $content;
}
this is working fine, but how can I pass parameters to this function? I can call it like this
$fs = $app['funky_service'];
but passing arguments to it is still puzzling my
As per the services chapter in the silex documentation, you need to protect your function if you want to store it as a parameter:
$app['function_parameter'] = $app->protect(function ($resource) {
$content = file_get_contents($resource);
return $content;
});
$example = $app['function_parameter']('http://example.com');

The youtube API sometimes throws error: Call to a member function children() on a non-object

When i launch the php script, sometime works fine, but many other times it retrieve me this errror
Fatal error: Call to a member function children() on a non-object in
/membri/americanhorizon/ytvideo/rilevametadatadaurlyoutube.php on line
21
This is the first part of the code
// set feed URL
$feedURL = 'http://gdata.youtube.com/feeds/api/videos/dZec2Lbr_r8';
// read feed into SimpleXML object
$entry = simplexml_load_file($feedURL);
$video = parseVideoEntry($entry);
function parseVideoEntry($entry) {
$obj= new stdClass;
// get nodes in media: namespace for media information
$media = $entry->children('http://search.yahoo.com/mrss/'); //<----this is the doomed line 21
UPDATE: solution adopted
for ($i=0 ; $i< count($fileArray); $i++)
{
// set feed URL
$feedURL = 'http://gdata.youtube.com/feeds/api/videos/'.$fileArray[$i];
// read feed into SimpleXML object
$entry = simplexml_load_file($feedURL);
if (is_object($entry))
{
$video = parseVideoEntry($entry);
echo ($video->description."|".$video->length);
echo "<br>";
}
else
{
$i--;
}
}
In this mode i force the script to re-check the file that caused the error
You are first of all calling a function:
$entry = simplexml_load_file($feedURL);
That function has a return value. You find it documented on the manual page of that function:
http://php.net/simplexml_load_file
Then you use that return value in form of a variable $entry without verifying that the function call was successful.
Because of that, you run into an error next. However your error/mistake is how you treat the return value of the function.
Not dealing with return values properly is like calling for trouble. Read about the function you use, check the return value(s) and proceed according to success or error conditions.
$entry = simplexml_load_file($feedURL);
if (FALSE === $entry)
{
// youtube not available.
}
else
{
// that's what I love!
}
Sometimes? Really?
Take a look at this:
<?php
$dummy; //IN FACT, this var is NULL now
// Will throw exactly the same error you get
$dummy->children();
Why? Because, we can call method from an object type.
So, if you wanna avoid errors like this one, next time you would call the method ensure that it's "possible".
<?php
if ( is_object($dummy) && method_exists($dummy, 'children') ){
//sure it works
$dummy->children();
}

Content Type not being passed in functional test using sfBrowser in Symfony 1.4

The test is for a POST api endpoint where the data is contained in the body of the post as JSON. Prior to making the post call I set the Content-Type to 'application/json'. However, when I test the format isFormat('JSON') the response is null. If I dump the $request->contentType() this also produces null.
Any reason to why setHttpHeader('Content-Type','application/json') is not setting the header correctly during functional testing?
Your setting method is correct, but inside sfBrowserBase there is this bug:
foreach ($this->headers as $header => $value)
{
$_SERVER['HTTP_'.strtoupper(str_replace('-', '_', $header))] = $value;
}
that set content_type with prefix HTTP. But in your action $request->getContentType() method suppose that you don't have prefix.
so if you change this:
foreach ($this->headers as $header => $value)
{
$_SERVER[strtoupper(str_replace('-', '_', $header))] = $value;
}
you can make $request->getContentType() correctly!
You can find update here .
Right thanks to #nicolx I can explain more about what is happening and offer some further guidance.
As noted by #nicolx $request->getContentType() is looking for HTTP header without the prefix HTTP_ (see line 163 to 173 in sfWebRequest). However, sfBrowserBase always adds HTTP_ prefix to all headers. So add in this mod:
foreach($this->headers as $header => $value)
{
if(strotolower($header) == 'content-type' || strtolower($header) == 'content_type')
{
$_SERVER[strtoupper(str_replace('-','_',$header))] = $value;
} else {
$_SERVER['HTTP_'.strtoupper(str_replace('-','_',$header))] = $value;
}
}
That will deal with ContentType header being set and detectable in your actions. If you don't include the HTTP_ prefix the other headers won't work (e.g. $request->isXmlHtttpHeader() will fail even if you set this in the test file).
The test method isFormat() isn't testing the ContentType header but the Symfony route setting sf_format. If I set the route to specifically have sf_format: json e.g.
some_route:
url: /something/to/do
param: {module: top, action: index, sf_format: json}
then the test
with('request')->begin()->
isFormat('json')->
end()->
returns true.
As I wanted to test the header settings, I added a new tester method to sfTesterRequest called isContentType(). The code for this method is:
public function isContentType($type)
{
$this->tester->is($this->request->getContentType(),$type, sprintf('request method is "%s"',strtoupper($type)));
return $this->getObjectToReturn();
}
Calling this test simply becomes:
with('request')->begin()->
isContentType('Application/Json')->
end()->

Twitter - sign request fail

I'm trying to get a request signed with twitter so I can get a request token and got stuck. I have used the info that twitter use in their documentation to be sure that I have formated t correctly etc. I have identical Basestring and Key but still I'm not getting the same Signature. I have looked at several other examples and I seem to have done the same thing.
Would love some help to sort this out!
Here is the code:
private function sign_request($http_method, $url, $params, $oath)
{
// SET BASE STRING
$sign_params = $this->set_sign_params($params, $oath);
$sign_url = $this->set_sign_url($url);
$base_string = $this->set_sign_basestring($http_method, $sign_params, $sign_url);
print $base_string; // Output the same as the twitter example: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%3A%2F%2Flocalhost%3A3005%2Fthe_dance%2Fprocess_callback%3Fservice_provider_id%3D11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0
// GET HMAC-SHA1 SIGNATURE
if($this->signature_method == 'HMAC-SHA1')
{
// SET KEY
$key = $this->set_sign_key();
print $key; // Output the same as the twitter example: MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98&
//SIGN
$signature = base64_encode(hash_hmac('sha1', $base_string, $key, true));
print $signature; // DO NOT output the same as the twitter example. Twitteroutput: 8wUi7m5HFQy76nowoCThusfgB+Q= and my outout: Ewqbgi+AMRZGMcqwQTjhE5/ZD80=
}
return $signature;
}
What have I missed? Anyone got any Idea?
Also a "fun" thing is that if I set the signture to the one in the twitter example I still can't get a request token...
Thanks in advanced!
Your base string is not the same as Twitter's. That is why you are getting different signatures.
Twitter's:
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252Fthe_dance%252Fprocess_callback%253Fservice_provider_id%253D11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0
Your's:
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%3A%2F%2Flocalhost%3A3005%2Fthe_dance%2Fprocess_callback%3Fservice_provider_id%3D11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0
The difference is in the oauth_callback variable.
Twitter's:
oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252Fthe_dance%252Fprocess_callback%253Fservice_provider_id%253D11%26
Your's:
oauth_callback%3Dhttp%3A%2F%2Flocalhost%3A3005%2Fthe_dance%2Fprocess_callback%3Fservice_provider_id%3D11%26

Resources