mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge branch 'master' into 2.5
Conflicts: CONTRIBUTING.md lib/Cake/Model/Datasource/DboSource.php
This commit is contained in:
commit
8acb75425d
10 changed files with 122 additions and 72 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
<<<<<<< HEAD
|
||||||
# How to contribute
|
# How to contribute
|
||||||
|
|
||||||
CakePHP loves to welcome your contributions. There are several ways to help out:
|
CakePHP loves to welcome your contributions. There are several ways to help out:
|
||||||
|
|
|
@ -1704,8 +1704,7 @@ class DboSource extends DataSource {
|
||||||
if (!empty($assocData['order'])) {
|
if (!empty($assocData['order'])) {
|
||||||
$queryData['order'][] = $assocData['order'];
|
$queryData['order'][] = $assocData['order'];
|
||||||
}
|
}
|
||||||
|
if (!in_array($join, $queryData['joins'], true)) {
|
||||||
if (!in_array($join, $queryData['joins'])) {
|
|
||||||
$queryData['joins'][] = $join;
|
$queryData['joins'][] = $join;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2705,8 +2705,9 @@ class Model extends Object implements CakeEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
$ids = $this->find('all', array_merge(array(
|
$ids = $this->find('all', array_merge(array(
|
||||||
'fields' => "DISTINCT {$this->alias}.{$this->primaryKey}",
|
'fields' => "{$this->alias}.{$this->primaryKey}",
|
||||||
'order' => false,
|
'order' => false,
|
||||||
|
'group' => "{$this->alias}.{$this->primaryKey}",
|
||||||
'recursive' => 0), compact('conditions'))
|
'recursive' => 0), compact('conditions'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -62,24 +62,31 @@ class CakeTestCaseTest extends CakeTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testAssertGoodTags
|
* testAssertTags
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function testAssertTagsQuotes() {
|
public function testAssertTagsBasic() {
|
||||||
$test = new AssertTagsTestCase('testAssertTagsQuotes');
|
$test = new AssertTagsTestCase('testAssertTagsQuotes');
|
||||||
$result = $test->run();
|
$result = $test->run();
|
||||||
$this->assertEquals(0, $result->errorCount());
|
$this->assertEquals(0, $result->errorCount());
|
||||||
$this->assertTrue($result->wasSuccessful());
|
$this->assertTrue($result->wasSuccessful());
|
||||||
$this->assertEquals(0, $result->failureCount());
|
$this->assertEquals(0, $result->failureCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test assertTags works with single and double quotes
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testAssertTagsQuoting() {
|
||||||
$input = '<a href="/test.html" class="active">My link</a>';
|
$input = '<a href="/test.html" class="active">My link</a>';
|
||||||
$pattern = array(
|
$pattern = array(
|
||||||
'a' => array('href' => '/test.html', 'class' => 'active'),
|
'a' => array('href' => '/test.html', 'class' => 'active'),
|
||||||
'My link',
|
'My link',
|
||||||
'/a'
|
'/a'
|
||||||
);
|
);
|
||||||
$this->assertTrue($test->assertTags($input, $pattern), 'Double quoted attributes %s');
|
$this->assertTags($input, $pattern);
|
||||||
|
|
||||||
$input = "<a href='/test.html' class='active'>My link</a>";
|
$input = "<a href='/test.html' class='active'>My link</a>";
|
||||||
$pattern = array(
|
$pattern = array(
|
||||||
|
@ -87,7 +94,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
||||||
'My link',
|
'My link',
|
||||||
'/a'
|
'/a'
|
||||||
);
|
);
|
||||||
$this->assertTrue($test->assertTags($input, $pattern), 'Single quoted attributes %s');
|
$this->assertTags($input, $pattern);
|
||||||
|
|
||||||
$input = "<a href='/test.html' class='active'>My link</a>";
|
$input = "<a href='/test.html' class='active'>My link</a>";
|
||||||
$pattern = array(
|
$pattern = array(
|
||||||
|
@ -95,7 +102,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
||||||
'My link',
|
'My link',
|
||||||
'/a'
|
'/a'
|
||||||
);
|
);
|
||||||
$this->assertTrue($test->assertTags($input, $pattern), 'Single quoted attributes %s');
|
$this->assertTags($input, $pattern);
|
||||||
|
|
||||||
$input = "<span><strong>Text</strong></span>";
|
$input = "<span><strong>Text</strong></span>";
|
||||||
$pattern = array(
|
$pattern = array(
|
||||||
|
@ -105,7 +112,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
||||||
'/strong',
|
'/strong',
|
||||||
'/span'
|
'/span'
|
||||||
);
|
);
|
||||||
$this->assertTrue($test->assertTags($input, $pattern), 'Tags with no attributes');
|
$this->assertTags($input, $pattern);
|
||||||
|
|
||||||
$input = "<span class='active'><strong>Text</strong></span>";
|
$input = "<span class='active'><strong>Text</strong></span>";
|
||||||
$pattern = array(
|
$pattern = array(
|
||||||
|
@ -115,7 +122,34 @@ class CakeTestCaseTest extends CakeTestCase {
|
||||||
'/strong',
|
'/strong',
|
||||||
'/span'
|
'/span'
|
||||||
);
|
);
|
||||||
$this->assertTrue($test->assertTags($input, $pattern), 'Test attribute presence');
|
$this->assertTags($input, $pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that assertTags runs quickly.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testAssertTagsRuntimeComplexity() {
|
||||||
|
$pattern = array(
|
||||||
|
'div' => array(
|
||||||
|
'attr1' => 'val1',
|
||||||
|
'attr2' => 'val2',
|
||||||
|
'attr3' => 'val3',
|
||||||
|
'attr4' => 'val4',
|
||||||
|
'attr5' => 'val5',
|
||||||
|
'attr6' => 'val6',
|
||||||
|
'attr7' => 'val7',
|
||||||
|
'attr8' => 'val8',
|
||||||
|
),
|
||||||
|
'My div',
|
||||||
|
'/div'
|
||||||
|
);
|
||||||
|
$input = '<div attr8="val8" attr6="val6" attr4="val4" attr2="val2"' .
|
||||||
|
' attr1="val1" attr3="val3" attr5="val5" attr7="val7" />' .
|
||||||
|
'My div' .
|
||||||
|
'</div>';
|
||||||
|
$this->assertTags($input, $pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -92,6 +92,8 @@ class InflectorTest extends CakeTestCase {
|
||||||
$this->assertEquals(Inflector::singularize('faxes'), 'fax');
|
$this->assertEquals(Inflector::singularize('faxes'), 'fax');
|
||||||
$this->assertEquals(Inflector::singularize('waxes'), 'wax');
|
$this->assertEquals(Inflector::singularize('waxes'), 'wax');
|
||||||
$this->assertEquals(Inflector::singularize('niches'), 'niche');
|
$this->assertEquals(Inflector::singularize('niches'), 'niche');
|
||||||
|
$this->assertEquals(Inflector::singularize('caves'), 'cave');
|
||||||
|
$this->assertEquals(Inflector::singularize('graves'), 'grave');
|
||||||
$this->assertEquals(Inflector::singularize('waves'), 'wave');
|
$this->assertEquals(Inflector::singularize('waves'), 'wave');
|
||||||
$this->assertEquals(Inflector::singularize('bureaus'), 'bureau');
|
$this->assertEquals(Inflector::singularize('bureaus'), 'bureau');
|
||||||
$this->assertEquals(Inflector::singularize('genetic_analyses'), 'genetic_analysis');
|
$this->assertEquals(Inflector::singularize('genetic_analyses'), 'genetic_analysis');
|
||||||
|
|
|
@ -881,6 +881,7 @@ class FormHelperTest extends CakeTestCase {
|
||||||
'/div',
|
'/div',
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
$result = $this->Form->submit('Cancel', array('name' => 'cancel'));
|
$result = $this->Form->submit('Cancel', array('name' => 'cancel'));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'div' => array('class' => 'submit'),
|
'div' => array('class' => 'submit'),
|
||||||
|
@ -1863,8 +1864,8 @@ class FormHelperTest extends CakeTestCase {
|
||||||
'preg:/[^<]+/',
|
'preg:/[^<]+/',
|
||||||
'/label',
|
'/label',
|
||||||
'input' => array(
|
'input' => array(
|
||||||
'type' => 'text', 'name' => 'preg:/[^<]+/',
|
'type' => 'text', 'name', 'id',
|
||||||
'id' => 'preg:/[^<]+/', 'class' => 'form-error'
|
'class' => 'form-error'
|
||||||
),
|
),
|
||||||
array('div' => array('class' => 'error-message')),
|
array('div' => array('class' => 'error-message')),
|
||||||
'You must have a last name',
|
'You must have a last name',
|
||||||
|
@ -1888,7 +1889,7 @@ class FormHelperTest extends CakeTestCase {
|
||||||
'label' => array('for'),
|
'label' => array('for'),
|
||||||
'Balance',
|
'Balance',
|
||||||
'/label',
|
'/label',
|
||||||
'input' => array('name', 'type' => 'number', 'id'),
|
'input' => array('name', 'type' => 'number', 'id', 'step'),
|
||||||
'/div',
|
'/div',
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
@ -5750,14 +5751,14 @@ class FormHelperTest extends CakeTestCase {
|
||||||
$result = $this->Form->checkbox('Contact.field', array('id' => 'theID', 'value' => 'myvalue'));
|
$result = $this->Form->checkbox('Contact.field', array('id' => 'theID', 'value' => 'myvalue'));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'input' => array('type' => 'hidden', 'class' => 'form-error', 'name' => 'data[Contact][field]', 'value' => '0', 'id' => 'theID_'),
|
'input' => array('type' => 'hidden', 'class' => 'form-error', 'name' => 'data[Contact][field]', 'value' => '0', 'id' => 'theID_'),
|
||||||
array('input' => array('preg:/[^<]+/', 'value' => 'myvalue', 'id' => 'theID', 'checked' => 'checked', 'class' => 'form-error'))
|
array('input' => array('type', 'name', 'value' => 'myvalue', 'id' => 'theID', 'checked' => 'checked', 'class' => 'form-error'))
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
$result = $this->Form->checkbox('Contact.field', array('value' => 'myvalue'));
|
$result = $this->Form->checkbox('Contact.field', array('value' => 'myvalue'));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'input' => array('type' => 'hidden', 'class' => 'form-error', 'name' => 'data[Contact][field]', 'value' => '0', 'id' => 'ContactField_'),
|
'input' => array('type' => 'hidden', 'class' => 'form-error', 'name' => 'data[Contact][field]', 'value' => '0', 'id' => 'ContactField_'),
|
||||||
array('input' => array('preg:/[^<]+/', 'value' => 'myvalue', 'id' => 'ContactField', 'checked' => 'checked', 'class' => 'form-error'))
|
array('input' => array('type', 'name', 'value' => 'myvalue', 'id' => 'ContactField', 'checked' => 'checked', 'class' => 'form-error'))
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* This class helpes in indirectly testing the functionalities of CakeTestCase::assertTags
|
* This class helps in indirectly testing the functionalities of CakeTestCase::assertTags
|
||||||
*
|
*
|
||||||
* @package Cake.Test.Fixture
|
* @package Cake.Test.Fixture
|
||||||
*/
|
*/
|
||||||
|
@ -115,4 +115,5 @@ class AssertTagsTestCase extends CakeTestCase {
|
||||||
);
|
);
|
||||||
$this->assertTags($input, $pattern);
|
$this->assertTags($input, $pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,9 +340,14 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
*
|
*
|
||||||
* Checks for an input tag with a name attribute (contains any non-empty value) and an id
|
* Checks for an input tag with a name attribute (contains any non-empty value) and an id
|
||||||
* attribute that contains 'my-input':
|
* attribute that contains 'my-input':
|
||||||
|
*
|
||||||
|
* {{{
|
||||||
* array('input' => array('name', 'id' => 'my-input'))
|
* array('input' => array('name', 'id' => 'my-input'))
|
||||||
|
* }}}
|
||||||
*
|
*
|
||||||
* Checks for two p elements with some text in them:
|
* Checks for two p elements with some text in them:
|
||||||
|
*
|
||||||
|
* {{{
|
||||||
* array(
|
* array(
|
||||||
* array('p' => true),
|
* array('p' => true),
|
||||||
* 'textA',
|
* 'textA',
|
||||||
|
@ -351,13 +356,17 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
* 'textB',
|
* 'textB',
|
||||||
* '/p'
|
* '/p'
|
||||||
* )
|
* )
|
||||||
|
* }}}
|
||||||
*
|
*
|
||||||
* You can also specify a pattern expression as part of the attribute values, or the tag
|
* You can also specify a pattern expression as part of the attribute values, or the tag
|
||||||
* being defined, if you prepend the value with preg: and enclose it with slashes, like so:
|
* being defined, if you prepend the value with preg: and enclose it with slashes, like so:
|
||||||
|
*
|
||||||
|
* {{{
|
||||||
* array(
|
* array(
|
||||||
* array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
|
* array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
|
||||||
* 'preg:/My\s+field/'
|
* 'preg:/My\s+field/'
|
||||||
* )
|
* )
|
||||||
|
* }}}
|
||||||
*
|
*
|
||||||
* Important: This function is very forgiving about whitespace and also accepts any
|
* Important: This function is very forgiving about whitespace and also accepts any
|
||||||
* permutation of attribute order. It will also allow whitespace between specified tags.
|
* permutation of attribute order. It will also allow whitespace between specified tags.
|
||||||
|
@ -439,8 +448,13 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
$val = '.+?';
|
$val = '.+?';
|
||||||
$explanations[] = sprintf('Attribute "%s" present', $attr);
|
$explanations[] = sprintf('Attribute "%s" present', $attr);
|
||||||
} elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
|
} elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
|
||||||
$quotes = '["\']?';
|
$val = str_replace(
|
||||||
$val = $matches[1];
|
array('.*', '.+'),
|
||||||
|
array('.*?', '.+?'),
|
||||||
|
$matches[1]
|
||||||
|
);
|
||||||
|
$quotes = $val !== $matches[1] ? '["\']' : '["\']?';
|
||||||
|
|
||||||
$explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
|
$explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
|
||||||
} else {
|
} else {
|
||||||
$explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
|
$explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
|
||||||
|
@ -451,16 +465,9 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
if ($attrs) {
|
if ($attrs) {
|
||||||
$permutations = $this->_arrayPermute($attrs);
|
|
||||||
|
|
||||||
$permutationTokens = array();
|
|
||||||
foreach ($permutations as $permutation) {
|
|
||||||
$permutationTokens[] = implode('', $permutation);
|
|
||||||
}
|
|
||||||
$regex[] = array(
|
$regex[] = array(
|
||||||
sprintf('%s', implode(', ', $explanations)),
|
'explains' => $explanations,
|
||||||
$permutationTokens,
|
'attrs' => $attrs,
|
||||||
$i,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$regex[] = array(
|
$regex[] = array(
|
||||||
|
@ -470,9 +477,14 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($regex as $i => $assertation) {
|
foreach ($regex as $i => $assertion) {
|
||||||
list($description, $expressions, $itemNum) = $assertation;
|
|
||||||
$matches = false;
|
$matches = false;
|
||||||
|
if (isset($assertion['attrs'])) {
|
||||||
|
$string = $this->_assertAttributes($assertion, $string);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($description, $expressions, $itemNum) = $assertion;
|
||||||
foreach ((array)$expressions as $expression) {
|
foreach ((array)$expressions as $expression) {
|
||||||
if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
|
if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
|
||||||
$matches = true;
|
$matches = true;
|
||||||
|
@ -495,32 +507,32 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates all permutation of an array $items and returns them in a new array.
|
* Check the attributes as part of an assertTags() check.
|
||||||
*
|
*
|
||||||
* @param array $items An array of items
|
* @param array $assertions Assertions to run.
|
||||||
* @param array $perms
|
* @param string $string The HTML string to check.
|
||||||
* @return array
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function _arrayPermute($items, $perms = array()) {
|
protected function _assertAttributes($assertions, $string) {
|
||||||
static $permuted;
|
$asserts = $assertions['attrs'];
|
||||||
if (empty($perms)) {
|
$explains = $assertions['explains'];
|
||||||
$permuted = array();
|
while (count($asserts) > 0) {
|
||||||
|
$matches = false;
|
||||||
|
foreach ($asserts as $j => $assert) {
|
||||||
|
if (preg_match(sprintf('/^%s/s', $assert), $string, $match)) {
|
||||||
|
$matches = true;
|
||||||
|
$string = substr($string, strlen($match[0]));
|
||||||
|
array_splice($asserts, $j, 1);
|
||||||
|
array_splice($explains, $j, 1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($items)) {
|
|
||||||
$permuted[] = $perms;
|
|
||||||
} else {
|
|
||||||
$numItems = count($items) - 1;
|
|
||||||
for ($i = $numItems; $i >= 0; --$i) {
|
|
||||||
$newItems = $items;
|
|
||||||
$newPerms = $perms;
|
|
||||||
list($tmp) = array_splice($newItems, $i, 1);
|
|
||||||
array_unshift($newPerms, $tmp);
|
|
||||||
$this->_arrayPermute($newItems, $newPerms);
|
|
||||||
}
|
}
|
||||||
return $permuted;
|
if ($matches === false) {
|
||||||
|
$this->assertTrue(false, 'Attribute did not match. Was expecting ' . $explains[$j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,7 @@ abstract class ControllerTestCase extends CakeTestCase {
|
||||||
* ### Mocks:
|
* ### Mocks:
|
||||||
*
|
*
|
||||||
* - `methods` Methods to mock on the controller. `_stop()` is mocked by default
|
* - `methods` Methods to mock on the controller. `_stop()` is mocked by default
|
||||||
* - `models` Models to mock. Models are added to the ClassRegistry so they any
|
* - `models` Models to mock. Models are added to the ClassRegistry so any
|
||||||
* time they are instantiated the mock will be created. Pass as key value pairs
|
* time they are instantiated the mock will be created. Pass as key value pairs
|
||||||
* with the value being specific methods on the model to mock. If `true` or
|
* with the value being specific methods on the model to mock. If `true` or
|
||||||
* no value is passed, the entire model will be mocked.
|
* no value is passed, the entire model will be mocked.
|
||||||
|
|
|
@ -117,7 +117,7 @@ class Inflector {
|
||||||
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
|
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
|
||||||
'/([ftw]ax)es/i' => '\1',
|
'/([ftw]ax)es/i' => '\1',
|
||||||
'/(cris|ax|test)es$/i' => '\1is',
|
'/(cris|ax|test)es$/i' => '\1is',
|
||||||
'/(shoe|slave)s$/i' => '\1',
|
'/(shoe)s$/i' => '\1',
|
||||||
'/(o)es$/i' => '\1',
|
'/(o)es$/i' => '\1',
|
||||||
'/ouses$/' => 'ouse',
|
'/ouses$/' => 'ouse',
|
||||||
'/([^a])uses$/' => '\1us',
|
'/([^a])uses$/' => '\1us',
|
||||||
|
@ -130,7 +130,7 @@ class Inflector {
|
||||||
'/(hive)s$/i' => '\1',
|
'/(hive)s$/i' => '\1',
|
||||||
'/(drive)s$/i' => '\1',
|
'/(drive)s$/i' => '\1',
|
||||||
'/([le])ves$/i' => '\1f',
|
'/([le])ves$/i' => '\1f',
|
||||||
'/([^rfo])ves$/i' => '\1fe',
|
'/([^rfoa])ves$/i' => '\1fe',
|
||||||
'/(^analy)ses$/i' => '\1sis',
|
'/(^analy)ses$/i' => '\1sis',
|
||||||
'/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
|
'/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
|
||||||
'/([ti])a$/i' => '\1um',
|
'/([ti])a$/i' => '\1um',
|
||||||
|
@ -147,7 +147,6 @@ class Inflector {
|
||||||
),
|
),
|
||||||
'irregular' => array(
|
'irregular' => array(
|
||||||
'foes' => 'foe',
|
'foes' => 'foe',
|
||||||
'waves' => 'wave',
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue