Completed
Push — 3.2 ( d51264...ff5ed6 )
by Damian
13:29 queued 01:53
created

VersionedTest::testPublishCreateNewVersion()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 36
rs 8.8571
cc 1
eloc 29
nc 1
nop 0
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
	);
19
20
	protected $requiredExtensions = array(
21
		"VersionedTest_DataObject" => array('Versioned'),
22
		"VersionedTest_WithIndexes" => array('Versioned'),
23
	);
24
25
	public function testUniqueIndexes() {
26
		$tableExpectations = array(
27
			'VersionedTest_WithIndexes' =>
28
				array('value' => true, 'message' => 'Unique indexes are unique in main table'),
29
			'VersionedTest_WithIndexes_versions' =>
30
				array('value' => false, 'message' => 'Unique indexes are no longer unique in _versions table'),
31
			'VersionedTest_WithIndexes_Live' =>
32
				array('value' => false, 'message' => 'Unique indexes are no longer unique in _Live table'),
33
		);
34
35
		// Test each table's performance
36
		foreach ($tableExpectations as $tableName => $expectation) {
37
			$indexes = DB::get_schema()->indexList($tableName);
38
39
			// Check for presence of all unique indexes
40
			$indexColumns = array_map(function($index) {
41
				return $index['value'];
42
			}, $indexes);
43
			sort($indexColumns);
44
			$expectedColumns = array('"UniqA"', '"UniqS"');
45
			$this->assertEquals(
46
					array_values($expectedColumns),
47
					array_values(array_intersect($indexColumns, $expectedColumns)),
48
					"$tableName has both indexes");
49
50
			// Check unique -> non-unique conversion
51
			foreach ($indexes as $indexKey => $indexSpec) {
52
				if (in_array($indexSpec['value'], $expectedColumns)) {
53
					$isUnique = $indexSpec['type'] === 'unique';
54
					$this->assertEquals($isUnique, $expectation['value'], $expectation['message']);
55
}
56
			}
57
		}
58
	}
59
60
	public function testDeletingOrphanedVersions() {
61
		$obj = new VersionedTest_Subclass();
62
		$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...
63
		$obj->write();
64
		$obj->publish('Stage', 'Live');
65
66
		$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...
67
		$obj->write();
68
		$obj->publish('Stage', 'Live');
69
70
		$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
71
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
72
73
		$this->assertGreaterThan(0, $versions, 'At least 1 version exists in the history of the page');
74
75
		// Force orphaning of all versions created earlier, only on parent record.
76
		// The child versiones table should still have the correct relationship
77
		DB::query("DELETE FROM \"VersionedTest_DataObject_versions\" WHERE \"RecordID\" = $obj->ID");
78
79
		// insert a record with no primary key (ID)
80
		DB::query("INSERT INTO \"VersionedTest_DataObject_versions\" (\"RecordID\") VALUES ($obj->ID)");
81
82
		// run the script which should clean that up
83
		$obj->augmentDatabase();
84
85
		$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
86
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
87
		$this->assertEquals(0, $versions, 'Orphaned versions on child tables are removed');
88
89
		// test that it doesn't delete records that we need
90
		$obj->write();
91
		$obj->publish('Stage', 'Live');
92
93
		$count = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
94
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
95
		$obj->augmentDatabase();
96
97
		$count2 = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\""
98
			. " WHERE \"RecordID\" = '$obj->ID'")->value();
99
100
		$this->assertEquals($count, $count2);
101
	}
102
103
	public function testDuplicate() {
104
		$obj1 = new VersionedTest_Subclass();
105
		$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...
106
		$obj1->write(); // version 1
107
		$obj1->publish('Stage', 'Live');
108
		$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...
109
		$obj1->write(); // version 2
110
111
		// Make duplicate
112
		$obj2 = $obj1->duplicate();
113
114
		// Check records differ
115
		$this->assertNotEquals($obj1->ID, $obj2->ID);
116
		$this->assertEquals(2, $obj1->Version);
117
		$this->assertEquals(1, $obj2->Version);
118
	}
119
120
	public function testForceChangeUpdatesVersion() {
121
		$obj = new VersionedTest_DataObject();
122
		$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...
123
		$obj->write();
124
125
		$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...
126
		$obj->forceChange();
127
		$obj->write();
128
129
		$this->assertTrue(
130
			($obj->Version > $oldVersion),
131
			"A object Version is increased when just calling forceChange() without any other changes"
132
		);
133
	}
134
135
	/**
136
	 * Test Versioned::get_including_deleted()
137
	 */
138
	public function testGetIncludingDeleted() {
139
		// Get all ids of pages
140
		$allPageIDs = DataObject::get(
141
			'VersionedTest_DataObject',
142
			"\"ParentID\" = 0", "\"VersionedTest_DataObject\".\"ID\" ASC"
143
		)->column('ID');
144
145
		// Modify a page, ensuring that the Version ID and Record ID will differ,
146
		// and then subsequently delete it
147
		$targetPage = $this->objFromFixture('VersionedTest_DataObject', 'page3');
148
		$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...
149
		$targetPage->write();
150
		$targetPage->delete();
151
152
		// Get all items, ignoring deleted
153
		$remainingPages = DataObject::get("VersionedTest_DataObject", "\"ParentID\" = 0",
154
			"\"VersionedTest_DataObject\".\"ID\" ASC");
155
		// Check that page 3 has gone
156
		$this->assertNotNull($remainingPages);
157
		$this->assertEquals(array("Page 1", "Page 2", "Subclass Page 1"), $remainingPages->column('Title'));
158
159
		// Get all including deleted
160
		$allPages = Versioned::get_including_deleted("VersionedTest_DataObject", "\"ParentID\" = 0",
161
			"\"VersionedTest_DataObject\".\"ID\" ASC");
162
		// Check that page 3 is still there
163
		$this->assertEquals(array("Page 1", "Page 2", "Page 3", "Subclass Page 1"), $allPages->column('Title'));
164
165
		// Check that the returned pages have the correct IDs
166
		$this->assertEquals($allPageIDs, $allPages->column('ID'));
167
168
		// Check that this still works if we switch to reading the other stage
169
		Versioned::reading_stage("Live");
170
		$allPages = Versioned::get_including_deleted("VersionedTest_DataObject", "\"ParentID\" = 0",
171
			"\"VersionedTest_DataObject\".\"ID\" ASC");
172
		$this->assertEquals(array("Page 1", "Page 2", "Page 3", "Subclass Page 1"), $allPages->column('Title'));
173
174
		// Check that the returned pages still have the correct IDs
175
		$this->assertEquals($allPageIDs, $allPages->column('ID'));
176
	}
177
178
	public function testVersionedFieldsAdded() {
179
		$obj = new VersionedTest_DataObject();
180
		// Check that the Version column is added as a full-fledged column
181
		$this->assertInstanceOf('Int', $obj->dbObject('Version'));
182
183
		$obj2 = new VersionedTest_Subclass();
184
		// Check that the Version column is added as a full-fledged column
185
		$this->assertInstanceOf('Int', $obj2->dbObject('Version'));
186
	}
187
188
	public function testVersionedFieldsNotInCMS() {
189
		$obj = new VersionedTest_DataObject();
190
191
		// the version field in cms causes issues with Versioned::augmentWrite()
192
		$this->assertNull($obj->getCMSFields()->dataFieldByName('Version'));
193
	}
194
195
	public function testPublishCreateNewVersion() {
196
		$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
197
		$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...
198
		$page1->write();
199
		$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...
200
		$page1->publish('Stage', 'Live', false);
201
		$this->assertEquals(
202
			$firstVersion,
203
			$page1->Version,
204
			'publish() with $createNewVersion=FALSE does not create a new version'
205
		);
206
207
		$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...
208
		$page1->write();
209
		$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...
210
		$this->assertTrue($firstVersion < $secondVersion, 'write creates new version');
211
212
		$page1->publish('Stage', 'Live', true);
213
		$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...
214
		$liveVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Live', $page1->ID);
215
		$stageVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Stage', $page1->ID);
216
		$this->assertTrue(
217
			$secondVersion < $thirdVersion,
218
			'publish() with $createNewVersion=TRUE creates a new version'
219
		);
220
		$this->assertEquals(
221
			$liveVersion,
222
			$thirdVersion,
223
			'publish() with $createNewVersion=TRUE publishes to live'
224
		);
225
		$this->assertEquals(
226
			$stageVersion,
227
			$secondVersion,
228
			'publish() with $createNewVersion=TRUE does not affect stage'
229
		);
230
	}
