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) »
  • The future of Custom
Pages: 1 2 [3]

Author Topic: The future of Custom  (Read 5762 times)

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
May 29, 2011, 05:02:20 am
Hi,

I have put an example of the api being used in nesting here

http://svn.civicrm.org/civicrm/branches/v3.4/api/v3/examples/Contact/APIChainedArrayMultipleCustom.php

This shows it next to the other API which is handy to see how well the output 'fits'
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

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
June 06, 2011, 07:17:26 pm
So, having implemented the new formats & chaining we have talked about, I can some limitations on how the unique format of CustomValue works in the api v3 framework. It may turn out to be impossibly but here's the thoughts I have.

The formats (getSingleValue, only_id, getCount, getSingleEntity) don't work (on default settings) in a useful way on custom_value because it has an extra layer.

Of the new api formats the one I would probably use would be

civicrm_api('contact','get',array('display_name' => 'Batman',
                                           'version'=> 3,
                                          'api.CustomValue.getSingleValue' => array('return' => 'custom_123')));

then that would functionally replace

civicrm_api('contact','get',array('display_name' => 'Batman',
                                            'version'=> 3,
                                            'return' => 'custom_123'));

As in both cases the value is equally easy to access

$result['values'][$result['id']['custom_123']
$result['values'][$result['id']['api.CustomValue']

- No foreachs & as long as I know the field value  I know exactly how to access it

(note that with regards to the contact API it may not ever make sense to phase out the current custom handling as it is done via SQL & is probably more efficient - in all these examples Contact is probably the wrong entity to use but it's easy to come up with examples)


The other thing I can see as a limitation looking at the new formats is that we will want to be able to use CustomValueGet to search by value rather than just by entity at some later point & to use that as part of a chain

At that point the call to 'get all contacts who love Batman' & change their prefix to 'hero'

civicrm_api('CustomValue','get',array('123' => 'Batman',
                                           'version'=> 3,
                                          'api.Contact.create' => array('prefix' => 'hero'));

(entity_id should be passed in automagically as 'id' -  hopefully this currently happens with 'note').


For this to work we'd need 'entity_id' & 'entity_table' in the results array.

I think it would need to look something like the below

(I'm not advocating necessarily reverting to keeping the 'custom_123'  - mostly the example is just thinking about keys & the depth of the arrays/ types of fields that are in it. This is just trying to work through what would fit with the 'full capacity of chaining'. Also, not quite sure how you'd chain on getting extra detail from CustomField api if you wanted it)

          'api.CustomValue.get' => array(
              'is_error' => 0,
              'version' => 3,
              'count' => 3,
              'values' => array(
                  '1-2' => array( //where custom group is 1 & field value is 2
                          'entity_id' => '123',
                          'entity_table' => 'civicrm_contact',
                          'custom_222' => 'value 4',                       
                    ),
                  '4-3' => array(
                          'entity_id' => '123',
                          'entity_table' => 'civicrm_contact',                     
                          'custom_254' => 'value 2',
                          'custom_244' => 'warm beer',
                          'custom_288' => '',
                        ),
                   '4-4' => array(
                          'entity_id' => '123',
                          'entity_table' => 'civicrm_contact',
                          'custom_254' => 'value 3',
                          'custom_244' => '',
                          'custom_288' => '',
                        ),
                    ),

I suspect the 'sequential' param still wouldn't work without some bullying with the indexing above.
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

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: The future of Custom
June 06, 2011, 10:12:30 pm
Hi,

Been confirmed that the field name (well label but as one generates the other...) is already checked to be unique. Ie. we can drop the "my_group:some_field" and go directly "some_field (well probably "custom_some_field")

Quote from: colemanw on May 25, 2011, 09:48:18 pm
OK, have added the file, however it's not done, and I agree with Eileen that we should try to get it right from the start.
-Specifying what you want returned could use some love. I don't really like the format 'return.my_group:some_field'. Since you're specifying the group, why not just leave it at that? Why would you ever not want every field in a group returned?

 * 'custom_some_group:my_field => 'myinfo', // you can use group_name:field_name instead of ID
 * 'custom_some_big_group:my_other_field:8 => 'myinfo', // updates record ID 8 in my_other_field in multi-valued some_big_group


@Eileen, need to have a second coffee before digging into your post.
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: The future of Custom
June 07, 2011, 11:16:21 am
Quote
What would be the benefit over custom_xxx ? Just a different syntax or to better handle multiple value or?

That was a good question. I don't think it was fully answered, and that probably led to some miscommunication. I think there are at least three issues that have been batted about:

Issue 1. As part of the api/v3 project, Eileen and Xavier have done a lot of work to improve the consistency of different API operations.  One source of inconsistency in api/v2 was custom data -- i.e.  the 'Contact' API supported lots of custom data magic, but the APIs for other entities were spotty or non-existent.  To achieve greater consistency, we need a generic way to process custom-data for all entities.

Issue 2. The "custom_123" convention makes it hard for API adopters to reuse their PHP/Smarty/JS code (or, for that matter, to reuse email templates, profile forms, or smart groups) on different sites.  This leads third-party developers to improvise ways
to identify custom fields (e.g. using a PHP "define" and then tweaking it on each installation; using a library+admin page to let users tweak the mapping; or matching a regular-expression to a SQL column name or field label). To improve portability, we need better programmatic symbols for custom fields.

Issue 3. Single-row CustomGroups have different requirements than multi-row CustomGroups.  For single-row CustomGroups, the use of an extra SQL table is "a mere implementation detail" -- one can intuitively think of each CustomField as extending the original entity.  For multi-row CustomGroups, the lifecycle looks more like "civicrm_participant", "civicrm_contribution", or "civicrm_email" -- i.e.  you need to the ability to independently CRUD several rows. However, the old approach managed to tackle both single- and multi-row data with some notational magic -- but notational magic is functionally incomplete, harder to grok, harder to integrate. ("OK, so I can add a new row with -1; how do I delete one?") To improve data management, we need clear (and different) conventions for processing single-row and multi-row data.

The fact that there are three issues makes it harder to find solutions. For example, xavier made this useful observation:

Quote
Been confirmed that the field name (well label but as one generates the other...) is already checked to be unique.  Ie.  we can drop the "my_group:some_field" and go directly "some_field (well probably "custom_some_field")

This is good news for issue #2 -- it's much more natural (and more portable) to write code for "some_field" rather
than "custom_123" or "somegroupthatmightchangeonothersites:some_field". It's tangential to issue #1
(because it doesn't provide any generic helpers) and it's counter-productive for issue #3 (because consumers working with multi-row CustomGroups need to see the group structure).

Anyway, I'm not certain about how each proposed solution addresses each problem, but maybe it will help to have an explicit problem statement.

Coleman Watts

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 2346
  • Karma: 183
  • CiviCRM version: The Bleeding Edge
  • CMS version: Various
Re: The future of Custom
June 08, 2011, 12:54:37 pm
That last post really helped me to clarify my thinking on this whole thing. I just realized that for the purposes of this api, fieldgroups don't matter, only fields. For fields in single-valued groups, the array key should always be 0. For others, it should be the id of the entry. Should several fields from different groups have the same id, it won't matter. Check it out:
If we input 'custom_value', 'create' like this:
Code: [Select]
array(
  0 => array(
    'my_single_field' => 'updating the value',
    'my_other_single_from_another_group' => '20110608',
    'my_checkboxes_from_a_single_group' => array('foo', 'bar', 'baz'),
    'my_multi_field' => 'inserting a value',
  ),
  55 => array(
    'my_multi_field' => 'updating value 55',
  ),
  '-1' => array(
    'my_multi_field' => 'inserting another new value',
  ),
);

then we can get output from 'custom_value', 'get' like this:
Code: [Select]
[0] => array(
  'my_single_field' => 'updating the value',
  'my_other_single_from_another_group' => '2011-06-08',
  'my_checkboxes_from_a_single_group' => array('foo' => 'Foo's Value', 'bar' => 'Bar's Value', 'baz' => 'Value for Baz'),
)
[55] => array(
  'my_multi_field' => 'updating value 55'
)
[56] => array(
  'my_multi_field' => 'inserting a value'
)
[57] => array(
  'my_multi_field' => 'inserting another new value'
)

How nice!
« Last Edit: June 08, 2011, 01:04:10 pm by colemanw »
Try asking your question on the new CiviCRM help site.

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
To create
June 08, 2011, 01:20:14 pm
Hi,

Revising on IRC my position: we shouldn't hide the set/group at all, quite the opposite

we need to add an id in the array that is returned. Trying to think if we expose the group:

Create a new record mono or multi-value

api.customField.create
Code: [Select]
array(
    'set' => 'set_A',
    'entity_id' => 123,
    'my_single_field' => 'updating the value'),
    'my_multi_field' => 'inserting a value')
   );


Update a record

api.customField.create
Code: [Select]
array(
    'set' => 'set_A',
    'id' => 42,
    'my_single_field' => 'updating the value'),
    'my_multi_field' => 'inserting a value')
   );

If you want to create/update several records from the same multi value set or several mono value, api.chain is your friend.

What do you think ?
« Last Edit: June 08, 2011, 01:48:25 pm by xavier »
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
and get
June 08, 2011, 01:40:46 pm
note: just remembered that when writing the book, we decided to use "set" instead of "group" for the custom fields

So for the api.custom.get, we have

to return a single record from a single set on a multiple value
api.customField.get (set => 'set_A', id => 42, entity_id=> 123, return => array ('my_single_field', 'my_second_field'), sequential => 1)

Code: [Select]
array(array (
    'id'=> 42,
    'entity_id' => 123,
    'entity_table' => 'civicrm_contact', // I think we should abstract and put the entity name
    'my_single_field' => 'updating the value'),
    'my_second_field' => 'inserting a value')
    ));


