Commit | Line | Data |
---|---|---|
fd1ea018 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | Copyright CiviCRM LLC. All rights reserved. | | |
5 | | | | |
6 | | This work is published under the GNU AGPLv3 license with some | | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
9 | +--------------------------------------------------------------------+ | |
10 | */ | |
11 | ||
12 | /** | |
13 | * | |
14 | * @package CRM | |
15 | * @copyright CiviCRM LLC https://civicrm.org/licensing | |
16 | */ | |
ee44263e | 17 | class CRM_Core_BAO_Translation extends CRM_Core_DAO_Translation implements \Civi\Core\HookInterface { |
7782deca TO |
18 | |
19 | use CRM_Core_DynamicFKAccessTrait; | |
fd1ea018 TO |
20 | |
21 | /** | |
22 | * Get a list of valid statuses for translated-strings. | |
23 | * | |
815facd4 | 24 | * @return array[] |
fd1ea018 | 25 | */ |
815facd4 CW |
26 | public static function getStatuses() { |
27 | return [ | |
fd1ea018 TO |
28 | ['id' => 1, 'name' => 'active', 'label' => ts('Active')], |
29 | ['id' => 2, 'name' => 'draft', 'label' => ts('Draft')], | |
30 | ]; | |
fd1ea018 TO |
31 | } |
32 | ||
33 | /** | |
34 | * Get a list of tables with translatable strings. | |
35 | * | |
36 | * @return string[] | |
37 | * Ex: ['civicrm_event' => 'civicrm_event'] | |
38 | */ | |
39 | public static function getEntityTables() { | |
40 | if (!isset(Civi::$statics[__CLASS__]['allTables'])) { | |
41 | $tables = array_keys(self::getTranslatedFields()); | |
42 | Civi::$statics[__CLASS__]['allTables'] = array_combine($tables, $tables); | |
43 | } | |
44 | return Civi::$statics[__CLASS__]['allTables']; | |
45 | } | |
46 | ||
47 | /** | |
48 | * Get a list of fields with translatable strings. | |
49 | * | |
50 | * @return string[] | |
51 | * Ex: ['title' => 'title', 'description' => 'description'] | |
52 | */ | |
53 | public static function getEntityFields() { | |
54 | if (!isset(Civi::$statics[__CLASS__]['allFields'])) { | |
55 | $allFields = []; | |
56 | foreach (self::getTranslatedFields() as $columns) { | |
57 | foreach ($columns as $column => $sqlExpr) { | |
58 | $allFields[$column] = $column; | |
59 | } | |
60 | } | |
61 | Civi::$statics[__CLASS__]['allFields'] = $allFields; | |
62 | } | |
63 | return Civi::$statics[__CLASS__]['allFields']; | |
64 | } | |
65 | ||
fd1ea018 TO |
66 | /** |
67 | * @return array | |
68 | * List of data fields to translate, organized by table and column. | |
69 | * Omitted/unlisted fields are not translated. Any listed field may be translated. | |
70 | * Values should be TRUE. | |
71 | * Ex: $fields['civicrm_event']['summary'] = TRUE | |
72 | */ | |
73 | public static function getTranslatedFields() { | |
74 | $key = 'translatedFields'; | |
75 | $cache = Civi::cache('fields'); | |
76 | if (($r = $cache->get($key)) !== NULL) { | |
77 | return $r; | |
78 | } | |
79 | ||
80 | $f = []; | |
81 | \CRM_Utils_Hook::translateFields($f); | |
82 | ||
83 | // Future: Assimilate defaults originating in XML (incl extension-entities) | |
84 | // e.g. CRM_Core_I18n_SchemaStructure::columns() will grab core fields | |
85 | ||
86 | $cache->set($key, $f); | |
87 | return $f; | |
88 | } | |
89 | ||
7782deca TO |
90 | /** |
91 | * When manipulating strings via the `Translation` entity (APIv4), ensure that the references are well-formed. | |
92 | * | |
93 | * @param \Civi\Api4\Event\ValidateValuesEvent $e | |
94 | */ | |
95 | public static function self_civi_api4_validate(\Civi\Api4\Event\ValidateValuesEvent $e) { | |
815facd4 | 96 | $statuses = array_column(self::getStatuses(), 'id'); |
7782deca | 97 | $dataTypes = [CRM_Utils_Type::T_STRING, CRM_Utils_Type::T_TEXT, CRM_Utils_Type::T_LONGTEXT]; |
9ac45bdf | 98 | $htmlTypes = ['Text', 'TextArea', 'RichTextEditor', '']; |
7782deca TO |
99 | |
100 | foreach ($e->records as $r => $record) { | |
815facd4 | 101 | if (array_key_exists('status_id', $record) && !in_array($record['status_id'], $statuses)) { |
7782deca TO |
102 | $e->addError($r, 'status_id', 'invalid', ts('Invalid status')); |
103 | } | |
104 | ||
105 | $entityIdFields = ['entity_table', 'entity_field', 'entity_id']; | |
106 | $entityIdCount = (empty($record['entity_table']) ? 0 : 1) | |
107 | + (empty($record['entity_field']) ? 0 : 1) | |
108 | + (empty($record['entity_id']) ? 0 : 1); | |
109 | if ($entityIdCount === 0) { | |
110 | continue; | |
111 | } | |
112 | elseif ($entityIdCount < 3) { | |
113 | $e->addError($r, $entityIdFields, 'full_entity', ts('Must specify all entity identification fields')); | |
114 | } | |
115 | ||
116 | $simpleName = '/^[a-zA-Z0-9_]+$/'; | |
117 | if (!preg_match($simpleName, $record['entity_table']) || !preg_match($simpleName, $record['entity_field']) || !is_numeric($record['entity_id'])) { | |
118 | $e->addError($r, $entityIdFields, 'malformed_entity', ts('Entity reference is malformed')); | |
119 | continue; | |
120 | } | |
121 | ||
122 | // Which fields support translation? | |
123 | // - One could follow the same path as "Multilingual". Use | |
124 | // $translatable = CRM_Core_I18n_SchemaStructure::columns(); | |
125 | // if (!isset($translatable[$record['entity_table']][$record['entity_field']])) { | |
126 | // - Or, since we don't need schema-changes, we could be more generous and allow all freeform text fields... | |
127 | ||
128 | $daoClass = CRM_Core_DAO_AllCoreTables::getClassForTable($record['entity_table']); | |
129 | if (!$daoClass) { | |
130 | $e->addError($r, 'entity_table', 'bad_table', ts('Entity reference specifies a non-existent or non-translatable table')); | |
131 | continue; | |
132 | } | |
133 | ||
134 | $dao = new $daoClass(); | |
135 | $dao->id = $record['entity_id']; | |
136 | ||
137 | $field = $dao->getFieldSpec($record['entity_field']); | |
138 | if (!$field || !in_array($field['type'] ?? '', $dataTypes) || !in_array($field['html']['type'] ?? '', $htmlTypes)) { | |
139 | $e->addError($r, 'entity_field', 'bad_field', ts('Entity reference specifies a non-existent or non-translatable field')); | |
140 | } | |
141 | if (!$dao->find()) { | |
142 | $e->addError($r, 'entity_id', 'nonexistent_id', ts('Entity does not exist')); | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
fd1ea018 | 147 | } |