Completed
Branch develop (009098)
by Anton
04:36
created

Record::save()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 49
Code Lines 24

Duplication

Lines 11
Ratio 22.45 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 11
loc 49
rs 6.1404
cc 8
eloc 24
nc 10
nop 1
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\ORM;
10
11
use Spiral\Database\Exceptions\QueryException;
12
use Spiral\Models\ActiveEntityInterface;
13
use Spiral\Models\Events\EntityEvent;
14
use Spiral\ORM\Entities\RecordSource;
15
use Spiral\ORM\Exceptions\ORMException;
16
use Spiral\ORM\Exceptions\RecordException;
17
use Spiral\ORM\Traits\FindTrait;
18
19
/**
20
 * Entity with ability to be saved and direct access to source.
21
 */
22
class Record extends RecordEntity implements ActiveEntityInterface
23
{
24
    /**
25
     * Static find methods.
26
     */
27
    use FindTrait;
28
29
    /**
30
     * Indication that save methods must be validated by default, can be altered by calling save
31
     * method with user arguments.
32
     */
33
    const VALIDATE_SAVE = true;
34
35
    /**
36
     * {@inheritdoc}
37
     *
38
     * Create or update record data in database. Record will validate all EMBEDDED and loaded
39
     * relations.
40
     *
41
     * @see   sourceTable()
42
     * @see   updateChriteria()
43
     * @param bool|null $validate  Overwrite default option declared in VALIDATE_SAVE to force or
44
     *                             disable validation before saving.
45
     * @return bool
46
     * @throws RecordException
47
     * @throws QueryException
48
     * @event saving()
49
     * @event saved()
50
     * @event updating()
51
     * @event updated()
52
     */
53
    public function save($validate = null)
54
    {
55
        if (is_null($validate)) {
56
            //Using default model behaviour
57
            $validate = static::VALIDATE_SAVE;
58
        }
59
60
        if ($validate && !$this->isValid()) {
61
            return false;
62
        }
63
64
        if (!$this->isLoaded()) {
65
            $this->dispatch('saving', new EntityEvent($this));
66
67
            //Primary key field name (if any)
68
            $primaryKey = $this->ormSchema()[ORM::M_PRIMARY_KEY];
69
70
            //We will need to support records with multiple primary keys in future
71
            unset($this->fields[$primaryKey]);
72
73
            //Creating
74
            $lastID = $this->sourceTable()->insert($this->fields = $this->serializeData());
75
            if (!empty($primaryKey)) {
76
                //Updating record primary key
77
                $this->fields[$primaryKey] = $lastID;
78
            }
79
80
            $this->loadedState(true)->dispatch('saved', new EntityEvent($this));
81
82
            //Saving record to entity cache if we have space for that
83
            $this->orm->rememberEntity($this, false);
84
85 View Code Duplication
        } elseif ($this->isSolid() || $this->hasUpdates()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
            $this->dispatch('updating', new EntityEvent($this));
87
88
            //Updating changed/all field based on model criteria (in usual case primaryKey)
89
            $this->sourceTable()->update(
90
                $this->compileUpdates(),
91
                $this->stateCriteria()
92
            )->run();
93
94
            $this->dispatch('updated', new EntityEvent($this));
95
        }
96
97
        $this->flushUpdates();
98
        $this->saveRelations($validate);
99
100
        return true;
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     *
106
     * @event deleting()
107
     * @event deleted()
108
     */
109
    public function delete()
110
    {
111
        $this->dispatch('deleting', new EntityEvent($this));
112
113
        if ($this->isLoaded()) {
114
            $this->sourceTable()->delete($this->stateCriteria())->run();
115
        }
116
117
        //We don't really need to delete embedded or loaded relations,
118
        //we have foreign keys for that
119
120
        $this->fields = $this->ormSchema()[ORM::M_COLUMNS];
121
        $this->loadedState(self::DELETED)->dispatch('deleted', new EntityEvent($this));
122
    }
123
124
    /**
125
     * Instance of ORM Selector associated with specific document.
126
     *
127
     * @see   Component::staticContainer()
128
     * @param ORM $orm ORM component, global container will be called if not instance provided.
129
     * @return RecordSource
130
     * @throws ORMException
131
     */
132 View Code Duplication
    public static function source(ORM $orm = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133
    {
134
        /**
135
         * Using global container as fallback.
136
         *
137
         * @var ORM $orm
138
         */
139
        if (empty($orm)) {
140
            //Using global container as fallback
141
            $orm = self::staticContainer()->get(ORM::class);
142
        }
143
144
        return $orm->source(static::class);
145
    }
146
147
    /**
148
     * Save embedded relations.
149
     *
150
     * @param bool $validate
151
     */
152
    private function saveRelations($validate)
153
    {
154
        foreach ($this->relations as $name => $relation) {
155
            if (!$relation instanceof RelationInterface) {
156
                //Was never constructed
157
                continue;
158
            }
159
160
            if ($this->isEmbedded($name) && !$relation->saveAssociation($validate)) {
161
                throw new RecordException("Unable to save relation '{$name}'.");
162
            }
163
        }
164
    }
165
}