or for those that like it like that:

api.customField.get (set => 'set_A', id => 42, entity_id=> 123, return => array ('my_single_field', 'my_second_field'))

Code: [Select]
array(
   42 = > array (
     'id'=> 42,
     'entity_id' => 123,
     'entity_table' => 'civicrm_contact', // I think we should abstract and put the entity name
     'my_single_field' => 'updating the value'),
     'my_second_field' => 'inserting a value')
    ));


to return a single record from a single set
api.customField.get (set=>'set_A' , entity_id=> 123,return => array ('my_single_field', 'my_second_field'))

Code: [Select]
array(array (
    //not sure there is an id
    entity_id=> 123,
    'my_single_field' => 'updating the value'),
    'my_second_field' => 'inserting a value')
    ));

to return all the records from a multivalue

api.customField.get (set=>'set_A' , entity_id=> 123,return => array ('my_single_field', 'my_second_field'))

Code: [Select]
array(
    array (
     id =>42,
     entity_id=> 123,
    'my_single_field' => 'updating the value'),
    'my_second_field' => 'inserting a value')
    ), array (
     entity_id=> 123,
     id => 13,
    'my_single_field' => 'bla'),
    'my_second_field' => 'bla')
    ));


to return the latest record from a multivalue or a mono value one

api.customField.getSingle (set=>'set_A' , entity_id=> 123,return => array ('my_single_field', 'my_second_field'))


