-
Notifications
You must be signed in to change notification settings - Fork 0
/
FeedsAFGParser.inc
269 lines (264 loc) · 12.1 KB
/
FeedsAFGParser.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<?php
/**
* A simple parser that extends FeedsSimplePieParser by adding support for AllForGood's Footprint XML tags.
*/
class FeedsAFGParser extends FeedsSimplePieParser {
/**
* Define the extra mapping sources from the AFG feed.
*/
public function getMappingSources() {
return parent::getMappingSources() + array(
/* Field sources with data generated from other fields. */
/* Custom field sources for enforcing uniqueness. */
// stripped_guid is deprecated for use as GUID now, as per conversation with Dan Stryker
// (sometimes feeds will have multiple opportunities at the same URL)
'stripped_guid' => array(
'name' => t('AFG: Opportunity URL'),
'description' => t('The GUID stripped of the fp:id which is appended after a hash character (#). This should be equivalent to fp:detailurl, but that doesn\'t show up in the AFG feed output.'),
),
'volopp_hash' => array(
'name' => t('AFG: Hash of Title, Description, Provider'),
'description' => t('The md5 hash of the title, description, and fp:provider for a given feed item. Used as a GUID.'),
),
/* Custom field for latitude from fp:latlong */
'afg_lat' => array(
'name' => t('AFG: Latitude'),
'description' => t('The latitude of a volunteer opportunity. (Taken from fp:latlong.)'),
),
/* Custom field for longitude from fp:latlong */
'afg_long' => array(
'name' => t('AFG: Longitude'),
'description' => t('The longitude of a volunteer opportunity. (Taken from fp:latlong.)'),
),
/* Custom field for opportunity start date from fp:startDate */
'afg_startDate' => array(
'name' => t('AFG: Opportunity Start Date'),
'description' => t('The opportunity start date in MM/DD/YYYY format.'),
),
/* Custom field for opportunity end date from fp:endDate */
'afg_endDate' => array(
'name' => t('AFG: Opportunity End Date'),
'description' => t('The opportunity end date in MM/DD/YYYY format.'),
),
/* Field sources taken directly from the AFG feed. */
/* Fields that are always present on an AFG feed. */
'fp_id' => array(
'name' => t('AFG: Hash (fp:id)'),
'description' => t('Hashed ID of the opportunity in AFG feed output. Supposedly changes each day.'),
),
'fp_groupid' => array(
'name' => t('AFG: ID of Merged Opps (fp:groupid)'),
'description' => t('An ID for a deduped set of results.'),
),
'fp_provider' => array(
'name' => t('AFG: Raw Opportunity Source (fp:provider)'),
'description' => t('Provider of the opportunity. It is a "machine name", so is always lowercase and will not necessarily have spaces.'),
),
'fp_startDate' => array(
'name' => t('AFG: Raw Opportunity Start Date (fp:startDate)'),
'description' => t('The start date for a volunteer opportunity.'),
),
'fp_endDate' => array(
'name' => t('Opportunity End Date (fp:endDate)'),
'description' => t('The end date for a volunteer opportunity.'),
),
'fp_base_url' => array(
'name' => t('AFG: Hash (fp:base_url)'),
'description' => t('Same as fp:id.'),
),
'fp_xml_url' => array(
'name' => t('AFG: Opportunity URL with Hash (fp:xml_url)'),
'description' => t('Full URL to opportunity, including hash. (Same as GUID of opportunity.)'),
),
'fp_url_short' => array(
'name' => t('AFG: Opportunity URL Domain Name (fp:url_short)'),
'description' => t('The domain name of the site where the original opportunity listing is found.'),
),
'fp_latlong' => array(
'name' => t('AFG: Raw Latitude/Longitude (fp:latlong)'),
'description' => t('Latitude, Longitude to seven digits of precision. Needs custom parsing to be mapped.'),
),
'fp_location_name' => array(
'name' => t('AFG: Opportunity City, State Zip (fp:location_name)'),
'description' => t('Opportunity location, with city, state, and zip all in one field.'),
),
'fp_interest_count' => array(
'name' => t('AFG: Clickthrus? (fp:interest_count)'),
'description' => t('Unsure - possibly number of clickthrus.'),
),
'fp_impressions' => array(
'name' => t('AFG: Number of Pageviews? (fp:impressions)'),
'description' => t('Unsure - possibly number of pageviews, possibly related to an ad campaign.'),
),
'fp_quality_score' => array(
'name' => t('AFG: Opportunity Rating (fp:quality_score)'),
'description' => t('Internal rating from 0 to 10 of quality of opportunity.'),
),
'fp_virtual' => array(
'name' => t('AFG: Virtual Opportunity Status (fp:virtual)'),
'description' => t('Whether opportunity is virtual - True or False.'),
),
'fp_sponsoringOrganizationName' => array(
'name' => t('AFG: Sponsoring Organization Name (fp:sponsoringOrganizationName)'),
'description' => t('Name of organization offering this opportunity.'),
),
'fp_openEnded' => array(
'name' => t('AFG: Open-Ended Opportunity Status (fp:openEnded)'),
'description' => t('Whether opportunity is open-ended (no specific start or end date).'),
),
'fp_startTime' => array(
'name' => t('AFG: Opportunity Start Time (fp:startTime)'),
'description' => t('Opportunity start time.'),
),
'fp_endTime' => array(
'name' => t('AFG: Opportunity End Time (fp:endTime)'),
'description' => t('Opportunity end time.'),
),
/* Fields that are sometimes present on an AFG feed. */
'fp_skills' => array(
'name' => t('AFG: Opportunity Skills (fp:skills)'),
'description' => t('Skills needed for this opportunity. (Many providers use this as a detailed description.)'),
),
'fp_contactEmail' => array(
'name' => t('AFG: Email Address for Primary Contact (fp:contactEmail)'),
'description' => t('The email address for the primary contact for the opportunity.'),
),
'fp_contactPhone' => array(
'name' => t('AFG: Phone Number for Primary Contact (fp:contactPhone)'),
'description' => t('The phone number for the primary contact for the opportunity.'),
),
/* Feeds that are never (so far) present on an AFG feed. */
'fp_categories' => array(
'name' => t('AFG: Opportunity Categories (fp:categories)'),
'description' => t('The categories with which the opportunity is tagged. (Providers won\'t usually offer this.)'),
),
'fp_s' => array(
'name' => t('fp:s'),
'description' => t('Unsure.'),
),
'fp_m' => array(
'name' => t('fp:m'),
'description' => t('Unsure.'),
),
'fp_addr1' => array(
'name' => t('AFG: First Line of Address? (fp:addr1)'),
'description' => t('First line of address?'),
),
'fp_addrname' => array(
'name' => t('AFG: Address Name? (fp:addrname)'),
'description' => t('Address Name?'),
),
'fp_contactNoneNeeded' => array(
'name' => t('fp:contactNoneNeeded'),
'description' => t('Unsure.'),
),
'fp_contactName' => array(
'name' => t('AFG: Name of Primary Contact? (fp:contactName)'),
'description' => t('Name of Primary Contact?'),
),
'fp_detailUrl' => array(
'name' => t('AFG: Link to Original Opportunity? (fp:detailUrl)'),
'description' => t('Link to Original Opportunity?'),
),
'fp_audienceAll' => array(
'name' => t('fp:audienceAll'),
'description' => t('Unsure.'),
),
'fp_audienceAge' => array(
'name' => t('AFG: Acceptable Ages? (fp:audienceAge)'),
'description' => t('What ages of volunteer the opportunity is suited for?'),
),
'fp_minAge' => array(
'name' => t('AFG: Minimum Age? (fp:minAge)'),
'description' => t('Minimum age for volunteers?'),
),
'fp_audienceSexRestricted' => array(
'name' => t('AFG: Volunteers Only of a Particular Gender? (fp:audienceSexRestricted)'),
'description' => t('Whether volunteers can only be of a particular gender?'),
),
'fp_street1' => array(
'name' => t('AFG: Street Address Line 1? (fp:street1)'),
'description' => t('Street Address Line 1?'),
),
'fp_street2' => array(
'name' => t('AFG: Street Address Line 2? (fp:street2)'),
'description' => t('Street Address Line 2?'),
),
'fp_city' => array(
'name' => t('AFG: City? (fp:city)'),
'description' => t('City?'),
),
'fp_region' => array(
'name' => t('AFG: Region/State? (fp:region)'),
'description' => t('Region/State?'),
),
'fp_postalCode' => array(
'name' => t('AFG: Postal Code/Zipcode? (fp:postalCode)'),
'description' => t('Postal Code/Zipcode?'),
),
'fp_country' => array(
'name' => t('AFG: Country? (fp:country)'),
'description' => t('Country?'),
),
/* Service and Interest Area Auto-Tagged Value */
'volopp_tagged_value' => array(
'name' => t('Opportunity Currently Auto-Tagged'),
'description' => t('Whether or not the opportunity is currently auto-tagged by cron (always 0 on an import)'),
),
);
}
/**
* Parse the extra mapping sources from the AFG feed.
*/
protected function parseExtensions(&$item, $simplepie_item) {
// define the AllForGood namespace (needed for SimplePie's get_item_tags() method)
$afg_namespace = 'http://www.allforgood.org/';
// define the tags from the AFG feed
// also have custom fields for latitude/longitude and start/end date, below
$fp_tags = array('id', 'groupid', 'provider', 'startDate', 'endDate', 'base_url', 'xml_url',
'url_short', 'latlong', 'location_name', 'interest_count', 'impressions',
'quality_score', 'virtual', 'sponsoringOrganizationName', 'openEnded', 'startTime',
'endTime', 'skills', 'contactEmail', 'contactPhone', 'categories', 's', 'm', 'v',
'addr1', 'addrname1', 'contactNoneNeeded', 'contactName', 'detailUrl',
'audienceAll', 'audienceAge', 'minAge', 'audienceSexRestricted', 'street1',
'street2', 'city', 'region', 'postalCode', 'country');
// set the value for "stripped_guid"
if ($value = $simplepie_item->get_id()) {
// split the GUID on the '#' and set the stripped_guid to be just the part before it
$guid_pieces = explode('#', $value);
$item['stripped_guid'] = $guid_pieces[0];
}
// set the values for the AFG tags
foreach($fp_tags as $tagname) {
if($value = $simplepie_item->get_item_tags($afg_namespace, $tagname)) {
$item['fp_' . $tagname] = $value[0]['data'];
}
}
// set the values for the separate latitude and longitude fields
if ($value = $simplepie_item->get_item_tags($afg_namespace, 'latlong')) {
// split apart the fp:latlong on the comma
$points = explode(',', $value[0]['data']);
// latitude comes first
$item['afg_lat'] = $points[0];
// longitude comes second
$item['afg_long'] = $points[1];
}
// set the value for the opportunity start date in MM/DD/YYYY format
if ($value = $simplepie_item->get_item_tags($afg_namespace, 'startDate')) {
$timestamp = strtotime($value[0]['data']);
$item['afg_startDate'] = date('m/d/Y', $timestamp);
}
// set the value for the opportunity end date in MM/DD/YYYY format
if ($value = $simplepie_item->get_item_tags($afg_namespace, 'endDate')) {
$timestamp = strtotime($value[0]['data']);
$item['afg_endDate'] = date('m/d/Y', $timestamp);
}
if (isset($item['title']) && !empty($item['title']) && isset($item['description']) && !empty($item['description']) &&
isset($item['fp_provider']) && !empty($item['fp_provider'])) {
$item['volopp_hash'] = md5($item['title'] . $item['description'] . $item['fp_provider']);
dd($item['volopp_hash']);
}
// Set the service area tagged value to 0 to avoid "cannot be NULL" warning
$item['volopp_tagged_value'] = 0;
}
}