`Unexpected token < in JSON` error when passing PHP array to JSON - wordpress-rest-api

If anybody can point me in the right direction on this one, I will be eternally grateful!
I’m playing around with the WordPress register_rest_field() function (for the first time) to add a custom field to an existing endpoint in the Rest API.
Here is the snippet where I’ve registered my field:
register_rest_field(
'country',
'featured_post',
array(
'get_callback' => 'dd_return_featured_sound'
)
);
And here is the callback function:
function dd_return_featured_sound( $object, $field_name, $request ) {
$posts = get_field( 'featured_sound', $object['taxonomy'] . '_' . $object['id'] );
$post = $posts[0]; // $posts is an array, but there is only 1 featured post
return array(
'link' => get_the_permalink( $post ),
'title' => get_the_title( $post ),
'terms' => get_the_terms( $post, $object['taxonomy'] ),
'image' => get_the_post_thumbnail( $post )
);
}
The problem is that I keep getting the following error in the console:
Uncaught SyntaxError: Unexpected token < in JSON at position 0
Here’s the relevant snippet of the js:
if (request.status >= 200 && request.status < 400) {
const data = JSON.parse(request.responseText);
// if there are terms to show
if (data.length) {
data.forEach(term => {
console.log(term);
});
}
}
I’ve been trying to work this one out for the a couple of hours now and I’m close to tearing my hair out (I have a healthy head of hair and would very much like to keep it that way).
If anybody can help at all, like I said before, I'd be eternally grateful!

Solved. Literally banging my head against the desk in disbelief at the fact that I didn’t realise this right away…
It transpires that the featured_sound field is in fact not mandatory, so naturally everything broke in the callback function when trying to get [0] of a non-existent array.

Related

Drupal Node comment redirection when validation fail

I've been banging my head on this trying to find a solution, searching all around for something that would work, but I got no chance.
I have a "dashboard" where users have a list of event they took part in where they can rate/comment the event. I'ts basically a custom comment form for a node that is not displaying on the node page itself. The user click on an icon in their dashboard next to the event they want to comment, they get to the form, fill it and it returns them back to the dashboard. The return is adding parameters with a custom submit function and using the redirect function to make sure the user return to the proper tab in their dashboard.
function custom_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'comment_node_event_form') {
$form['#submit'][] = 'customcomment_form_submit';
}
}
function customcomment_form_submit($form, &$form_state) {
if($form['#form_id']=='comment_node_event_form'){
$pos = strpos($_SERVER['HTTP_REFERER'], 'qt-dashboard');
if ($pos !== FALSE) {
$form_state['redirect'] = array(
'dashboard',
array(
'query' => array(
'qt-dashboard' => '2',
'qt-dashboard_event' => '2',
),));
}else{
$form_state['redirect'] = array(
'dashboard',
array(
'query' => array(
'qt-dashboard' => '2',
'qt-dashboard_event' => '1',
),));
}
}
}
This portion is working as it should and expected. The problem is when form validation fails, it send the comment form error message and form to refill to the node page instead of staying where it is.
I found that if I set the #action with the link where my comment form is, it does send the fail to the proper page
$form['#action']='/rating_comment/'.$form['#node']->vid.'?destination=dashboard&qt-dashboard=2&qt-dashboard_event=2';
But, doing so break the redirect when successfully submitting the form and it doesn't take the parameter in the redirect..it basically send the user directly to dashboard and scrapes the parameter. Now there might be a better solution for form validation fail to stay on the same page and that is pretty much what I am looking for.
Thanks
Looks like this form isn’t in your module - and you’re altering the other module.
Now, when the validate function gets invoked at the end you can check for failure and if there is failure cancel processing/redirect etc.
$form_state['no_redirect'] = FALSE:
Also, you can use the error function to check for errors and if so cancel the rest. This goes inside validate method.
if (form_get_errors()) { return FALSE ; }
// .. Otherwise, process validation
Check out the following
https://drupal.stackexchange.com/questions/170815/is-it-possible-to-stop-a-webform-form-during-submission
https://drupal.stackexchange.com/questions/5861/how-to-redirect-to-a-page-after-submitting-a-form

Can someone provide a php sample using nusoap/sugarcrm api to create an acct/lead in sugarcrn?

