Blogs

07 Dec 2017

This summary explains how we are using webform to allow multiple people to be registered for multiple events - with each person registering for any variation of events

13 Jun 2017

Per a request in StackExchanged I cloned this View and cleaned it up in case it could help in their use case.  The view ensures the block shows activities Assigned to the logged in user.

16 Nov 2016

Quickly built this to provide an example view for this question on Stack Exchange. Obviously the relationship types may need resetting to match which relationships are required.

26 May 2016

This came up as a question for a civi report that could provide a pivot table for contacts created each month v the Source field.

21 Nov 2015

A question on StackExchange had me wondering if a View would provide a solution for showing Civi Memberships and OG Mem

21 Oct 2015

A StackExchange question asked how to provide a link to whatever was the latest newsletter. Seemed like a good fit for a View so tried one out. Here is the file. if it helps, let us know.

28 Aug 2015

I spotted this on StackExchange and Link was okay with me adding this to the repository here.

28 Jul 2015

If you have the CiviCRM Entities module (2.x version)  and the Calendar module then in View

25 Jul 2015

A request on StackExchange seemed like a good candidate for a View using Aggregation that would give a count of


23 May 2011

A customer recently requested that the little contact search box in the top left corner be made available on all their drupal pages and that it link to the contact's Drupal page.

 

Re-using the Civi-search box seemed a bit too difficult but there was a fairly easy solution to this request using existing drupal modules - finder + views (plus features to deploy).

 

Finder module will create an autocomplete box off any view. I created a basic View based on drupal users. After Pete had finished with it it had 3 fields: contact display name - linked to CiviCRM contact, Drupal user name - linked to Drupal contact & drupal email linked to a mail to. It was also filtered to 'Is Primary Email'. It looks like this (filtered to a single record).

 

CiviFinder view

 

Next up I installed Finder module along with finder_views and finder_autocomplete. Finder appears under site building when installed. I chose to add a Views Finder and selected my View.  I selected both to be able to view the Finder as form and as a block. I then went to 'add element' and chose an autocomplete textfield. There is a 'find items by field' box and I chose the same 3 fields as above. In order to reduce the load I chose the drupal email which is in the same table as the drupal username rather than the Civi email. I'll see if I get a request for the CiviCRM email to be used...

Those few steps were enough that my Finder page now looks like the below. It will autocomplete on username, email or CiviCRM display name.

CiviFinder

The block sits on the left hand side & currently looks like this.

 

After a bit of tinkering when it seemed OK I packaged the view into a Feature which can be downloaded & installed from the fuzion svn (accept the certificate - it's self-signed). One of my biggest gripes about the Finder module is that it isn't possible to export finders as a Feature. The maintainer seems fairly opposed for some reason I can't make sense of. Anyway, I did find I could add the Finder module to the install hook on my Feature so it was possible to package it with the view although it's not possible to maintain it in code going forwards like you can with a Feature.

So, to use our implementation - you need a bunch of modules; Views, Features, Finder, CTools. Once you have all of them enabled just enable civifinder and there will be a block available for you to enable wherever you want on your site


05 May 2011

I recently had a requirement to set up a CiviCRM install so that whenever an event (or specific types) was created an organic group would also be created. When someone registered for that event they would be added to the organic group and if they were registered as a teacher they would become the manager of the organic group.

The focus of this blog is on the code implementation of this requirement using rules integration. I wanted to see if it could be done by rules & if that would set a useful precedent. The two aspects of Rules that where the crux of what I was trying to do were not mplemented in the CiviCRM Rules module so I will describe them in some detail.

The way in which the CiviCRM rules module works is that has functions for the various drupal hooks. When one is called CiviCRM Rules evaluates whether or not CiviCRM Rules integration exists for that hook for the specific entity and option.

In our case the focus is on the POST hook. The post hook is called once a CiviCRM entity is created (an entity could be a Contact, an Event, a Group etc). I wanted to expose the POST hook on Event & Participant - but also to do it in a way that I could add other entities easily so I added a drupal admin settings form to provide an interface to allow the site administrator to specify when to call it. At the moment there is no code way of generating a list of entities that call the POST hook but we have talked about introducing that in CiviCRM 4.1. (at the moment available entities are just coded as an array).

So, once the civicrm POST hook is called it calls 'RULES' & gives it the 'event' - so when a contact is created RULES is called with 'contact_create'. I felt that with such things as groups and events there was a risk of confusion with events exposed by other drupal modules so for the additional objects I called rules with a prefix ie. 'civicrm_event_create'. Note that I will try to use 'rules event' & civicrm event in this blog to distinguish the two.

So, what is involved

1) register the event types. You register the types of events that should be available from your module to rules. So, I registered create, view, delete, edit for each enabled entity. I did this by calling a function in a separate file as I wanted to keep my code as separate as possible (as it may wind up being a separate module).

