Skip to content

Commit f98de17

Browse files
authored
Merge pull request #24 from LibreCodeCoop/refactor/l10n-literal-strings-in-services
refactor(php): inject IL10N into services, translate exception messages at throw site
2 parents 556a4d9 + fc59d73 commit f98de17

15 files changed

+133
-60
lines changed

lib/Controller/FieldDefinitionApiController.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use OCP\AppFramework\Http\Attribute\ApiRoute;
1818
use OCP\AppFramework\Http\DataResponse;
1919
use OCP\AppFramework\OCSController;
20+
use OCP\IL10N;
2021
use OCP\IRequest;
2122

2223
/**
@@ -26,6 +27,7 @@ class FieldDefinitionApiController extends OCSController {
2627
public function __construct(
2728
IRequest $request,
2829
private FieldDefinitionService $fieldDefinitionService,
30+
private IL10N $l10n,
2931
) {
3032
parent::__construct(Application::APP_ID, $request);
3133
}
@@ -129,7 +131,7 @@ public function update(
129131
): DataResponse {
130132
$existing = $this->fieldDefinitionService->findById($id);
131133
if ($existing === null) {
132-
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
134+
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
133135
}
134136

135137
try {
@@ -167,7 +169,7 @@ public function update(
167169
public function delete(int $id): DataResponse {
168170
$definition = $this->fieldDefinitionService->delete($id);
169171
if ($definition === null) {
170-
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
172+
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
171173
}
172174

173175
return new DataResponse($definition->jsonSerialize(), Http::STATUS_OK);

lib/Controller/FieldValueAdminApiController.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OCP\AppFramework\Http\Attribute\ApiRoute;
2020
use OCP\AppFramework\Http\DataResponse;
2121
use OCP\AppFramework\OCSController;
22+
use OCP\IL10N;
2223
use OCP\IRequest;
2324
use OCP\IUser;
2425
use OCP\IUserManager;
@@ -35,6 +36,7 @@ public function __construct(
3536
private FieldDefinitionService $fieldDefinitionService,
3637
private FieldValueService $fieldValueService,
3738
private IUserManager $userManager,
39+
private IL10N $l10n,
3840
private ?string $userId,
3941
) {
4042
parent::__construct(Application::APP_ID, $request);
@@ -82,12 +84,12 @@ public function upsert(
8284
?string $currentVisibility = null,
8385
): DataResponse {
8486
if ($this->userId === null) {
85-
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
87+
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
8688
}
8789

8890
$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
8991
if ($definition === null || !$definition->getActive()) {
90-
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
92+
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
9193
}
9294

9395
try {
@@ -122,12 +124,12 @@ public function lookup(
122124
array|string|int|float|bool|null $fieldValue = null,
123125
): DataResponse {
124126
if ($this->userId === null) {
125-
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
127+
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
126128
}
127129

128130
$definition = $this->fieldDefinitionService->findByFieldKey($fieldKey);
129131
if ($definition === null || !$definition->getActive()) {
130-
return new DataResponse(['message' => 'Lookup field definition not found'], Http::STATUS_NOT_FOUND);
132+
return new DataResponse(['message' => $this->l10n->t('Lookup field definition not found')], Http::STATUS_NOT_FOUND);
131133
}
132134

133135
try {
@@ -137,11 +139,11 @@ public function lookup(
137139
}
138140

139141
if ($matches === []) {
140-
return new DataResponse(['message' => 'User not found for lookup field value'], Http::STATUS_NOT_FOUND);
142+
return new DataResponse(['message' => $this->l10n->t('User not found for lookup field value')], Http::STATUS_NOT_FOUND);
141143
}
142144

143145
if (count($matches) > 1) {
144-
return new DataResponse(['message' => 'Multiple users match the lookup field value'], Http::STATUS_CONFLICT);
146+
return new DataResponse(['message' => $this->l10n->t('Multiple users match the lookup field value')], Http::STATUS_CONFLICT);
145147
}
146148

147149
return new DataResponse($this->serializeLookupResult($definition, $matches[0]), Http::STATUS_OK);
@@ -174,12 +176,12 @@ public function search(
174176
int $offset = 0,
175177
): DataResponse {
176178
if ($this->userId === null) {
177-
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
179+
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
178180
}
179181

180182
$definition = $this->fieldDefinitionService->findByFieldKey($fieldKey);
181183
if ($definition === null || !$definition->getActive()) {
182-
return new DataResponse(['message' => 'Search field definition not found'], Http::STATUS_NOT_FOUND);
184+
return new DataResponse(['message' => $this->l10n->t('Search field definition not found')], Http::STATUS_NOT_FOUND);
183185
}
184186

185187
try {

lib/Controller/FieldValueApiController.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
2020
use OCP\AppFramework\Http\DataResponse;
2121
use OCP\AppFramework\OCSController;
22+
use OCP\IL10N;
2223
use OCP\IRequest;
2324

2425
/**
@@ -32,6 +33,7 @@ public function __construct(
3233
private FieldDefinitionService $fieldDefinitionService,
3334
private FieldValueService $fieldValueService,
3435
private FieldAccessService $fieldAccessService,
36+
private IL10N $l10n,
3537
private ?string $userId,
3638
) {
3739
parent::__construct(Application::APP_ID, $request);
@@ -52,7 +54,7 @@ public function __construct(
5254
#[ApiRoute(verb: 'GET', url: '/api/v1/me/values')]
5355
public function index(): DataResponse {
5456
if ($this->userId === null) {
55-
return new DataResponse(['message' => 'Authenticated user is required'], 401);
57+
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
5658
}
5759

5860
$definitions = $this->fieldDefinitionService->findActiveOrdered();
@@ -113,20 +115,20 @@ public function upsert(
113115
?string $currentVisibility = null,
114116
): DataResponse {
115117
if ($this->userId === null) {
116-
return new DataResponse(['message' => 'Authenticated user is required'], 401);
118+
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
117119
}
118120

119121
$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
120122
if ($definition === null || !$definition->getActive()) {
121-
return new DataResponse(['message' => 'Field definition not found'], 404);
123+
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], 404);
122124
}
123125

124126
if (!$this->fieldAccessService->canEditValue($this->userId, $this->userId, $definition, false)) {
125-
return new DataResponse(['message' => 'Field cannot be edited by the user'], 403);
127+
return new DataResponse(['message' => $this->l10n->t('Field cannot be edited by the user')], 403);
126128
}
127129

128130
if ($currentVisibility !== null && !$this->fieldAccessService->canChangeVisibility($this->userId, $this->userId, false)) {
129-
return new DataResponse(['message' => 'Field visibility cannot be changed by the user'], 403);
131+
return new DataResponse(['message' => $this->l10n->t('Field visibility cannot be changed by the user')], 403);
130132
}
131133

132134
try {
@@ -160,20 +162,20 @@ public function updateVisibility(
160162
string $currentVisibility,
161163
): DataResponse {
162164
if ($this->userId === null) {
163-
return new DataResponse(['message' => 'Authenticated user is required'], 401);
165+
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
164166
}
165167

166168
$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
167169
if ($definition === null || !$definition->getActive()) {
168-
return new DataResponse(['message' => 'Field definition not found'], 404);
170+
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], 404);
169171
}
170172

171173
if (!$this->fieldAccessService->canEditValue($this->userId, $this->userId, $definition, false)) {
172-
return new DataResponse(['message' => 'Field cannot be edited by the user'], 403);
174+
return new DataResponse(['message' => $this->l10n->t('Field cannot be edited by the user')], 403);
173175
}
174176

175177
if (!$this->fieldAccessService->canChangeVisibility($this->userId, $this->userId, false)) {
176-
return new DataResponse(['message' => 'Field visibility cannot be changed by the user'], 403);
178+
return new DataResponse(['message' => $this->l10n->t('Field visibility cannot be changed by the user')], 403);
177179
}
178180

179181
try {

lib/Service/FieldDefinitionService.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
use OCA\ProfileFields\Db\FieldDefinition;
1616
use OCA\ProfileFields\Db\FieldDefinitionMapper;
1717
use OCA\ProfileFields\Db\FieldValueMapper;
18+
use OCP\IL10N;
1819

1920
class FieldDefinitionService {
2021
public function __construct(
2122
private FieldDefinitionMapper $fieldDefinitionMapper,
2223
private FieldValueMapper $fieldValueMapper,
2324
private FieldDefinitionValidator $validator,
25+
private IL10N $l10n,
2426
) {
2527
}
2628

@@ -30,7 +32,7 @@ public function __construct(
3032
public function create(array $definition): FieldDefinition {
3133
$validated = $this->validator->validate($definition);
3234
if ($this->fieldDefinitionMapper->findByFieldKey($validated['field_key']) !== null) {
33-
throw new InvalidArgumentException('field_key already exists');
35+
throw new InvalidArgumentException($this->l10n->t('field_key already exists'));
3436
}
3537

3638
$createdAt = $this->parseImportedDate($definition['created_at'] ?? null) ?? new DateTime();
@@ -46,7 +48,7 @@ public function create(array $definition): FieldDefinition {
4648
try {
4749
$entity->setOptions(isset($validated['options']) ? json_encode($validated['options'], JSON_THROW_ON_ERROR) : null);
4850
} catch (JsonException $e) {
49-
throw new InvalidArgumentException('options could not be encoded: ' . $e->getMessage(), 0, $e);
51+
throw new InvalidArgumentException($this->l10n->t('options could not be encoded: %s', [$e->getMessage()]), 0, $e);
5052
}
5153
$entity->setCreatedAt($createdAt);
5254
$entity->setUpdatedAt($updatedAt);
@@ -60,11 +62,11 @@ public function create(array $definition): FieldDefinition {
6062
public function update(FieldDefinition $existing, array $definition): FieldDefinition {
6163
$validated = $this->validator->validate($definition + ['field_key' => $existing->getFieldKey()]);
6264
if (($definition['field_key'] ?? $existing->getFieldKey()) !== $existing->getFieldKey()) {
63-
throw new InvalidArgumentException('field_key cannot be changed');
65+
throw new InvalidArgumentException($this->l10n->t('field_key cannot be changed'));
6466
}
6567

6668
if ($validated['type'] !== $existing->getType() && $this->fieldValueMapper->hasValuesForFieldDefinitionId($existing->getId())) {
67-
throw new InvalidArgumentException('type cannot be changed after values exist');
69+
throw new InvalidArgumentException($this->l10n->t('type cannot be changed after values exist'));
6870
}
6971

7072
$existing->setLabel($validated['label']);
@@ -76,7 +78,7 @@ public function update(FieldDefinition $existing, array $definition): FieldDefin
7678
try {
7779
$existing->setOptions(isset($validated['options']) ? json_encode($validated['options'], JSON_THROW_ON_ERROR) : null);
7880
} catch (JsonException $e) {
79-
throw new InvalidArgumentException('options could not be encoded: ' . $e->getMessage(), 0, $e);
81+
throw new InvalidArgumentException($this->l10n->t('options could not be encoded: %s', [$e->getMessage()]), 0, $e);
8082
}
8183
$existing->setUpdatedAt($this->parseImportedDate($definition['updated_at'] ?? null) ?? new DateTime());
8284

lib/Service/FieldValueService.php

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use OCA\ProfileFields\Workflow\Event\ProfileFieldVisibilityUpdatedEvent;
2525
use OCA\ProfileFields\Workflow\ProfileFieldValueWorkflowSubject;
2626
use OCP\EventDispatcher\IEventDispatcher;
27+
use OCP\IL10N;
2728

2829
class FieldValueService {
2930
private const SEARCH_OPERATOR_EQ = 'eq';
@@ -33,6 +34,7 @@ class FieldValueService {
3334
public function __construct(
3435
private FieldValueMapper $fieldValueMapper,
3536
private IEventDispatcher $eventDispatcher,
37+
private IL10N $l10n,
3638
) {
3739
}
3840

@@ -51,7 +53,7 @@ public function upsert(
5153
$valueJson = $this->encodeValue($normalizedValue);
5254
$visibility = $currentVisibility ?? FieldExposurePolicy::from($definition->getExposurePolicy())->initialVisibility()->value;
5355
if (!FieldVisibility::isValid($visibility)) {
54-
throw new InvalidArgumentException('current_visibility is not supported');
56+
throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported'));
5557
}
5658

5759
$entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid) ?? new FieldValue();
@@ -143,16 +145,16 @@ public function searchByDefinition(
143145
int $offset,
144146
): array {
145147
if ($limit < 1 || $limit > self::SEARCH_MAX_LIMIT) {
146-
throw new InvalidArgumentException(sprintf('limit must be between 1 and %d', self::SEARCH_MAX_LIMIT));
148+
throw new InvalidArgumentException($this->l10n->t('limit must be between 1 and %d', [self::SEARCH_MAX_LIMIT]));
147149
}
148150

149151
if ($offset < 0) {
150-
throw new InvalidArgumentException('offset must be greater than or equal to 0');
152+
throw new InvalidArgumentException($this->l10n->t('offset must be greater than or equal to 0'));
151153
}
152154

153155
$normalizedOperator = strtolower(trim($operator));
154156
if (!in_array($normalizedOperator, [self::SEARCH_OPERATOR_EQ, self::SEARCH_OPERATOR_CONTAINS], true)) {
155-
throw new InvalidArgumentException('search operator is not supported');
157+
throw new InvalidArgumentException($this->l10n->t('search operator is not supported'));
156158
}
157159

158160
$searchValue = $this->normalizeSearchValue($definition, $normalizedOperator, $rawValue);
@@ -175,12 +177,12 @@ public function searchByDefinition(
175177

176178
public function updateVisibility(FieldDefinition $definition, string $userUid, string $updatedByUid, string $currentVisibility): FieldValue {
177179
if (!FieldVisibility::isValid($currentVisibility)) {
178-
throw new InvalidArgumentException('current_visibility is not supported');
180+
throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported'));
179181
}
180182

181183
$entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid);
182184
if ($entity === null) {
183-
throw new InvalidArgumentException('field value not found');
185+
throw new InvalidArgumentException($this->l10n->t('field value not found'));
184186
}
185187

186188
$previousValue = $this->extractScalarValue($entity->getValueJson());
@@ -227,7 +229,7 @@ public function serializeForResponse(FieldValue $value): array {
227229
*/
228230
private function normalizeTextValue(array|string|int|float|bool $rawValue): array {
229231
if (is_array($rawValue)) {
230-
throw new InvalidArgumentException('text fields expect a scalar value');
232+
throw new InvalidArgumentException($this->l10n->t('text fields expect a scalar value'));
231233
}
232234

233235
return ['value' => trim((string)$rawValue)];
@@ -239,13 +241,13 @@ private function normalizeTextValue(array|string|int|float|bool $rawValue): arra
239241
*/
240242
private function normalizeSelectValue(array|string|int|float|bool $rawValue, FieldDefinition $definition): array {
241243
if (!is_string($rawValue)) {
242-
throw new InvalidArgumentException('select fields expect a string value');
244+
throw new InvalidArgumentException($this->l10n->t('select fields expect a string value'));
243245
}
244246

245247
$value = trim($rawValue);
246248
$options = json_decode($definition->getOptions() ?? '[]', true);
247249
if (!in_array($value, $options, true)) {
248-
throw new InvalidArgumentException(sprintf('"%s" is not a valid option for this field', $value));
250+
throw new InvalidArgumentException($this->l10n->t('"%s" is not a valid option for this field', [$value]));
249251
}
250252

251253
return ['value' => $value];
@@ -257,7 +259,7 @@ private function normalizeSelectValue(array|string|int|float|bool $rawValue, Fie
257259
*/
258260
private function normalizeNumberValue(array|string|int|float|bool $rawValue): array {
259261
if (is_array($rawValue) || is_bool($rawValue) || !is_numeric($rawValue)) {
260-
throw new InvalidArgumentException('number fields expect a numeric value');
262+
throw new InvalidArgumentException($this->l10n->t('number fields expect a numeric value'));
261263
}
262264

263265
return ['value' => str_contains((string)$rawValue, '.') ? (float)$rawValue : (int)$rawValue];
@@ -270,7 +272,7 @@ private function encodeValue(array $value): string {
270272
try {
271273
return json_encode($value, JSON_THROW_ON_ERROR);
272274
} catch (JsonException $exception) {
273-
throw new InvalidArgumentException('value_json could not be encoded', 0, $exception);
275+
throw new InvalidArgumentException($this->l10n->t('value_json could not be encoded'), 0, $exception);
274276
}
275277
}
276278

@@ -281,11 +283,11 @@ private function decodeValue(string $valueJson): array {
281283
try {
282284
$decoded = json_decode($valueJson, true, 512, JSON_THROW_ON_ERROR);
283285
} catch (JsonException $exception) {
284-
throw new InvalidArgumentException('value_json could not be decoded', 0, $exception);
286+
throw new InvalidArgumentException($this->l10n->t('value_json could not be decoded'), 0, $exception);
285287
}
286288

287289
if (!is_array($decoded)) {
288-
throw new InvalidArgumentException('value_json must decode to an object payload');
290+
throw new InvalidArgumentException($this->l10n->t('value_json must decode to an object payload'));
289291
}
290292

291293
return $decoded;
@@ -326,13 +328,13 @@ private function normalizeSearchValue(FieldDefinition $definition, string $opera
326328
}
327329

328330
if (FieldType::from($definition->getType()) !== FieldType::TEXT) {
329-
throw new InvalidArgumentException('contains operator is only supported for text fields');
331+
throw new InvalidArgumentException($this->l10n->t('contains operator is only supported for text fields'));
330332
}
331333

332334
$normalized = $this->normalizeValue($definition, $rawValue);
333335
$value = $normalized['value'] ?? null;
334336
if (!is_string($value) || $value === '') {
335-
throw new InvalidArgumentException('contains operator requires a non-empty text value');
337+
throw new InvalidArgumentException($this->l10n->t('contains operator requires a non-empty text value'));
336338
}
337339

338340
return ['value' => $value];

0 commit comments

Comments
 (0)