Code: [Select]
array(
     id =>42,// still not sure it makes sense for a mono value
     entity_id=> 123,
    'my_single_field' => 'updating the value'),
    'my_second_field' => 'inserting a value')
);


et voila,

if you want custom values from different set, chain the calls.
I'm updating the get post under
« Last Edit: June 08, 2011, 02:47:07 pm by xavier »
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
June 08, 2011, 03:05:07 pm
A couple of notes from IRC - Xavier's example would be id indexed by the id in the custom table. His example relies on only getting one group @ a time - hence, no conflicts.

To my mind as long as we add entity_id & entity_table to Coleman's example the 3 proposed would work within the API structure.
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

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: The future of Custom
June 08, 2011, 03:13:52 pm
Quote from: Eileen on June 08, 2011, 03:05:07 pm
A couple of notes from IRC - Xavier's example would be id indexed by the id in the custom table. His example relies on only getting one group @ a time - hence, no conflicts.
Sometimes, it's easier to avoid the problem that solving it ;)

Seriously, there isn't any benefit of merging datas from different sets, chaining the API calls is as fast, but much simplier to read and predictable.

Quote from: Eileen on June 08, 2011, 03:05:07 pm
To my mind as long as we add entity_id & entity_table to Coleman's example the 3 proposed would work within the API structure.