The rules function that registers the events is called

function civicrm_rules_event_info()

(My additions are in function civicrm_rules_entities_event_info())

 

So, registering my function means that when you go to set up a rule you can choose the rules event you want

 

2) Arguments: Once I have created a rules event I need to be able to do something with it. In this case I wanted to create a node. It turns out you can't create a node using Rules unless you have a User object available to your events. Being able to access alternate objects is called an argument in Rules parlance.

In order to create the argument for the CiviCRM Event I declared this argument when I registered the event.

 

return array(

'cms_user' => array(

'type' => 'user',

'label' => t('User that edited the event'),

'handler' => 'civicrm_rules_events_argument_civicrm_event',

) ,)

 

 

The handler is a function that is called & must return an object of the defined type - in this case 'user' .

This 'argument' - the user object - becomes available for all drupal actions (like creating content - or organic groups in this case) where a user object is required. This might also include adding a role to user or making them inactive.It would be pretty easy to also add a contact object argument here so you could carry out rules actions on that contact like adding them to a group.

 

 

 

Conditions & Arguments

So, I wanted to be able to say

"WHEN the event that I have just created event is of type x, y,z"

Is of type xyz is a condition. I struggled with this for a bit but basically it's a case of declaring the condition

function civicrm_rules_entities_condition_info() {

return array(

'civicrm_rules_condition_participant_role' => array(

'label' => t('Participant Role'),

'arguments' => civicrm_rules_entities_conditions( t( 'Participant Role' ),'civicrm_participant' ),

'module' => 'CiviCRM participant',

),

'civicrm_rules_condition_event_type' => array(

'label' => t('Event Type'),

'module' => 'CiviCRM event',

),

);

For the civicrm_rules_condition_event_type I wanted to allow the admin to use checkboxes to choose the type - I took a while to figure out how to do that but it turned out I just needed a function with _form on the end:

/**

* Condition: Check for content types - Configuration form

*/

function civicrm_rules_condition_event_type_form($settings, &$form) {

$form['settings']['civicrm_event_type'] = array(

'#type' => 'checkboxes',

'#title' => t('CiviCRM Event Types'),

'#options' => civicrm_rules_get_options( 'event_type'),

'#multiple' => TRUE,

'#default_value' => isset($settings['type'] ? $settings['type'] : array(),

'#required' => TRUE,

);

}

 AARGH _ wrong arguments currently being passed in! - CHECKING FIXING

If the administrator specifies this condition as part of their rule it calls the function which is the array key from the 'info' function

/**

* Condition civicrm_event type

*/

function civicrm_rules_condition_event_type(&$entityobj,$types,$field) {

return array_key_exists($event['values'][$entityobj>id]['event_type_id'],$types) ? true : false;

}

 

 

 

So, conditions + arguments

It took me a while to figure out conditions & arguments . Here is the next part of the workflow broken up in Rules-speak

- When someone registers for an event (rules event : civicrm_participant_create)

- If their Role is '1' (rules condition : civicrm_rules_condition_participant_role)

- Subscribe 'the user who signed up' (argument) to 'the node related to the event' (argument)

Loading up the 'node related to the event' seemed to me to require a cck field against the event & turned out to be an odessey of it's own. In the end I have just implemented code that will load up a node based on the value in a cck field called 'civicrm_event' matching the event ID.

CODE

https://svn.fuzion.co.nz/repos/fuzion-code/trunk/drupal/modules/custom/civicrm_rules

In order to deploy the rules I packaged them as a feature. The feature is not good to go out of the box for someone else as it also includes views, and migrate tasks in order to create organic groups from existing events

https://svn.fuzion.co.nz/repos/egw/trunk/sites/all/modules/egwc_custom_modules/ogevents

The rule itself is defined in

https://svn.fuzion.co.nz/repos/egw/trunk/sites/all/modules/egwc_custom_modules/ogevents/ogevents.features.inc

 

 

Where to go:

I think it's fairly easy to extend the POST hook side of rules with more arguments & conditions & ideally offer civicrm entities as arguments.

I think deciding whether to present civicrm_entities with the 'civicrm_' prefix is a

 

I kept my code mostly in a separate file & referred to it as entities but I suspect all the generic 'stuff' should be in one file & there should be another file for entity specific arguments / conditions (per entity) although sometimes a file for conditions & one for arguments appeal. Whatever way .. it needs structure.

Doing this integration highlighted to me the usefulness of some things we have talked about implementing :

1) Having the POST hooks defined in Code. Lobo, Xavier & I have talked about moving the POST hooks to the DAO and having a function somewhere that defines which DAO actually call it - since we probably don't need to call it for all DAO

2) A major reason I didn't go with cck field was that I couldn't make it do autocomplete on event using the existing API - the API should accept '%blah%' arguments on all fields - another one for the long to-do list.


