Browse Source

Merge pull request #12576 from ndm2/feature/getter-setter-split-association-class-name

Add getter/setter for `Association::className()`.
Mark Story 7 years ago
parent
commit
b4809ce0f4
2 changed files with 113 additions and 4 deletions
  1. 40 1
      src/ORM/Association.php
  2. 73 3
      tests/TestCase/ORM/AssociationTest.php

+ 40 - 1
src/ORM/Association.php

@@ -335,13 +335,52 @@ abstract class Association
     }
 
     /**
+     * Sets the class name of the target table object.
+     *
+     * @param string $className Class name to set.
+     * @return $this
+     * @throws \InvalidArgumentException In case the class name is set after the target table has been
+     *  resolved, and it doesn't match the target table's class name.
+     */
+    public function setClassName($className)
+    {
+        if ($this->_targetTable !== null &&
+            get_class($this->_targetTable) !== App::className($className, 'Model/Table', 'Table')
+        ) {
+            throw new InvalidArgumentException(
+                'The class name doesn\'t match the target table\'s class name.'
+            );
+        }
+
+        $this->_className = $className;
+
+        return $this;
+    }
+
+    /**
+     * Gets the class name of the target table object.
+     *
+     * @return string
+     */
+    public function getClassName()
+    {
+        return $this->_className;
+    }
+
+    /**
      * The class name of the target table object
      *
+     * @deprecated 3.7.0 Use getClassName() instead.
      * @return string
      */
     public function className()
     {
-        return $this->_className;
+        deprecationWarning(
+            get_called_class() . '::className() is deprecated. ' .
+            'Use getClassName() instead.'
+        );
+
+        return $this->getClassName();
     }
 
     /**

+ 73 - 3
tests/TestCase/ORM/AssociationTest.php

@@ -14,6 +14,7 @@
  */
 namespace Cake\Test\TestCase\ORM;
 
+use Cake\Core\Configure;
 use Cake\Core\Plugin;
 use Cake\ORM\Table;
 use Cake\TestSuite\TestCase;
@@ -139,7 +140,7 @@ class AssociationTest extends TestCase
      *
      * @return void
      */
-    public function testSetNameAfterTarger()
+    public function testSetNameAfterTarget()
     {
         $this->expectException(\InvalidArgumentException::class);
         $this->expectExceptionMessage('Association name does not match target table alias.');
@@ -162,11 +163,80 @@ class AssociationTest extends TestCase
     /**
      * Tests that className() returns the correct association className
      *
+     * @group deprecated
      * @return void
      */
     public function testClassName()
     {
-        $this->assertEquals('\Cake\Test\TestCase\ORM\TestTable', $this->association->className());
+        $this->deprecated(function () {
+            $this->assertEquals('\Cake\Test\TestCase\ORM\TestTable', $this->association->className());
+        });
+    }
+
+    /**
+     * Tests that setClassName() succeeds before the target table is resolved.
+     *
+     * @return void
+     */
+    public function testSetClassNameBeforeTarget()
+    {
+        $this->assertEquals('\Cake\Test\TestCase\ORM\TestTable', $this->association->getClassName());
+        $this->assertSame($this->association, $this->association->setClassName('\TestApp\Model\Table\AuthorsTable'));
+        $this->assertEquals('\TestApp\Model\Table\AuthorsTable', $this->association->getClassName());
+    }
+
+    /**
+     * Tests that setClassName() fails after the target table is resolved.
+     *
+     * @return void
+     */
+    public function testSetClassNameAfterTarget()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionMessage('The class name doesn\'t match the target table\'s class name.');
+        $this->association->getTarget();
+        $this->association->setClassName('\TestApp\Model\Table\AuthorsTable');
+    }
+
+    /**
+     * Tests that setClassName() fails after the target table is resolved.
+     *
+     * @return void
+     */
+    public function testSetClassNameWithShortSyntaxAfterTarget()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionMessage('The class name doesn\'t match the target table\'s class name.');
+        $this->association->getTarget();
+        $this->association->setClassName('Authors');
+    }
+
+    /**
+     * Tests that setClassName() succeeds if name equals target table's class name.
+     *
+     * @return void
+     */
+    public function testSetClassNameToTargetClassName()
+    {
+        $className = get_class($this->association->getTarget());
+        $this->association->setClassName($className);
+        $this->assertEquals($className, $this->association->getClassName());
+    }
+
+    /**
+     * Tests that setClassName() succeeds if the short name resolves to the target table's class name.
+     *
+     * @return void
+     */
+    public function testSetClassNameWithShortSyntaxToTargetClassName()
+    {
+        Configure::write('App.namespace', 'TestApp');
+
+        $this->association->setClassName('\TestApp\Model\Table\AuthorsTable');
+        $className = get_class($this->association->getTarget());
+        $this->assertEquals('TestApp\Model\Table\AuthorsTable', $className);
+        $this->association->setClassName('Authors');
+        $this->assertEquals('Authors', $this->association->getClassName());
     }
 
     /**
@@ -187,7 +257,7 @@ class AssociationTest extends TestCase
             ->setConstructorArgs(['Foo', $config])
             ->getMock();
 
-        $this->assertEquals('Test', $this->association->className());
+        $this->assertEquals('Test', $this->association->getClassName());
     }
 
     /**