Yeap, almost the same and was inspired by Colemans example. The main diff (beside the new rule "on set at a time") is to force the id or the entity_id/table AND not to use the index but rely on the id (or lack of instead of the weird -1)

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

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
June 08, 2011, 04:47:28 pm
I do note that using X's example the 'id' & 'count' fields in the return array become meaningful.
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

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
June 09, 2011, 03:37:08 pm
(10:13:50 AM) colemanw: my example would have been more useful (to me) and easier to impliment in the api. There aren't, to my knowledge, bao functions that do what x is wanting to do.
(10:13:51 AM) eileen: colemanw - agree. But I realised today that there was trivial point that we discussed to death about the way the values array would look & it turns out that if we hadn't the whole chaining thing wouldn't work now
(10:15:54 AM) eileen: well, that's 2 separate things. Less interested in ease of implementatation for now as to what would be better in the long run. But the usefulness is important -
(10:16:08 AM) eileen: ie. you are saying his idea would be hard to use?
(10:16:41 AM) colemanw: (re point 2) the customValue BAO only cares about field ids, and there is no method that works with them by set
(10:17:10 AM) colemanw: (re point 1) I don't know, I am still trying to figure out what exactly he's saying
(10:19:02 AM) eileen: Re point 2 - can always push back on X to help deal with the coding on that
(10:19:28 AM) eileen: re 1, he's suggesting basically getting around the id conflict by making each call group specific
(10:19:56 AM) colemanw: but there is no conflict (unless I'm missing something)
(10:21:00 AM) eileen: ie. civicrm_api('Contact', 'Get', array('id' => 1, 'api.CustomValue.get => array('set'=>1, 'set' => 2); would be the call

(10:22:10 AM) eileen: No, there isn't a conflict as long as we only ever allow you to GET a single entity's fields
(10:22:40 AM) eileen: but, I guess if we aspire to allowing people to search on values other than 'entity_id' at some point in the future then there would be
(10:24:30 AM) colemanw: mmm
(10:25:22 AM) colemanw: I think this is workable. My only beef with it is that it's requiring the developer to know something that we don't actually need to know
(10:25:35 AM) colemanw: that is, in order to get custom fields for an entity, all we need is an entity id and entity type
(10:25:38 AM) colemanw: that's it
(10:25:56 AM) colemanw: but this is requiring them to know the ids of all the sets
(10:26:04 AM) colemanw: which the bao doesn't care about and will just discard anyway
(10:31:41 AM) eileen: well, we could allow 'set' = '*' as an option I guess - which pretty much brings us back to how it would be formatted then - which would have to look like either my example or an extra layer on Xavier's. Maybe I'll just post these thoughts back onto the forum & see what X can think of when he wakes up

(10:34:19 AM) eileen: Actually - I'm thinking that instead of any sort of 'set' = '*' we'd probably add an extra function. That's probably the way. So, if, we accept Xavier's as the underlying then we'd add something like 'api.CustomValue.getGroups => array('set'=>1, 'set' => 2);
(10:34:32 AM) eileen: sorry, w'out the set=1 & 2
(10:34:40 AM) eileen: will post back on the forum
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

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: The future of Custom
June 10, 2011, 12:20:22 am
Hi,

(kind of hard to read a log ;)

So the BAO is hiding the set? I'm not sure that helps a lot (ie. you know where you put your custom fields) and is potentially a way of making a wrong structure of custom sets (too much/too many/wrongly grouped) without realising it.

Anyway, for mono values, would work to have a api.customFields.get ( with set = array (set1,set2) or optional).

Not convinced about how clever it is, but could work as well to have set optional on the create

For update, I think having an id on the create and several set is black magic at best and a way of letting users hang themselves.

For multi-values, anything more clever than my suggestion is too clever for its own good I think.

Colemans, not sure I understood your point about the complexity of the code.

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

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: The future of Custom
August 28, 2011, 03:07:55 pm
I committed this which is a little different to any of the suggested (it was the easiest). Happy to see another tweak b4 3.4.6 goes out

http://svn.civicrm.org/civicrm/branches/v3.4/api/v3/examples/Contact/APIChainedArrayMultipleCustom.php
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 2 [3]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • The future of Custom

This forum was archived on 2017-11-26.