1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
|
4
|
|
|
class CopyFactoryDataExtension extends DataExtension |
5
|
|
|
{ |
6
|
|
|
public static function get_extra_config($className, $extension, $args) |
7
|
|
|
{ |
8
|
|
|
//foreach($config as $name => $value) { |
9
|
|
|
// Config::inst()->update($className, $name, $value); |
10
|
|
|
//} |
11
|
|
|
// Force all subclass DB caches to invalidate themselves since their db attribute is now expired |
12
|
|
|
//DataObject::reset(); |
13
|
|
|
return array( |
14
|
|
|
'has_one' => array( |
15
|
|
|
"Copy".$className => $className, |
16
|
|
|
"Copy".$className."_Completed" => $className |
17
|
|
|
) |
18
|
|
|
); |
19
|
|
|
} |
20
|
|
|
|
21
|
|
|
public function updateCMSFields(FieldList $fields) |
22
|
|
|
{ |
23
|
|
|
parent::updateCMSFields($fields); |
24
|
|
|
$className = $this->owner->ClassName; |
|
|
|
|
25
|
|
|
$uncompletedField = $this->owner->CopyFromFieldName(); |
26
|
|
|
$uncompletedFieldWithID = $uncompletedField."ID"; |
27
|
|
|
$completedField = $this->owner->CopiedFromFieldName(); |
28
|
|
|
$completedFieldWithID = $completedField."ID"; |
29
|
|
|
//remove by default |
30
|
|
|
$fields->removeByName($uncompletedFieldWithID); |
31
|
|
|
$fields->removeByName($completedFieldWithID); |
32
|
|
|
|
33
|
|
|
if ( |
34
|
|
|
$this->owner->exists() && |
35
|
|
|
SiteConfig::current_site_config()->AllowCopyingOfRecords && |
|
|
|
|
36
|
|
|
Permission::check('ADMIN') |
37
|
|
|
) { |
38
|
|
|
$changeMessage = |
39
|
|
|
"<p class=\"message good\">". |
40
|
|
|
_t("CopyFactory.CHANGE_SETTINGS", "You can change the settings for copying in"). |
41
|
|
|
" <a href=\"/admin/settings/\">"._t("CopyFactory.SITE_CONFIG", "The Site Config (see Copy Tab)")."</a>. ". |
42
|
|
|
_t("CopyFactory.TURN_OFF_WHEN_NOT_IN_USE", "It is recommended you turn off the copy facility when not in use, as it will slow down the CMS.")." |
43
|
|
|
</p>"; |
44
|
|
|
//reload goes here ... @todo |
45
|
|
|
/* |
46
|
|
|
if($this->owner->ID && Session::get("CopyFactoryReload") == $this->owner->ID) { |
47
|
|
|
Session::set("CopyFactoryReload", 0); |
48
|
|
|
return Controller::curr()->redirectBack(); |
49
|
|
|
} |
50
|
|
|
*/ |
51
|
|
|
if ($this->owner->$completedFieldWithID) { |
52
|
|
|
if ($obj = $this->owner->$completedField()) { |
53
|
|
|
$fields->addFieldToTab( |
54
|
|
|
"Root.Copy", |
55
|
|
|
new ReadonlyField( |
56
|
|
|
$completedField."_EXPLANATION", |
57
|
|
|
_t("CopyFactory.COPIED_FROM", "This record has been copied from: "), |
58
|
|
|
$this->owner->CopyFactoryTitleMaker($obj) |
59
|
|
|
) |
60
|
|
|
); |
61
|
|
|
} |
62
|
|
|
} elseif ($situation = SiteConfig::current_site_config()->AllowCopyingOfRecords) { |
|
|
|
|
63
|
|
|
if ($situation == 1) { |
64
|
|
|
$message = _t( |
65
|
|
|
'CopyFactory.DRY_RUN_ONLY', |
66
|
|
|
"Dry run only --- any changes below will be tested once your press 'SAVE' but no actual changes will be made. You will find a log of intended changes below for review." |
67
|
|
|
); |
68
|
|
|
} |
69
|
|
|
if ($situation == 2) { |
70
|
|
|
$message = _t( |
71
|
|
|
'CopyFactory.THIS_IS_FOR_REAL', |
72
|
|
|
"Any changes below will be actioned once you press 'SAVE' - please use with care." |
73
|
|
|
); |
74
|
|
|
} |
75
|
|
|
$fields->addFieldToTab( |
76
|
|
|
"Root.Copy", |
77
|
|
|
$copyField = new LiteralField( |
78
|
|
|
$uncompletedFieldWithID."_WARNING", |
79
|
|
|
"<p class=\"warning message\">".$message."</p>". |
|
|
|
|
80
|
|
|
$changeMessage |
81
|
|
|
) |
82
|
|
|
); |
83
|
|
|
$copyableObjects = $className::get() |
84
|
|
|
->exclude(array("ID" => intval($this->owner->ID) - 0)) |
|
|
|
|
85
|
|
|
->filter(array("ClassName" => $this->owner->ClassName)); |
86
|
|
|
if ($this->owner->hasMethod("additionalFiltersForCopyableObjects")) { |
87
|
|
|
$copyAbleObjects = $this->owner->additionalFiltersForCopyableObjects($copyableObjects); |
|
|
|
|
88
|
|
|
} |
89
|
|
|
//there are objects to copy from |
90
|
|
|
if ($copyableObjects->count() > 0) { |
91
|
|
|
$fields->addFieldToTab( |
92
|
|
|
"Root.Copy", |
93
|
|
|
$copyField = new DropdownField( |
94
|
|
|
$uncompletedFieldWithID, |
95
|
|
|
_t( |
96
|
|
|
'CopyFactory.COPY_EXPLANATION', |
97
|
|
|
"Copy from {name}. CAREFUL - this will replace everything in the current {name} with the one copied from ...", |
98
|
|
|
'Explanation on how copying works', |
99
|
|
|
array('name' => $this->owner->i18n_singular_name()) |
|
|
|
|
100
|
|
|
), |
101
|
|
|
$copyableObjects->map("ID", CopyFactory::preferred_title_field($this->owner)) |
102
|
|
|
) |
103
|
|
|
); |
104
|
|
|
$copyField->setEmptyString(_t("CopyFactory.SELECT_ONE", "--- Select One ---")); |
105
|
|
|
} else { |
106
|
|
|
$fields->addFieldToTab( |
107
|
|
|
"Root.Copy", |
108
|
|
|
$copyField = new LiteralField( |
109
|
|
|
$uncompletedFieldWithID."_EXPLANATION", |
110
|
|
|
"<h2>". |
111
|
|
|
_t( |
112
|
|
|
'CopyFactory.COPY_FACTORY_HELP_NO_RECORDS', |
113
|
|
|
"There are no records to copy from." |
114
|
|
|
). |
115
|
|
|
"</h2>" |
116
|
|
|
) |
117
|
|
|
); |
118
|
|
|
} |
119
|
|
|
} else { |
120
|
|
|
$fields->addFieldToTab( |
121
|
|
|
"Root.Copy", |
122
|
|
|
$copyField = new LiteralField( |
123
|
|
|
"CopyFactoryNotTurnedOn", |
124
|
|
|
"<h2>". |
125
|
|
|
_t( |
126
|
|
|
'CopyFactory.COPY_FACTORY_TURNED_OFF', |
127
|
|
|
"Copying of records is currently turned off." |
128
|
|
|
). |
129
|
|
|
"</h2>". |
130
|
|
|
$changeMessage |
131
|
|
|
) |
132
|
|
|
); |
133
|
|
|
} |
134
|
|
|
if (Config::inst()->get("CopyFactory", "debug")) { |
135
|
|
|
$source = CopyFactoryLog::get() |
136
|
|
|
->filter(array("CopyCausingClassName" => $this->owner->ClassName, "CopyCausingClassNameID" => $this->owner->ID)) |
137
|
|
|
->exclude(array("CopyIntoClassName" => $this->owner->ClassName, "CopyIntoClassNameID" => $this->owner->ID)) |
138
|
|
|
->exclude(array("CopyIntoClassName" => $this->owner->ClassName, "CopyFromClassNameID" => $this->owner->ID)); |
139
|
|
|
if ($source->count()) { |
140
|
|
|
$name = "COPY_CAUSING_GRIDFIELD"; |
141
|
|
|
$title = _t("CopyFactory.COPY_CAUSING_TITLE", "Copy actions originated from this record."); |
142
|
|
|
$fields->addFieldToTab("Root.Copy", $this->gridFieldMaker($name, $title, $source)); |
143
|
|
|
} |
144
|
|
|
$source = CopyFactoryLog::get() |
145
|
|
|
->filter(array("CopyIntoClassName" => $this->owner->ClassName, "CopyIntoClassNameID" => $this->owner->ID)) |
146
|
|
|
//->exclude(array("CopyCausingClassName" => $this->owner->ClassName, "CopyCausingClassNameID" => $this->owner->ID)) |
147
|
|
|
->exclude(array("CopyIntoClassName" => $this->owner->ClassName, "CopyFromClassNameID" => $this->owner->ID)); |
148
|
|
|
if ($source->count()) { |
149
|
|
|
$name = "COPY_INTO_GRIDFIELD"; |
150
|
|
|
$title = _t("CopyFactory.COPY_INTO_TITLE", "Copy actioned into this record."); |
151
|
|
|
$fields->addFieldToTab("Root.Copy", $this->gridFieldMaker($name, $title, $source)); |
152
|
|
|
} |
153
|
|
|
$source = CopyFactoryLog::get() |
154
|
|
|
->filter(array("CopyIntoClassName" => $this->owner->ClassName, "CopyFromClassNameID" => $this->owner->ID)) |
155
|
|
|
->exclude(array("CopyIntoClassName" => $this->owner->ClassName, "CopyIntoClassNameID" => $this->owner->ID)) |
156
|
|
|
->exclude(array("CopyCausingClassName" => $this->owner->ClassName, "CopyCausingClassNameID" => $this->owner->ID)); |
157
|
|
|
if ($source->count()) { |
158
|
|
|
$name = "COPY_FROM_GRIDFIELD"; |
159
|
|
|
$title = _t("CopyFactory.COPY_FROM_TITLE", "Copy actions from this record into another record."); |
160
|
|
|
$fields->addFieldToTab("Root.Copy", $this->gridFieldMaker($name, $title, $source)); |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
} else { |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* @param String $name |
169
|
|
|
* @param String $title |
170
|
|
|
* @param DataList $source |
171
|
|
|
* |
172
|
|
|
* @return GridField |
173
|
|
|
*/ |
174
|
|
|
private function gridFieldMaker($name, $title, $source) |
175
|
|
|
{ |
176
|
|
|
return new GridField( |
177
|
|
|
$name, |
178
|
|
|
_t("CopyFactory.COPY_FACTORY_LOG", "Copy Log: ").$title, |
179
|
|
|
$source, |
180
|
|
|
GridFieldConfig_RecordViewer::create(30) |
181
|
|
|
); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* The field that indicate where the object shall be copied FROM |
186
|
|
|
* note the future tense. |
187
|
|
|
* @return String |
188
|
|
|
*/ |
189
|
|
View Code Duplication |
public function CopyFromFieldName($withID = false) |
|
|
|
|
190
|
|
|
{ |
191
|
|
|
$str = Config::inst()->get("CopyFactory", "copy_fields_prefix"). |
192
|
|
|
$this->findOriginalObjectClassName(); |
193
|
|
|
if ($withID) { |
194
|
|
|
$str .= "ID"; |
195
|
|
|
} |
196
|
|
|
return $str; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* The field that indicates where the object was copied FROM |
201
|
|
|
* note the past tense ... |
202
|
|
|
* (links to "parent" object) |
203
|
|
|
* @return String |
204
|
|
|
*/ |
205
|
|
View Code Duplication |
public function CopiedFromFieldName($withID = false) |
|
|
|
|
206
|
|
|
{ |
207
|
|
|
$str = Config::inst()->get("CopyFactory", "copy_fields_prefix"). |
208
|
|
|
$this->findOriginalObjectClassName(). |
209
|
|
|
Config::inst()->get("CopyFactory", "completed_field_appendix"); |
210
|
|
|
if ($withID) { |
211
|
|
|
$str .= "ID"; |
212
|
|
|
} |
213
|
|
|
return $str; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* |
218
|
|
|
* @var array of DataObject |
219
|
|
|
*/ |
220
|
|
|
private static $my_original_object = array(); |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* finds the class name for the object |
224
|
|
|
* being copied in terms of the exact object being |
225
|
|
|
* extended by CopyFactoryDataExtension |
226
|
|
|
* @return string |
227
|
|
|
*/ |
228
|
|
|
private function findOriginalObjectClassName() |
229
|
|
|
{ |
230
|
|
|
$key = $this->owner->ClassName.$this->owner->ID; |
|
|
|
|
231
|
|
|
if (!isset(self::$my_original_object[$key])) { |
232
|
|
|
$obj = $this->owner; |
233
|
|
|
while ($obj->hasExtension("CopyFactoryDataExtension")) { |
234
|
|
|
$finalObject = $obj; |
235
|
|
|
$obj = Injector::inst()->get(get_parent_class($obj)); |
236
|
|
|
} |
237
|
|
|
self::$my_original_object[$key] = $finalObject; |
|
|
|
|
238
|
|
|
} |
239
|
|
|
return self::$my_original_object[$key]->ClassName; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* provides a meaningful title for an object |
245
|
|
|
* |
246
|
|
|
* @param String $obj - the object you want the name for ... |
247
|
|
|
* |
248
|
|
|
* @return String ... |
249
|
|
|
*/ |
250
|
|
View Code Duplication |
public function CopyFactoryTitleMaker($obj) |
|
|
|
|
251
|
|
|
{ |
252
|
|
|
$methodOrField = $this->CopyFactoryPreferredTitleField(); |
253
|
|
|
if ($obj->hasMethod($methodOrField)) { |
|
|
|
|
254
|
|
|
return $obj->$methodOrField(); |
|
|
|
|
255
|
|
|
} elseif ($obj->hasMethod("get".$methodOrField)) { |
|
|
|
|
256
|
|
|
$methodName = "get".$methodOrField; |
257
|
|
|
return $obj->$methodName(); |
|
|
|
|
258
|
|
|
} else { |
259
|
|
|
return $obj->$methodOrField; |
260
|
|
|
} |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* |
265
|
|
|
* @return String |
266
|
|
|
*/ |
267
|
|
|
public function CopyFactoryPreferredTitleField() |
268
|
|
|
{ |
269
|
|
|
$titleMap = Config::inst()->get("CopyFactory", "title_map_for_display_of_record_name"); |
270
|
|
|
if (isset($titleMap[$this->owner->ClassName])) { |
271
|
|
|
return $titleMap[$this->owner->ClassName]; |
|
|
|
|
272
|
|
|
} |
273
|
|
|
return "Title"; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* |
278
|
|
|
* @return String |
279
|
|
|
*/ |
280
|
|
|
protected function getCopyFactorySessionName() |
281
|
|
|
{ |
282
|
|
|
return |
283
|
|
|
Config::inst()->get("CopyFactory", "dry_run_for_session_base_name") |
284
|
|
|
."_". |
285
|
|
|
implode("_", array($this->ClassName, $this->ID)); |
|
|
|
|
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* mark that we are doing a copy ... |
290
|
|
|
*/ |
291
|
|
|
public function onBeforeWrite() |
292
|
|
|
{ |
293
|
|
|
parent::onBeforeWrite(); |
294
|
|
|
if (isset($this->owner->ID) && $this->owner->ID) { |
295
|
|
|
$fieldNameWithID = $this->owner->CopyFromFieldName(true); |
296
|
|
|
if (isset($_POST[$fieldNameWithID]) && $_POST[$fieldNameWithID]) { |
297
|
|
|
Session::set("CopyFactoryReload", $this->owner->ID); |
|
|
|
|
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* we run the actual copying onAfterWrite |
304
|
|
|
*/ |
305
|
|
|
public function onAfterWrite() |
306
|
|
|
{ |
307
|
|
|
parent::onAfterWrite(); |
308
|
|
|
if (SiteConfig::current_site_config()->AllowCopyingOfRecords) { |
|
|
|
|
309
|
|
|
$fieldName = $this->owner->CopyFromFieldName(false); |
310
|
|
|
$fieldNameWithID = $this->owner->CopyFromFieldName(true); |
311
|
|
|
if ($this->owner->$fieldNameWithID) { |
312
|
|
|
if ($copyFrom = $this->owner->$fieldName()) { |
313
|
|
|
$factory = CopyFactory::create($this->owner); |
314
|
|
|
$factory->copyObject($copyFrom, $this->owner); |
|
|
|
|
315
|
|
|
} else { |
316
|
|
|
// a little cleanup: lets reset ... |
317
|
|
|
$this->owner->$fieldNameWithID = 0; |
318
|
|
|
$this->owner->write(); |
319
|
|
|
} |
320
|
|
|
} |
321
|
|
|
} |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
public function CopiedFromObject() |
|
|
|
|
325
|
|
|
{ |
326
|
|
|
if ( |
327
|
|
|
$this->owner->exists() |
328
|
|
|
) { |
329
|
|
|
$completedField = $this->owner->CopiedFromFieldName(); |
330
|
|
|
$completedFieldWithID = $completedField."ID"; |
331
|
|
|
if ($this->owner->$completedFieldWithID) { |
332
|
|
|
return $this->owner->$completedField(); |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.