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 »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • API v3 - a dead end?
Pages: [1]

Author Topic: API v3 - a dead end?  (Read 1670 times)

donquixote

  • I post occasionally
  • **
  • Posts: 42
  • Karma: 3
  • CiviCRM version: none
  • CMS version: Drupal
  • MySQL version: 5
  • PHP version: 5.2
API v3 - a dead end?
February 22, 2011, 12:26:30 pm
I (temporarily?) joined the CiviCRM development on the code sprint in Bxl, when it had been already decided how the new API v3 should look like.
The plan was to make the v2 naming scheme of civicrm_[entity]_[action] more rigid. Fine.

Part of the plan was:
- v3 will have function names that already existed in v2, just with a different (more consistent) signature and behavior.
- we keep both v2 and v3 in place. We want that old code can still use v2, while new code can use v3.

The consequence:
- v2 and v3 will have terrible name clashes, if we include them together.
- we can only ever use one API version in one request.
- in any request, the first time the api is used, we have to pick a version. there is only one chance for the calling code to have a say in choosing that version. After that, the decision is done.
- all code that we write needs to work with any of the two versions.

Anything that I have committed to svn since then was based on this plan, trying to make the impossible possible. And I guess it worked, somewhat.

But:
Thinking more about this, I get the idea that no matter how nicely we wrap the api version, this move is bound to be a dead end. Having two versions of code that can not be used together is just asking for trouble, and gonna cause a ton of problems. If not now, then later. Yes it's gonna explode.

And most importantly, what worth is an api that needs to be wrapped, and abstracted away? An API is supposed to be the reliable interface of a system. If we have to wrap that, we did something wrong.

--------------

Here is what I suggest.
- Yes, let's keep v2 in place for any code that wants to use it.
- The new API v3 needs function names that do not clash with v2.
- This means, goodbye to civicrm_[entity]_[action]. These names are already spoiled by v2 with its inconsistent signatures and behavior.
- If we already make up new names, then why not go one step further and be more generic? Make something like civicrm_api() the new public thing. Or if we want, add some method chaining, so we can write civicrm_api('contact')->create($values).

Public API:
We can allow one or more of the following:

civicrm_api('contact', 'create', $values);
civicrm_api()->create('contact', $values);
civicrm_api('contact')->create($values);
civicrm_api()->getApi('contact')->create($values);

// class X wants a civi api injected.
$civi_entity_gateway = civicrm_api();
$x new X($civi_gateway);
class X {
  [..]
  function foo() {
    [..]
    $this->_civiGateway->create('contact', $values);
  }
}

class Y wants a civi contact api injected.
$civi_contact_gateway = civicrm_api('contact');
$x new X($civi_contact_gateway);
class X {
  [..]
  function foo() {
    [..]
    $this->_contactGateway->create($values);
  }
}

We could rename civicrm_api() to something else, if we like to do so.

-------------

Entity-specific implementation functions / classes

The generic api functions would try to find a function with a specific name.
Example:
civicrm_api('contact', 'create', $values)
will look for a
function _civicrm_contact_create()

Look at the underscore - a very cheap way to avoid the nameclash.

The generic api function will also take care of all the require_once magic that we need.

Noone is supposed to call _civicrm_contact_create() directly.

Why is this cool?
Because then we are free to refactor the implementation details without changing the API.
Maybe there are some entity types that are so conformal (or will be) that we don't need the implementation function, and can use a generic fallback instead.

-----------

Gateway and mediator objects.
The object that you get for civicrm_api('contact') could be an instance of
class civicrm_EntitySpecificGateway.
We don't need a separate class per entity type. Just one generic class, that will get the details for the entity type injected as constructor parameters.

We also want a class for the object that is returned from
civicrm_api().

As part of the refactoring process, we might want to wrap BAO and other things into objects that can be injected, so we no longer need static calls all over the place.

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: API v3 - a dead end?
February 22, 2011, 12:43:54 pm
Hi,

100% on the rename v3 to avoid name clash. We sill need a name for functions, even if they are not called directly, I like the idea of "drop the whatever.php in the api/V3, put a civicrm_apiv3_whatever_get" and you get civicrm_api ('whatever', 'get',$param) working.

We haven't changed it because we haven't found a way of changing automatically all the function names without screwing up (well, I haven't at least, my sed let me down on that one).

Not sure what would be the benefit of having a class civicrm_api() vs a simple function. Could you elaborate ?



X+
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

donquixote

  • I post occasionally
  • **
  • Posts: 42
  • Karma: 3
  • CiviCRM version: none
  • CMS version: Drupal
  • MySQL version: 5
  • PHP version: 5.2
Re: API v3 - a dead end?
February 22, 2011, 02:14:48 pm
First of all, the objects are all optional, and can be introduced later in the process.

I imagine the following benefits:

Objects can keep and encapsulate data that would otherwise have to live in static function variables. The object itself might itself be cached in a static function var, but the data (like a $bao reference) is better off living in protected object vars.

Objects can be constructor-injected into other objects. An object that gets the civi API injected, doesn't need to do any static calls. And we can give that consumer object a mocked civi api instead.

The API objects can get other civi things injected - such as, a $bao wrapper. These can again be mocked, for easier testing of the API object. Things we could inject in the the API: A $bao wrapper, a wrapper for access checks, various policy and listener objects that can do entity-specific stuff whenever something is created, deleted, etc.

The API objects can be passed around as function parameters, where we would otherwise pass around strings (like "contact" or "tag"). The functions then don't have to make static api calls.

donquixote

  • I post occasionally
  • **
  • Posts: 42
  • Karma: 3
  • CiviCRM version: none
  • CMS version: Drupal
  • MySQL version: 5
  • PHP version: 5.2
Re: API v3 - a dead end?
February 23, 2011, 11:40:16 am
There was this other thread,
http://forum.civicrm.org/index.php/topic,18728.0.html
(CiviCRM API limitations)

I read there we want to have a log of crud actions.
That's a great example for the benefit of a centralized/generic api function: There will be only one place where we need to add this kind of thing. We don't have to modify every function like _civicrm_contact_create(), but instead we just modify the civicrm_api() function.

Going one step further: If civicrm_api() behaviors are pluggable, we don't even need to modify that function. Instead, we would implement a hook OR register a listener or behavioral policy plugin. In case of the log, it would be a listener object, or listener hook.


"Hook" Solution
===============

Similar to the hook_nodeapi() in Drupal 6, we would have something like hook_civicrm_api($entity, $op, $values). The $op would represent not just the action, but an execution step for this action.

The log would then implement the hook as civicrm_log_civicrm_api().
Of course this only works this way if "civicrm_log" is actually a Drupal module, or something that behaves in a similar way. I have no idea how something like this is done in Joomla, or how you Civi guys usually do it.

Example: D6 hook_nodeapi() node creation.
For instance, for a node creation, Drupal will call a 'validate' op, and later a 'create' op, when the node has been successfully created (probably this is inaccurate, please look it up if you really want to know). Some of these might get the $values by reference so they can manipulate them, others can not manipulate but just react.

Example: D7 hook_nodeapi_$op()
D7 has replaced this one hook with many.
This is more convenient, but also means more namespace pollution.

Namespace pollution by Drupal hooks is far worse than namespace pollution by regular functions. Instead of just occupying one name, it occupies one function name per Drupal module name. Even if that function does not exist, it means that if anyone does want this name for something else, it will be regarded as a hook implementation.


"Plugin" Solution
====================

Instead of having a ton of hooks, we just have one hook that allows to register plugins. Actually this could be done by something else than a hook, and I'm not sure if the Drupal hook technique is the correct solution for CiviCRM.

But anyway:
- modules / components get a chance to register plugin objects to the API, or to some underlying system.
- a plugin object can act as a listener or policy. That means, it has methods that will be called on specific events, that can either (passively) react to the event, or alter the way an action is executed.

The log component would register a plugin object that reacts to newly created or updated entities.
« Last Edit: February 23, 2011, 11:43:19 am by donquixote »

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: API v3 - a dead end?
February 23, 2011, 01:31:46 pm
hi,

the regular webforms don't use the api, so wouldn't be that useful. Would need to be introduced at the BAO/DAO level.

This being said, would be great to have a hook/plugin system as you described. Either as something at the DAO level, or moving the Form to use the API.

Anyway, having one common place no matter where it's called (form/api) would definitely be useful and being able to have a hook there too.

X+
« Last Edit: February 23, 2011, 01:38:32 pm by xavier »
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

donquixote

  • I post occasionally
  • **
  • Posts: 42
  • Karma: 3
  • CiviCRM version: none
  • CMS version: Drupal
  • MySQL version: 5
  • PHP version: 5.2
Re: API v3 - a dead end?
February 23, 2011, 01:52:06 pm
Yeah, I guess BAO would be a more appropriate layer, if some things and especially things in core go around the api.
Unfortunately the BAO layer in Civi is as messy/inconsistent as v2 api, and has no central place - yet.

If we had a BAO wrapper/facade that would hide the inconsistencies and provide a central place chokepoint for all operations, we could use that.
But then again, this BAO wrapper would already be very much like an API :)

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: API v3 - a dead end?
February 24, 2011, 05:28:43 pm
donquixote - I note the temporarily? with a question mark - we'd love to have you as a "not temporary" member of the A-team.

We certainly learnt a lot since we embarked on the v3 api and I think both Xavier & I have agreed that ideally we would fix all existing v3 functions to have the v3 in the function & have the civicrm_api function handle all calls.

I haven't thought through all your ideas yet - but I think you are right that if we don't rename the functions now we'll regret it later. (I'd certainly like to spend some time later thinking about chaining because that's definitely wanted)

My inclination to include the version rather than use the initial _ is that when we change version again (eventually) we'll have a solution in place
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

donquixote

  • I post occasionally
  • **
  • Posts: 42
  • Karma: 3
  • CiviCRM version: none
  • CMS version: Drupal
  • MySQL version: 5
  • PHP version: 5.2
Re: API v3 - a dead end?
February 25, 2011, 08:53:46 am
I imagine in v4 we won't be talking about "civicrm_$entity_$action" anymore.
But it doesn't matter, because external code is not supposed to call these functions anyway.

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: API v3 - a dead end?
February 25, 2011, 01:13:55 pm
Michau / Piotr have re-opened api branch to test my renaming. I used the Zend refactor functionality & then reverted everything outside of the v3 folder & v3 tests. I have committed. First run hit one snag. Waiting for second run
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

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • API v3 - a dead end?

This forum was archived on 2017-11-26.