231
232
	public function testRollbackTo() {
233
		$page1 = $this->objFromFixture('VersionedTest_AnotherSubclass', 'subclass1');
234
		$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...
235
		$page1->write();
236
		$page1->publish('Stage', 'Live');
237
		$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...
238
239
		$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...
240
		$page1->write();
241
		$page1->publish('Stage', 'Live');
242
		$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...
243
244
		$page1->doRollbackTo($origVersion);
245
		$page1 = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', array(
246
			'"VersionedTest_DataObject"."ID" = ?' => $page1->ID
247
		));
248
249
		$this->assertTrue($page1->Version == $changedVersion + 1, 'Create a new higher version number');
250
		$this->assertEquals('orig', $page1->Content, 'Copies the content from the old version');
251
252
		// check db entries
253
		$version = DB::prepared_query("SELECT MAX(\"Version\") FROM \"VersionedTest_DataObject_versions\" WHERE \"RecordID\" = ?",
254
			array($page1->ID)
255
		)->value();
256
		$this->assertEquals($page1->Version, $version, 'Correct entry in VersionedTest_DataObject_versions');
257
258
		$version = DB::prepared_query("SELECT MAX(\"Version\") FROM \"VersionedTest_AnotherSubclass_versions\" WHERE \"RecordID\" = ?",
259
			array($page1->ID)
260
		)->value();
261
		$this->assertEquals($page1->Version, $version, 'Correct entry in VersionedTest_AnotherSubclass_versions');
262
	}
