Browse Source

NeighborBehavior

Mark Scherer 10 years ago
parent
commit
697ec8a6f1

+ 81 - 0
src/Model/Behavior/NeighborBehavior.php

@@ -0,0 +1,81 @@
+<?php
+namespace Tools\Model\Behavior;
+
+use Cake\ORM\Behavior;
+use Cake\ORM\Query;
+use Cake\Utility\Hash;
+
+/**
+ * WhoDidIt Behavior
+ *
+ * Handles created_by, modified_by fields for a given Model, if they exist in the Model DB table.
+ * It's similar to the created, modified automagic, but it stores the id of the logged in user
+ * in the models that have $actsAs = array('WhoDidIt').
+ *
+ * This is useful to track who created records, and the last user that has changed them.
+ *
+ * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#using-created-and-modified
+ */
+class NeighborBehavior extends Behavior {
+
+	/**
+	 * Default config for a model that has this behavior attached.
+	 *
+	 * Setting force_modified to true will have the same effect as overriding the save method as
+	 * described in the code example for "Using created and modified" in the Cookbook.
+	 *
+	 * @var array
+	 * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#using-created-and-modified
+	 */
+	protected $_defaultConfig = array(
+	);
+
+	public function neighbors($id, array $options = []) {
+		if (empty($id)) {
+			throw new \InvalidArgumentException("The 'id' key is required for find('neighbors')");
+		}
+		$sortField = $this->_table->hasField('created') ? 'created' : $this->_table->primaryKey();
+		$defaults = [
+			'sortField' => $this->_table->alias() . '.' . $sortField,
+			//'displayField' => $this->_table->alias() . '.' . $this->_table->displayField()
+		];
+		$options += $defaults;
+
+		$normalDirection = (!empty($options['reverse']) ? false : true);
+		$sortDirWord = $normalDirection ? ['ASC', 'DESC'] : ['DESC', 'ASC'];
+		$sortDirSymb = $normalDirection ? ['>=', '<='] : ['<=', '>='];
+
+		if (empty($options['value'])) {
+			$data = $this->_table->find('all', ['conditions' => [$this->_table->primaryKey() => $id]])->first();
+			list($model, $sortField) = pluginSplit($options['sortField']);
+			$options['value'] = $data[$sortField];
+		}
+
+		$return = [];
+
+		$findOptions = [];
+		if (isset($options['contain'])) {
+			$findOptions['contain'] = $options['contain'];
+		}
+
+		if (!empty($options['fields'])) {
+			$findOptions['fields'] = $options['fields'];
+		}
+		$findOptions['conditions'][$this->_table->alias() . '.' . $this->_table->primaryKey() . ' !='] = $id;
+
+		$prevOptions = $findOptions;
+		$prevOptions['conditions'] = Hash::merge($prevOptions['conditions'], [$options['sortField'] . ' ' . $sortDirSymb[1] => $options['value']]);
+		$prevOptions['order'] = [$options['sortField'] => $sortDirWord[1]];
+		//debug($prevOptions);
+		$return['prev'] = $this->_table->find('all', $prevOptions)->first();
+
+		$nextOptions = $findOptions;
+		$nextOptions['conditions'] = Hash::merge($nextOptions['conditions'], [$options['sortField'] . ' ' . $sortDirSymb[0] => $options['value']]);
+		$nextOptions['order'] = [$options['sortField'] => $sortDirWord[0]];
+		//debug($nextOptions);
+		$return['next'] = $this->_table->find('all', $nextOptions)->first();
+
+		return $return;
+	}
+
+}

+ 72 - 0
tests/Fixture/StoriesFixture.php

