Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
FundsCreator
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 2
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createFund
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3declare(strict_types=1);
4
5namespace App\Domain\Funds\Service;
6
7use App\Domain\Funds\Data\FundData;
8use App\Domain\Funds\Repository\FundsRepository;
9use InvalidArgumentException;
10use JsonException;
11
12final class FundsCreator
13{
14    private const VALID_TYPES = [
15        'Private Equity',
16        'Credit',
17        'Real Assets',
18        'Real Estate',
19        'Hedge',
20        'Other',
21    ];
22
23    private const VALID_STATUSES = [
24        'Active',
25        'Raising',
26        'Closed',
27        'Coming Soon',
28    ];
29
30    public function __construct(
31        private readonly FundsRepository $repository,
32    ) {}
33
34    /**
35     * @param list<string>|null $investmentHighlights
36     */
37    public function createFund(
38        string $name,
39        string $type,
40        string $status,
41        ?string $descriptionShort,
42        ?string $descriptionFull,
43        ?string $heroImageUrl,
44        ?string $aum,
45        ?string $targetReturn,
46        ?string $minInvestment,
47        ?string $managerName,
48        ?string $irEmail,
49        bool $published,
50        ?int $vintageYear,
51        ?string $fundLife,
52        ?string $geographicFocus,
53        ?string $targetIrr,
54        ?string $managementFeePct,
55        ?string $carriedInterestPct,
56        ?array $investmentHighlights,
57        ?string $riskFactors,
58        ?string $managerBio,
59        ?string $managerPhotoUrl,
60        ?string $irContactName,
61        ?string $irContactPhone,
62        ?string $nextDistributionDate,
63        ?string $liquidity,
64        ?string $heroImageAlt,
65    ): FundData {
66        $name = trim($name);
67        if ($name === '') {
68            throw new InvalidArgumentException('Fund name is required');
69        }
70
71        if (!in_array($type, self::VALID_TYPES, true)) {
72            throw new InvalidArgumentException('Invalid fund type');
73        }
74
75        if (!in_array($status, self::VALID_STATUSES, true)) {
76            throw new InvalidArgumentException('Invalid fund status');
77        }
78
79        if ($aum !== null && $aum !== '' && !is_numeric($aum)) {
80            throw new InvalidArgumentException('AUM must be a numeric string');
81        }
82
83        if ($minInvestment !== null && $minInvestment !== '' && !is_numeric($minInvestment)) {
84            throw new InvalidArgumentException('Min investment must be a numeric string');
85        }
86
87        $investmentHighlightsJson = null;
88        if ($investmentHighlights !== null) {
89            try {
90                $investmentHighlightsJson = json_encode(array_values($investmentHighlights), JSON_THROW_ON_ERROR);
91            } catch (JsonException) {
92                throw new InvalidArgumentException('Invalid investment highlights');
93            }
94        }
95
96        return $this->repository->createFund(
97            name: $name,
98            type: $type,
99            status: $status,
100            descriptionShort: $descriptionShort,
101            descriptionFull: $descriptionFull,
102            heroImageUrl: $heroImageUrl,
103            aum: $aum,
104            targetReturn: $targetReturn,
105            minInvestment: $minInvestment,
106            managerName: $managerName,
107            irEmail: $irEmail,
108            published: $published,
109            vintageYear: $vintageYear,
110            fundLife: $fundLife,
111            geographicFocus: $geographicFocus,
112            targetIrr: $targetIrr,
113            managementFeePct: $managementFeePct,
114            carriedInterestPct: $carriedInterestPct,
115            investmentHighlightsJson: $investmentHighlightsJson,
116            riskFactors: $riskFactors,
117            managerBio: $managerBio,
118            managerPhotoUrl: $managerPhotoUrl,
119            irContactName: $irContactName,
120            irContactPhone: $irContactPhone,
121            nextDistributionDate: $nextDistributionDate,
122            liquidity: $liquidity,
123            heroImageAlt: $heroImageAlt,
124        );
125    }
126}
127