7
7
use Drupal \Core \Config \Entity \ConfigEntityBase ;
8
8
use Drupal \Core \Database \Connection ;
9
9
use Drupal \Core \Entity \ContentEntityInterface ;
10
- use Drupal \ocha_content_classification \Exception \AlreadyProcessedException ;
10
+ use Drupal \Core \Session \AccountProxyInterface ;
11
+ use Drupal \ocha_content_classification \Enum \ClassificationMessage ;
12
+ use Drupal \ocha_content_classification \Enum \ClassificationStatus ;
13
+ use Drupal \ocha_content_classification \Exception \AttemptsLimitReachedException ;
14
+ use Drupal \ocha_content_classification \Exception \ClassificationCompletedException ;
11
15
use Drupal \ocha_content_classification \Exception \ClassificationFailedException ;
16
+ use Drupal \ocha_content_classification \Exception \FieldAlreadySpecifiedException ;
12
17
use Drupal \ocha_content_classification \Exception \UnsupportedEntityException ;
18
+ use Drupal \ocha_content_classification \Exception \WorkflowNotEnabledException ;
13
19
use Drupal \ocha_content_classification \Helper \EntityHelper ;
14
20
use Drupal \ocha_content_classification \Plugin \ClassifierPluginInterface ;
15
21
use Drupal \ocha_content_classification \Plugin \ClassifierPluginManagerInterface ;
@@ -126,6 +132,13 @@ class ClassificationWorkflow extends ConfigEntityBase implements ClassificationW
126
132
*/
127
133
protected Connection $ database ;
128
134
135
+ /**
136
+ * The current user.
137
+ *
138
+ * @var \Drupal\Core\Session\AccountProxyInterface
139
+ */
140
+ protected AccountProxyInterface $ currentUser ;
141
+
129
142
/**
130
143
* {@inheritdoc}
131
144
*/
@@ -348,6 +361,12 @@ public function classifyEntity(ContentEntityInterface $entity): bool {
348
361
* {@inheritdoc}
349
362
*/
350
363
public function validateEntity (ContentEntityInterface $ entity , bool $ check_status = TRUE ): bool {
364
+ if (!$ this ->enabled ()) {
365
+ throw new WorkflowNotEnabledException (strtr ('Workflow @id not enabled. ' , [
366
+ '@id ' => $ this ->id (),
367
+ ]));
368
+ }
369
+
351
370
if ($ entity ->getEntityTypeId () !== $ this ->getTargetEntityTypeId () || $ entity ->bundle () !== $ this ->getTargetBundle ()) {
352
371
throw new UnsupportedEntityException ('Entity type or bundle not supported. ' );
353
372
}
@@ -357,25 +376,26 @@ public function validateEntity(ContentEntityInterface $entity, bool $check_statu
357
376
$ status = $ existing_record ['status ' ] ?? '' ;
358
377
$ attempts = $ existing_record ['attempts ' ] ?? 0 ;
359
378
360
- // Skip if the entity is already processed .
361
- if ($ check_status && $ status === ' processed ' ) {
362
- throw new AlreadyProcessedException (strtr ('@bundle_label @id already processed . ' , [
379
+ // Skip if the classification is marked as completed .
380
+ if ($ check_status && $ status === ClassificationStatus:: COMPLETED ) {
381
+ throw new ClassificationCompletedException (strtr ('Classification already completed for @bundle_label @id. ' , [
363
382
'@bundle_label ' => $ bundle_label ,
364
383
'@id ' => $ entity ->id (),
365
384
]));
366
385
}
367
386
368
387
// Skip if the classification is marked as failure.
369
- if ($ check_status && $ status === ' failed ' ) {
370
- throw new ClassificationFailedException (strtr ('Classification failed for @bundle_label @id. ' , [
388
+ if ($ check_status && $ status === ClassificationStatus:: FAILED ) {
389
+ throw new ClassificationFailedException (strtr ('Classification previously failed for @bundle_label @id. ' , [
371
390
'@bundle_label ' => $ bundle_label ,
372
391
'@id ' => $ entity ->id (),
373
392
]));
374
393
}
375
394
376
395
// Skip if we reached the maximum number of classification attempts.
377
396
if ($ check_status && $ attempts >= $ this ->getAttemptsLimit ()) {
378
- throw new ClassificationFailedException (strtr ('Maximum classification attempts reached for @bundle_label @id. ' , [
397
+ throw new AttemptsLimitReachedException (strtr ('Limit of @limit classification attempts reached for @bundle_label @id. ' , [
398
+ '@limit ' => $ this ->getAttemptsLimit (),
379
399
'@bundle_label ' => $ bundle_label ,
380
400
'@id ' => $ entity ->id (),
381
401
]));
@@ -394,8 +414,11 @@ public function validateEntity(ContentEntityInterface $entity, bool $check_statu
394
414
}
395
415
396
416
// The field is not empty, we consider the classification done.
417
+ // @todo review adding some settings to the workflow to control the
418
+ // behavior when a classifiable is already specified but other
419
+ // classifiable fields are not.
397
420
if (!$ entity ->get ($ field_name )->isEmpty ()) {
398
- throw new AlreadyProcessedException (strtr ('@field_label already specified for @bundle_label @id. ' , [
421
+ throw new FieldAlreadySpecifiedException (strtr ('@field_label already specified for @bundle_label @id. ' , [
399
422
'@field_label ' => $ entity ->get ($ field_name )->getFieldDefinition ()->getLabel (),
400
423
'@bundle_label ' => $ bundle_label ,
401
424
'@id ' => $ entity ->id (),
@@ -413,35 +436,47 @@ public function validateEntity(ContentEntityInterface $entity, bool $check_statu
413
436
*/
414
437
public function updateClassificationProgress (
415
438
ContentEntityInterface $ entity ,
416
- string $ message ,
417
- string $ status ,
439
+ ClassificationMessage $ message ,
440
+ ClassificationStatus $ status ,
418
441
bool $ new = FALSE ,
419
- ): string {
442
+ ): void {
420
443
// Extract necessary information from the entity.
421
444
$ entity_type_id = $ entity ->getEntityTypeId ();
422
445
$ entity_bundle = $ entity ->bundle ();
423
446
$ entity_id = $ entity ->id ();
447
+ $ entity_revision_id = $ entity ->getRevisionId ();
448
+
449
+ // When creating or resetting a record, if the status is not queued, then
450
+ // we consider there was one attempt already.
451
+ $ new_record_attempts = ($ new && $ status === ClassificationStatus::QUEUED ) ? 0 : 1 ;
452
+
453
+ // Get the current timestamp.
454
+ $ time = time ();
455
+
456
+ // Get the ID of the classifier plugin.
457
+ $ classifier = $ this ->getClassifierPluginId ();
424
458
425
459
// Retrieve the existing progress record if any.
426
460
$ existing_record = $ this ->getClassificationProgress ($ entity );
427
461
428
462
if (!empty ($ existing_record )) {
429
- // Update existing record: increment attempts and update status/message.
463
+ // Update existing record. If new was specified, reset the user ID,
464
+ // creation time and attempts.
430
465
$ this ->getDatabase ()->update ('ocha_content_classification_progress ' )
431
466
->fields ([
432
- 'status ' => $ status ,
433
- 'attempts ' => $ new ? 1 : $ existing_record ['attempts ' ] + 1 ,
434
- 'created ' => $ new ? time () : $ existing_record ['created ' ],
435
- 'changed ' => time (),
436
- 'message ' => $ message ,
437
- 'classifier ' => $ this ->getClassifierPluginId (),
467
+ 'entity_revision_id ' => $ entity_revision_id ,
468
+ 'user_id ' => $ new ? $ this ->getCurrentUser ()->id () : $ existing_record ['user_id ' ],
469
+ 'status ' => $ status ->value ,
470
+ 'attempts ' => $ new ? $ new_record_attempts : $ existing_record ['attempts ' ] + 1 ,
471
+ 'created ' => $ new ? $ time : $ existing_record ['created ' ],
472
+ 'changed ' => $ time ,
473
+ 'message ' => $ message ->value ,
474
+ 'classifier ' => $ classifier ,
438
475
])
439
476
->condition ('entity_type_id ' , $ entity_type_id )
440
477
->condition ('entity_bundle ' , $ entity_bundle )
441
478
->condition ('entity_id ' , $ entity_id )
442
479
->execute ();
443
-
444
- return $ existing_record ['status ' ];
445
480
}
446
481
else {
447
482
// Insert a new record.
@@ -450,30 +485,58 @@ public function updateClassificationProgress(
450
485
'entity_type_id ' => $ entity_type_id ,
451
486
'entity_bundle ' => $ entity_bundle ,
452
487
'entity_id ' => $ entity_id ,
453
- 'status ' => $ status ,
454
- 'attempts ' => $ status === 'queued ' ? 0 : 1 ,
455
- 'created ' => time (),
456
- 'changed ' => time (),
457
- 'message ' => $ message ,
458
- 'classifier ' => $ this ->getClassifierPluginId (),
488
+ 'entity_revision_id ' => $ entity_revision_id ,
489
+ 'user_id ' => $ this ->getCurrentUser ()->id (),
490
+ 'status ' => $ status ->value ,
491
+ 'attempts ' => $ new_record_attempts ,
492
+ 'created ' => $ time ,
493
+ 'changed ' => $ time ,
494
+ 'message ' => $ message ->value ,
495
+ 'classifier ' => $ classifier ,
459
496
])
460
497
->execute ();
461
-
462
- return '' ;
463
498
}
464
499
}
465
500
466
501
/**
467
502
* {@inheritdoc}
468
503
*/
469
504
public function getClassificationProgress (ContentEntityInterface $ entity ): ?array {
470
- return $ this ->getDatabase ()->select ('ocha_content_classification_progress ' , 'ocp ' )
505
+ $ record = $ this ->getDatabase ()->select ('ocha_content_classification_progress ' , 'ocp ' )
471
506
->fields ('ocp ' )
472
507
->condition ('entity_type_id ' , $ entity ->getEntityTypeId ())
473
508
->condition ('entity_bundle ' , $ entity ->bundle ())
474
509
->condition ('entity_id ' , $ entity ->id ())
475
510
->execute ()
476
511
?->fetchAssoc() ?: NULL ;
512
+
513
+ // Ensure the record properties have the proper types.
514
+ if (isset ($ record ['entity_id ' ])) {
515
+ $ record ['entity_id ' ] = (int ) $ record ['entity_id ' ];
516
+ }
517
+ if (isset ($ record ['revision_id ' ])) {
518
+ $ record ['revision_id ' ] = (int ) $ record ['revision_id ' ];
519
+ }
520
+ if (isset ($ record ['user_id ' ])) {
521
+ $ record ['user_id ' ] = (int ) $ record ['user_id ' ];
522
+ }
523
+ if (isset ($ record ['status ' ])) {
524
+ $ record ['status ' ] = ClassificationStatus::tryFrom ($ record ['status ' ]) ?? '' ;
525
+ }
526
+ if (isset ($ record ['attempts ' ])) {
527
+ $ record ['attempts ' ] = (int ) $ record ['attempts ' ];
528
+ }
529
+ if (isset ($ record ['created ' ])) {
530
+ $ record ['created ' ] = (int ) $ record ['created ' ];
531
+ }
532
+ if (isset ($ record ['changed ' ])) {
533
+ $ record ['changed ' ] = (int ) $ record ['changed ' ];
534
+ }
535
+ if (isset ($ record ['message ' ])) {
536
+ $ record ['message ' ] = ClassificationMessage::tryFrom ($ record ['message ' ]) ?? '' ;
537
+ }
538
+
539
+ return $ record ;
477
540
}
478
541
479
542
/**
@@ -513,4 +576,17 @@ protected function getDatabase(): Connection {
513
576
return $ this ->database ;
514
577
}
515
578
579
+ /**
580
+ * Get the current user.
581
+ *
582
+ * @return \Drupal\Core\Session\AccountProxyInterface
583
+ * The current user.
584
+ */
585
+ protected function getCurrentUser (): AccountProxyInterface {
586
+ if (!isset ($ this ->currentUser )) {
587
+ $ this ->currentUser = \Drupal::currentUser ();
588
+ }
589
+ return $ this ->currentUser ;
590
+ }
591
+
516
592
}
0 commit comments