Passed
Push — master ( a543f3...90e139 )
by Dmitry
04:46
created

BillRepository::save()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 16
rs 9.8333
c 0
b 0
f 0
ccs 0
cts 16
cp 0
cc 3
nc 1
nop 1
crap 12
1
<?php
2
/**
3
 * API for Billing
4
 *
5
 * @link      https://github.com/hiqdev/billing-hiapi
6
 * @package   billing-hiapi
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\billing\hiapi\bill;
12
13
use hiqdev\php\billing\bill\BillInterface;
14
use hiqdev\php\billing\bill\BillRepositoryInterface;
15
use hiqdev\php\billing\charge\ChargeInterface;
16
use hiqdev\yii\DataMapper\expressions\CallExpression;
17
use hiqdev\yii\DataMapper\expressions\HstoreExpression;
18
use hiqdev\yii\DataMapper\models\relations\Bucket;
19
use hiqdev\yii\DataMapper\query\Specification;
20
use Yii;
21
use yii\db\ArrayExpression;
22
use yii\db\Query;
23
use yii\helpers\ArrayHelper;
24
25
class BillRepository extends \hiqdev\yii\DataMapper\repositories\BaseRepository implements BillRepositoryInterface
26
{
27
    /** {@inheritdoc} */
28
    public $queryClass = BillQuery::class;
29
30
    /**
31
     * @param BillInterface $bill
32
     */
33
    public function save(BillInterface $bill)
34
    {
35
        $hstore = $this->prepareHstore($bill);
36
        $this->db->transaction(function() use ($bill, $hstore) {
37
            $chargeIds = [];
38
            $call = new CallExpression('set_bill', [$hstore]);
39
            $command = (new Query())->select($call);
40
            $bill->setId($command->scalar($this->db));
41
            foreach ($bill->getCharges() as $charge) {
42
                $charge->setBill($bill);
43
                $this->em->save($charge);
44
                $chargeIds[] = $charge->getId();
45
            }
46
            if ($chargeIds) {
47
                $call = new CallExpression('set_bill_charges', [$bill->getId(), new ArrayExpression($chargeIds, 'integer')]);
48
                (new Query())->select($call)->scalar($this->db);
49
            }
50
        });
51
    }
52
53
    public function findId(BillInterface $bill)
54
    {
55
        if ($bill->getId()) {
56
            return $bill->getId();
57
        }
58
59
        $hstore = $this->prepareHstore($bill);
60
        $call = new CallExpression('bill_id', [$hstore]);
61
62
        return (new Query())->select($call)->scalar($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new yii\db\Query(...all)->scalar($this->db) also could return the type false which is incompatible with the return type mandated by hiqdev\php\billing\bill\...toryInterface::findId() of integer|null|string.
Loading history...
63
    }
64
65
    /**
66
     * undocumented function
67
     *
68
     * @return HstoreExpression
69
     */
70
    protected function prepareHstore(BillInterface $bill): HstoreExpression
71
    {
72
        return new HstoreExpression([
73
            'id'            => $bill->getId(),
74
            'object_id'     => $bill->getTarget()->getId(),
75
            'tariff_id'     => $bill->getPlan() ? $bill->getPlan()->getId() : null,
76
            'type_id'       => $bill->getType()->getId(),
77
            'type'          => $bill->getType()->getName(),
78
            'buyer_id'      => $bill->getCustomer()->getId(),
79
            'buyer'         => $bill->getCustomer()->getLogin(),
80
            'currency'      => $bill->getSum()->getCurrency()->getCode(),
81
            'sum'           => $bill->getSum()->getAmount(),
82
            'quantity'      => $bill->getQuantity()->getQuantity(),
83
            'unit'          => $bill->getQuantity()->getUnit()->getName(),
84
            'time'          => $bill->getTime()->format('c'),
85
            'label'         => $bill->getComment() ?: null,
86
            'is_finished'   => $bill->isFinished(),
87
            'increment'     => true,
88
        ]);
89
    }
90
91
    public function findByIds(array $ids): array
92
    {
93
        $spec = Yii::createObject(Specification::class)
94
            ->with('charges')
95
            ->where(['id' => $ids]);
96
97
        return $this->findAll($spec);
98
    }
99
100
    protected function joinCharges(&$rows)
101
    {
102
        $bucket = Bucket::fromRows($rows, 'id');
103
        $spec = (new Specification())->with('parent')->where(['bill-id' => $bucket->getKeys()]);
104
        $charges = $this->getRepository(ChargeInterface::class)->queryAll($spec);
105
        $bucket->fill($charges, 'bill.id', 'id');
106
        $bucket->pour($rows, 'charges');
107
108
        $indexedCharges = ArrayHelper::index($charges, 'id');
109
        foreach ($rows as &$bill) {
110
            foreach ($bill['charges'] as &$charge) {
111
                $charge = $this->enrichChargeWithParents($indexedCharges, $charge);
112
            }
113
        }
114
    }
115
116
    private function enrichChargeWithParents(array $charges, ?array $charge = null): array
117
    {
118
        if (isset($charge['parent-id'], $charges[$charge['parent-id']])) {
119
            $charge['parent'] = $this->enrichChargeWithParents($charges, $charges[$charge['parent-id']]);
120
        }
121
122
        return $charge;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $charge could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
123
    }
124
}
125