15 Oct 2010

Table Wizard offers a quick & dirty way to get a csv into a Drupal mysql DB as a table. You need to start by downloading & enabling tablewizard and  schema. Make sure you choose to enable the delimited import part.

You should then be able to navigate to admin/content/tw via the content menu and upload your csv file.

If you want the table available in views, However you need to access MySQL (e.g via PHPMyAdmin)

and add a primary key column e.g.

ALTER TABLE `contacts_import` ADD `twid` INT( 12 ) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ;

The table name will be the same as your view. Once you have done that flush caches & 'analyse' the table in the table wizard dashboard- you need to re-analyze & save. You can also comment on and exclude fields. Make sure to set any fields that connect to other tables as available keys


15 Oct 2010

The joy of CiviMigrate is when you have a complicated destination for your data. In our example we have a simple csv with 6 fields but we want to create a Contact (see previous blog), a membership for that contact and an attached contribution record for the payment received. This blog will describe how to do a membership import and then a contribution import off the same data set.

This blog follows on very closely from the previous blog and continues the same example.

Prequisites

Your data needs to be already in a view with a unique key - here is one way to get it there from csv

 

Civimigrate module installed & enabled. (see previous blog)

Your view needs to have a contact_id field already (see previous blog)

Getting started

TBC - need to write getting data in with TW first


15 Oct 2010

