Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.91% covered (warning)
73.91%
17 / 23
87.50% covered (success)
87.50%
7 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
FileCopyOperation
73.91% covered (warning)
73.91%
17 / 23
87.50% covered (success)
87.50%
7 / 8
14.56
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDescription
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getSource
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDestination
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 toArray
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 shortenPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3/**
4 * File copy operation for migrations.
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2023-2026 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2026-01-25
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Setup\Migration\Operations;
21
22use phpMyFAQ\Filesystem\Filesystem;
23
24readonly class FileCopyOperation implements OperationInterface
25{
26    public function __construct(
27        private Filesystem $filesystem,
28        private string $source,
29        private string $destination,
30        private bool $onlyIfExists = true,
31    ) {
32    }
33
34    public function getType(): string
35    {
36        return 'file_copy';
37    }
38
39    public function getDescription(): string
40    {
41        $sourceShort = $this->shortenPath($this->source);
42        $destShort = $this->shortenPath($this->destination);
43        return sprintf('Copy file: %s -> %s', $sourceShort, $destShort);
44    }
45
46    public function getSource(): string
47    {
48        return $this->source;
49    }
50
51    public function getDestination(): string
52    {
53        return $this->destination;
54    }
55
56    public function execute(): bool
57    {
58        if ($this->onlyIfExists && !file_exists($this->source)) {
59            return true; // Skip if a source doesn't exist and onlyIfExists is true
60        }
61
62        try {
63            $this->filesystem->copy($this->source, $this->destination);
64            return true;
65        } catch (\Exception) {
66            return false;
67        }
68    }
69
70    public function toArray(): array
71    {
72        return [
73            'type' => $this->getType(),
74            'description' => $this->getDescription(),
75            'source' => $this->source,
76            'destination' => $this->destination,
77            'onlyIfExists' => $this->onlyIfExists,
78        ];
79    }
80
81    private function shortenPath(string $path): string
82    {
83        // Remove common prefixes to shorten the path for display
84        if (defined('PMF_ROOT_DIR')) {
85            $path = str_replace(search: (string) PMF_ROOT_DIR, replace: '', subject: $path);
86        }
87        return $path;
88    }
89}