Can someone provide a sample code chunk of php using the sugarcrm API/nusoap for adding creating an acct. and then linking a lead to the acct?
I've got a sample function that adds a lead, and I can see how to create an acct, but I can't see how to tie a lead to the acct, to simulate the subpanel process in the sugarcrm acct/subpanel process.
thanks
// Create a new Lead, return the SOAP result
function createLead($data)
{
// Parse the data and store it into a name/value list
// which will then pe passed on to Sugar via SOAP
$name_value_list = array();
foreach($data as $key => $value)
array_push($name_value_list, array('name' => $key, 'value' => $value));
// Fire the set_entry call to the Leads module
$result = $this->soap->call('set_entry', array(
'session' => $this->session,
'module_name' => 'Leads',
'name_value_list' => $name_value_list
));
return $result;
}
$result = $sugar->createLead(array(
'lead_source' => 'Web Site',
'lead_source_description' => 'Inquiry form on the website',
'lead_status' => 'New',
'first_name' => $_POST['first_name'],
'last_name' => $_POST['last_name'],
'email1' => $_POST['email'],
'description' => $_POST['message']
));
You need to find the ID for the account and assign that ID to whatever the account_id field name is in the Lead Module. I have run into a couple things like this before and I have found it easier to go straight to the Sugar database. So, write a statement that will return the account is, for example: SELECT id WHERE something_in_the_account_table = something else;
Then you can assign that id in your $result array. I hope it helps. I didn't have any code or documentation in front of me or I would have helped more.

zf2 restful not reach update method

I made a restful controller that if I send the id the get method receives it. But when I update a form I expect the update method to process but I cant get to the right config for this and after 1 day with this issue I decided to right it down here.
Here the code involved
route in module config:
'activities' => array(
'type' => 'segment',
'options' => array(
'route' => '/activities[/:id][/:action][.:formatter]',
'defaults' => array(
'controller' => 'activities'
),
'constraints' => array(
'formatter' => '[a-zA-Z0-9_-]*',
'id' => '[0-9_-]*'
),
),
),
Head of controller:
namespace Clock\Controller;
use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\Mvc\MvcEvent;
use Zend\View\Model\ViewModel;
use Zend\Form\Annotation\AnnotationBuilder;
use Zend\Form;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Clock\Entity\Activity;
use \Clock\Entity\Project;
Wich contains the get method:
public function get($id)
{
$entity = $this->getRepository()->find($id);
$form = $this->buildForm(new Activity());
#$form->setAttribute('action', $this->url()->fromRoute("activities", array('action' => 'update')));
$form->setAttribute('action', "/activities/$id/update");
$form->bind($entity);
return array(
"activities" => $entity,
"form" => $form
);
}
That feeds this view:
<h3>Edit activity</h3>
<div>
<?php echo $this->form()->openTag($form);?>
<?php echo $this->formSelect($form->get("project"));?><br>
<?php echo $this->formInput($form->get("duration"));?><br>
<?php echo $this->formInput($form->get("description"));?><br>
<input type="submit" value="save changes" />
<?php echo $this->form()->closeTag($form);?>
</div>
After sending it, I expect update method in activities to take control, but I get:
A 404 error occurred
Page not found.
The requested controller was unable to dispatch the request.
Controller:
activities
EDIT:#DrBeza
This is what i get, that i think (not a master in routes) is right:
Zend\Mvc\Router\Http\RouteMatch Object
(
[length:protected] => 21
[params:protected] => Array
(
[controller] => activities
[id] => 30
[action] => update
)
[matchedRouteName:protected] => activities
)
--
That's it.
Any help?
Quick Fix
The RouteMatch object tries to dispatch ActivitiesController::updateAction but you have defined ActivitiesController::update
That's due to you using a Restful Controller. the Controller::update-Method is specifically tied to PUT-Requests. You need to define an extra method to handle updates via POST-Requests.
I suggest you define ActivitiesController::updateAction, make clear in the docblock it is meant to handle POST-Update requests and refactor both ::updateAction and ::update to share as much common helper-methods as possible for a fast solution.
Common URI Structur information
As a nice information to have when you start developing RESTful applications/APIs:
The ruby community suggests the following url-structure for your resources:
# These are restful
/resource GET (lists) | POST (creates)
/resource/:id PUT (updates) | DELETE (deletes)
# these are just helpers, not restful, and may accept POST too.
/resource/new GET (shows the create-form), POST
/resource/:id/edit GET (shows the update-form), POST
Detailed Problem Analysis
A restful update will be sent by an consumer via PUT, but browsers sending HTML-forms may only send GET or POST requests. You should never use GET to create something. So you have to use POST in a forms-context.
Looking at the problem from an architectural perspective a multitude of possibilities emerge, depending on how big your application is.
For a small application, tight integration (formhandling and API handling in the controller) apply best.
Getting bigger you may want to split up API-Controllers (only restful actions) from Helper-Controllers (form, website handling) which talk to your API-Controllers
Being big (multitude of API-Users) you will want to have dedicated API Servers and dedicated Website Servers (independent applications!). In this case your website will consume the API serverside (thats what twitter is doing). API Servers and Website Servers still may share libraries (for filtering, utilities).
Code Sample
As an educational example I made an gist to show how such a controller could look like in principle. This controller is a) untested b) not production ready and c) only marginally configurable.
For your special interest here two excerpts about updating:
/* the restful method, defined in AbstractRestfulController */
public function update($id, $data)
{
$response = $this->getResponse();
if ( ! $this->getService()->has($id) )
{
return $this->notFoundAction();
}
$form = $this->getEditForm();
$form->setData($data);
if ( ! $form->isValid() )
{
$response->setStatusCode(self::FORM_INVALID_STATUSCODE);
return [ 'errors' => $form->getMessages() ];
}
$data = $form->getData(); // you want the filtered & validated data from the form, not the raw data from the request.
$status = $this->getService()->update($id, $data);
if ( ! $status )
{
$response->setStatusCode(self::SERVERSIDE_ERROR_STATUSCODE);
return [ 'errors' => [self::SERVERSIDE_ERROR_MESSAGE] ];
}
// if everything went smooth, we just return the new representation of the entity.
return $this->get($id);
}
and the editAction which satisfies browser-requests:
public function editAction()
{
/*
* basically the same as the newAction
* differences:
* - first fetch the data from the service
* - prepopulate the form
*/
$id = $this->params('id', false);
$dataExists = $this->getService()->has($id);
if ( ! $dataExists )
{
$this->flashMessenger()->addErrorMessage("No entity with {$id} is known");
return $this->notFoundAction();
}
$request = $this->getRequest();
$form = $this->getEditForm();
$data = $this->getService()->get($id);
if ( ! $request->isPost() )
{
$form->populateValues($data);
return ['form' => $form];
}
$this->update($id, $request->getPost()->toArray());
$response = $this->getResponse();
if ( ! $response->isSuccess() )
{
return [ 'form' => $form ];
}
$this->flashMessenger()->addSuccessMessage('Entity changed successfully');
return $this->redirect()->toRoute($this->routeIdentifiers['entity-changed']);
}
That error message suggests the dispatch process is unable to find the requested controller action and therefore using notFoundAction().
I would check the route matched and make sure the values are as expected. You can do this by adding the following into your module's onBootstrap() method:
$e->getApplication()->getEventManager()->attach('route', function($event) {
var_dump($event->getRouteMatch());
exit;
});

