CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • 5.0 Saloon »
  • Dependency Injection to abstract from presentation layer and persistence layer
Pages: [1]

Author Topic: Dependency Injection to abstract from presentation layer and persistence layer  (Read 1761 times)

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Dependency Injection to abstract from presentation layer and persistence layer
June 03, 2014, 08:32:55 pm
In working on a GSoC project for Voice Integration I thought it would be good to share code with a D8 version of VoIP Drupal for the 'application business logic' layer implementing VoIP functionality like voice broadcasting. This would require code for that layer that can work with D8 FAPI and D8 DBTNG, as well as with the civix code for the form layer and data persistence layer. We also will need to have a plugin approach for supporting different VoIP providers like Plivo and Twilio.

It seems like a software architecture we might want would make the presentation layer and the persistent layer into Symfony Service Containers, where either D8 or CiviCRM services would provide the presentation and persistence layers. But I haven't used these Symfony approaches before, and worry that it isn't appropriate to make the higher presentation layer a service of a middle layer. More appropriate it seems to me would be making the business logic layer into a service that is called from either civix extension code or D8 FAPI code, and which calls out to a persistence service that could be instantiated by a D8 service or a CiviCRM Doctrine based service.

Advice on whether this is over-complicated and over-abstracted, or whether it is a good model for potentially sharing code amongst a larger community would be appreciated. Also, advice from those with more experience in using Dependency Injection and Service Containers would be appreciated.
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Dependency Injection to abstract from presentation layer and persistence layer
June 04, 2014, 01:16:11 am
IIRC, Drupal-VOIP provided value on a few different fronts:
  (a) Drivers for different VOIP providers
  (b) Script engine for VOIP interactions. (This is necessary because HTTP is a series of stateless interactions -- but it's much easier to think of VOIP interactions as stateful/sequential.)
  (c) Small[?] apps which use the script-engine as well as FAPI, Node API, DBTNG, etc

My gut says that (a) and (b) would be amenable to packaging up as libraries that can be used in any PHP application or PHP framework (Drupal, Civi, Joomla, Symfony, etc) -- you could probably count on one hand the number of interfaces between the VOIP library and the host application. For example, perhaps a central part of the library is:

Code: [Select]
<?php
// FILE: Voip\VoipController.php
namespace Voip;
use 
Symfony\Component\HttpFOundation\Request as HttpRequest;
use 
Symfony\Component\HttpFOundation\Response as HttpResponse;

class 
VoipController {
  
/**
   * @param VoipDriverRepositoryInterface $drivers a list of active VOIP service providers
   * @param VoipScriptRepositoryInterface $scripts a list the available VOIP scripts
   * @param VoipSessionRepositoryInterface $sessions a service which can store data about
   *     on-going VOIP interactions
   */
  
function __construct($drivers, $scripts, $sessions) { ... }

  
/**
   * Process an incoming notification from a VOIP service. The notification
   * will be parsed and examined to determine if it is part of an on-going VOIP session
   * or a new session. When the session is determined, control will be passed to
   * the appropriate VOIP script. 
   *
   * @param HttpRequest $request
   * @return HttpResponse
   */
  
function receive(HttpRequest $request) { ... }
}

Any PHP application can instantiate VoipController and inject the required services. In a simple custom application, one might use hardcoded values:

Code: [Select]
<?php
// FILE: my-custom-voip-app.php
require 'vendor/autoload.php';
$controller = new \Voip\VoipController(
  
// Hard-code the details of our Twilio connection
  
new \Voip\SimpleDriverRepository(array(
    new \
Voip\TwilioDriver('myuser', 't0ps3cr3t')
  )),
  
// Load VOIP scripts from files
  
new \Voip\FileScriptRepository('/var/www/my-voip-scripts'),
  
// Store session-state in memcache using hardcoded connection info
  
new \Voip\MemcacheSessionRepository('localhost', '1234')
);
$request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
$response = $controller->receive($request);
$response->send();

For the Drupal-integration, the implementation of DrupalVoipDriverRepository could load a list of VOIP drivers from YAML files using D8's new config API, and the DrupalVoipScriptRepository could retrieve a list of scripts using Node API.

--

This gets you reuse of (a)+(b) (assuming that I remembered the concepts well), but it may or may not get to the holy-grail of reusing the mini-apps. It frankly depends on the app. For a simple app that's written entirely in VOIP-script and doesn't require any web UI, it could probably work anywhere. But if the VOIP-script needs to append data to a Civi contact record and display a report in the admin's web browser, then I don't think there's a general solution to making the app look Drupal-native *and* Civi-native. However, if we focus the discussion on the specific requirements for specific apps, then maybe we could find ways.

--

You may have noticed that I didn't exactly speak about how the VOIP package could access the dependency-injection system or the presentation-layer in D8 or Civi. That's not really an accident. A key part of the design-aesthetic shared by Symfony and the new crop of PHP frameworks is to encourage the development of loosely-coupled libraries that don't depend directly on any framework.

I don't want to say it's impossible to do an all-purpose abstraction of forms and persistence in Civi and Drupal, but... suffice to say it's not gonna happen in time for GSoC 2014. ;)

jaapjansma

  • I post frequently
  • ***
  • Posts: 247
  • Karma: 9
    • CiviCoop
  • CiviCRM version: 4.4.2
  • CMS version: Drupal 7
  • MySQL version: 5
  • PHP version: 5.4
Re: Dependency Injection to abstract from presentation layer and persistence layer
June 04, 2014, 01:52:41 am
As an experienced Symfony developer I do agree with Tim's approach.

I have only one concern. And Tim also mentions this, the new way Symfony and other framework works is that they abstract a lot and this leads to loose coupled modules. So I wouldn't be to bother about the form injection etc... I would create a module which does what it should without any user input (but rather as an interface). Then you could create another module which depends on the pervious module and probably depends on twig or dupal or civi and in this module you create the UI. That way you have extracted the UI and the functionality from each other.

In the interface module you add functionality to add drivers which comply to an interface so that the real implementation is also backend independend.

I hope you get the poin which is as soon as you are worried about dependencies you should break up your module and create interfaces for the different dependencies.
Developer at Edeveloper / CiviCoop

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Dependency Injection to abstract from presentation layer and persistence layer
June 04, 2014, 05:36:29 am
Thanks totten and jaapjansma for the useful feedback. We'll come back with more specific questions perhaps.

Cheers!
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Dependency Injection to abstract from presentation layer and persistence layer
June 04, 2014, 02:55:18 pm
Joe - you mentioned D8 - if you want to fire Civi up with D8 Torrance's code is here https://github.com/torrance/civicrm-drupal
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Dependency Injection to abstract from presentation layer and persistence layer
June 05, 2014, 11:38:15 am
Thanks, Eileen. VoIP Drupal hasn't started on a D8 branch, and we are hoping to collaborate on this with them.
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • 5.0 Saloon »
  • Dependency Injection to abstract from presentation layer and persistence layer

This forum was archived on 2017-11-26.