The Migrate module is a powerful tool for importing data into Drupal and Drupal modules. It is also an approach we have been using for large, complicated or recurring imports into CiviCRM. Some advantages of using Migrate module for imports:

  1.  You can specify how many (and which) records you wish to import in order to do a small test.
  2.  You can then make changes and remove / re-import the records until you are happy
  3. You can manipulate data on the way in using hooks
  4. You can automate the import using drush
  5. You can run the update on a regular basis via cron & new additions will be picked up (this is a technique we are using to get 3 click csv uploads into multiple Civi types
  6. It is easy to visualise what is happening & come back to it over a period of time
  7. Advantages of CiviMigrate are the ability to import related entities - eg memberships with related contributions from one source

In this blog we will look at a very basic contact import & then in the following one will look at creating memberships for those contacts based on the same csv. The csv we are using is (will be) attached.

CiviMigrate does not replace existing CiviCRM migrate methods. It is good for different things. In general you need to set up a migration step per entity so if you wish to create a contact and a related contact and a relationship between them you need three steps.

 

Prequisites

Your data needs to be already in a view with a unique key - here is one way to get it there from csv

migrate module installed & enabled (drush dl migrate / drush en migrate )

Note that migrate module has table wizard as a pre-requisite but will not in the future. I have mostly switched to using Data module with it now. Schema is a pre-requisite of Table Wizard. You may wish to supress schema warnings @ admin/build/schema/settings

Civimigrate module installed & enabled. Civimigrate is currently just being hosted in the Fuzion repository although after (considerable) tidy-up it will hopefully eventually reside on drupal.org. For now you can get it by

svn co https://svn.fuzion.co.nz/repos/fuzion-code/trunk/drupal/modules/custom/civimigrate

drush en civimigrate

Getting started

Start at the migrate dashboard - admin/content/migrate/dashboard or navigate via 'content' from the admin menu.

Choose to add a set. Choose your view as the source and CiviCRM Contact as the destination. I recommend you set a weight on all steps & use a numbering scheme like 10, 20, 30 to enable you to re-order steps more easily later.

Setting up a mapping

In this next step you match your views fields to CiviCRM fields. Make sure you set the Unique ID first if necessary - in this case we are using system ID. CiviMigrate will create a table which maps this ID to the civicrm contact_id which is important for us to import related items (like contributions).

CiviMigrate uses the CiviCRM API to import data and generally the fields available for you to map to are the fields from the relevant tables with some manual additions & subtractions. In this case we will choose to map:

first_name to first_name

last_name to last_name

SystemID to external_identifier

phone to phone

optional: phone_type_id - we are going to set this to 1 - see civicrm/admin/options/phone_type&group=phone_type&reset=1 for the values. (without this it will still import but phone type won't be set).

optional: source  - something to identify our import

Running the Import

Once you have saved the mappings you run the import by ticking the box next to it and opening up the execute section. You can specify to only import one record.under sample size and click run.

When I run the above I find that '0' records successfully import and I can see there is 1 error. Clicking on the error does not, however, show me the error - what's happening? When the migrate ran it created two new tables

migrate_map_contacts (my migration is called contacts)

migrate_map_msgs

The code also allows for the creation of views so we can see them but before we can access them the first time we need to flush all caches (well, I'm not sure which one so blunt hammer here). Now that I can access the table in the migrate_map_messages I see

88 Contact Type not specified

88 is the system ID for the first contact it attempted and Contact Type not Specified tells me I need to go back to my migrate map & enter 'Individual' against contact_type.

I re-do my import with another '1' record and the next record updates fine. My first record won't be touched until I choose the update existing option - but read the section on that below before you go there.

Looking at what has happened

Go to views and filter on 'tw' - you will see the migrate_map table for your import. It has a sourceid - your unique ID and a destid - the CiviCRM contact ID, and a 'needs_update' field. It can be very helpful to edit the destid field to output as link - use this link and it will link to your CiviCRM Contact

civicrm/contact/view?reset=1&cid=[destid]

When you next run an import it will look for any records in your source view that are not in your migrate_map or that are in your migrate map & have needs_update=1  against them and run the update command on them.

dupe matching

Civimigrate will always treat an external identifier match as a match - whether it's in your dedupe rule or not.

If your contact matches an existing CiviCRM contact based on your default de-dupe rule Civimigrate currently has 2 possible behaviours (only because that's all we've needed so far as we have mostly used an external_identifier for our contact import matches)

By default CiviMigrate will treat your imported contact as a match for the CiviCRM contact with the lowest ID and create any that don't exist.

If you choose 'Only update (don't create) and only if ONLY one match is found' CiviCRM will only update matches and not create any new contacts (existing ID is used). To choose this put 1 in the default for this field. This option is often valid when you don't want to import contacts at all - just contributions but you need to map up the contact_id first - see below for that.

Not hugely useful but you can tell CiviCRM to consider the logged in users permissions when determining a match by choosing "Do you want the current users's permissions used to limit dupe matching?(default = False)"

Changing your import - deletes

You can use 'clear' to delete your records if you wish to re-do them. Most probably if you are using a 3.2 version of CiviCRM this will cause the contact to be soft-deleted but 3.1 & 3.3 should cause hard deletes (desired in this case). Be careful if using an existing data set as contacts that have been matched by de-dupe will be deleted!

Updates & mapping contact ids

If you wish to do an update there is a very important step to do first (this is less important for contacts where matches can be done based on dedupe & external identifiers than it is for other civimigrate entities but let's do it here as good practice and prevents 'odd' things happening).

A word first about table wizard & data. Table Wizard is deprecated but I have been unable to create the joins described here using Data module with Migrate 1. I believe it is because Table Wizard manages the migrate_map tables and you need Data to manage them in order to use Data

Table Wizard Relationship 

Go to the Table Wizard dashboard admin/content/tw  - choose Add existing tables and add your source table.  Then go to 'Relationships' admin/content/tw/relationships. Add a relationship from (the top field / base table) the unique ID of your source table to (bottom field) the equivalent of migrate_map_contacts.sourceid. The Automatic setting is fine.

Each time you accidentally connect to the migrate_msg_contacts instead log onto CiviCRM & make a small donation - this will save you time in the long run.

Once the relationship is added sort out your view

Now go back to your source view (the one based on your data table) stopping only to clear your views cache. Now try to add fields. You should now see the fields from the migrate_map_contacts table. Remember, your destid is your CiviCRM contact_id. Add migrate_map_contacts.destid to the view and label it contact_id (and probably link it to civicrm/contact/view?reset=1&cid=[destid] )

Update your migrate map

Finally, go back to your migrate job map and map this new contact_id field to the contact_id field. When you update your records now there will be no danger of a new contact being created. For contributions mapping the id field is absolutely essential

Updating records

Once you have your contact ID mapped up you can change your mapping and then click 'update existing' to update previously migrated records with your new settings. This is especially useful if you have changed your mind about where to map a particular value to.

Caution selecting 'update previously-imported content' sets the value needs_update to 1 for ALL records in the migrate_map table. Even if you have set your import to update 1 record next time you run it it will try to update all the others as needs_update is set to 1

 

Where to?

These were the basics of importing a contact using CiviMigrate but the real power is related transactions. The next blog will explain how to import our next 2 fields 'amount' & date as a membership & a related contribution.

 

 

 


15 Oct 2010

NOTE: This approach has been superceded by our work developing the bridge module for using the Drupal Migrate module to migrate legacy data in to CivICRM. Read about it here

 

Often data that you need to import into CiviCRM is presented to you in an Excel or CSV format. Of course there are various ways to do this but the Data / Feeds module combo provides a nice method if you are likely to be uploading a similar csv more than once, or if the person actually uploading doesn't have the access or knowledge to directly edit the database. This method is also really nice for nightly uploads from another system because the most technical thing you have to do is write a script to ftp your csv onto the server. Follow on blogs from this will describe how to migrate data from these imports into CiviCRM & UberCart

Feeds allows you to get data from a range of formats (csv, RSS etc) and put them into a range of formats (nodes, mySQL table) but here the focus is csv to MySQL table.

Prerequisites:

CSV of the data you want to upload

Schema module installed (drush dl schema / drush en schema)

Data module installed (drush dl data / drush en data, drush dl data_ui / drush en data_ui )

Feeds module installed (drush dl feeds / drush en feeds, drush dl feeds_ui / drush en feeds_ui)

Views module installed (drush dl views / drush en views, drush dl views_ui / drush en views_ui)

Set up the feed config

Start at this URL (under structure/ feeds importers / New Importer on the admin menu or site building/ feeds importers / New Importer)

/admin/build/feeds/create

Give your feed a sensible machine name (pref lower case with underscores but no spaces, not too long) and a descriptive name & click create.

Settings

Many of the settings are self-explanatory - I'm just going to mention those you should change / consider or those that took me a  while to make sense of

1) Select a Fetcher - click on 'Select' next to 'File Upload'

2) Optional - check 'Supply path to file directly' - this is good when you are ftping files up to the server (e.g by script) & you want them to be uploaded automatically. There isn't s downside to this setting

3) Parser - select csv Parser. You can then edit the default separator typeif you wish  it can also be changed at the point of import