263
264
	public function testDeleteFromStage() {
265
		$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
266
		$pageID = $page1->ID;
267
268
		$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...
269
		$page1->write();
270
		$page1->publish('Stage', 'Live');
271
272
		$this->assertEquals(1,
273
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
274
		$this->assertEquals(1,
275
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
276
277
		$page1->deleteFromStage('Live');
278
279
		// Confirm that deleteFromStage() doesn't manipulate the original record
280
		$this->assertEquals($pageID, $page1->ID);
281
282
		$this->assertEquals(1,
283
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
284
		$this->assertEquals(0,
285
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
286
287
		$page1->delete();
288
289
		$this->assertEquals(0, $page1->ID);
290
		$this->assertEquals(0,
291
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject" WHERE "ID" = '.$pageID)->value());
292
		$this->assertEquals(0,
293
			DB::query('SELECT COUNT(*) FROM "VersionedTest_DataObject_Live" WHERE "ID" = '.$pageID)->value());
294
	}
295
296
	public function testWritingNewToStage() {
297
		$origStage = Versioned::current_stage();
298
299
		Versioned::reading_stage("Stage");
300
		$page = new VersionedTest_DataObject();
301
		$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...
302
		$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...
303
		$page->write();
304
305
		$live = Versioned::get_by_stage('VersionedTest_DataObject', 'Live', array(
306
			'"VersionedTest_DataObject_Live"."ID"' => $page->ID
307
		));
308
		$this->assertEquals(0, $live->count());
309
310
		$stage = Versioned::get_by_stage('VersionedTest_DataObject', 'Stage',array(
311
			'"VersionedTest_DataObject"."ID"' => $page->ID
312
		));
313
		$this->assertEquals(1, $stage->count());
314
		$this->assertEquals($stage->First()->Title, 'testWritingNewToStage');
315
316
		Versioned::reading_stage($origStage);
317
	}
318
319
	/**
320
	 * This tests for the situation described in the ticket #5596.
321
	 * Writing new Page to live first creates a row in VersionedTest_DataObject table (to get the new ID),
322
	 * then "changes it's mind" in Versioned and writes VersionedTest_DataObject_Live. It does not remove
323
	 * the VersionedTest_DataObject record though.
324
	 */
325
	public function testWritingNewToLive() {
326
		$origStage = Versioned::current_stage();
327
328
		Versioned::reading_stage("Live");
329
		$page = new VersionedTest_DataObject();
330
		$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...
331
		$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...
332
		$page->write();
333
334
		$live = Versioned::get_by_stage('VersionedTest_DataObject', 'Live',array(
335
			'"VersionedTest_DataObject_Live"."ID"' => $page->ID
336
		));
337
		$this->assertEquals(1, $live->count());
338
		$this->assertEquals($live->First()->Title, 'testWritingNewToLive');
339
340
		$stage = Versioned::get_by_stage('VersionedTest_DataObject', 'Stage',array(
341
			'"VersionedTest_DataObject"."ID"' => $page->ID
342
		));
343
		$this->assertEquals(0, $stage->count());
344
345
		Versioned::reading_stage($origStage);
346
	}
347
348
	/**
349
	 * Tests DataObject::hasOwnTableDatabaseField
350
	 */
351
	public function testHasOwnTableDatabaseFieldWithVersioned() {
352
		$noversion    = new DataObject();
353
		$versioned    = new VersionedTest_DataObject();
354
		$versionedSub = new VersionedTest_Subclass();
355
		$versionedAno = new VersionedTest_AnotherSubclass();
356
		$versionField = new VersionedTest_UnversionedWithField();
357
358
		$this->assertFalse(
359
			(bool) $noversion->hasOwnTableDatabaseField('Version'),
360
			'Plain models have no version field.'
361
		);
362
		$this->assertEquals(
363
			'Int', $versioned->hasOwnTableDatabaseField('Version'),
364
			'The versioned ext adds an Int version field.'
365
		);
366
		$this->assertEquals(
367
			null,
368
			$versionedSub->hasOwnTableDatabaseField('Version'),
369
			'Sub-classes of a versioned model don\'t have a Version field.'
370
		);
371
		$this->assertEquals(
372
			null,
373
			$versionedAno->hasOwnTableDatabaseField('Version'),
374
			'Sub-classes of a versioned model don\'t have a Version field.'
375
		);
376
		$this->assertEquals(
377
			'Varchar', $versionField->hasOwnTableDatabaseField('Version'),
378
			'Models w/o Versioned can have their own Version field.'
379
		);
380
	}
381
382
	/**
383
	 * Test that SQLQuery::queriedTables() applies the version-suffixes properly.
384
	 */
385
	public function testQueriedTables() {
386
		Versioned::reading_stage('Live');
387
388
		$this->assertEquals(array(
389
			'VersionedTest_DataObject_Live',
390
			'VersionedTest_Subclass_Live',
391
		), DataObject::get('VersionedTest_Subclass')->dataQuery()->query()->queriedTables());
392
	}
393
394
	public function testGetVersionWhenClassnameChanged() {
395
		$obj = new VersionedTest_DataObject;
396
		$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...
397
		$obj->write();
398
		$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...
399
		$obj->ClassName = "VersionedTest_Subclass";
400
		$obj->write();
401
		$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...
402
403
		$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...
404
		$obj->ClassName = "VersionedTest_DataObject";
405
		$obj->write();
406
407
		// We should be able to pass the subclass and still get the correct class back
408
		$obj2 = Versioned::get_version("VersionedTest_Subclass", $obj->ID, $subclassVersion);
409
		$this->assertInstanceOf("VersionedTest_Subclass", $obj2);
410
		$this->assertEquals("test2", $obj2->Name);
411
412
		$obj3 = Versioned::get_latest_version("VersionedTest_Subclass", $obj->ID);
413
		$this->assertEquals("test3", $obj3->Name);
414
		$this->assertInstanceOf("VersionedTest_DataObject", $obj3);
415
416
	}
417
418
	public function testArchiveVersion() {
419
420
		// In 2005 this file was created
421
		SS_Datetime::set_mock_now('2005-01-01 00:00:00');
422
		$testPage = new VersionedTest_Subclass();
423
		$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...
424
		$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...
425
		$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...
426
		$testPage->write();
427
428
		// In 2007 we updated it
429
		SS_Datetime::set_mock_now('2007-01-01 00:00:00');
430
		$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...
431
		$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...
432
		$testPage->write();
433
434
		// In 2009 we updated it again
435
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
436
		$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...
437
		$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...
438
		$testPage->write();
439
440
		// End mock, back to the present day:)
441
		SS_Datetime::clear_mock_now();
442
443
		// Test 1 - 2006 Content
444
		singleton('VersionedTest_Subclass')->flushCache(true);
445
		Versioned::set_reading_mode('Archive.2006-01-01 00:00:00');
446
		$testPage2006 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
447
		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2006);
448
		$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...
449
		$this->assertEquals("This is the content from 2005", $testPage2006->Content);
450
451
		// Test 2 - 2008 Content
452
		singleton('VersionedTest_Subclass')->flushCache(true);
453
		Versioned::set_reading_mode('Archive.2008-01-01 00:00:00');
454
		$testPage2008 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
455
		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2008);
456
		$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...
457
		$this->assertEquals("It's 2007 already!", $testPage2008->Content);
458
459
		// Test 3 - Today
460
		singleton('VersionedTest_Subclass')->flushCache(true);
461
		Versioned::set_reading_mode('Stage.Stage');
462
		$testPageCurrent = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))
463
			->first();
464
		$this->assertInstanceOf("VersionedTest_Subclass", $testPageCurrent);
465
		$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...
466
		$this->assertEquals("I'm enjoying 2009", $testPageCurrent->Content);
467
	}
468
469
	public function testAllVersions()
470
	{
471
		// In 2005 this file was created
472
		SS_Datetime::set_mock_now('2005-01-01 00:00:00');
473
		$testPage = new VersionedTest_Subclass();
474
		$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...
475
		$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...
476
		$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...
477
		$testPage->write();
478
479
		// In 2007 we updated it
480
		SS_Datetime::set_mock_now('2007-01-01 00:00:00');
481
		$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...
482
		$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...
483
		$testPage->write();
484
485
		// Check both versions are returned
486
		$versions = Versioned::get_all_versions('VersionedTest_Subclass', $testPage->ID);
487
		$content = array();
488
		$extraFields = array();
489
		foreach($versions as $version)
490
		{
491
			$content[] = $version->Content;
492
			$extraFields[] = $version->ExtraField;
493
		}
494
495
		$this->assertEquals($versions->Count(), 2, 'All versions returned');
496
		$this->assertEquals($content, array('This is the content from 2005', "It's 2007 already!"),
497
			'Version fields returned');
498
		$this->assertEquals($extraFields, array('2005', '2007'), 'Version fields returned');
499
500
		// In 2009 we updated it again
501
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
502
		$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...
503
		$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...
504
		$testPage->write();
505
506
		// End mock, back to the present day:)
507
		SS_Datetime::clear_mock_now();
508
509
		$versions = Versioned::get_all_versions('VersionedTest_Subclass', $testPage->ID);
510
		$content = array();
511
		$extraFields = array();
512
		foreach($versions as $version)
513
		{
514
			$content[] = $version->Content;
515
			$extraFields[] = $version->ExtraField;
516
		}
517
518
		$this->assertEquals($versions->Count(), 3, 'Additional all versions returned');
519
		$this->assertEquals($content,
520
			array('This is the content from 2005', "It's 2007 already!", "I'm enjoying 2009"),
521
			'Additional version fields returned');
522
		$this->assertEquals($extraFields, array('2005', '2007', '2009'), 'Additional version fields returned');
523
	}
524
525
	public function testArchiveRelatedDataWithoutVersioned() {
526
		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
527
528
		$relatedData = new VersionedTest_RelatedWithoutVersion();
529
		$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...
530
		$relatedDataId = $relatedData->write();
531
532
		$testData = new VersionedTest_DataObject();
533
		$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...
534
		$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...
535
		$testData->Related()->add($relatedData);
536
		$id = $testData->write();
537
538
		SS_Datetime::set_mock_now('2010-01-01 00:00:00');
539
		$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...
540
		$testData->write();
541
542
		Versioned::reading_archived_date('2009-01-01 19:00:00');
543
544
		$fetchedData = VersionedTest_DataObject::get()->byId($id);
545
		$this->assertEquals('Before Content', $fetchedData->Content, 'We see the correct content of the older version');
546
547
		$relatedData = VersionedTest_RelatedWithoutVersion::get()->byId($relatedDataId);
548
		$this->assertEquals(
549
			1,
550
			$relatedData->Related()->count(),
551
			'We have a relation, with no version table, querying it still works'
552
		);
553
	}
554
555
	public function testVersionedWithSingleStage() {
556
		$tables = DB::table_list();
557
		$this->assertContains(
558
			'versionedtest_singlestage',
559
			array_keys($tables),
560
			'Contains base table'
561
		);
562
		$this->assertContains(
563
			'versionedtest_singlestage_versions',
564
			array_keys($tables),
565
			'Contains versions table'
566
		);
567
		$this->assertNotContains(
568
			'versionedtest_singlestage_live',
569
			array_keys($tables),
570
			'Does not contain separate table with _Live suffix'
571
		);
572
		$this->assertNotContains(
573
			'versionedtest_singlestage_stage',
574
			array_keys($tables),
575
			'Does not contain separate table with _Stage suffix'
576
		);
577
578
		Versioned::reading_stage("Stage");
579
		$obj = new VersionedTest_SingleStage(array('Name' => 'MyObj'));
580
		$obj->write();
581
		$this->assertNotNull(
582
			VersionedTest_SingleStage::get()->byID($obj->ID),
583
			'Writes to and reads from default stage if its set explicitly'
584
		);
585
586
		Versioned::reading_stage("Live");
587
		$obj = new VersionedTest_SingleStage(array('Name' => 'MyObj'));
588
		$obj->write();
589
		$this->assertNotNull(
590
			VersionedTest_SingleStage::get()->byID($obj->ID),
591
			'Writes to and reads from default stage even if a non-matching stage is set'
592
		);
593
	}
594
595
	/**
596
	 * Test that publishing processes respects lazy loaded fields
597
	 */
598
	public function testLazyLoadFields() {
599
		$originalMode = Versioned::get_reading_mode();
600
601
		// Generate staging record and retrieve it from stage in live mode
602
		Versioned::reading_stage('Stage');
603
		$obj = new VersionedTest_Subclass();
604
		$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...
605
		$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...
606
		$obj->write();
607
		$objID = $obj->ID;
608
		$filter = sprintf('"VersionedTest_DataObject"."ID" = \'%d\'', Convert::raw2sql($objID));
609
		Versioned::reading_stage('Live');
610
611
		// Check fields are unloaded prior to access
612
		$objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
613
		$lazyFields = $objLazy->getQueriedDatabaseFields();
614
		$this->assertTrue(isset($lazyFields['ExtraField_Lazy']));
615
		$this->assertEquals('VersionedTest_Subclass', $lazyFields['ExtraField_Lazy']);
616
617
		// Check lazy loading works when viewing a Stage object in Live mode
618
		$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...
619
620
		// Test that writeToStage respects lazy loaded fields
621
		$objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
622
		$objLazy->writeToStage('Live');
623
		$objLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', $filter, false);
624
		$liveLazyFields = $objLive->getQueriedDatabaseFields();
625
626
		// Check fields are unloaded prior to access
627
		$this->assertTrue(isset($liveLazyFields['ExtraField_Lazy']));
628
		$this->assertEquals('VersionedTest_Subclass', $liveLazyFields['ExtraField_Lazy']);
629
630
		// Check that live record has original value
631
		$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...
632
633
		Versioned::set_reading_mode($originalMode);
634
	}
635
636
	/**
637
	 * Tests that reading mode persists between requests
638
	 */
639
	public function testReadingPersistent() {
640
		$session = Injector::inst()->create('Session', array());
641
642
		// Set to stage
643
		Director::test('/?stage=Stage', null, $session);
644
		$this->assertEquals(
645
			'Stage.Stage',
646
			$session->inst_get('readingMode'),
647
			'Check querystring changes reading mode to Stage'
648
		);
649
		Director::test('/', null, $session);
650
		$this->assertEquals(
651
			'Stage.Stage',
652
			$session->inst_get('readingMode'),
653
			'Check that subsequent requests in the same session remain in Stage mode'
654
		);
655
656
		// Test live persists
657
		Director::test('/?stage=Live', null, $session);
658
		$this->assertEquals(
659
			'Stage.Live',
660
			$session->inst_get('readingMode'),
661
			'Check querystring changes reading mode to Live'
662
		);
663
		Director::test('/', null, $session);
664
		$this->assertEquals(
665
			'Stage.Live',
666
			$session->inst_get('readingMode'),
667
			'Check that subsequent requests in the same session remain in Live mode'
668
		);
669
670
		// Test that session doesn't redundantly store the default stage if it doesn't need to
671
		$session2 = Injector::inst()->create('Session', array());
672
		Director::test('/', null, $session2);
673
		$this->assertEmpty($session2->inst_changedData());
674
		Director::test('/?stage=Live', null, $session2);
675
		$this->assertEmpty($session2->inst_changedData());
676
677
		// Test choose_site_stage
678
		Session::set('readingMode', 'Stage.Stage');
679
		Versioned::choose_site_stage();
680
		$this->assertEquals('Stage.Stage', Versioned::get_reading_mode());
681
		Session::set('readingMode', 'Archive.2014-01-01');
682
		Versioned::choose_site_stage();
683
		$this->assertEquals('Archive.2014-01-01', Versioned::get_reading_mode());
684
		Session::clear('readingMode');
685
		Versioned::choose_site_stage();
686
		$this->assertEquals('Stage.Live', Versioned::get_reading_mode());
687
	}
688
689
	/**
690
	 * Ensures that the latest version of a record is the expected value
691
	 *
692
	 * @param type $record
693
	 * @param type $version
694
	 */
695
	protected function assertRecordHasLatestVersion($record, $version) {
696
		foreach(ClassInfo::ancestry(get_class($record), true) as $table) {
697
			$versionForClass = DB::prepared_query(
698
				$sql = "SELECT MAX(\"Version\") FROM \"{$table}_versions\" WHERE \"RecordID\" = ?",
699
				array($record->ID)
700
			)->value();
701
			$this->assertEquals($version, $versionForClass, "That the table $table has the latest version $version");
702
		}
703
	}
704
705
	/**
706
	 * Tests that multi-table dataobjects are correctly versioned
707
	 */
708
	public function testWriteToStage() {
709
		// Test subclass with versioned extension directly added
710
		$record = VersionedTest_Subclass::create();
711
		$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...
712
		$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...
713
		$record->writeToStage("Stage");
714
		$this->assertRecordHasLatestVersion($record, 1);
715
		$record->publish("Stage", "Live");
716
		$this->assertRecordHasLatestVersion($record, 1);
717
		$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...
718
		$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...
719
		$record->writeToStage("Stage");
720
		$this->assertRecordHasLatestVersion($record, 2);
721
722
		// Test subclass without changes to base class
723
		$record = VersionedTest_Subclass::create();
724
		$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...
725
		$record->writeToStage("Stage");
726
		$this->assertRecordHasLatestVersion($record, 1);
727
		$record->publish("Stage", "Live");
728
		$this->assertRecordHasLatestVersion($record, 1);
729
		$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...
730
		$record->writeToStage("Stage");
731
		$this->assertRecordHasLatestVersion($record, 2);
732
733
		// Test subclass without changes to sub class
734
		$record = VersionedTest_Subclass::create();
735
		$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...
736
		$record->writeToStage("Stage");
737
		$this->assertRecordHasLatestVersion($record, 1);
738
		$record->publish("Stage", "Live");
739
		$this->assertRecordHasLatestVersion($record, 1);
740
		$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...
741
		$record->writeToStage("Stage");
742
		$this->assertRecordHasLatestVersion($record, 2);
743
744
		// Test subclass with versioned extension only added to the base clases
745
		$record = VersionedTest_AnotherSubclass::create();
746
		$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...
747
		$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...
748
		$record->writeToStage("Stage");
749
		$this->assertRecordHasLatestVersion($record, 1);
750
		$record->publish("Stage", "Live");
751
		$this->assertRecordHasLatestVersion($record, 1);
752
		$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...
753
		$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...
754
		$record->writeToStage("Stage");
755
		$this->assertRecordHasLatestVersion($record, 2);
756
757
758
		// Test subclass without changes to base class
759
		$record = VersionedTest_AnotherSubclass::create();
760
		$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...
761
		$record->writeToStage("Stage");
762
		$this->assertRecordHasLatestVersion($record, 1);
763
		$record->publish("Stage", "Live");
764
		$this->assertRecordHasLatestVersion($record, 1);
765
		$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...
766
		$record->writeToStage("Stage");
767
		$this->assertRecordHasLatestVersion($record, 2);
768
769
		// Test subclass without changes to sub class
770
		$record = VersionedTest_AnotherSubclass::create();
771
		$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...
772
		$record->writeToStage("Stage");
773
		$this->assertRecordHasLatestVersion($record, 1);
774
		$record->publish("Stage", "Live");
775
		$this->assertRecordHasLatestVersion($record, 1);
776
		$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...
777
		$record->writeToStage("Stage");
778
		$this->assertRecordHasLatestVersion($record, 2);
779
	}
780
781
	public function testVersionedHandlesRenamedDataObjectFields(){
782
		Config::inst()->remove('VersionedTest_RelatedWithoutVersion','db','Name','Varchar');
783
784
		Config::inst()->update('VersionedTest_RelatedWithoutVersion','db',array(
785
			"NewField" => "Varchar",
786
		));
787
788
		VersionedTest_RelatedWithoutVersion::add_extension("Versioned('Stage', 'Live')");
789
		$this->resetDBSchema(true);
790
		$testData = new VersionedTest_RelatedWithoutVersion();
791
		$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...
792
		$testData->write();
793
	}
794
}
795
796
797
/**
798
 * @package framework
799
 * @subpackage tests
800
 */