SoundCloud API: Tweeting on upload and disable comments

The following PHP code uploads a new track to SoundCloud successfully, but the tweet is not sent.
Is there something I need to have in there as well in order to do this?
$track = $soundcloud->post('tracks',
array(
'track[asset_data]' => '#audio.mp3',
'track[title]' => "my audio",
'track[description]' => "Updated: " . date('l jS F Y h:i:s A'),
'track[sharing]' => 'public',
'track[shared_to][connections][][id]' => '123',
'track[sharing_note]' => 'Have a listen to'
));
Also I'd like to be able to disable comments on the audio I upload, but I wasn't sure what the parameter for that would be too?
Thanks!
dB
I'm unable the repro the sharing problem. Please note that sometimes sharing on other social networks doesn't happen right away. Are you still having trouble? Here's the code I used:
<?php
require_once 'Services/Soundcloud.php';
$client = new Services_Soundcloud("foo", "bar");
$client->setAccessToken('ACCESS_TOKEN');
$track = $client->post('tracks', array(
'track[title]' => 'Foooo',
'track[asset_data]' => '#/Users/paul/audio.wav',
'track[sharing]' => 'public',
'track[shared_to][connections][][id]' => 'CONNECTION_ID',
'track[sharing_note]' => 'Check it out'
));
print_r($track);
Also verify that your CONNECTION_ID is correct. Some code to get a list of connections so you can verify the id:
<?php
require_once 'Services/Soundcloud.php';
$client = new Services_Soundcloud("foo", "bar");
$client->setAccessToken('ACCESS_TOKEN');
print_r(json_decode($client->get('me/connections')));
Unfortunately there's no way currently to disable comments via the API. I'll file a bug and see about getting this fixed.
Hope that helps!

