Passed
Push — pulls/manymanylist-add-callbac... ( 7684da...77b6c5 )
by Sam
09:25
created

RelationList::setDeleteOnRemove()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
b 0
f 1
1
<?php
2
3
namespace SilverStripe\ORM;
4
5
use Exception;
6
7
/**
8
 * A DataList that represents a relation.
9
 *
10
 * Adds the notion of a foreign ID that can be optionally set.
11
 */
12
abstract class RelationList extends DataList implements Relation
13
{
14
    protected $addCallback;
15
16
    /**
17
     * Set a callback that is called after the add() action is completed.
18
     *
19
     * Callback will be passed ($this, $item, $extraFields).
20
     * If a relation methods is manually defined, this can be called to adjust the behaviour
21
     * when adding records to this list.
22
     *
23
     * Needs to be defined through an overloaded relationship getter
24
     * to ensure it is set consistently. These getters return a new object
25
     * every time they're called.
26
     *
27
     * Note that subclasses of RelationList must implement the callback for it to function
28
     *
29
     * @return this
30
     */
31
    public function setAddCallback($callback): self
32
    {
33
        $this->addCallback = $callback;
34
        return $this;
35
    }
36
37
    /**
38
     * @var Callable
39
     */
40
    protected $removeCallback;
41
42
    /**
43
     * Set a callback that is called after the remove() action is completed.
44
     * Callback will be passed ($this, $removedIds).
45
     *
46
     * Needs to be defined through an overloaded relationship getter
47
     * to ensure it is set consistently. These getters return a new object
48
     * every time they're called. Example:
49
     *
50
     * ```php
51
     * class MyObject extends DataObject()
52
     * {
53
     *   private static $many_many = [
54
     *     'MyRelationship' => '...',
55
     *   ];
56
     *   public function MyRelationship()
57
     *   {
58
     *     $list = $this->getManyManyComponents('MyRelationship');
59
     *     $list->setRemoveCallback(function ($removedIds) {
60
     *       // ...
61
     *     });
62
     *     return $list;
63
     *   }
64
     * }
65
     * ```
66
     *
67
     * If a relation methods is manually defined, this can be called to adjust the behaviour
68
     * when adding records to this list.
69
     *
70
     * Subclasses of RelationList must implement the callback for it to function
71
     *
72
     * @return this
73
     */
74
    public function setRemoveCallback($callback): self
75
    {
76
        $this->removeCallback = $callback;
77
        return $this;
78
    }
79
80
    /**
81
     * Any number of foreign keys to apply to this list
82
     *
83
     * @return string|array|null
84
     */
85
    public function getForeignID()
86
    {
87
        return $this->dataQuery->getQueryParam('Foreign.ID');
88
    }
89
90
    public function getQueryParams()
91
    {
92
        $params = parent::getQueryParams();
93
94
        // Remove `Foreign.` query parameters for created objects,
95
        // as this would interfere with relations on those objects.
96
        foreach (array_keys($params) as $key) {
97
            if (stripos($key, 'Foreign.') === 0) {
98
                unset($params[$key]);
99
            }
100
        }
101
102
        return $params;
103
    }
104
105
    /**
106
     * Returns a copy of this list with the ManyMany relationship linked to
107
     * the given foreign ID.
108
     *
109
     * @param int|array $id An ID or an array of IDs.
110
     *
111
     * @return static
112
     */
113
    public function forForeignID($id)
114
    {
115
        // Turn a 1-element array into a simple value
116
        if (is_array($id) && sizeof($id) == 1) {
117
            $id = reset($id);
118
        }
119
120
        // Calculate the new filter
121
        $filter = $this->foreignIDFilter($id);
122
123
        $list = $this->alterDataQuery(function (DataQuery $query) use ($id, $filter) {
124
            // Check if there is an existing filter, remove if there is
125
            $currentFilter = $query->getQueryParam('Foreign.Filter');
126
            if ($currentFilter) {
127
                try {
128
                    $query->removeFilterOn($currentFilter);
129
                } catch (Exception $e) {
130
                    /* NOP */
131
                }
132
            }
133
134
            // Add the new filter
135
            $query->setQueryParam('Foreign.ID', $id);
136
            $query->setQueryParam('Foreign.Filter', $filter);
137
            $query->where($filter);
138
        });
139
140
        return $list;
141
    }
142
143
    /**
144
     * Returns a where clause that filters the members of this relationship to
145
     * just the related items.
146
     *
147
     *
148
     * @param array|integer $id (optional) An ID or an array of IDs - if not provided, will use the current ids as
149
     * per getForeignID
150
     * @return array Condition In array(SQL => parameters format)
151
     */
152
    abstract protected function foreignIDFilter($id = null);
153
}
154