Completed
Pull Request — master (#5157)
by Damian
11:28
created

VersionedTest   D

Complexity

Total Complexity 36

Size/Duplication

Total Lines 997
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 24

Importance

Changes 2
Bugs 1 Features 1
Metric Value
wmc 36
c 2
b 1
f 1
lcom 1
cbo 24
dl 0
loc 997
rs 4.6095

30 Methods

Rating   Name   Duplication   Size   Complexity  
B testUniqueIndexes() 0 34 4
B testDeletingOrphanedVersions() 0 42 1
A testInvalidPublish() 0 12 1
A testDuplicate() 0 16 1
A testForceChangeUpdatesVersion() 0 14 1
B testGetIncludingDeleted() 0 39 1
A testVersionedFieldsAdded() 0 9 1
A testVersionedFieldsNotInCMS() 0 6 1
B testPublishCreateNewVersion() 0 36 1
B testRollbackTo() 0 31 1
B testDeleteFromStage() 0 31 1
B testHasOwnTableDatabaseFieldWithVersioned() 0 30 1
A testQueriedTables() 0 8 1
A testWritingNewToStage() 0 22 1
A testWritingNewToLive() 0 22 1
A sleep() 0 6 1
B testGetVersion() 0 80 1
A testGetVersionWhenClassnameChanged() 0 23 1
A testArchiveVersion() 0 50 1
A testAllVersions() 0 55 3
B testArchiveRelatedDataWithoutVersioned() 0 29 1
B testVersionedWithSingleStage() 0 39 1
B testLazyLoadFields() 0 37 1
A testReadingPersistent() 0 54 1
A testReadingModeSecurity() 0 5 1
A assertRecordHasLatestVersion() 0 9 2
A testWriteToStage() 0 72 1
A testVersionedHandlesRenamedDataObjectFields() 0 13 1
A testCanView() 0 47 1
B testCanViewStage() 0 32 1
1
<?php
2
3
/**
4
 * @package framework
5
 * @subpackage tests
6
 */
7
class VersionedTest extends SapphireTest {
8
9
	protected static $fixture_file = 'VersionedTest.yml';
10
11
	protected $extraDataObjects = array(
12
		'VersionedTest_DataObject',
13
		'VersionedTest_Subclass',
14
		'VersionedTest_AnotherSubclass',
15
		'VersionedTest_RelatedWithoutVersion',
16
		'VersionedTest_SingleStage',
17
		'VersionedTest_WithIndexes',
18
		'VersionedTest_PublicStage',
19
		'VersionedTest_PublicViaExtension',
20
	);
21
22
	protected $requiredExtensions = array(
23
		"VersionedTest_DataObject" => array('Versioned'),
24
		"VersionedTest_WithIndexes" => array('Versioned'),
25
	);
26
27
	public function testUniqueIndexes() {
28
		$tableExpectations = array(
29
			'VersionedTest_WithIndexes' =>
30
				array('value' => true, 'message' => 'Unique indexes are unique in main table'),
31
			'VersionedTest_WithIndexes_versions' =>
32
				array('value' => false, 'message' => 'Unique indexes are no longer unique in _versions table'),
33
			'VersionedTest_WithIndexes_Live' =>
34
				array('value' => false, 'message' => 'Unique indexes are no longer unique in _Live table'),
35
		);
36
37
		// Test each table's performance
38
		foreach ($tableExpectations as $tableName => $expectation) {
39
			$indexes = DB::get_schema()->indexList($tableName);
40
41
			// Check for presence of all unique indexes
42
			$indexColumns = array_map(function($index) {
43
				return $index['value'];
44
			}, $indexes);
45
			sort($indexColumns);
46
			$expectedColumns = array('"UniqA"', '"UniqS"');
47
			$this->assertEquals(
48
					array_values($expectedColumns),
49
					array_values(array_intersect($indexColumns, $expectedColumns)),
50
					"$tableName has both indexes");
51
52
			// Check unique -> non-unique conversion
53
			foreach ($indexes as $indexKey => $indexSpec) {
54
				if (in_array($indexSpec['value'], $expectedColumns)) {
55
					$isUnique = $indexSpec['type'] === 'unique';
56
					$this->assertEquals($isUnique, $expectation['value'], $expectation['message']);
57
}
58
			}
59
		}
60
	}
61
62
	public function testDeletingOrphanedVersions() {
63
		$obj = new VersionedTest_Subclass();
64
		$obj->ExtraField = 'Foo'; // ensure that child version table gets written
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
65
		$obj->write();
66
		$obj->publish('Stage', 'Live');
67
68
		$obj->ExtraField = 'Bar'; // ensure that child version table gets written
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
69
		$obj->write();
70
		$obj->publish('Stage', 'Live');
71
72
		$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
73
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
74
75
		$this->assertGreaterThan(0, $versions, 'At least 1 version exists in the history of the page');
76
77
		// Force orphaning of all versions created earlier, only on parent record.
78
		// The child versiones table should still have the correct relationship
79
		DB::query("DELETE FROM \"VersionedTest_DataObject_versions\" WHERE \"RecordID\" = $obj->ID");
80
81
		// insert a record with no primary key (ID)
82
		DB::query("INSERT INTO \"VersionedTest_DataObject_versions\" (\"RecordID\") VALUES ($obj->ID)");
83
84
		// run the script which should clean that up
85
		$obj->augmentDatabase();
86
87
		$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
88
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
89
		$this->assertEquals(0, $versions, 'Orphaned versions on child tables are removed');
90
91
		// test that it doesn't delete records that we need
92
		$obj->write();
93
		$obj->publish('Stage', 'Live');
94
95
		$count = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
96
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
97
		$obj->augmentDatabase();
98
99
		$count2 = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
100
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
101
102
		$this->assertEquals($count, $count2);
103
	}
104
105
	/**
106
	 * Test that publishing from invalid stage will throw exception
107
	 */
108
	public function testInvalidPublish() {
109
		$obj = new VersionedTest_Subclass();
110
		$obj->ExtraField = 'Foo'; // ensure that child version table gets written
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
111
		$obj->write();
112
		$this->setExpectedException(
113
			'InvalidArgumentException',
114
			"Can't find VersionedTest_DataObject#{$obj->ID} in stage Live"
115
		);
116
117
		// Fail publishing from live to stage
118
		$obj->publish('Live', 'Stage');
119
	}
120
121
	public function testDuplicate() {
122
		$obj1 = new VersionedTest_Subclass();
123
		$obj1->ExtraField = 'Foo';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
124
		$obj1->write(); // version 1
125
		$obj1->publish('Stage', 'Live');
126
		$obj1->ExtraField = 'Foo2';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
127
		$obj1->write(); // version 2
128
129
		// Make duplicate
130
		$obj2 = $obj1->duplicate();
131
132
		// Check records differ
133
		$this->assertNotEquals($obj1->ID, $obj2->ID);
134
		$this->assertEquals(2, $obj1->Version);
135
		$this->assertEquals(1, $obj2->Version);
136
	}
137
138
	public function testForceChangeUpdatesVersion() {
139
		$obj = new VersionedTest_DataObject();
140
		$obj->Name = "test";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
141
		$obj->write();
142
143
		$oldVersion = $obj->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
144
		$obj->forceChange();
145
		$obj->write();
146
147
		$this->assertTrue(
148
			($obj->Version > $oldVersion),
149
			"A object Version is increased when just calling forceChange() without any other changes"
150
		);
151
	}
152
153
	/**
154
	 * Test Versioned::get_including_deleted()
155
	 */
156
	public function testGetIncludingDeleted() {
157
		// Get all ids of pages
158
		$allPageIDs = DataObject::get(
159
			'VersionedTest_DataObject',
160
			"\"ParentID\" = 0", "\"VersionedTest_DataObject\".\"ID\" ASC"
161
		)->column('ID');
162
163
		// Modify a page, ensuring that the Version ID and Record ID will differ,
164
		// and then subsequently delete it
165
		$targetPage = $this->objFromFixture('VersionedTest_DataObject', 'page3');
166
		$targetPage->Content = 'To be deleted';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
167
		$targetPage->write();
168
		$targetPage->delete();
169
170
		// Get all items, ignoring deleted
171
		$remainingPages = DataObject::get("VersionedTest_DataObject", "\"ParentID\" = 0",
172
			"\"VersionedTest_DataObject\".\"ID\" ASC");
173
		// Check that page 3 has gone
174
		$this->assertNotNull($remainingPages);
175
		$this->assertEquals(array("Page 1", "Page 2", "Subclass Page 1"), $remainingPages->column('Title'));
176
177
		// Get all including deleted
178
		$allPages = Versioned::get_including_deleted("VersionedTest_DataObject", "\"ParentID\" = 0",
179
			"\"VersionedTest_DataObject\".\"ID\" ASC");
180
		// Check that page 3 is still there
181
		$this->assertEquals(array("Page 1", "Page 2", "Page 3", "Subclass Page 1"), $allPages->column('Title'));
182
183
		// Check that the returned pages have the correct IDs
184
		$this->assertEquals($allPageIDs, $allPages->column('ID'));
185
186
		// Check that this still works if we switch to reading the other stage
187
		Versioned::set_stage(Versioned::LIVE);
188
		$allPages = Versioned::get_including_deleted("VersionedTest_DataObject", "\"ParentID\" = 0",
189
			"\"VersionedTest_DataObject\".\"ID\" ASC");
190
		$this->assertEquals(array("Page 1", "Page 2", "Page 3", "Subclass Page 1"), $allPages->column('Title'));
191
192
		// Check that the returned pages still have the correct IDs
193
		$this->assertEquals($allPageIDs, $allPages->column('ID'));
194
	}
195
196
	public function testVersionedFieldsAdded() {
197
		$obj = new VersionedTest_DataObject();
198
		// Check that the Version column is added as a full-fledged column
199
		$this->assertInstanceOf('Int', $obj->dbObject('Version'));
200
201
		$obj2 = new VersionedTest_Subclass();
202
		// Check that the Version column is added as a full-fledged column
203
		$this->assertInstanceOf('Int', $obj2->dbObject('Version'));
204
	}
205
206
	public function testVersionedFieldsNotInCMS() {
207
		$obj = new VersionedTest_DataObject();
208
209
		// the version field in cms causes issues with Versioned::augmentWrite()
210
		$this->assertNull($obj->getCMSFields()->dataFieldByName('Version'));
211
	}
212
213
	public function testPublishCreateNewVersion() {
214
		$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
215
		$page1->Content = 'orig';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
216
		$page1->write();
217
		$firstVersion = $page1->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
218
		$page1->publish('Stage', 'Live', false);
219
		$this->assertEquals(
220
			$firstVersion,
221
			$page1->Version,
222
			'publish() with $createNewVersion=FALSE does not create a new version'
223
		);
224
225
		$page1->Content = 'changed';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
226
		$page1->write();
227
		$secondVersion = $page1->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
228
		$this->assertTrue($firstVersion < $secondVersion, 'write creates new version');
229
230
		$page1->publish('Stage', 'Live', true);
231
		$thirdVersion = Versioned::get_latest_version('VersionedTest_DataObject', $page1->ID)->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
232
		$liveVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Live', $page1->ID);
233
		$stageVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Stage', $page1->ID);
234
		$this->assertTrue(
235
			$secondVersion < $thirdVersion,
236
			'publish() with $createNewVersion=TRUE creates a new version'
237
		);
238
		$this->assertEquals(
239
			$liveVersion,
240
			$thirdVersion,
241
			'publish() with $createNewVersion=TRUE publishes to live'
242
		);
243
		$this->assertEquals(
244
			$stageVersion,
245
			$secondVersion,
246
			'publish() with $createNewVersion=TRUE does not affect stage'
247
		);
248
	}
249
250
	public function testRollbackTo() {
251
		$page1 = $this->objFromFixture('VersionedTest_AnotherSubclass', 'subclass1');
252
		$page1->Content = 'orig';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
253
		$page1->write();
254
		$page1->publish('Stage', 'Live');
255
		$origVersion = $page1->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
256
257
		$page1->Content = 'changed';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
258
		$page1->write();
259
		$page1->publish('Stage', 'Live');
260
		$changedVersion = $page1->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
261
262
		$page1->doRollbackTo($origVersion);
263
		$page1 = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', array(
264
			'"VersionedTest_DataObject"."ID" = ?' => $page1->ID
265
		));
266
267
		$this->assertTrue($page1->Version == $changedVersion + 1, 'Create a new higher version number');
268
		$this->assertEquals('orig', $page1->Content, 'Copies the content from the old version');
269
270
		// check db entries
271
		$version = DB::prepared_query("SELECT MAX(\"Version\") FROM \"VersionedTest_DataObject_versions\" WHERE \"RecordID\" = ?",
272
			array($page1->ID)
273
		)->value();
274
		$this->assertEquals($page1->Version, $version, 'Correct entry in VersionedTest_DataObject_versions');
275
276
		$version = DB::prepared_query("SELECT MAX(\"Version\") FROM \"VersionedTest_AnotherSubclass_versions\" WHERE \"RecordID\" = ?",
277
			array($page1->ID)
278
		)->value();
279
		$this->assertEquals($page1->Version, $version, 'Correct entry in VersionedTest_AnotherSubclass_versions');
280
	}
