@@ -64,6 +64,16 @@ class UnduplicateCommand extends Command
6464 */
6565 private $ dryRun = false ;
6666
67+ /**
68+ * @var String|bool
69+ */
70+ private $ force = false ;
71+
72+ /**
73+ * @var bool
74+ */
75+ private $ keepOldest = false ;
76+
6777 /**
6878 * @var SymfonyStyle
6979 */
@@ -85,7 +95,8 @@ public function __construct($name = null, ConnectionPool $connectionPool = null)
8595 */
8696 public function configure ()
8797 {
88- $ this ->setDescription ('Finds duplicates in sys_file and unduplicates them ' );
98+ $ this ->setDescription ('Finds duplicates in sys_file and unduplicates them.
99+ By default it will use the newest (highest uid) record as master and delete the older records. ' );
89100 $ this ->setHelp (
90101 'currently fix references in ' . LF .
91102 '- sys_file_reference::link ' . LF .
@@ -115,6 +126,20 @@ public function configure()
115126 'Only use this storage ' ,
116127 -1
117128 )
129+ ->addOption (
130+ 'force ' ,
131+ 'f ' ,
132+ InputOption::VALUE_OPTIONAL ,
133+ 'Force keep or overwrite of metadata of the master record in case of conflict. Possible values: keep, keep-nonempty.
134+ Default: overwrite. Keep-nonempty is keeping only nonempty metadata in master, but updating the empty. ' ,
135+ false
136+ )
137+ ->addOption (
138+ 'keep-oldest ' ,
139+ 'o ' ,
140+ InputOption::VALUE_NONE ,
141+ 'Use the oldest record as master instead of the newest ' ,
142+ )
118143 ->addOption (
119144 'meta-fields ' ,
120145 'm ' ,
@@ -146,6 +171,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
146171 $ this ->updateReferenceIndex ($ input );
147172
148173 $ this ->dryRun = $ input ->getOption ('dry-run ' );
174+ $ this ->force = $ input ->getOption ('force ' ); // force will be null if no value is passed -> overwrite
175+ if ($ this ->force === null ) {
176+ $ this ->force = 'overwrite ' ;
177+ }
178+ $ this ->keepOldest = $ input ->getOption ('keep-oldest ' );
149179 $ onlyThisIdentifier = $ input ->getOption ('identifier ' );
150180 $ onlyThisStorage = (int )$ input ->getOption ('storage ' );
151181
@@ -258,7 +288,7 @@ private function findDuplicateFilesForIdentifier(string $identifier, int $storag
258288 'storage ' ,
259289 $ fileQueryBuilder ->createNamedParameter ($ storage , Connection::PARAM_INT )
260290 )
261- )->orderBy ('uid ' , 'DESC ' );
291+ )->orderBy ('uid ' , $ this -> keepOldest ? ' ASC ' : 'DESC ' );
262292
263293 $ whereClause = 'MD5(identifier) = MD5( ' . $ fileQueryBuilder ->createNamedParameter ($ identifier , \PDO ::PARAM_STR ) . ') ' ;
264294 $ fileQueryBuilder ->add ('where ' , $ whereClause );
@@ -370,22 +400,36 @@ public function getSysRefIndexData(int $oldFileUid): Result
370400 public function updateMetadataRecord (int $ masterFileUid , array $ referenceRow ): bool
371401 {
372402
373- $ metadata = $ this ->isMetadataRecordPopulated ($ referenceRow ['ref_uid ' ]);
403+ $ oldMetadata = $ this ->isMetadataRecordPopulated ($ referenceRow ['ref_uid ' ]);
374404 $ masterFileMetadata = $ this ->isMetadataRecordPopulated ($ masterFileUid );
405+ $ masterEmoty = !$ masterFileMetadata ;
375406
376- if (!$ metadata || $ metadata === $ masterFileMetadata ) { // check if record is empty or if the values are the same as in master
407+ if (!$ oldMetadata || $ oldMetadata === $ masterFileMetadata ) { // check if record is empty or if the values are the same as in master
377408 $ this ->output ->writeln ('<info>Deleting old metadata record</info> ' );
378409
379410 if (!$ this ->dryRun ) {
380411 $ this ->deleteReferencedRecord ($ referenceRow );
381412 $ this ->deleteReference ($ referenceRow );
382413 }
383414
384- } elseif ($ metadata && !$ masterFileMetadata ) { // check if master record has metadata, if not, copy the old ones
385- $ this ->output ->writeln ('<info>Old metadata is not empty and master is empty, copying values to master</info> ' );
415+ } elseif ($ oldMetadata && ($ masterEmoty || $ this ->force !== false )) { // check if master record has metadata, if not, copy the old ones
416+
417+ if ($ masterEmoty ) {
418+ $ this ->output ->writeln ('<info>Old metadata is not empty and master is empty, copying values to master. Deleting old metadata record</info> ' );
419+ } else if ($ this ->force !== false ) {
420+ if ($ this ->force !== 'keep ' ) {
421+ $ this ->output ->writeln ('<info>Force overwriting metadata in master. Deleting old metadata record</info> ' );
422+ } else {
423+ $ this ->output ->writeln ('<info>Force keeping metadata in master. Deleting old metadata record. Action may be required.</info> ' );
424+ }
425+ }
386426
387427 if (!$ this ->dryRun ) {
388- $ this ->updateMasterFileMetadata ($ masterFileUid , $ metadata );
428+ if ($ this ->force === false ||
429+ $ this ->force === 'overwrite ' ||
430+ $ masterEmoty && $ this ->force === 'keep-nonempty ' ) {
431+ $ this ->updateMasterFileMetadata ($ masterFileUid , $ oldMetadata );
432+ }
389433 $ this ->deleteReferencedRecord ($ referenceRow );
390434 $ this ->deleteReference ($ referenceRow );
391435 }
0 commit comments