4) Processor - select 'Data Processor'

5) Under data processor settings consider whether you want the records created to be removed from your table after a period. I recommend you do select 'Replace Existing Records' which will allow you to do updates as well as inserts

6) Mapping- For each field in your csv enter the field's name in the source and choose the field type under target. If you choose integer or VarChar you will be able to make the field unique. You should select unique for any fields that uniquely identify the record in your csv. You don't have to create mappings for fields you aren't interested in

Note: Leave 'Attach to content type' as standalone form - this setting is really for when you want to have a content type like 'Bob's blog feed and use it to create blog content items from an RSS feed.

That's it to set it up!

Importing your data

Go to /import and click on the feed you set up. From this URL you can select & upload your csv. Any columns in your csv that match will be imported. If you are regularly importing this is the ONLY step you need to keep doing. One URL, 3 clicks.

Note that you can look at the csv that was used if you want to edit it and re-upload. There is also a 'delete items' option

 

Viewing your data

A View will have been created for you - you can navigate to it by selecting structure / site configuration in the admin menu/ data tables/ overview. Click on the link to 'visit the Data table Content Page' (I always overlook this link and go round a loop getting there)

You will now be at /admin/content/data. Click on View and you will be in your table's view. This is a normal view which you can edit.

Using your data

I will look at importing the data into CiviCRM in a separate blog

 

 

 

 


24 Sep 2010

Open Source projects often suffer from development ideas not getting sufficient resources to implement properly, with the outcome being lots of users continue to use work arounds or poor fixes.

Eileen has put some time in to setting up CiviCRM with a Make it Happen facility so that clients and consultants can make donations to particular projects. If the particular project does not get sufficient funding, then the donor has the option of a refund, or to shift it to another project.

Check out the options here: Make it Happen - support your favorite Civi project!


18 Jun 2010

Nice to see some praise for the Aus Greens site. From the ABC website http://www.abc.net.au/unleashed/stories/s2955511.htm

"The Australian Greens have by far the best online presence. The smell of a (non-)oily rag has produced a more vibrant site. Candidates and MPs have livelier and more personal blogs and there's a sense of a frequently updated and topical site.

The Greens are also much better marketers: there are frequent and prominent calls to action sprinkled throughout the site."