How to handle the big int facebook uid returned by FQL?

I've a problem in handling the big userid's of facebook and properly storing them into my database..
As the fql.query REST api is going to be deprecated ,I'm using the GRAPH API for getting the results of the FQL.
I want to get the list of my friends with sex,relationship_status .
The query i executed is
$allFriends = $facebook->api("/fql
?q=SELECT+uid,+name,+sex,+relationship_status+FROM+user+where+uid+in+
(SELECT+uid2+FROM+friend+WHERE+uid1+=$fbuid)"
);
I tried the above in the Graph API explorer and the result is something like this,
{
"data": [
{
"uid": 100003082853071,
"name": "Sam jones",
"sex": "male",
"relationship_status": null
}
]
}
Note the uid is returned as int, so whenever i print the array itself it has values like (1.34234422 +E03). So even json_encode for that array doesn't help.
But when i call the GRAPH API directly something like 'graph.facebook.com/1585213/friends' that returns the data as
{
"data": [
{
"name": "Vijay Kannan",
"id": "102937142343"
}
]
}
Note the id is returned as string..
Whenever I'm using the graph API call for FQL query, it returns the whole data as an 'Array' ,so the long big facebook uid's are transformed to a float like (1.34234422 +E03) .
How can i convert them into proper uid's and store/process them back.
I think the inconsistency of FQL and GRAPH API call should be also taken care by Facebook .. But i could not wait for that!!
Any ideas on this?
I tried most methods and after Google some more forums and facebook code list if found the following worked like a charm for me.
After i get the results from a FQL query i used the following line of code,
$friends = json_decode(preg_replace('/"uid":(\d+)/', '"uid":"$1"', $result),true);
// consider $result as the result rendered by the FQL query.
When i use the file_get_contents for a FB call you could have seen the error with error codes, so the best way to go with that is using CURL for all the FB API calls whenever necessary.
Please find the complete code i've used to get proper results,
$access_token = $facebook->getAccessToken();
$request_url ="https://graph.facebook.com/fql
?q=SELECT+uid,+name,+sex+FROM+user+where+uid+in+
(SELECT+uid2+FROM+friend+WHERE+uid1+=$fbuid)".
"&access_token=".$access_token;
$opts = array(
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_USERAGENT => 'facebook-php-3.1',
CURLOPT_CAINFO => /lib/fb_ca_chain_bundle.crt',
//replace the above path with proper path of the crt file
//in order to avoid the exceptions rendered by FB
//when we try to use CURL without proper certification file.
);
$opts[CURLOPT_URL] = $request_url;
if (isset($opts[CURLOPT_HTTPHEADER])) {
$existing_headers = $opts[CURLOPT_HTTPHEADER];
$existing_headers[] = 'Expect:';
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
} else {
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
}
$ch = curl_init();
curl_setopt_array($ch, $opts);
$result = curl_exec($ch);
if ($result === false) {
$e = new FacebookApiException(array(
'error_code' => curl_errno($ch),
'error' => array(
'message' => curl_error($ch),
'type' => 'CurlException',
),
));
curl_close($ch);
throw $e;
}
curl_close($ch);
$friends = json_decode(preg_replace('/"uid":(\d+)/','"uid":"$1"',$result));
I just to post this answers so it may help others until Facebook resolve this inconsistency.
There are two things very consistent about Facebook. They are: 1) changing their APIs at their whim without any headsup. 2) Inconsistency between graph and fql objects.
As you have indicated, the unquoted values returned from Facebook are always long's (aka big int, aka Int64). And the quoted values are string representations of the long value.
What it appears to me is that the $facebook->api call is munging the longs into floats. I'd suggest logging it as a bug with the $facebook->api team.
In the interim while they fix that bug, you can code your own code to do the HTTP post to the graph and parse the returned results. I don't encounter this issue with the C# API, nor with the Javascript API.
If youre using php (http://php.net/manual/en/function.sprintf.php):
printf("%14.0f", 1.00000145202E+14);
outputs:
100000145202000
Javascript:
parseFloat('1.00000145202E+14')