I need to consume a rest API in my Drupal website and display the data as a table. Can you suggest me to how to do that ?
I am new to Drupal so need to know where I need to add the custom code to fetch data and also I went through couple of modules but still did not get the clear picture on how to do it.
For Drupal 7 it was drupal_http_request however for Drupal 8, you can use Guzzle for that. You can find more detail with example here
https://www.drupal.org/node/1862446
For consuming REST GET request
<?php
/**
* #file
* Contains \Drupal\testmodule\Controller\TestController.
*/
namespace Drupal\testmodule\Controller;
use GuzzleHttp\Client;
public function current_contentp(){
$client = new Client();
$json = $client->get('https://catfact.ninja/breeds')->getBody()->getContents();
//..
}
Related
I'm trying to implement in my symfony project some api. Currently the project have many controller with standard crud, based on html table, form/validator etc.
I'm looking to the api-platform project that seam to make very easy the construction of standard rest api, and for the GET part it fit my necessities.
But for the POST/PUT/DELETE part it seam a very basic persist action on an entity, and suddenly in my project, i need to do many more actions after the persist of the entity.
I've red the docs and I'm really confused on how to do that...
I see two possibilities:
Using the event system, subscribing for the POST_WRITE for every entities
Creating a custom action for every create/update/delete actions of an entity
In both the case, I would have a really high number of single actions or event subscriber in the project (30/40), and it's really unconfortable to maintain. Also I probably have to replicate the same code that I already have in the controller, to maintain the old form system until is all rewitten in an API format.
Any suggestion on how to approach this problem?
There isn't a way to use the same controller actions, like in the FOSRestBundle, so that I can receive the data, do the various validation/persist/extra actions, and then return a result that is managed by the api-platform events?
Any way to manually call some part of the api-platform, like the deserialization/serialization, the filter and pagination from a standard controller action?
Thanks to all
Cheers
Daniele
Forgive me if I do not completely understand your question but if you already have the functionality written in the controller and you want to access the same actions via an api then maybe you can set multiple routes on each action and depending on how the action was called you can respond differently. For example:
/**
* #Route("/api/v1/tester", name="api_tester")
* #Route("/tester", name="tester")
*/
public function testerAction( Request $request )
{
$route = $request->attributes->get('_route');
if( $route == "api_tester" )
#..do things the api way
response = array( "success" => 1, "data" => $return_string );
return new Response( json_encode( $response ) );
} else { //non-api
$this->render('tester/basic.html.twig', array();
}
}
You can evaluate which route was used and in various sections of your actions you can handle things differently based on if the action was called via the api or from a normal request.
What is the best way to check whether a request is an API request?
Note that the request might be a custom API request, which means it may be as follows:
mysite.com/wp-json/my_namespace/my_version/my_action
Obviously, I can check whether the API route wp-json, but there should be a built-in function to check that.
I need it to do some hooks such as
add_action('init', 'do_something_only_if_api_request');
function do_something_only_if_api_request()
{
if ( ! wp_api_request() ) {
return;
}
// do stuff
}
You can check defined('REST_REQUEST'). This constant is defined as true in rest_api_loaded() (and not defined otherwise).
There was a discussion of WP Rest API developers about the introduction of a new function like is_rest_request(). In the end they went for this constant.
As of December 2016, the REST API documentation is pretty poor regarding everything which doesn't look like an endpoint.
However, a few functions exist and you can find the documentation right in the file as they're very well documented, see: wordpress/wp-includes/rest-api.php
If you want add an action only on an REST API call then you probably want to hook the action: rest_api_init, it would look like:
add_action('rest_api_init', 'do_something_only_if_api_request');
function do_something_only_if_api_request($wp_rest_server)
{
// do stuff
}
You can find the details in the PHPdoc comment:
/**
* Fires when preparing to serve an API request.
*
* Endpoint objects should be created and register their hooks on this action rather
* than another action to ensure they're only loaded when needed.
*
* #since 4.4.0
*
* #param WP_REST_Server $wp_rest_server Server object.
*/
In my case, the plugin is doing wp_redirect for users to login page.
I want to avoid this in case that the rest api is called.
So I'm using
if (! strpos( $_SERVER['REQUEST_URI'], 'wp-json')) // It's not a rest-api call
Currently, my symfony 1.4 app is using the myUser class. But I need to override the behaviour of this class to work with a single plugin. As it is not the proper way to change the base code, I would like to know whether there is a way to extend the myUser class and use it with my plugin?
What I am trying to achieve is, keeping a separate session timeout for my plugin. In order to do so, I have to separate the http requests of other plugins from the http requests of my plugin. If there is another way of achieving this, it is even better. Thanks!
Look to see if there is a myUser.class.php file in the lib folder of your app. If there isn't create one and in it add:
<?php
class myUser extends sfBasicSecurityUser
{
}
?>
Or if you are using sfGuardPlugin:
<?php
class myUser extends sfGuardSecurityUser
{
}
?>
Then clear the cache.
You will be able to use it with your plugin.
As far as the session expiration goes. It's not clear what kind of information your plugin is managing. Can't you just expire the information at a certain point? Symfony allows you to save session data to different namespaces. (The example below uses 'plugin_info'.) Can't that namespace have an expiration time?
Example:
$this->setAttribute('plugin_expiration', time() + 1000, 'plugin_info');
$expiration = $this->getAttribute('plugin-plugin_expiration', time() + 1000, 'plugin_info');
if ($expiration > time())
{
$this->getAttributeHolder()->removeNamespace('plugin_info');
// then restart the session here.
}
A project I am working on contains a search feature. I would like users to have the ability to bookmark a page along with their query so they can bookmark their search page.
In the traditional implementation, I simply used GET parameters in the URL.
However, with symfony I am having a hard time understanding what is best to use for this functionality? is it just a matter of preference?
Should I just create a controller such as:
search/{query}/{page}
and when a user clicks on an option
description/{id}
or should I implement the traditional get variable in the URL:
Note the URL's on Stack Overflow, for example. When you search for something and you navigate the pages, the URL is something like:
search?q="nav&page=2 But then when you click on a post the URL becomes something like questions/19157969/expanded-navigation-by-default, so it is kind of a mix of the two.
Couldn't SO use something like search/search-term-here/2 for the same functionality? is there any benefit for picking GET over the alternative, using Symfony?
I appreciate any suggestions! many thanks in advance!
It is a matter of preference. Some say that the URL is more important than the query string for SEO purposes. Also, /search/{query}/{page} is better looking in general, but that's just my opinion.
Search terms can get very long. Perhaps your searching mechanism is fairly simple, but personally I wouldn't want to make that assumption, especially if you plan on using the same feature for something in future you haven't designed the scale of yet.
Using a typical GET string is safe enough in my opinion, the controller should know what variables it needs, and GET queries generally don't (shouldn't) have an impact on routing.
However if you want to achieve pretty search URLs which can always be revisited, you could try storing each search in a database.
An example (untested):
class SearchController extends Controller
{
/**
* #Route("/search" name="search")
* #Method("GET")
*/
public function searchAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$search = new Search();
$search->setQuery($request->query);
// The query field would be of an object type in this example,
// but you could store the data any way you want really.
// Add any additional information about the search/request to the entity.
$em->persist($search);
$em->flush();
$this->redirect($this->generateUrl('search_results', array(
'search_id' => $search->getId()
)));
}
/**
* #Route("/search/{search_id}", name="search_results")
* #Method("GET")
* #Template()
*/
public function resultsAction($search_id)
{
$em = $this->getDoctrine()->getManager();
if(! $search = $em->getRepository('AcmePostBundle:Search')) {
throw $this->createNotFoundException();
}
$query = $search->getQuery(); // This will be a ParameterBag
// Run your search filters
return array(
// Your search results
);
}
}
In this example the request is to an action with a GET string as normal (could be POST if you prefer), which saves the search data and then redirects to an action which gets the search data from the database, does its filtering and show the results.
I can't see any real performance loss in a technique like this, the database queries to insert and select the search should be relatively small, but I can see the table in which you store them getting very full very quickly.
Then again it is always useful (occasionally) to draw reports on popular search terms.
I have organic groups setup and within those group users are allowed to post certain content.
What I woulkd like to do is, when you create a node inside an organic group, it automatically defaults back to frontpage of the group, or the same page that I used to create the node.
At present it defaults to the node view page.I assume there must be a way to add some kind of code so that after the node creation it defauls back to its origin. I.E. the page from where the node was created from.
thanks :)
UPDATE: Got the below, but not entirly sure how to ensure that it redirects back to the GROUP node, from where it was created,
<?php
/**
* Grabs current node ID
*/
$node_nid = nid;
/**
* Implements hook_form_alter().
*/
function mod_form_alter(&$form, $form_state) {
$form['buttons']['submit']['#submit'][] = 'mod_form_finish_redirect';
unset($form['buttons']['preview']);
}
/**
* Custom submit handler. Overwrites the form redirection variable.
*/
function mod_form_finish_redirect($form, &$form_state) {
$form_state['redirect'] = '/content/<?php print $node_nid; ?>';
}
?>
I would recommend the rules module. Rules is a great module that allows you to do many kinds of workflow and it is perfect for this. You can write a rule that triggers when a specified node type is created (and include any other conditions you require as well). After the node is created you can specify a redirect action rule to the home page. This can all be done without any code.
Rules (as 'We Love Drupal' says) is a possibility, but also quite a big module for such a small change in behavior. Another option is to write a custom module implementing hook_form_alter setting the #redirect value of the form.
Keep in mind that of seeing the node you have just created is important feedback for a user. When you perform an action, you want confirmation that you have achieved your task. While it's technically possible to do what you ask, it may be bad for usability.
I had the same requirment. Rules worked for me.