3

I'm using AngularJS one of my module's settings page, so I have a javascript object in client side as a model. Could anyone help me please, how to catch this data in a controller if I send it as JSON with ajax?

This is the model I assembled is angular:

var model = {
  title: 'This is a title',
  url: '/random-custom-url',
  description: 'little descrp',
  blocks: [
    {id: 1, name: 'block1', description: 'blockdecrtiption1', terms: [{"tid":"1","name":"term1","vid":"tags"}]},
    {id: null, name: 'block2', description: 'blockdecrtiption2', terms: []},
    {id: 3, name: 'block3', description: 'blockdecrtiption3', terms: []}
  ]
};

I'd like to "catch" it in a controller's function(as a php associative array), so then I can process it and save to database(I have some own table in the database, created in the module's hook_schema()). What's the right route setup for this? In the controller's function how can I get the data posted with ajax and how to convert it to associative array?

Thanks a lot!

  • This is way too broad to answer; I am not calling for close because it has the chance of being a very good question. What sort of data? Are you, say, creating an entity? – user49 Jul 27 '14 at 23:17
  • Thanks for the response, I edited my question, hope it will be ok. – Peter Hurtony Jul 28 '14 at 0:07
5

Simply put: do not do this! Do not create your own table; that's not the way in Drupal 8. Much rather, have your own entity type. See https://drupal.stackexchange.com/a/95208/49 https://www.drupal.org/developing/api/entity https://api.drupal.org/api/drupal/core%21modules%21system%21core.api.php/group/entity_api/8 for more. The storage controller will generate the SQL schema for you and do all the storage work. The REST module will handle what you need. And so on.

Edit: For a generic case to receive and reply with JSON. First make sure there's not a Drupal API for it. Likely there is. REST gives you entities, Views gives you lists of entities (and lists of more).

If not then, you need to write a custom controller with the request as an argument. (see Parameters in routes for more) by just adding Request $request as an argument.

To respond with JSON, any Response object, among them JsonResponse. Check TimezoneController::getTimeZone and the relevant routing entry in core/modules/system/system.routing.yml.

So:

class MyController {
  public function myJson(Request $request) {
    $params = array();
    $content = $request->getContent();
    if (!empty($content)) {
      // 2nd param to get as array
      $params = json_decode($content, TRUE);
    }
    // Process $params...
    return new JsonResponse($params);
  }
}
  • Okey, that's quite good, but it's not exactly what I'm looking for. This is not a bad solution for this exact problem, but let's forget about this model and entities. How can I make an endpoint for my javascripts that waits for json(or just a http get), and responds with json for the ajax calls? Thanks a lot! – Peter Hurtony Jul 28 '14 at 9:49
  • Added the how to do those things. – user49 Jul 28 '14 at 10:49
9

In case you want to do it more the D8 way here is a rough outline what you could do, which allows you to be flexible without the requirement to do everything in your own. A proper rest integration requires you to work with all the different HTTP status codes, header fields etc. Rest takes partly care of that

The rest module provides a generic abstraction for REST, not tight to entities in the first place. Entities are just one example.

First you should register your rest plugin, like every other plugin:

namespace Drupal\pinguin\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;

/**
 * Provides a resource for database watchdog log entries.
 *
 * @RestResource(
 *   id = "pinguin",
 *   label = @Translation("Example rest plugin for pinguins"),
 *   uri_paths = {
 *     "canonical" = "/pinguin/{id}"
 *   },
 *   serialization_class = "Drupal\pinguin\PingInterface"
 * )
 */
class Pinguin extends ResourceBase {
}

If you do an updating request like PUSH or UPDATE, it uses the serializer component to convert your data into some php array/ object. It uses two steps in order to do that. First the data incoming is decoded, for example from JSON into a PHP array. The next step is the denormalization. This step converts the denormalized data (PHP array) into a domain object, for example the Ping (a single pinguin).

The first step is to specify the resulting class in the annotation (see above). To register a new denormalization you add the following entry into your .services.yml:

services:
  pinguin.denormalizer.pinguin:
    class: Drupal\pinguin\normalizer\PinguinDenormalizer
    tags:
      - { name: normalizer }

This normalizer specifies which interface it can convert to:

<?php

namespace Drupal\pinguin\normalizer;

use \Drupal\serialization\Normalizer\NormalizerBase;

class PinguinDenormalizer extends NormalizerBase {

   // IMPORTANT
   /**
    * The interface or class that this Normalizer supports.
    *
    * @var array
    */
    protected $supportedInterfaceOrClass = array('Drupal\pinguin\PingInterface');

    /**
    * {@inheritdoc}
    */
    public function denormalize($data, $class, $format = NULL, array $context  = array()) {     
      // Validate the data.
      if (empty($data['location']) || $data['location'] == 'northpole') {
        throw new \UnexpectedValueException("this can't be real pinguins");
      }

      // create the domain object.
      return new Ping($data['name'], $data['location'], $data['family']);
    }
 }

Once this serialization is done, it calls a method named after the HTTP method on the plugin class, so for example "post". There you can do whatever you want.

<?php
class Pinguin extends ResourceBase {
  public function post(PingInterface $ping) {
    // deal with the data, save it for example.
    $ping_storage->save($ping):
  }
}

The advantages of these abstractions are that you don't have to deal with the incoming format but on the other hand it needs a bunch of code to get started.

  • Thanks so much, I spent so much time banging my head against the wall on this. For the record, I think this is a little out of date. To get this working I had to make the following changes: 1) MyNormalizerClass must implement the DenormalizerInterface. 2) MyNormalizerClass must implement the following methods, in addition to those you named: normalize, supportsNormalization, supportsDenormalization – Matt Korostoff Sep 19 '16 at 20:26
4

In the controller's function how can I get the data posted with ajax and how to convert it to associative array?

use Drupal\Component\Serialization\Json;
//...
class MyController {
  public function myPostAction(Request $request) {
    $params = Json::decode($request->getContent());
    //...
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.