@@ -0,0 +1,72 @@
+<?php
+namespace Tools\Test\Fixture;
+
+use Cake\TestSuite\Fixture\TestFixture;
+
+/**
+ * RoleFixture
+ *
+ */
+class StoriesFixture extends TestFixture {
+
+	/**
+	 * Fields
+	 *
+	 * @var array
+	 */
+	public $fields = [
+		'id' => ['type' => 'integer'],
+		'title' => ['type' => 'string', 'null' => false, 'length' => 64, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'],
+		'slug' => ['type' => 'string', 'null' => true, 'default' => null, 'length' => 20, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'],
+		'created' => ['type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''],
+		'modified' => ['type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''],
+		'sort' => ['type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10, 'collate' => null, 'comment' => ''],
+		'active' => ['type' => 'boolean', 'null' => false, 'default' => false, 'collate' => null, 'comment' => ''],
+		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
+	];
+
+	/**
+	 * Records
+	 *
+	 * @var array
+	 */
+	public $records = [
+		[
+			'id' => '1',
+			'title' => 'Second',
+			'slug' => 'second',
+			'created' => '2010-01-07 03:36:32',
+			'modified' => '2010-01-07 03:36:33',
+			'sort' => '2',
+			'active' => 1
+		],
+		[
+			'id' => '2',
+			'title' => 'Third',
+			'slug' => 'third',
+			'created' => '2010-01-07 03:36:33',
+			'modified' => '2010-01-07 03:36:33',
+			'sort' => '3',
+			'active' => 1
+		],
+		[
+			'id' => '3',
+			'title' => 'First',
+			'slug' => 'first',
+			'created' => '2010-01-07 03:36:31',
+			'modified' => '2010-01-07 03:36:33',
+			'sort' => '4',
+			'active' => 1
+		],
+		[
+			'id' => '4',
+			'title' => 'Forth',
+			'slug' => 'forth',
+			'created' => '2010-01-07 03:36:34',
+			'modified' => '2010-01-07 03:36:33',
+			'sort' => '1',
+			'active' => 1
+		],
+	];
+
+}

+ 117 - 0
tests/TestCase/Model/Behavior/NeighborBehaviorTest.php

@@ -0,0 +1,117 @@
+<?php
+
+namespace Tools\Model\Behavior;
+
+use Tools\Model\Behavior\NeighborBehavior;
+use Tools\TestSuite\TestCase;
+//use App\Model\AppModel;
+use Cake\ORM\TableRegistry;
+use Tools\Model\Table\Table;
+use Cake\Core\Configure;
+
+class NeighborBehaviorTest extends TestCase {
+
+	public $Table;
+
+	public $fixtures = ['plugin.tools.stories'];
+
+	public function setUp() {
+		parent::setUp();
+
+		//Configure::write('App.namespace', 'TestApp');
+
+		$this->Table = TableRegistry::get('Stories');
+		$this->Table->addBehavior('Tools.Neighbor');
+	}
+
+	public function tearDown() {
+		TableRegistry::clear();
+
+		parent::tearDown();
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighbors() {
+		$id = 2;
+
+		$result = $this->Table->neighbors($id);
+
+		$this->assertEquals('Second', $result['prev']['title']);
+		$this->assertEquals('Forth', $result['next']['title']);
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighborsReverse() {
+		$id = 2;
+
+		$result = $this->Table->neighbors($id, ['reverse' => true]);
+
+		$this->assertEquals('Forth', $result['prev']['title']);
+		$this->assertEquals('Second', $result['next']['title']);
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighborsCustomSortField() {
+		$id = 2;
+
+		$result = $this->Table->neighbors($id, ['sortField' => 'sort']);
+
+		$this->assertEquals('Second', $result['prev']['title']);
+		$this->assertEquals('First', $result['next']['title']);
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighborsCustomFields() {
+		$id = 2;
+
+		$result = $this->Table->neighbors($id, ['sortField' => 'sort', 'fields' => ['title']]);
+		//debug($result);
+		$this->assertEquals(['title' => 'Second'], $result['prev']->toArray());
+		$this->assertEquals(['title' => 'First'], $result['next']->toArray());
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighborsStart() {
+		$id = 1;
+
+		$result = $this->Table->neighbors($id, ['sortField' => 'id']);
+
+		$this->assertNull($result['prev']);
+		$this->assertEquals('Third', $result['next']['title']);
+	}
+
+	/**
+	 * NeighborBehaviorTest::testNeighborRecords()
+	 *
+	 * @return void
+	 */
+	public function testNeighborsEnd() {
+		$id = 4;
+
+		$result = $this->Table->neighbors($id);
+		//debug($result);
+		$this->assertEquals('Third', $result['prev']['title']);
+		$this->assertNull($result['next']);
+	}
+
+}