281
282
	public function testDeleteFromStage() {
283
		$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
284
		$pageID = $page1->ID;
285
286
		$page1->Content = 'orig';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
287
		$page1->write();
288
		$page1->publish('Stage', 'Live');
289
290
		$this->assertEquals(1,
291
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
292
		$this->assertEquals(1,
293
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
294
295
		$page1->deleteFromStage('Live');
296
297
		// Confirm that deleteFromStage() doesn't manipulate the original record
298
		$this->assertEquals($pageID, $page1->ID);
299
300
		$this->assertEquals(1,
301
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
302
		$this->assertEquals(0,
303
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
304
305
		$page1->delete();
306
307
		$this->assertEquals(0, $page1->ID);
308
		$this->assertEquals(0,
309
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
310
		$this->assertEquals(0,
311
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
312
	}
313
314
	public function testWritingNewToStage() {
315
		$origStage = Versioned::get_stage();
316
317
		Versioned::set_stage(Versioned::DRAFT);
318
		$page = new VersionedTest_DataObject();
319
		$page->Title = "testWritingNewToStage";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
320
		$page->URLSegment = "testWritingNewToStage";
0 ignored issues
show
Documentation introduced by
The property URLSegment does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
321
		$page->write();
322
323
		$live = Versioned::get_by_stage('VersionedTest_DataObject', 'Live', array(
324
			'"VersionedTest_DataObject_Live"."ID"' => $page->ID
325
		));
326
		$this->assertEquals(0, $live->count());
327
328
		$stage = Versioned::get_by_stage('VersionedTest_DataObject', 'Stage',array(
329
			'"VersionedTest_DataObject"."ID"' => $page->ID
330
		));
331
		$this->assertEquals(1, $stage->count());
332
		$this->assertEquals($stage->First()->Title, 'testWritingNewToStage');
333
334
		Versioned::set_stage($origStage);
335
	}
336
337
	/**
338
	 * This tests for the situation described in the ticket #5596.
339
	 * Writing new Page to live first creates a row in VersionedTest_DataObject table (to get the new ID),
340
	 * then "changes it's mind" in Versioned and writes VersionedTest_DataObject_Live. It does not remove
341
	 * the VersionedTest_DataObject record though.
342
	 */
343
	public function testWritingNewToLive() {
344
		$origStage = Versioned::get_stage();
345
346
		Versioned::set_stage(Versioned::LIVE);
347
		$page = new VersionedTest_DataObject();
348
		$page->Title = "testWritingNewToLive";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
349
		$page->URLSegment = "testWritingNewToLive";
0 ignored issues
show
Documentation introduced by
The property URLSegment does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
350
		$page->write();
351
352
		$live = Versioned::get_by_stage('VersionedTest_DataObject', 'Live',array(
353
			'"VersionedTest_DataObject_Live"."ID"' => $page->ID
354
		));
355
		$this->assertEquals(1, $live->count());
356
		$this->assertEquals($live->First()->Title, 'testWritingNewToLive');
357
358
		$stage = Versioned::get_by_stage('VersionedTest_DataObject', 'Stage',array(
359
			'"VersionedTest_DataObject"."ID"' => $page->ID
360
		));
361
		$this->assertEquals(0, $stage->count());
362
363
		Versioned::set_stage($origStage);
364
	}
365
366
	/**
367
	 * Tests DataObject::hasOwnTableDatabaseField
368
	 */
369
	public function testHasOwnTableDatabaseFieldWithVersioned() {
370
		$noversion    = new DataObject();
371
		$versioned    = new VersionedTest_DataObject();
372
		$versionedSub = new VersionedTest_Subclass();
373
		$versionedAno = new VersionedTest_AnotherSubclass();
374
		$versionField = new VersionedTest_UnversionedWithField();
375
376
		$this->assertFalse(
377
			(bool) $noversion->hasOwnTableDatabaseField('Version'),
378
			'Plain models have no version field.'
379
		);
380
		$this->assertEquals(
381
			'Int', $versioned->hasOwnTableDatabaseField('Version'),
382
			'The versioned ext adds an Int version field.'
383
		);
384
		$this->assertEquals(
385
			null,
386
			$versionedSub->hasOwnTableDatabaseField('Version'),
387
			'Sub-classes of a versioned model don\'t have a Version field.'
388
		);
389
		$this->assertEquals(
390
			null,
391
			$versionedAno->hasOwnTableDatabaseField('Version'),
392
			'Sub-classes of a versioned model don\'t have a Version field.'
393
		);
394
		$this->assertEquals(
395
			'Varchar', $versionField->hasOwnTableDatabaseField('Version'),
396
			'Models w/o Versioned can have their own Version field.'
397
		);
398
	}
399
400
	/**
401
	 * Test that SQLSelect::queriedTables() applies the version-suffixes properly.
402
	 */
403
	public function testQueriedTables() {
404
		Versioned::set_stage(Versioned::LIVE);
405
406
		$this->assertEquals(array(
407
			'VersionedTest_DataObject_Live',
408
			'VersionedTest_Subclass_Live',
409
		), DataObject::get('VersionedTest_Subclass')->dataQuery()->query()->queriedTables());
410
	}
411
412
	/**
413
	 * Virtual "sleep" that doesn't actually slow execution, only advances SS_DateTime::now()
414
	 *
415
	 * @param int $minutes
416
	 */
417
	protected function sleep($minutes) {
418
		$now = SS_Datetime::now();
419
		$date = DateTime::createFromFormat('Y-m-d H:i:s', $now->getValue());
420
		$date->modify("+{$minutes} minutes");
421
		SS_Datetime::set_mock_now($date->format('Y-m-d H:i:s'));
422
	}
423
424
	/**
425
	 * Tests records selected by specific version
426
	 */
427
	public function testGetVersion() {
428
		// Create a few initial versions to ensure this version
429
		// doesn't clash with child versions
430
		$this->sleep(1);
431
		/** @var VersionedTest_DataObject $page2 */
432
		$page2 = $this->objFromFixture('VersionedTest_DataObject', 'page2');
433
		$page2->Title = 'dummy1';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
434
		$page2->write();
435
		$this->sleep(1);
436
		$page2->Title = 'dummy2';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
437
		$page2->write();
438
		$this->sleep(1);
439
		$page2->Title = 'Page 2 - v1';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
440
		$page2->write();
441
		$version1Date = $page2->LastEdited;
442
		$version1 = $page2->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
443
444
		// Create another version where this object and some
445
		// child records have been modified
446
		$this->sleep(1);
447
		/** @var VersionedTest_DataObject $page2a */
448
		$page2a = $this->objFromFixture('VersionedTest_DataObject', 'page2a');
449
		$page2a->Title = 'Page 2a - v2';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
450
		$page2a->write();
451
		$this->sleep(1);
452
		$page2->Title = 'Page 2 - v2';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
453
		$page2->write();
454
		$version2Date = $page2->LastEdited;
455
		$version2 = $page2->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
456
		$this->assertGreaterThan($version1, $version2);
457
		$this->assertDOSEquals(
458
			[
459
				['Title' => 'Page 2a - v2'],
460
				['Title' => 'Page 2b'],
461
			],
462
			$page2->Children()
463
		);
464
465
		// test selecting v1
466
		/** @var VersionedTest_DataObject $page2v1 */
467
		$page2v1 = Versioned::get_version('VersionedTest_DataObject', $page2->ID, $version1);
468
		$this->assertEquals('Page 2 - v1', $page2v1->Title);
469
470
		// When selecting v1, related records should by filtered by
471
		// the modified date of that version
472
		$archiveParms = [
473
			'Versioned.mode' => 'archive',
474
			'Versioned.date' => $version1Date
475
		];
476
		$this->assertEquals($archiveParms, $page2v1->getInheritableQueryParams());
477
		$this->assertArraySubset($archiveParms, $page2v1->Children()->getQueryParams());
478
		$this->assertDOSEquals(
479
			[
480
				['Title' => 'Page 2a'],
481
				['Title' => 'Page 2b'],
482
			],
483
			$page2v1->Children()
484
		);
485
486
		// When selecting v2, we get the same as on stage
487
		/** @var VersionedTest_DataObject $page2v2 */
488
		$page2v2 = Versioned::get_version('VersionedTest_DataObject', $page2->ID, $version2);
489
		$this->assertEquals('Page 2 - v2', $page2v2->Title);
490
491
		// When selecting v2, related records should by filtered by
492
		// the modified date of that version
493
		$archiveParms = [
494
			'Versioned.mode' => 'archive',
495
			'Versioned.date' => $version2Date
496
		];
497
		$this->assertEquals($archiveParms, $page2v2->getInheritableQueryParams());
498
		$this->assertArraySubset($archiveParms, $page2v2->Children()->getQueryParams());
499
		$this->assertDOSEquals(
500
			[
501
				['Title' => 'Page 2a - v2'],
502
				['Title' => 'Page 2b'],
503
			],
504
			$page2v2->Children()
505
		);
506
	}
507
508
	public function testGetVersionWhenClassnameChanged() {
509
		$obj = new VersionedTest_DataObject;
510
		$obj->Name = "test";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
511
		$obj->write();
512
		$obj->Name = "test2";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
513
		$obj->ClassName = "VersionedTest_Subclass";
514
		$obj->write();
515
		$subclassVersion = $obj->Version;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
516
517
		$obj->Name = "test3";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
518
		$obj->ClassName = "VersionedTest_DataObject";
519
		$obj->write();
520
521
		// We should be able to pass the subclass and still get the correct class back
522
		$obj2 = Versioned::get_version("VersionedTest_Subclass", $obj->ID, $subclassVersion);
523
		$this->assertInstanceOf("VersionedTest_Subclass", $obj2);
524
		$this->assertEquals("test2", $obj2->Name);
525
526
		$obj3 = Versioned::get_latest_version("VersionedTest_Subclass", $obj->ID);
527
		$this->assertEquals("test3", $obj3->Name);
528
		$this->assertInstanceOf("VersionedTest_DataObject", $obj3);
529
530
	}
531
532
	public function testArchiveVersion() {
533
534
		// In 2005 this file was created
535
		SS_Datetime::set_mock_now('2005-01-01 00:00:00');
536
		$testPage = new VersionedTest_Subclass();
537
		$testPage->Title = 'Archived page';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
538
		$testPage->Content = 'This is the content from 2005';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
539
		$testPage->ExtraField = '2005';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
540
		$testPage->write();
541
542
		// In 2007 we updated it
543
		SS_Datetime::set_mock_now('2007-01-01 00:00:00');
544
		$testPage->Content = "It's 2007 already!";
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
545
		$testPage->ExtraField = '2007';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
546
		$testPage->write();
547
548
		// In 2009 we updated it again
549
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
550
		$testPage->Content = "I'm enjoying 2009";
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
551
		$testPage->ExtraField = '2009';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
552
		$testPage->write();
553
554
		// End mock, back to the present day:)
555
		SS_Datetime::clear_mock_now();
556
557
		// Test 1 - 2006 Content
558
		singleton('VersionedTest_Subclass')->flushCache(true);
559
		Versioned::set_reading_mode('Archive.2006-01-01 00:00:00');
560
		$testPage2006 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
561
		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2006);
562
		$this->assertEquals("2005", $testPage2006->ExtraField);
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
563
		$this->assertEquals("This is the content from 2005", $testPage2006->Content);
564
565
		// Test 2 - 2008 Content
566
		singleton('VersionedTest_Subclass')->flushCache(true);
567
		Versioned::set_reading_mode('Archive.2008-01-01 00:00:00');
568
		$testPage2008 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
569
		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2008);
570
		$this->assertEquals("2007", $testPage2008->ExtraField);
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
571
		$this->assertEquals("It's 2007 already!", $testPage2008->Content);
572
573
		// Test 3 - Today
574
		singleton('VersionedTest_Subclass')->flushCache(true);
575
		Versioned::set_reading_mode('Stage.Stage');
576
		$testPageCurrent = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))
577
			->first();
578
		$this->assertInstanceOf("VersionedTest_Subclass", $testPageCurrent);
579
		$this->assertEquals("2009", $testPageCurrent->ExtraField);
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
580
		$this->assertEquals("I'm enjoying 2009", $testPageCurrent->Content);
581
	}
582
583
	public function testAllVersions()
584
	{
585
		// In 2005 this file was created
586
		SS_Datetime::set_mock_now('2005-01-01 00:00:00');
587
		$testPage = new VersionedTest_Subclass();
588
		$testPage->Title = 'Archived page';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
589
		$testPage->Content = 'This is the content from 2005';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
590
		$testPage->ExtraField = '2005';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
591
		$testPage->write();
592
593
		// In 2007 we updated it
594
		SS_Datetime::set_mock_now('2007-01-01 00:00:00');
595
		$testPage->Content = "It's 2007 already!";
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
596
		$testPage->ExtraField = '2007';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
597
		$testPage->write();
598
599
		// Check both versions are returned
600
		$versions = Versioned::get_all_versions('VersionedTest_Subclass', $testPage->ID);
601
		$content = array();
602
		$extraFields = array();
603
		foreach($versions as $version)
604
		{
605
			$content[] = $version->Content;
606
			$extraFields[] = $version->ExtraField;
607
		}
608
609
		$this->assertEquals($versions->Count(), 2, 'All versions returned');
610
		$this->assertEquals($content, array('This is the content from 2005', "It's 2007 already!"),
611
			'Version fields returned');
612
		$this->assertEquals($extraFields, array('2005', '2007'), 'Version fields returned');
613
614
		// In 2009 we updated it again
615
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
616
		$testPage->Content = "I'm enjoying 2009";
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
617
		$testPage->ExtraField = '2009';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
618
		$testPage->write();
619
620
		// End mock, back to the present day:)
621
		SS_Datetime::clear_mock_now();
622
623
		$versions = Versioned::get_all_versions('VersionedTest_Subclass', $testPage->ID);
624
		$content = array();
625
		$extraFields = array();
626
		foreach($versions as $version)
627
		{
628
			$content[] = $version->Content;
629
			$extraFields[] = $version->ExtraField;
630
		}
631
632
		$this->assertEquals($versions->Count(), 3, 'Additional all versions returned');
633
		$this->assertEquals($content,
634
			array('This is the content from 2005', "It's 2007 already!", "I'm enjoying 2009"),
635
			'Additional version fields returned');
636
		$this->assertEquals($extraFields, array('2005', '2007', '2009'), 'Additional version fields returned');
637
	}
638
639
	public function testArchiveRelatedDataWithoutVersioned() {
640
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
641
642
		$relatedData = new VersionedTest_RelatedWithoutVersion();
643
		$relatedData->Name = 'Related Data';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_RelatedWithoutVersion>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
644
		$relatedDataId = $relatedData->write();
645
646
		$testData = new VersionedTest_DataObject();
647
		$testData->Title = 'Test';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
648
		$testData->Content = 'Before Content';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
649
		$testData->Related()->add($relatedData);
650
		$id = $testData->write();
651
652
		SS_Datetime::set_mock_now('2010-01-01 00:00:00');
653
		$testData->Content = 'After Content';
0 ignored issues
show
Documentation introduced by
The property Content does not exist on object<VersionedTest_DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
654
		$testData->write();
655
656
		Versioned::reading_archived_date('2009-01-01 19:00:00');
657
658
		$fetchedData = VersionedTest_DataObject::get()->byId($id);
659
		$this->assertEquals('Before Content', $fetchedData->Content, 'We see the correct content of the older version');
660
661
		$relatedData = VersionedTest_RelatedWithoutVersion::get()->byId($relatedDataId);
662
		$this->assertEquals(
663
			1,
664
			$relatedData->Related()->count(),
665
			'We have a relation, with no version table, querying it still works'
666
		);
667
	}
668
669
	public function testVersionedWithSingleStage() {
670
		$tables = DB::table_list();
671
		$this->assertContains(
672
			'versionedtest_singlestage',
673
			array_keys($tables),
674
			'Contains base table'
675
		);
676
		$this->assertContains(
677
			'versionedtest_singlestage_versions',
678
			array_keys($tables),
679
			'Contains versions table'
680
		);
681
		$this->assertNotContains(
682
			'versionedtest_singlestage_live',
683
			array_keys($tables),
684
			'Does not contain separate table with _Live suffix'
685
		);
686
		$this->assertNotContains(
687
			'versionedtest_singlestage_stage',
688
			array_keys($tables),
689
			'Does not contain separate table with _Stage suffix'
690
		);
691
692
		Versioned::set_stage(Versioned::DRAFT);
693
		$obj = new VersionedTest_SingleStage(array('Name' => 'MyObj'));
694
		$obj->write();
695
		$this->assertNotNull(
696
			VersionedTest_SingleStage::get()->byID($obj->ID),
697
			'Writes to and reads from default stage if its set explicitly'
698
		);
699
700
		Versioned::set_stage(Versioned::LIVE);
701
		$obj = new VersionedTest_SingleStage(array('Name' => 'MyObj'));
702
		$obj->write();
703
		$this->assertNotNull(
704
			VersionedTest_SingleStage::get()->byID($obj->ID),
705
			'Writes to and reads from default stage even if a non-matching stage is set'
706
		);
707
	}
708
709
	/**
710
	 * Test that publishing processes respects lazy loaded fields
711
	 */
712
	public function testLazyLoadFields() {
713
		$originalMode = Versioned::get_reading_mode();
714
715
		// Generate staging record and retrieve it from stage in live mode
716
		Versioned::set_stage(Versioned::DRAFT);
717
		$obj = new VersionedTest_Subclass();
718
		$obj->Name = 'bob';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
719
		$obj->ExtraField = 'Field Value';
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
720
		$obj->write();
721
		$objID = $obj->ID;
722
		$filter = sprintf('"VersionedTest_DataObject"."ID" = \'%d\'', Convert::raw2sql($objID));
723
		Versioned::set_stage(Versioned::LIVE);
724
725
		// Check fields are unloaded prior to access
726
		$objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
727
		$lazyFields = $objLazy->getQueriedDatabaseFields();
728
		$this->assertTrue(isset($lazyFields['ExtraField_Lazy']));
729
		$this->assertEquals('VersionedTest_Subclass', $lazyFields['ExtraField_Lazy']);
730
731
		// Check lazy loading works when viewing a Stage object in Live mode
732
		$this->assertEquals('Field Value', $objLazy->ExtraField);
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
733
734
		// Test that writeToStage respects lazy loaded fields
735
		$objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
736
		$objLazy->writeToStage('Live');
737
		$objLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', $filter, false);
738
		$liveLazyFields = $objLive->getQueriedDatabaseFields();
739
740
		// Check fields are unloaded prior to access
741
		$this->assertTrue(isset($liveLazyFields['ExtraField_Lazy']));
742
		$this->assertEquals('VersionedTest_Subclass', $liveLazyFields['ExtraField_Lazy']);
743
744
		// Check that live record has original value
745
		$this->assertEquals('Field Value', $objLive->ExtraField);
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
746
747
		Versioned::set_reading_mode($originalMode);
748
	}
749
750
	/**
751
	 * Tests that reading mode persists between requests
752
	 */
753
	public function testReadingPersistent() {
0 ignored issues
show
Coding Style introduced by
testReadingPersistent uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
754
		$session = Injector::inst()->create('Session', array());
755
		$adminID = $this->logInWithPermission('ADMIN');
756
		$session->inst_set('loggedInAs', $adminID);
757
758
		// Set to stage
759
		Director::test('/?stage=Stage', null, $session);
760
		$this->assertEquals(
761
				'Stage.Stage',
762
				$session->inst_get('readingMode'),
763
				'Check querystring changes reading mode to Stage'
764
		);
765
		Director::test('/', null, $session);
766
		$this->assertEquals(
767
				'Stage.Stage',
768
				$session->inst_get('readingMode'),
769
				'Check that subsequent requests in the same session remain in Stage mode'
770
		);
771
772
		// Test live persists
773
		Director::test('/?stage=Live', null, $session);
774
		$this->assertEquals(
775
				'Stage.Live',
776
				$session->inst_get('readingMode'),
777
				'Check querystring changes reading mode to Live'
778
		);
779
		Director::test('/', null, $session);
780
		$this->assertEquals(
781
				'Stage.Live',
782
				$session->inst_get('readingMode'),
783
				'Check that subsequent requests in the same session remain in Live mode'
784
		);
785
786
		// Test that session doesn't redundantly store the default stage if it doesn't need to
787
		$session2 = Injector::inst()->create('Session', array());
788
		$session2->inst_set('loggedInAs', $adminID);
789
		Director::test('/', null, $session2);
790
		$this->assertArrayNotHasKey('readingMode', $session2->inst_changedData());
791
		Director::test('/?stage=Live', null, $session2);
792
		$this->assertArrayNotHasKey('readingMode', $session2->inst_changedData());
793
794
		// Test choose_site_stage
795
		unset($_GET['stage']);
796
		unset($_GET['archiveDate']);
797
		Session::set('readingMode', 'Stage.Stage');
798
		Versioned::choose_site_stage();
799
		$this->assertEquals('Stage.Stage', Versioned::get_reading_mode());
800
		Session::set('readingMode', 'Archive.2014-01-01');
801
		Versioned::choose_site_stage();
802
		$this->assertEquals('Archive.2014-01-01', Versioned::get_reading_mode());
803
		Session::clear('readingMode');
804
		Versioned::choose_site_stage();
805
		$this->assertEquals('Stage.Live', Versioned::get_reading_mode());
806
	}
807
808
	/**
809
	 * Test that stage parameter is blocked by non-administrative users
810
	 */
811
	public function testReadingModeSecurity() {
812
		$this->setExpectedException('SS_HTTPResponse_Exception');
813
		$session = Injector::inst()->create('Session', array());
814
		$result = Director::test('/?stage=Stage', null, $session);
815
	}
816
817
	/**
818
	 * Ensures that the latest version of a record is the expected value
819
	 *
820
	 * @param DataObject $record
821
	 * @param int $version
822
	 */
823
	protected function assertRecordHasLatestVersion($record, $version) {
824
		foreach(ClassInfo::ancestry(get_class($record), true) as $table) {
825
			$versionForClass = DB::prepared_query(
826
				$sql = "SELECT MAX(\"Version\") FROM \"{$table}_versions\" WHERE \"RecordID\" = ?",
827
				array($record->ID)
828
			)->value();
829
			$this->assertEquals($version, $versionForClass, "That the table $table has the latest version $version");
830
		}
831
	}
832
833
	/**
834
	 * Tests that multi-table dataobjects are correctly versioned
835
	 */
836
	public function testWriteToStage() {
837
		// Test subclass with versioned extension directly added
838
		$record = VersionedTest_Subclass::create();
839
		$record->Title = "Test A";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
840
		$record->ExtraField = "Test A";
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
841
		$record->writeToStage("Stage");
842
		$this->assertRecordHasLatestVersion($record, 1);
843
		$record->publish("Stage", "Live");
844
		$this->assertRecordHasLatestVersion($record, 1);
845
		$record->Title = "Test A2";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
846
		$record->ExtraField = "Test A2";
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
847
		$record->writeToStage("Stage");
848
		$this->assertRecordHasLatestVersion($record, 2);
849
850
		// Test subclass without changes to base class
851
		$record = VersionedTest_Subclass::create();
852
		$record->ExtraField = "Test B";
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
853
		$record->writeToStage("Stage");
854
		$this->assertRecordHasLatestVersion($record, 1);
855
		$record->publish("Stage", "Live");
856
		$this->assertRecordHasLatestVersion($record, 1);
857
		$record->ExtraField = "Test B2";
0 ignored issues
show
Bug introduced by
The property ExtraField does not seem to exist. Did you mean many_many_extraFields?

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.

Loading history...
858
		$record->writeToStage("Stage");
859
		$this->assertRecordHasLatestVersion($record, 2);
860
861
		// Test subclass without changes to sub class
862
		$record = VersionedTest_Subclass::create();
863
		$record->Title = "Test C";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
864
		$record->writeToStage("Stage");
865
		$this->assertRecordHasLatestVersion($record, 1);
866
		$record->publish("Stage", "Live");
867
		$this->assertRecordHasLatestVersion($record, 1);
868
		$record->Title = "Test C2";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_Subclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
869
		$record->writeToStage("Stage");
870
		$this->assertRecordHasLatestVersion($record, 2);
871
872
		// Test subclass with versioned extension only added to the base clases
873
		$record = VersionedTest_AnotherSubclass::create();
874
		$record->Title = "Test A";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
875
		$record->AnotherField = "Test A";
0 ignored issues
show
Documentation introduced by
The property AnotherField does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
876
		$record->writeToStage("Stage");
877
		$this->assertRecordHasLatestVersion($record, 1);
878
		$record->publish("Stage", "Live");
879
		$this->assertRecordHasLatestVersion($record, 1);
880
		$record->Title = "Test A2";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
881
		$record->AnotherField = "Test A2";
0 ignored issues
show
Documentation introduced by
The property AnotherField does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
882
		$record->writeToStage("Stage");
883
		$this->assertRecordHasLatestVersion($record, 2);
884
885
886
		// Test subclass without changes to base class
887
		$record = VersionedTest_AnotherSubclass::create();
888
		$record->AnotherField = "Test B";
0 ignored issues
show
Documentation introduced by
The property AnotherField does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
889
		$record->writeToStage("Stage");
890
		$this->assertRecordHasLatestVersion($record, 1);
891
		$record->publish("Stage", "Live");
892
		$this->assertRecordHasLatestVersion($record, 1);
893
		$record->AnotherField = "Test B2";
0 ignored issues
show
Documentation introduced by
The property AnotherField does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
894
		$record->writeToStage("Stage");
895
		$this->assertRecordHasLatestVersion($record, 2);
896
897
		// Test subclass without changes to sub class
898
		$record = VersionedTest_AnotherSubclass::create();
899
		$record->Title = "Test C";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
900
		$record->writeToStage("Stage");
901
		$this->assertRecordHasLatestVersion($record, 1);
902
		$record->publish("Stage", "Live");
903
		$this->assertRecordHasLatestVersion($record, 1);
904
		$record->Title = "Test C2";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<VersionedTest_AnotherSubclass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
905
		$record->writeToStage("Stage");
906
		$this->assertRecordHasLatestVersion($record, 2);
907
	}
908
909
	public function testVersionedHandlesRenamedDataObjectFields(){
910
		Config::inst()->remove('VersionedTest_RelatedWithoutVersion','db','Name','Varchar');
911
912
		Config::inst()->update('VersionedTest_RelatedWithoutVersion','db',array(
913
			"NewField" => "Varchar",
914
		));
915
916
		VersionedTest_RelatedWithoutVersion::add_extension("Versioned('Stage', 'Live')");
917
		$this->resetDBSchema(true);
918
		$testData = new VersionedTest_RelatedWithoutVersion();
919
		$testData->NewField = 'Test';
0 ignored issues
show
Documentation introduced by
The property NewField does not exist on object<VersionedTest_RelatedWithoutVersion>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
920
		$testData->write();
921
	}
922
923
	public function testCanView() {
924
		$public1ID = $this->idFromFixture('VersionedTest_PublicStage', 'public1');
925
		$public2ID = $this->idFromFixture('VersionedTest_PublicViaExtension', 'public2');
926
		$privateID = $this->idFromFixture('VersionedTest_DataObject', 'page1');
927
928
		// Test that all (and only) public pages are viewable in stage mode
929
		Session::clear("loggedInAs");
930
		Versioned::set_stage(Versioned::DRAFT);
931
		$public1 = Versioned::get_one_by_stage('VersionedTest_PublicStage', 'Stage', array('"ID"' => $public1ID));
932
		$public2 = Versioned::get_one_by_stage('VersionedTest_PublicViaExtension', 'Stage', array('"ID"' => $public2ID));
933
		$private = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', array('"ID"' => $privateID));
934
935
		$this->assertTrue($public1->canView());
936
		$this->assertTrue($public2->canView());
937
		$this->assertFalse($private->canView());
938
939
		// Adjusting the current stage should not allow objects loaded in stage to be viewable
940
		Versioned::set_stage(Versioned::LIVE);
941
		$this->assertTrue($public1->canView());
942
		$this->assertTrue($public2->canView());
943
		$this->assertFalse($private->canView());
944
945
		// Writing the private page to live should be fine though
946
		$private->publish("Stage", "Live");
947
		$privateLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', array('"ID"' => $privateID));
948
		$this->assertTrue($private->canView());
949
		$this->assertTrue($privateLive->canView());
950
951
		// But if the private version becomes different to the live version, it's once again disallowed
952
		Versioned::set_stage(Versioned::DRAFT);
953
		$private->Title = 'Secret Title';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
954
		$private->write();
955
		$this->assertFalse($private->canView());
956
		$this->assertTrue($privateLive->canView());
957
958
		// And likewise, viewing a live page (when mode is draft) should be ok
959
		Versioned::set_stage(Versioned::DRAFT);
960
		$this->assertFalse($private->canView());
961
		$this->assertTrue($privateLive->canView());
962
963
		// Logging in as admin should allow all permissions
964
		$this->logInWithPermission('ADMIN');
965
		Versioned::set_stage(Versioned::DRAFT);
966
		$this->assertTrue($public1->canView());
967
		$this->assertTrue($public2->canView());
968
		$this->assertTrue($private->canView());
969
	}
970
971
	public function testCanViewStage() {
972
		$public = $this->objFromFixture('VersionedTest_PublicStage', 'public1');
973
		$private = $this->objFromFixture('VersionedTest_DataObject', 'page1');
974
		Session::clear("loggedInAs");
975
		Versioned::set_stage(Versioned::DRAFT);
976
977
		// Test that all (and only) public pages are viewable in stage mode
978
		// Unpublished records are not viewable in live regardless of permissions
979
		$this->assertTrue($public->canViewStage('Stage'));
980
		$this->assertFalse($private->canViewStage('Stage'));
981
		$this->assertFalse($public->canViewStage('Live'));
982
		$this->assertFalse($private->canViewStage('Live'));
983
984
		// Writing records to live should make both stage and live modes viewable
985
		$private->publish("Stage", "Live");
986
		$public->publish("Stage", "Live");
987
		$this->assertTrue($public->canViewStage('Stage'));
988
		$this->assertTrue($private->canViewStage('Stage'));
989
		$this->assertTrue($public->canViewStage('Live'));
990
		$this->assertTrue($private->canViewStage('Live'));
991
992
		// If the draft mode changes, the live mode remains public, although the updated
993
		// draft mode is secured for non-public records.
994
		$private->Title = 'Secret Title';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
995
		$private->write();
996
		$public->Title = 'Public Title';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
997
		$public->write();
998
		$this->assertTrue($public->canViewStage('Stage'));
999
		$this->assertFalse($private->canViewStage('Stage'));
1000
		$this->assertTrue($public->canViewStage('Live'));
1001
		$this->assertTrue($private->canViewStage('Live'));
1002
	}
1003
}
1004
1005
1006
/**
1007
 * @method VersionedTest_DataObject Parent()
1008
 * @method HasManyList Children()
1009
 * @method ManyManyList Related()
1010
 *
1011
 * @package framework
1012
 * @subpackage tests
1013
 */
1014
class VersionedTest_DataObject extends DataObject implements TestOnly {
1015
	private static $db = array(
1016
		"Name" => "Varchar",
1017
		'Title' => 'Varchar',
1018
		'Content' => 'HTMLText',
1019
	);
1020
1021
	private static $extensions = array(
1022
		"Versioned('Stage', 'Live')",
1023
	);
1024
1025
	private static $has_one = array(
1026
		'Parent' => 'VersionedTest_DataObject',
1027
	);
1028
1029
	private static $has_many = array(
1030
		'Children' => 'VersionedTest_DataObject',
1031
	);
1032
1033
	private static $many_many = array(
1034
		'Related' => 'VersionedTest_RelatedWithoutVersion',
1035
	);
1036
1037
1038
	public function canView($member = null) {
1039
		$extended = $this->extendedCan(__FUNCTION__, $member);
1040
		if($extended !== null) {
1041
			return $extended;
1042
		}
1043
		return true;
1044
	}
1045
}
1046
1047
class VersionedTest_WithIndexes extends DataObject implements TestOnly {
1048
1049
	private static $db = array(
1050
		'UniqA' => 'Int',
1051
		'UniqS' => 'Int',
1052
	);
1053
	private static $extensions = array(
1054
		"Versioned"
1055
	);
1056
	private static $indexes = array(
1057
		'UniqS_idx' => 'unique ("UniqS")',
1058
		'UniqA_idx' => array('type' => 'unique', 'name' => 'UniqA_idx', 'value' => '"UniqA"',),
1059
	);
1060
1061
}
1062
1063
/**
1064
 * @package framework
1065
 * @subpackage tests
1066
 */
1067
class VersionedTest_RelatedWithoutVersion extends DataObject implements TestOnly {
1068
1069
	private static $db = array(
1070
		'Name' => 'Varchar'
1071
	);
1072
1073
	private static $belongs_many_many = array(
1074
		'Related' => 'VersionedTest_DataObject'
1075
	);
1076
1077
}
1078
1079
/**
1080
 * @package framework
1081
 * @subpackage tests
1082
 */
1083
class VersionedTest_Subclass extends VersionedTest_DataObject implements TestOnly {
1084
	private static $db = array(
1085
		"ExtraField" => "Varchar",
1086
	);
1087
}
1088
1089
/**
1090
 * @package framework
1091
 * @subpackage tests
1092
 */
1093
class VersionedTest_AnotherSubclass extends VersionedTest_DataObject implements TestOnly {
1094
	private static $db = array(
1095
		"AnotherField" => "Varchar"
1096
	);
1097
}
1098
1099
/**
1100
 * @package framework
1101
 * @subpackage tests
1102
 */
1103
class VersionedTest_UnversionedWithField extends DataObject implements TestOnly {
1104
	private static $db = array('Version' => 'Varchar(255)');
1105
}
1106
1107
class VersionedTest_SingleStage extends DataObject implements TestOnly {
1108
	private static $db = array(
1109
		'Name' => 'Varchar'
1110
	);
1111
1112
	private static $extensions = array(
1113
		'Versioned("Versioned")'
1114
	);
1115
}
1116
1117
/**
1118
 * Versioned dataobject with public stage mode
1119
 */
1120
class VersionedTest_PublicStage extends DataObject implements TestOnly {
1121
	private static $db = array(
1122
		'Title' => 'Varchar'
1123
	);
1124
1125
	private static $extensions = array(
1126
		"Versioned"
1127
	);
1128
1129
	public function canView($member = null) {
1130
		$extended = $this->extendedCan(__FUNCTION__, $member);
1131
		if($extended !== null) {
1132
			return $extended;
1133
		}
1134
		return true;
1135
	}
1136
1137
	public function canViewVersioned($member = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $member is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1138
		// All non-live modes are public
1139
		return true;
1140
	}
1141
}
1142
1143
/**
1144
 * Public access is provided via extension rather than overriding canViewVersioned
1145
 */
1146
class VersionedTest_PublicViaExtension extends DataObject implements TestOnly {
1147
1148
	public function canView($member = null) {
1149
		$extended = $this->extendedCan(__FUNCTION__, $member);
1150
		if($extended !== null) {
1151
			return $extended;
1152
		}
1153
		return true;
1154
	}
1155
1156
	private static $db = array(
1157
		'Title' => 'Varchar'
1158
	);
1159
1160
	private static $extensions = array(
1161
		"Versioned",
1162
		"VersionedTest_PublicExtension"
1163
	);
1164
}
1165
1166
/**
1167
 * Alters stage mode of extended object to be public
1168
 */
1169
class VersionedTest_PublicExtension extends DataExtension implements TestOnly {
1170
	public function canViewNonLive($member = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $member is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1171
		return true;
1172
	}
1173
}
1174