Browse Source

Merge branch '4.x' into 4.next

Corey Taylor 3 years ago
parent
commit
9d42bacf66

+ 1 - 1
.github/CONTRIBUTING.md

@@ -98,5 +98,5 @@ If you've found a security related issue in CakePHP, please don't open an issue
 * [Forum](https://discourse.cakephp.org/)
 * [Stackoverflow](https://stackoverflow.com/tags/cakephp)
 * [IRC channel #cakephp](https://kiwiirc.com/client/irc.freenode.net#cakephp)
-* [Slack](https://cakesf.herokuapp.com/)
+* [Slack](https://slack-invite.cakephp.org/)
 * [Discord](https://discord.gg/k4trEMPebj)

+ 1 - 1
.github/ISSUE_TEMPLATE/bug_report.yml

@@ -16,7 +16,7 @@ body:
     attributes:
       label: CakePHP Version
       description: "The CakePHP version used."
-      placeholder: "4.3.0"
+      placeholder: "4.4.0"
     validations:
       required: true
   - type: input

+ 7 - 3
.github/SECURITY.md

@@ -6,9 +6,13 @@ We support fixing security issues on the following releases:
 
 | Version | Supported          | Security fixes until
 | ------- | ------------------ | -------------------- 
-| 4.x     | :white_check_mark: | 
-| 3.10.x  | :white_check_mark: | 15th December 2022 (36 months after 4.0.0)
-| 2.10.x  | :x:                | 15th June 2021 (18 months after 4.0.0)
+| 4.4     | :white_check_mark: | 24 Months after the release of 5.0
+| 4.3     | :white_check_mark: | Release of 5.0
+| 4.2     | :white_check_mark: | Release of 4.5
+| 4.1     | :x:                | No longer supported
+| 4.0     | :x:                | No longer supported
+| 3.10.x  | :x:                | No longer supported
+| 2.10.x  | :x:                | No longer supported
 
 ## Reporting a Vulnerability
 

+ 1 - 1
.github/workflows/api-docs.yml

@@ -16,7 +16,7 @@ jobs:
     steps:
       - name: Get Cakebot App Token
         id: app-token
-        uses: getsentry/action-github-app-token@v1
+        uses: getsentry/action-github-app-token@v2
         with:
           app_id: ${{ secrets.CAKEBOT_APP_ID }}
           private_key: ${{ secrets.CAKEBOT_APP_PRIVATE_KEY }}

+ 1 - 1
README.md

@@ -66,7 +66,7 @@ tests for CakePHP by doing the following:
 
 ## Get Support!
 
-* [Slack](https://cakesf.herokuapp.com/) - Join us on Slack.
+* [Slack](https://slack-invite.cakephp.org/) - Join us on Slack.
 * [Discord](https://discord.gg/k4trEMPebj) - Join us on Discord.
 * [#cakephp](https://webchat.freenode.net/?channels=#cakephp) on irc.freenode.net - Come chat with us, we have cake.
 * [Forum](https://discourse.cakephp.org/) - Official CakePHP forum.

+ 5 - 1
src/Command/I18nExtractCommand.php

@@ -830,7 +830,11 @@ class I18nExtractCommand extends Command
         }
 
         foreach ($this->_paths as $path) {
-            $path = realpath($path) . DIRECTORY_SEPARATOR;
+            $path = realpath($path);
+            if ($path === false) {
+                continue;
+            }
+            $path .= DIRECTORY_SEPARATOR;
             $fs = new Filesystem();
             $files = $fs->findRecursive($path, '/\.php$/');
             $files = array_keys(iterator_to_array($files));

+ 16 - 8
src/Console/ConsoleOutput.php

@@ -214,17 +214,25 @@ class ConsoleOutput
         if ($this->_outputAs === static::RAW) {
             return $text;
         }
-        if ($this->_outputAs === static::PLAIN) {
-            $tags = implode('|', array_keys(static::$_styles));
+        if ($this->_outputAs !== static::PLAIN) {
+            $output = preg_replace_callback(
+                '/<(?P<tag>[a-z0-9-_]+)>(?P<text>.*?)<\/(\1)>/ims',
+                [$this, '_replaceTags'],
+                $text
+            );
+            if ($output !== null) {
+                return $output;
+            }
+        }
 
-            return preg_replace('#</?(?:' . $tags . ')>#', '', $text);
+        $tags = implode('|', array_keys(static::$_styles));
+        $output = preg_replace('#</?(?:' . $tags . ')>#', '', $text);
+
+        if ($output === null) {
+            return $text;
         }
 
-        return preg_replace_callback(
-            '/<(?P<tag>[a-z0-9-_]+)>(?P<text>.*?)<\/(\1)>/ims',
-            [$this, '_replaceTags'],
-            $text
-        );
+        return $output;
     }
 
     /**

+ 13 - 0
src/Database/Query.php

@@ -1017,6 +1017,19 @@ class Query implements ExpressionInterface, IteratorAggregate
      * If you use string conditions make sure that your values are correctly quoted.
      * The safest thing you can do is to never use string conditions.
      *
+     * ### Using null-able values
+     *
+     * When using values that can be null you can use the 'IS' keyword to let the ORM generate the correct SQL based on the value's type
+     *
+     * ```
+     * $query->where([
+     *     'posted >=' => new DateTime('3 days ago'),
+     *     'category_id IS' => $category,
+     * ]);
+     * ```
+     *
+     * If $category is `null` - it will actually convert that into `category_id IS NULL` - if it's `4` it will convert it into `category_id = 4`
+     *
      * @param \Cake\Database\ExpressionInterface|\Closure|array|string|null $conditions The conditions to filter on.
      * @param array<string, string> $types Associative array of type names used to bind values to query
      * @param bool $overwrite whether to reset conditions with passed list or not

+ 0 - 8
src/Utility/Text.php

@@ -377,14 +377,6 @@ class Text
         }
         $options += ['width' => 72, 'wordWrap' => true, 'indent' => null, 'indentAt' => 0];
 
-        /** @phpstan-ignore-next-line */
-        if (!empty($options['indentAt']) && $options['indentAt'] === 0) {
-            $indentLength = !empty($options['indent']) ? strlen($options['indent']) : 0;
-            $options['width'] -= $indentLength;
-
-            return self::wrap($text, $options);
-        }
-
         $wrapped = self::wrap($text, $options);
 
         if (!empty($options['indent'])) {

+ 10 - 12
src/View/View.php

@@ -1620,8 +1620,8 @@ class View implements EventDispatcherInterface
         $templatePaths = App::path(static::NAME_TEMPLATE);
         $pluginPaths = $themePaths = [];
         if (!empty($plugin)) {
-            for ($i = 0, $count = count($templatePaths); $i < $count; $i++) {
-                $pluginPaths[] = $templatePaths[$i]
+            foreach ($templatePaths as $templatePath) {
+                $pluginPaths[] = $templatePath
                     . static::PLUGIN_TEMPLATE_FOLDER
                     . DIRECTORY_SEPARATOR
                     . $plugin
@@ -1634,16 +1634,14 @@ class View implements EventDispatcherInterface
             $themePaths[] = Plugin::templatePath(Inflector::camelize($this->theme));
 
             if ($plugin) {
-                for ($i = 0, $count = count($themePaths); $i < $count; $i++) {
-                    array_unshift(
-                        $themePaths,
-                        $themePaths[$i]
-                            . static::PLUGIN_TEMPLATE_FOLDER
-                            . DIRECTORY_SEPARATOR
-                            . $plugin
-                            . DIRECTORY_SEPARATOR
-                    );
-                }
+                array_unshift(
+                    $themePaths,
+                    $themePaths[0]
+                        . static::PLUGIN_TEMPLATE_FOLDER
+                        . DIRECTORY_SEPARATOR
+                        . $plugin
+                        . DIRECTORY_SEPARATOR
+                );
             }
         }
 

+ 19 - 0
tests/TestCase/Command/I18nExtractCommandTest.php

@@ -373,4 +373,23 @@ class I18nExtractCommandTest extends TestCase
         $expected = '#: ./tests/test_app/templates/Pages/extract.php:';
         $this->assertStringContainsString($expected, $result);
     }
+
+    /**
+     * test invalid path options
+     */
+    public function testExtractWithInvalidPaths(): void
+    {
+        $this->exec(
+            'i18n extract ' .
+            '--extract-core=no ' .
+            '--paths=' . TEST_APP . 'templates,' . TEST_APP . 'unknown ' .
+            '--output=' . $this->path . DS
+        );
+        $this->assertExitSuccess();
+        $this->assertFileExists($this->path . DS . 'default.pot');
+        $result = file_get_contents($this->path . DS . 'default.pot');
+
+        $expected = '#: ./tests/test_app/templates/Pages/extract.php:';
+        $this->assertStringContainsString($expected, $result);
+    }
 }