801
class VersionedTest_DataObject extends DataObject implements TestOnly {
802
	private static $db = array(
803
		"Name" => "Varchar",
804
		'Title' => 'Varchar',
805
		'Content' => 'HTMLText'
806
	);
807
808
	private static $extensions = array(
809
		"Versioned('Stage', 'Live')"
810
	);
811
812
	private static $has_one = array(
813
		'Parent' => 'VersionedTest_DataObject'
814
	);
815
816
	private static $many_many = array(
817
		'Related' => 'VersionedTest_RelatedWithoutVersion'
818
	);
819
820
}
821
822
class VersionedTest_WithIndexes extends DataObject implements TestOnly {
823
824
	private static $db = array(
825
		'UniqA' => 'Int',
826
		'UniqS' => 'Int',
827
	);
828
	private static $extensions = array(
829
		"Versioned('Stage', 'Live')"
830
	);
831
	private static $indexes = array(
832
		'UniqS_idx' => 'unique ("UniqS")',
833
		'UniqA_idx' => array('type' => 'unique', 'name' => 'UniqA_idx', 'value' => '"UniqA"',),
834
	);
835
836
}
837
838
/**
839
 * @package framework
840
 * @subpackage tests
841
 */
842
class VersionedTest_RelatedWithoutVersion extends DataObject implements TestOnly {
843
844
	private static $db = array(
845
		'Name' => 'Varchar'
846
	);
847
848
	private static $belongs_many_many = array(
849
		'Related' => 'VersionedTest_DataObject'
850
	);
851
852
}
853
854
/**
855
 * @package framework
856
 * @subpackage tests
857
 */
858
class VersionedTest_Subclass extends VersionedTest_DataObject implements TestOnly {
859
	private static $db = array(
860
		"ExtraField" => "Varchar",
861
	);
862
}
863
864
/**
865
 * @package framework
866
 * @subpackage tests
867
 */
868
class VersionedTest_AnotherSubclass extends VersionedTest_DataObject implements TestOnly {
869
	private static $db = array(
870
		"AnotherField" => "Varchar"
871
	);
872
}
873
874
/**
875
 * @package framework
876
 * @subpackage tests
877
 */
878
class VersionedTest_UnversionedWithField extends DataObject implements TestOnly {
879
	private static $db = array('Version' => 'Varchar(255)');
880
}
881
882
class VersionedTest_SingleStage extends DataObject implements TestOnly {
883
	private static $db = array(
884
		'Name' => 'Varchar'
885
	);
886
887
	private static $extensions = array(
888
		'Versioned("Stage")'
889
	);
890
}
891