Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | ||
3 | require_once 'CRM/Core/Page.php'; | |
4 | ||
5 | /** | |
6 | * This class is not a real page -- it contains helpers for rendering the profile-selector and profile-editor | |
7 | * widgets | |
8 | */ | |
9 | class CRM_UF_Page_ProfileEditor extends CRM_Core_Page { | |
3655bea4 | 10 | |
e8e8f3ad | 11 | /** |
12 | * Run page. | |
13 | * | |
14 | * @throws \Exception | |
15 | */ | |
00be9182 | 16 | public function run() { |
6a488035 TO |
17 | CRM_Core_Error::fatal('This is not a real page!'); |
18 | } | |
19 | ||
e8e8f3ad | 20 | /** |
21 | * Register profile scripts. | |
22 | */ | |
00be9182 | 23 | public static function registerProfileScripts() { |
6a488035 | 24 | static $loaded = FALSE; |
daf0f4f3 | 25 | if ($loaded || CRM_Core_Resources::isAjaxMode()) { |
6a488035 TO |
26 | return; |
27 | } | |
28 | $loaded = TRUE; | |
29 | ||
30 | CRM_Core_Resources::singleton() | |
353ffa53 | 31 | ->addSettingsFactory(function () { |
be2fb01f | 32 | $ufGroups = civicrm_api3('UFGroup', 'get', [ |
37375016 | 33 | 'sequential' => 1, |
34 | 'is_active' => 1, | |
be2fb01f CW |
35 | 'options' => ['limit' => 0], |
36 | ]); | |
58770077 | 37 | //CRM-16915 - insert 'module' param for the profile used by CiviEvent. |
37375016 | 38 | if (CRM_Core_Permission::check('manage event profiles') && !CRM_Core_Permission::check('administer CiviCRM')) { |
39 | foreach ($ufGroups['values'] as $key => $value) { | |
40 | $ufJoin = CRM_Core_BAO_UFGroup::getUFJoinRecord($value['id']); | |
b7fafaec | 41 | if (in_array('CiviEvent', $ufJoin) || in_array('CiviEvent_Additional', $ufJoin)) { |
37375016 | 42 | $ufGroups['values'][$key]['module'] = 'CiviEvent'; |
43 | } | |
44 | } | |
45 | } | |
be2fb01f CW |
46 | return [ |
47 | 'PseudoConstant' => [ | |
b2b0530a | 48 | 'locationType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'), |
1da6c733 | 49 | 'websiteType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'), |
b4f964d9 | 50 | 'phoneType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'), |
be2fb01f | 51 | ], |
37375016 | 52 | 'initialProfileList' => $ufGroups, |
21fced3b | 53 | 'contactSubTypes' => CRM_Contact_BAO_ContactType::subTypes(), |
6a488035 | 54 | 'profilePreviewKey' => CRM_Core_Key::get('CRM_UF_Form_Inline_Preview', TRUE), |
be2fb01f | 55 | ]; |
6a488035 | 56 | }) |
445b46bd TO |
57 | ->addScriptFile('civicrm.packages', 'backbone/json2.js', 100, 'html-header', FALSE) |
58 | ->addScriptFile('civicrm.packages', 'backbone/backbone.js', 120, 'html-header') | |
59 | ->addScriptFile('civicrm.packages', 'backbone/backbone.marionette.js', 125, 'html-header', FALSE) | |
60 | ->addScriptFile('civicrm.packages', 'backbone/backbone.collectionsubset.js', 125, 'html-header', FALSE) | |
61 | ->addScriptFile('civicrm.packages', 'backbone-forms/distribution/backbone-forms.js', 130, 'html-header', FALSE) | |
62 | ->addScriptFile('civicrm.packages', 'backbone-forms/distribution/adapters/backbone.bootstrap-modal.min.js', 140, 'html-header', FALSE) | |
63 | ->addScriptFile('civicrm.packages', 'backbone-forms/distribution/editors/list.min.js', 140, 'html-header', FALSE) | |
64 | ->addStyleFile('civicrm.packages', 'backbone-forms/distribution/templates/default.css', 140, 'html-header') | |
e7c93dd4 | 65 | ->addScript('CRM.BB = Backbone.noConflict();', 300, 'html-header') |
445b46bd TO |
66 | ->addScriptFile('civicrm.packages', 'jquery/plugins/jstree/jquery.jstree.js', 0, 'html-header', FALSE) |
67 | ->addStyleFile('civicrm.packages', 'jquery/plugins/jstree/themes/default/style.css', 0, 'html-header') | |
6a488035 TO |
68 | ->addStyleFile('civicrm', 'css/crm.designer.css', 140, 'html-header') |
69 | ->addScriptFile('civicrm', 'js/crm.backbone.js', 150) | |
70 | ->addScriptFile('civicrm', 'js/model/crm.schema-mapped.js', 200) | |
71 | ->addScriptFile('civicrm', 'js/model/crm.uf.js', 200) | |
72 | ->addScriptFile('civicrm', 'js/model/crm.designer.js', 200) | |
73 | ->addScriptFile('civicrm', 'js/model/crm.profile-selector.js', 200) | |
74 | ->addScriptFile('civicrm', 'js/view/crm.designer.js', 200) | |
75 | ->addScriptFile('civicrm', 'js/view/crm.profile-selector.js', 200) | |
76 | ->addScriptFile('civicrm', 'js/jquery/jquery.crmProfileSelector.js', 250) | |
77 | ->addScriptFile('civicrm', 'js/crm.designerapp.js', 250); | |
78 | ||
be2fb01f | 79 | CRM_Core_Region::instance('page-header')->add([ |
6a488035 | 80 | 'template' => 'CRM/UF/Page/ProfileTemplates.tpl', |
be2fb01f | 81 | ]); |
6a488035 TO |
82 | } |
83 | ||
84 | /** | |
e8e8f3ad | 85 | * Register entity schemas for use in the editor's palette. |
6a488035 | 86 | * |
5ce1712d TO |
87 | * @param array $entityTypes |
88 | * Strings, e.g. "IndividualModel", "ActivityModel". | |
6a488035 | 89 | */ |
00be9182 | 90 | public static function registerSchemas($entityTypes) { |
6a488035 TO |
91 | // TODO in cases where registerSchemas is called multiple times for same entity, be more efficient |
92 | CRM_Core_Resources::singleton()->addSettingsFactory(function () use ($entityTypes) { | |
be2fb01f | 93 | return [ |
6a488035 | 94 | 'civiSchema' => CRM_UF_Page_ProfileEditor::getSchema($entityTypes), |
be2fb01f | 95 | ]; |
6a488035 TO |
96 | }); |
97 | } | |
98 | ||
99 | /** | |
fe482240 | 100 | * AJAX callback. |
6a488035 | 101 | */ |
00be9182 | 102 | public static function getSchemaJSON() { |
6a488035 | 103 | $entityTypes = explode(',', $_REQUEST['entityTypes']); |
ecdef330 | 104 | CRM_Utils_JSON::output(self::getSchema($entityTypes)); |
6a488035 TO |
105 | } |
106 | ||
107 | /** | |
108 | * Get a list of Backbone-Form models | |
109 | * | |
5ce1712d TO |
110 | * @param array $entityTypes |
111 | * Model names ("IndividualModel"). | |
77b97be7 EM |
112 | * |
113 | * @throws CRM_Core_Exception | |
6a488035 TO |
114 | * @return array; keys are model names ("IndividualModel") and values describe 'sections' and 'schema' |
115 | * @see js/model/crm.core.js | |
116 | * @see js/model/crm.mappedcore.js | |
117 | */ | |
00be9182 | 118 | public static function getSchema($entityTypes) { |
6a488035 TO |
119 | // FIXME: Depending on context (eg civicrm/profile/create vs search-columns), it may be appropriate to |
120 | // pick importable or exportable fields | |
121 | ||
122 | $entityTypes = array_unique($entityTypes); | |
123 | $availableFields = NULL; | |
be2fb01f | 124 | $civiSchema = []; |
6a488035 TO |
125 | foreach ($entityTypes as $entityType) { |
126 | if (!$availableFields) { | |
127 | $availableFields = CRM_Core_BAO_UFField::getAvailableFieldsFlat(); | |
6a488035 TO |
128 | } |
129 | switch ($entityType) { | |
130 | case 'IndividualModel': | |
131 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
132 | 'Individual', | |
133 | ts('Individual'), | |
134 | $availableFields | |
135 | ); | |
136 | break; | |
9147c186 | 137 | |
133e2c99 | 138 | case 'OrganizationModel': |
139 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
140 | 'Organization', | |
141 | ts('Organization'), | |
142 | $availableFields | |
143 | ); | |
bf86535e | 144 | break; |
9147c186 | 145 | |
bf86535e | 146 | case 'HouseholdModel': |
147 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
148 | 'Household', | |
149 | ts('Household'), | |
150 | $availableFields | |
151 | ); | |
152 | break; | |
9147c186 | 153 | |
6a488035 TO |
154 | case 'ActivityModel': |
155 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
156 | 'Activity', | |
157 | ts('Activity'), | |
158 | $availableFields | |
159 | ); | |
160 | break; | |
9147c186 | 161 | |
6a488035 TO |
162 | case 'ContributionModel': |
163 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
164 | 'Contribution', | |
165 | ts('Contribution'), | |
166 | $availableFields | |
167 | ); | |
168 | break; | |
9147c186 | 169 | |
6a488035 TO |
170 | case 'MembershipModel': |
171 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
172 | 'Membership', | |
173 | ts('Membership'), | |
174 | $availableFields | |
175 | ); | |
176 | break; | |
9147c186 | 177 | |
6a488035 TO |
178 | case 'ParticipantModel': |
179 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
180 | 'Participant', | |
181 | ts('Participant'), | |
182 | $availableFields | |
183 | ); | |
184 | break; | |
9147c186 | 185 | |
cf1182e6 N |
186 | case 'CaseModel': |
187 | $civiSchema[$entityType] = self::convertCiviModelToBackboneModel( | |
188 | 'Case', | |
189 | ts('Case'), | |
190 | $availableFields | |
191 | ); | |
192 | break; | |
9147c186 | 193 | |
6a488035 TO |
194 | default: |
195 | throw new CRM_Core_Exception("Unrecognized entity type: $entityType"); | |
196 | } | |
197 | } | |
198 | ||
0103eaf0 | 199 | // Adding the oddball "formatting" field here because there's no other place to put it |
be2fb01f | 200 | foreach (['Individual', 'Organization', 'Household'] as $type) { |
0103eaf0 | 201 | if (isset($civiSchema[$type . 'Model'])) { |
be2fb01f CW |
202 | $civiSchema[$type . 'Model']['schema'] += [ |
203 | 'formatting' => [ | |
0103eaf0 CW |
204 | 'type' => 'Markup', |
205 | 'title' => ts('Free HTML'), | |
206 | 'civiFieldType' => 'Formatting', | |
207 | 'section' => 'formatting', | |
be2fb01f CW |
208 | ], |
209 | ]; | |
210 | $civiSchema[$type . 'Model']['sections'] += [ | |
211 | 'formatting' => [ | |
0103eaf0 CW |
212 | 'title' => ts('Formatting'), |
213 | 'is_addable' => FALSE, | |
be2fb01f CW |
214 | ], |
215 | ]; | |
0103eaf0 CW |
216 | } |
217 | } | |
218 | ||
6a488035 TO |
219 | return $civiSchema; |
220 | } | |
221 | ||
222 | /** | |
223 | * FIXME: Move to somewhere more useful | |
224 | * FIXME: Do real mapping of "types" | |
225 | * | |
5ce1712d TO |
226 | * @param string $extends |
227 | * Entity type; note: "Individual" means "Individual|Contact"; "Household" means "Household|Contact". | |
228 | * @param string $title | |
229 | * A string to use in section headers. | |
230 | * @param array $availableFields | |
231 | * List of fields that are allowed in profiles, e.g. $availableFields['my_field']['field_type']. | |
a6c01b45 CW |
232 | * @return array |
233 | * with keys 'sections' and 'schema' | |
6a488035 TO |
234 | * @see js/model/crm.core.js |
235 | * @see js/model/crm.mappedcore.js | |
236 | */ | |
00be9182 | 237 | public static function convertCiviModelToBackboneModel($extends, $title, $availableFields) { |
6a488035 TO |
238 | $locationFields = CRM_Core_BAO_UFGroup::getLocationFields(); |
239 | ||
c5c263ca AH |
240 | // schema in format array($fieldName => $fieldSchema) |
241 | // sections in format array($sectionName => $section) | |
be2fb01f CW |
242 | $result = [ |
243 | 'schema' => [], | |
244 | 'sections' => [], | |
245 | ]; | |
6a488035 TO |
246 | |
247 | // build field list | |
248 | foreach ($availableFields as $fieldName => $field) { | |
249 | switch ($extends) { | |
250 | case 'Individual': | |
251 | case 'Organization': | |
252 | case 'Household': | |
21fced3b | 253 | if ($field['field_type'] != $extends && $field['field_type'] != 'Contact' |
254 | //CRM-15595 check if subtype | |
353ffa53 TO |
255 | && !in_array($field['field_type'], CRM_Contact_BAO_ContactType::subTypes($extends)) |
256 | ) { | |
6a488035 TO |
257 | continue 2; |
258 | } | |
259 | break; | |
9147c186 | 260 | |
6a488035 TO |
261 | default: |
262 | if ($field['field_type'] != $extends) { | |
263 | continue 2; | |
264 | } | |
265 | } | |
c5c263ca | 266 | // FIXME: type set to "Text" |
be2fb01f | 267 | $result['schema'][$fieldName] = [ |
c5c263ca | 268 | 'type' => 'Text', |
6a488035 TO |
269 | 'title' => $field['title'], |
270 | 'civiFieldType' => $field['field_type'], | |
be2fb01f | 271 | ]; |
6a488035 TO |
272 | if (in_array($fieldName, $locationFields)) { |
273 | $result['schema'][$fieldName]['civiIsLocation'] = TRUE; | |
274 | } | |
1a228b4c | 275 | if ($fieldName == 'url') { |
1da6c733 | 276 | $result['schema'][$fieldName]['civiIsWebsite'] = TRUE; |
1a228b4c | 277 | } |
be2fb01f | 278 | if (in_array($fieldName, ['phone', 'phone_and_ext'])) { |
971d41b1 | 279 | // FIXME what about phone_ext? |
6a488035 TO |
280 | $result['schema'][$fieldName]['civiIsPhone'] = TRUE; |
281 | } | |
282 | } | |
283 | ||
284 | // build section list | |
be2fb01f | 285 | $result['sections']['default'] = [ |
6a488035 TO |
286 | 'title' => $title, |
287 | 'is_addable' => FALSE, | |
be2fb01f | 288 | ]; |
6a488035 TO |
289 | |
290 | $customGroup = CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity($extends); | |
291 | $customGroup->orderBy('weight'); | |
292 | $customGroup->is_active = 1; | |
293 | $customGroup->find(); | |
294 | while ($customGroup->fetch()) { | |
295 | $sectionName = 'cg_' . $customGroup->id; | |
be2fb01f CW |
296 | $section = [ |
297 | 'title' => ts('%1: %2', [1 => $title, 2 => $customGroup->title]), | |
0249f58e | 298 | 'is_addable' => $customGroup->is_reserved ? FALSE : TRUE, |
6a488035 TO |
299 | 'custom_group_id' => $customGroup->id, |
300 | 'extends_entity_column_id' => $customGroup->extends_entity_column_id, | |
301 | 'extends_entity_column_value' => CRM_Utils_Array::explodePadded($customGroup->extends_entity_column_value), | |
db7b725d | 302 | 'is_reserved' => $customGroup->is_reserved ? TRUE : FALSE, |
be2fb01f | 303 | ]; |
6a488035 TO |
304 | $result['sections'][$sectionName] = $section; |
305 | } | |
306 | ||
307 | // put fields in their sections | |
308 | $fields = CRM_Core_BAO_CustomField::getFields($extends); | |
309 | foreach ($fields as $fieldId => $field) { | |
310 | $sectionName = 'cg_' . $field['custom_group_id']; | |
311 | $fieldName = 'custom_' . $fieldId; | |
312 | if (isset($result['schema'][$fieldName])) { | |
313 | $result['schema'][$fieldName]['section'] = $sectionName; | |
314 | $result['schema'][$fieldName]['civiIsMultiple'] = (bool) CRM_Core_BAO_CustomField::isMultiRecordField($fieldId); | |
315 | } | |
316 | } | |
317 | return $result; | |
318 | } | |
96025800 | 319 | |
6a488035 | 320 | } |