<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../../vendor/squizlabs/php_codesniffer/phpcs.xsd"
         name="LaminasCodingStandard">
    <description>The Laminas coding standard.</description>

    <!-- 1. Overview -->

    <!-- This specification extends PSR-12, the coding style guide and
         requires adherence to PSR-1, the basic coding standard. -->

    <!-- 2. General -->

    <!-- 2.1 Basic Coding Standard -->

    <!-- Code MUST follow all rules outlined in PSR-1. -->
    <rule ref="PSR12">
        <exclude name="Squiz.WhiteSpace.ControlStructureSpacing.SpacingAfterOpen"/>
        <exclude name="Squiz.WhiteSpace.ControlStructureSpacing.SpacingBeforeClose"/>
        <!-- checked by WebimpressCodingStandard.WhiteSpace.BraceBlankLine -->
    </rule>

    <!-- The term 'StudlyCaps' in PSR-1 MUST be interpreted as PascalCase where
         the first letter of each word is capitalized including the very first
         letter. -->

    <!-- Additional Laminas rules -->

    <!-- There MAY NOT be any content before the opening tag. -->
    <rule ref="Generic.PHP.CharacterBeforePHPOpeningTag"/>

    <!-- The short open tag MAY NOT be used. -->
    <rule ref="Generic.PHP.DisallowShortOpenTag">
        <!-- The short echo tag MAY be used in templates. -->
        <exclude name="Generic.PHP.DisallowShortOpenTag.EchoFound"/>
    </rule>
    <!-- There MAY NOT be any inline HTML in PHP code. -->
    <rule ref="Generic.Files.InlineHTML"/>
    <!-- Deprecated PHP functions MUST be avoided. -->
    <rule ref="Generic.PHP.DeprecatedFunctions"/>
    <!-- The backtick operator MUST NOT be used. -->
    <rule ref="Generic.PHP.BacktickOperator"/>
    <!-- The PHP `goto` language construct SHOULD NOT be used. -->
    <rule ref="Generic.PHP.DiscourageGoto"/>
    <!-- The `global` keyword MUST NOT be used. -->
    <rule ref="Squiz.PHP.GlobalKeyword"/>
    <!-- The constant `PHP_SAPI` SHOULD be used instead of the
         `php_sapi_name()` function. -->
    <rule ref="Generic.PHP.SAPIUsage"/>
    <!-- Alias functions SHOULD NOT be used. -->
    <rule ref="Generic.PHP.ForbiddenFunctions">
        <properties>
            <property name="forbiddenFunctions" type="array">
                <element key="chop" value="rtrim"/>
                <element key="close" value="closedir"/>
                <element key="compact" value="null"/>
                <element key="delete" value="unset"/>
                <element key="doubleval" value="floatval"/>
                <element key="extract" value="null"/>
                <element key="fputs" value="fwrite"/>
                <element key="ini_alter" value="ini_set"/>
                <element key="is_double" value="is_float"/>
                <element key="is_integer" value="is_int"/>
                <element key="is_long" value="is_int"/>
                <element key="is_null" value="null"/>
                <element key="is_real" value="is_float"/>
                <element key="is_writeable" value="is_writable"/>
                <element key="join" value="implode"/>
                <element key="key_exists" value="array_key_exists"/>
                <element key="pos" value="current"/>
                <element key="settype" value="null"/>
                <element key="show_source" value="highlight_file"/>
                <element key="sizeof" value="count"/>
                <element key="strchr" value="strstr"/>
            </property>
        </properties>
    </rule>
    <!-- There MUST NOT be a space before a semicolon. Redundant semicolons
         SHOULD be avoided. -->
    <rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
    <rule ref="WebimpressCodingStandard.PHP.RedundantSemicolon"/>
    <!-- Non executable code MUST be removed. -->
    <rule ref="Squiz.PHP.NonExecutableCode"/>
    <!-- There MUST be a single space after language constructs. -->
    <rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
    <!-- Parentheses MUST be omitted where possible. -->
    <rule ref="WebimpressCodingStandard.Formatting.RedundantParentheses"/>
    <!-- PHP function calls MUST be in lowercase. -->
    <rule ref="Squiz.PHP.LowercasePHPFunctions"/>

    <!-- 2.2 Files -->

    <!-- All PHP files MUST use the Unix LF (linefeed) line ending only. -->
    <!-- checked by Generic.Files.LineEndings -->

    <!-- All PHP files MUST end with a non-blank line, terminated with a single
         LF. -->
    <!-- checked by PSR2.Files.EndFileNewline -->

    <!-- The closing ?> tag MUST be omitted from files containing only PHP. -->
    <!-- checked by PSR2.Files.ClosingTag -->

    <!-- Additional Laminas rules -->

    <!-- The declare(strict_types=1) directive MUST be declared and be the
         first statement in a file. -->
     <rule ref="SlevomatCodingStandard.TypeHints.DeclareStrictTypes">
        <properties>
            <property name="declareOnFirstLine" value="false"/>
            <property name="linesCountBeforeDeclare" value="1"/>
            <property name="spacesCountAroundEqualsSign" value="0"/>
            <property name="linesCountAfterDeclare" value="1"/>
        </properties>
    </rule>

    <!-- 2.3 Lines -->

    <!-- There MUST NOT be a hard limit on line length.
         The soft limit on line length MUST be 120 characters.
         Lines SHOULD NOT be longer than 80 characters; lines longer than that
         SHOULD be split into multiple subsequent lines of no more than 80
         characters each. -->
    <!-- checked by Generic.Files.LineLength -->

    <!-- There MUST NOT be trailing whitespace at the end of lines.
         Blank lines MAY be added to improve readability and to indicate
         related blocks of code except where explicitly forbidden. -->
    <!-- checked by Squiz.WhiteSpace.SuperfluousWhitespace -->

    <!-- There MUST NOT be more than one statement per line. -->
    <!-- checked by Generic.Formatting.DisallowMultipleStatements -->

    <!-- Additional Laminas rules -->

    <!-- There MAY be maximum one blank line to improve readability and to
         indicate related blocks of code except where explicitly forbidden. -->
    <rule ref="WebimpressCodingStandard.WhiteSpace.BlankLine"/>

    <!-- There MUST NOT be any blank line after opening braces and before
         closing braces. -->
    <rule ref="WebimpressCodingStandard.WhiteSpace.BraceBlankLine"/>

    <!-- 2.4 Indenting and Spacing -->

    <!-- Code MUST use an indent of 4 spaces for each indent level, and MUST
         NOT use tabs for indenting. -->
    <!-- checked by Generic.WhiteSpace.ScopeIndent -->
    <!-- checked by Generic.WhiteSpace.DisallowTabIndent -->

    <!-- Additional Laminas rules -->

    <!-- Encapsed strings MAY be used instead of concatenating strings. When
         concatenating strings, there MUST be a single whitespace before and
         after the concatenation operator. The concatenation operator MUST NOT
         be the at the end of a line. If multi-line concatenation is used
         there MUST be an indent of 4 spaces. -->
    <rule ref="Squiz.Strings.ConcatenationSpacing">
        <properties>
            <property name="spacing" value="1"/>
            <property name="ignoreNewlines" value="true"/>
        </properties>
    </rule>
    <rule ref="WebimpressCodingStandard.Strings.NoConcatenationAtTheEnd"/>
    <rule ref="Generic.Strings.UnnecessaryStringConcat">
        <!-- But multiline is useful for readability -->
        <properties>
            <property name="allowMultiline" value="true"/>
        </properties>
    </rule>

    <!-- 2.5 Keywords and Types -->

    <!-- All PHP reserved keywords and types MUST be in lower case.
         Any new types and keywords added to future PHP versions MUST be in
         lower case. -->
    <!-- checked by Generic.PHP.LowerCaseKeyword -->
    <!-- checked by Generic.PHP.LowerCaseConstant -->
    <!-- checked by Generic.PHP.LowerCaseType -->

    <!-- Short form of type keywords MUST be used i.e. bool instead of boolean,
         int instead of integer etc. -->
    <!-- checked by PSR12.Keywords.ShortFormTypeKeywords -->

    <!-- 2.6 Variables -->

    <!-- Additional Laminas rules -->

    <!-- Variable names MUST be declared in camelCase. -->
    <rule ref="WebimpressCodingStandard.NamingConventions.ValidVariableName"/>

    <!-- 2.7 Arrays -->

    <!-- Additional Laminas rules -->

    <!-- The short array syntax MUST be used to define arrays. -->
    <rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
    <!-- All values in multiline arrays must be indented with 4 spaces. -->
    <rule ref="Generic.Arrays.ArrayIndent"/>
    <!-- All array values must be followed by a comma, including the last value. -->
    <rule ref="WebimpressCodingStandard.Arrays.TrailingArrayComma"/>
    <!-- There MUST NOT be whitespace around the opening bracket or before the
         closing bracket when referencing an array. -->
    <rule ref="WebimpressCodingStandard.Arrays.Format"/>
    <!-- All double arrow symbols MUST be aligned to one space after the
         longest array key. -->
    <rule ref="WebimpressCodingStandard.Arrays.DoubleArrow">
        <properties>
            <property name="maxPadding" value="50"/>
        </properties>
    </rule>
    <!-- The short list syntax `[...]` SHOULD be used instead of `list(...)`. -->
    <rule ref="SlevomatCodingStandard.PHP.ShortList"/>

    <!-- 3. Declare Statements, Namespace, and Import Statements -->

    <!-- The header of a PHP file may consist of a number of different blocks.
         If present, each of the blocks below MUST be separated by a single
         blank line, and MUST NOT contain a blank line. Each block MUST be in
         the order listed below, although blocks that are not relevant may be
         omitted.

         - Opening php tag.
         - File-level docblock.
         - One or more declare statements.
         - The namespace declaration of the file.
         - One or more class-based use import statements.
         - One or more function-based use import statements.
         - One or more constant-based use import statements.
         - The remainder of the code in the file. -->
    <!-- checked by PSR12.Files.FileHeader -->

    <!-- When a file contains a mix of HTML and PHP, any of the above sections
         may still be used. If so, they MUST be present at the top of the file,
         even if the remainder of the code consists of a closing PHP tag and
         then a mixture of HTML and PHP. -->

    <!-- When the opening php tag is on the first line of the file, it MUST be
         on its own line with no other statements unless it is a file
         containing markup outside of PHP opening and closing tags. -->

    <!-- Import statements MUST never begin with a leading backslash as they
         must always be fully qualified. -->
    <!-- checked by PSR12.Files.ImportStatement -->

    <!-- Compound namespaces with a depth of more than two MUST NOT be used. -->
    <!-- checked by PSR12.Namespaces.CompoundNamespaceDepth -->

    <!-- When wishing to declare strict types in files containing markup
         outside PHP opening and closing tags, the declaration MUST be on the
         first line of the file and include an opening PHP tag, the strict
         types declaration and closing tag. -->
    <!-- Declare statements MUST contain no spaces and MUST be exactly
         declare(strict_types=1) (with an optional semi-colon terminator). -->
    <!-- Block declare statements are allowed and MUST be formatted as below. -->
    <!-- checked by PSR12.Files.DeclareStatement -->

    <!-- Additional Laminas rules -->

    <!-- TODO: Declare statements must be after the File level docblock if present. -->

    <!-- There MUST be a single space after the namespace keyword. -->
    <rule ref="WebimpressCodingStandard.WhiteSpace.Namespace"/>
    <!-- There MAY NOT be a space around a namespace separator. -->
    <rule ref="WebimpressCodingStandard.WhiteSpace.NamespaceSeparator"/>
    <!-- Import statements MUST be alphabetically sorted. -->
    <rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses"/>
    <!-- Functions and const keywords MUST be lowercase in import statements. -->
    <rule ref="WebimpressCodingStandard.Namespaces.ConstAndFunctionKeywords"/>
    <!-- Unused import statements MUST be removed.-->
    <rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
        <properties>
            <property name="searchAnnotations" value="true"/>
        </properties>
    </rule>
    <!-- Superfluous leading backslash in import statements MUST be removed. -->
    <rule ref="SlevomatCodingStandard.Namespaces.UseDoesNotStartWithBackslash"/>
    <!-- Fancy group import statements MUST NOT be used. -->
    <rule ref="SlevomatCodingStandard.Namespaces.DisallowGroupUse"/>
    <!-- Each import statement MUST be on its own line. -->
    <rule ref="SlevomatCodingStandard.Namespaces.MultipleUsesPerLine"/>
    <!-- Import statements must be grouped (classes, functions, constants) and
         MUST be separated by empty lines. -->
    <rule ref="SlevomatCodingStandard.Namespaces.NamespaceSpacing"/>
    <!-- Import statements aliases for classes, traits, functions and constants
         MUST be useful. -->
    <rule ref="SlevomatCodingStandard.Namespaces.UselessAlias"/>
    <!-- Classes, traits, interfaces, constants and functions MUST be imported. -->
    <rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly">
        <properties>
            <property name="allowFullyQualifiedGlobalClasses" value="false"/>
            <!-- Internal functions MUST be imported. -->
            <property name="allowFallbackGlobalFunctions" value="false"/>
            <property name="allowFullyQualifiedGlobalFunctions" value="false"/>
            <!-- Internal constants MUST be imported. -->
            <property name="allowFallbackGlobalConstants" value="false"/>
            <property name="allowFullyQualifiedGlobalConstants" value="false"/>
            <property name="allowFullyQualifiedNameForCollidingClasses" value="true"/>
            <property name="allowFullyQualifiedNameForCollidingConstants" value="true"/>
            <property name="allowFullyQualifiedNameForCollidingFunctions" value="true"/>
            <property name="searchAnnotations" value="true"/>
        </properties>
    </rule>

    <!-- 4. Classes, Properties, and Methods -->

    <!-- Any closing brace MUST NOT be followed by any comment or statement on
         the same line. -->
    <!-- checked by PSR12.Classes.ClosingBrace -->

    <!-- When instantiating a new class, parentheses MUST always be present
         even when there are no arguments passed to the constructor. -->
    <!-- checked by PSR12.Classes.ClassInstantiation -->

    <!-- Additional Laminas rules -->

    <!-- There MUST NOT be duplicate class names. -->
    <rule ref="Generic.Classes.DuplicateClassName"/>
    <!-- The file name MUST match the case of the terminating class name. -->
    <rule ref="Squiz.Classes.ClassFileName"/>
    <!-- PHP 4 style constructors MUST NOT be used. -->
    <rule ref="Generic.NamingConventions.ConstructorName"/>
    <!-- Abstract classes MUST have a `Abstract` prefix. -->
    <rule ref="WebimpressCodingStandard.NamingConventions.AbstractClass"/>
    <!-- Exception classes MUST have a `Exception` suffix. -->
    <rule ref="WebimpressCodingStandard.NamingConventions.Exception"/>
    <!-- Interface classes MUST have a `Interface` suffix. -->
    <rule ref="WebimpressCodingStandard.NamingConventions.Interface"/>
    <!-- Trait classes MUST have a `Trait` suffix. -->
    <rule ref="WebimpressCodingStandard.NamingConventions.Trait"/>
    <!-- Correct class name casing MUST be used. -->
    <rule ref="WebimpressCodingStandard.PHP.CorrectClassNameCase"/>
    <!-- For self-reference a class lower-case `self::` MUST be used without
         spaces around the scope resolution operator. -->
    <rule ref="Squiz.Classes.SelfMemberReference"/>
    <!-- Class name resolution via `::class` MUST be used instead of
         `__CLASS__`, `get_class()`, `get_class($this)`,
         `get_called_class()`, `get_parent_class()` and string reference. -->
    <rule ref="SlevomatCodingStandard.Classes.ModernClassNameReference"/>
    <rule ref="WebimpressCodingStandard.Formatting.StringClassReference"/>
    <!-- There MAY NOT be any whitespace around the double colon operator. -->
    <rule ref="WebimpressCodingStandard.Formatting.DoubleColon"/>

    <!-- 4.1 Extends and Implements -->

    <!-- The extends and implements keywords MUST be declared on the same line
         as the class name. -->
    <!-- The opening brace for the class MUST go on its own line; the closing
         brace for the class MUST go on the next line after the body. -->
    <!-- Opening braces MUST be on their own line and MUST NOT be preceded or
         followed by a blank line. -->
    <!-- Closing braces MUST be on their own line and MUST NOT be preceded by a
         blank line. -->
    <!-- Lists of implements and, in the case of interfaces, extends MAY be
         split across multiple lines, where each subsequent line is indented
         once. When doing so, the first item in the list MUST be on the next
         line, and there MUST be only one interface per line. -->
    <!-- checked by PSR2.Classes.ClassDeclaration -->

    <!-- 4.2 Using traits -->

    <!-- The use keyword used inside the classes to implement traits MUST be
         declared on the next line after the opening brace. -->
    <!-- Each individual trait that is imported into a class MUST be included
         one-per-line and each inclusion MUST have its own use import
         statement. -->
    <!-- When the class has nothing after the use import statement, the class
         closing brace MUST be on the next line after the use import statement.
         Otherwise, it MUST have a blank line after the use import statement. -->
    <!-- When using the insteadof and as operators they must be used as follows
         taking note of indentation, spacing, and new lines. -->
    <!-- checked by PSR12.Traits.UseDeclaration -->

    <!-- Additional Laminas rules -->

    <!-- Traits MUST be sorted alphabetically. -->
    <rule ref="WebimpressCodingStandard.Classes.AlphabeticallySortedTraits"/>

    <!-- 4.3 Properties and Constants -->

    <!-- Visibility MUST be declared on all properties. -->
    <!-- The var keyword MUST NOT be used to declare a property. -->
    <!-- There MUST NOT be more than one property declared per statement. -->
    <!-- Property names MUST NOT be prefixed with a single underscore to
         indicate protected or private visibility. That is, an underscore
         prefix explicitly has no meaning. -->
    <!-- There MUST be a space between type declaration and property name. -->
    <!-- checked by PSR2.Classes.PropertyDeclaration -->

    <!-- Visibility MUST be declared on all constants if your project PHP
         minimum version supports constant visibilities (PHP 7.1 or later). -->
    <!-- checked by PSR12.Properties.ConstantVisibility -->

    <!-- Additional Laminas rules -->

    <!-- Default null values MUST be omitted for class properties. -->
    <rule ref="WebimpressCodingStandard.Classes.NoNullValues"/>

    <!-- 4.4 Methods and Functions -->

    <!-- Visibility MUST be declared on all methods. -->
    <!-- checked by Squiz.Scope.MethodScope -->
    <!-- checked by Squiz.WhiteSpace.ScopeKeywordSpacing -->

    <!-- Method names MUST NOT be prefixed with a single underscore to indicate
         protected or private visibility. That is, an underscore prefix
         explicitly has no meaning. -->
    <!-- checked by PSR2.Methods.MethodDeclaration -->

    <!-- Method and function names MUST NOT be declared with space after the
         method name. The opening brace MUST go on its own line, and the
         closing brace MUST go on the next line following the body. There MUST
         NOT be a space after the opening parenthesis, and there MUST NOT be a
         space before the closing parenthesis. -->
    <!-- checked by PSR2.Methods.FunctionClosingBrace -->
    <!-- checked by Squiz.Functions.FunctionDeclaration -->
    <!-- checked by Squiz.Functions.LowercaseFunctionKeywords -->

    <!-- Additional Laminas rules -->

    <!-- There MUST be a single empty line between methods in a class. -->
    <rule ref="WebimpressCodingStandard.Methods.LineAfter"/>
    <!-- The pseudo-variable `$this` MUST NOT be called inside a static method
         or function. -->
    <rule ref="Squiz.Scope.StaticThisUsage"/>
    <!-- Returned variables SHOULD be useful and SHOULD NOT be assigned to a value
         and returned on the next line. -->
    <rule ref="SlevomatCodingStandard.Variables.UselessVariable"/>

    <!-- 4.5 Method and Function Arguments -->

    <!-- In the argument list, there MUST NOT be a space before each comma, and
         there MUST be one space after each comma. -->
    <!-- When using the reference operator & before an argument, there MUST NOT
         be a space after it. -->
    <!-- There MUST NOT be a space between the variadic three dot operator and
         the argument name. -->
    <!-- When combining both the reference operator and the variadic three dot
         operator, there MUST NOT be any space between the two of them. -->
    <!-- checked by Squiz.Functions.FunctionDeclarationArgumentSpacing -->
    <rule ref="WebimpressCodingStandard.WhiteSpace.CommaSpacing"/>
    <rule ref="WebimpressCodingStandard.Formatting.NoSpaceAfterSplat"/>
    <rule ref="WebimpressCodingStandard.Formatting.Reference"/>

    <!-- Method and function arguments with default values MUST go at the end
         of the argument list. -->
    <!-- checked by PEAR.Functions.ValidDefaultValue -->

    <!-- Argument lists MAY be split across multiple lines, where each
         subsequent line is indented once. When doing so, the first item in the
         list MUST be on the next line, and there MUST be only one argument per
         line. When the argument list is split across multiple lines, the
         closing parenthesis and opening brace MUST be placed together on their
         own line with one space between them. -->
    <!-- checked by Squiz.Functions.MultiLineFunctionDeclaration -->

    <!-- When you have a return type declaration present, there MUST be one
         space after the colon followed by the type declaration. The colon and
         declaration MUST be on the same line as the argument list closing
         parenthesis with no spaces between the two characters. -->
    <!-- checked by PSR12.Functions.ReturnTypeDeclaration -->

    <!-- In nullable type declarations, there MUST NOT be a space between the
         question mark and the type. -->
    <!-- checked by PSR12.Functions.NullableTypeDeclaration -->

    <!-- Additional Laminas rules -->

    <!-- The question mark MUST be used when the default argument value is null. -->
    <rule ref="SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue"/>

    <!-- 4.6 abstract, final, and static -->

    <!-- When present, the abstract and final declarations MUST precede the
         visibility declaration. -->
    <!-- When present, the static declaration MUST come after the visibility
         declaration. -->
    <!-- checked by PSR2.Methods.MethodDeclaration -->

    <!-- Additional Laminas rules -->

    <!-- The final keyword on methods MUST be omitted in final classes. -->
    <rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>

    <!-- 4.7 Method and Function Calls -->

    <!-- When making a method or function call, there MUST NOT be a space
         between the method or function name and the opening parenthesis, there
         MUST NOT be a space after the opening parenthesis, and there MUST NOT
         be a space before the closing parenthesis. In the argument list, there
         MUST NOT be a space before each comma, and there MUST be one space
         after each comma. -->
    <!-- Argument lists MAY be split across multiple lines, where each
         subsequent line is indented once. When doing so, the first item in the
         list MUST be on the next line, and there MUST be only one argument per
         line. A single argument being split across multiple lines (as might be
         the case with an anonymous function or array) does not constitute
         splitting the argument list itself. -->
    <!-- checked by Generic.Functions.FunctionCallArgumentSpacing -->
    <!-- checked by PSR2.Methods.FunctionCallSignature -->

    <!-- 5. Control Structures -->

    <!-- The general style rules for control structures are as follows:
         There MUST be one space after the control structure keyword.
         There MUST NOT be a space after the opening parenthesis.
         There MUST NOT be a space before the closing parenthesis.
         There MUST be one space between the closing parenthesis and the
         opening brace.
         The structure body MUST be indented once.
         The body MUST be on the next line after the opening brace.
         The closing brace MUST be on the next line after the body.
         The body of each structure MUST be enclosed by braces. This
         standardizes how the structures look and reduces the likelihood of
         introducing errors as new lines get added to the body. -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->
    <!-- checked by Squiz.WhiteSpace.ScopeClosingBrace -->
    <!-- checked by Squiz.ControlStructures.ForEachLoopDeclaration -->
    <!-- checked by Squiz.ControlStructures.ForLoopDeclaration -->
    <!-- checked by Squiz.ControlStructures.LowercaseDeclaration -->
    <!-- checked by Generic.ControlStructures.InlineControlStructure -->
    <!-- checked by WebimpressCodingStandard.WhiteSpace.BraceBlankLine -->

    <!-- Additional Laminas rules -->

    <!-- There SHOULD be one single space after `break` and `continue` structures with
         a numeric argument argument. -->
    <rule ref="WebimpressCodingStandard.ControlStructures.BreakAndContinue"/>
    <!-- Statements MUST NOT be empty, except for catch statements. -->
    <rule ref="Generic.CodeAnalysis.EmptyStatement">
        <!-- But allow empty catch -->
        <exclude name="Generic.CodeAnalysis.EmptyStatement.DetectedCatch"/>
    </rule>

    <!-- 5.1 if, elseif, else -->

    <!-- The else and elseif MUST be on the same line as the closing brace from
         the earlier body. -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- The keyword elseif SHOULD be used instead of else if so that all
         control keywords look like single words. -->
    <!-- checked by PSR2.ControlStructures.ElseIfDeclaration -->

    <!-- Expressions in parentheses MAY be split across multiple lines, where
         each subsequent line is indented at least once. When doing so, the
         first condition MUST be on the next line. The closing parenthesis and
         opening brace MUST be placed together on their own line with one space
         between them. Boolean operators between conditions MUST always be at
         the beginning or at the end of the line, not a mix of both. -->
    <!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
    <!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- 5.2 switch, case -->

    <!-- The case statement MUST be indented once from switch, and the break
         keyword (or other terminating keywords) MUST be indented at the same
         level as the case body. There MUST be a comment such as // no break
         when fall-through is intentional in a non-empty case body. -->
    <!-- checked by PSR2.ControlStructures.SwitchDeclaration -->

    <!-- Expressions in parentheses MAY be split across multiple lines, where
         each subsequent line is indented at least once. When doing so, the
         first condition MUST be on the next line. The closing parenthesis and
         opening brace MUST be placed together on their own line with one space
         between them. Boolean operators between conditions MUST always be at
         the beginning or at the end of the line, not a mix of both. -->
    <!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
    <!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- Additional Laminas rules -->

    <!-- The `continue` control structure MUST NOT be used in switch statements,
         `break` SHOULD be used instead. -->
    <rule ref="WebimpressCodingStandard.ControlStructures.ContinueInSwitch"/>

    <!-- 5.3.1 while -->

    <!-- Expressions in parentheses MAY be split across multiple lines, where
         each subsequent line is indented at least once. When doing so, the
         first condition MUST be on the next line. The closing parenthesis and
         opening brace MUST be placed together on their own line with one space
         between them. Boolean operators between conditions MUST always be at
         the beginning or at the end of the line, not a mix of both. -->
    <!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
    <!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- 5.3.2 do while -->

    <!-- Expressions in parentheses MAY be split across multiple lines, where
         each subsequent line is indented at least once. When doing so, the
         first condition MUST be on the next line. Boolean operators between
         conditions MUST always be at the beginning or at the end of the line,
         not a mix of both. -->
    <!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
    <!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- 5.4 for -->

    <!-- Expressions in parentheses MAY be split across multiple lines, where
         each subsequent line is indented at least once. When doing so, the
         first expression MUST be on the next line. The closing parenthesis and
         opening brace MUST be placed together on their own line with one space
         between them. -->
    <!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
    <!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
    <!-- checked by Squiz.ControlStructures.ControlSignature -->

    <!-- TODO: allow multiline for structure -->

    <!-- 5.5 foreach -->

    <!-- exclude these messages as they are already checked by PSR2.ControlStructures.ControlStructureSpacing -->
    <!-- checked by Squiz.ControlStructures.ForEachLoopDeclaration -->

    <!-- 5.6 try, catch, finally -->

    <!-- Additional Laminas rules -->

    <!-- All catch blocks MUST be reachable. -->
    <rule ref="SlevomatCodingStandard.Exceptions.DeadCatch"/>

    <!-- 6. Operators -->

    <!-- When space is permitted around an operator, multiple spaces MAY be
         used for readability purposes. -->
    <!-- All operators not described here are left undefined. -->

    <!-- Additional Laminas rules -->

    <!-- There MUST be at least one space on either side of an equals sign used
         to assign a value to a variable. In case of a block of related
         assignments, more spaces MUST be inserted before the equal sign to
         promote readability. -->
    <rule ref="Generic.Formatting.MultipleStatementAlignment">
        <properties>
            <property name="error" value="true"/>
            <property name="maxPadding" value="50"/>
        </properties>
    </rule>
    <rule ref="Squiz.WhiteSpace.OperatorSpacing">
        <properties>
            <property name="ignoreNewlines" value="true"/>
        </properties>
    </rule>
    <!-- There MUST NOT be any white space around the object operator UNLESS
         multilines are used. -->
    <rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
    <rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
        <properties>
            <property name="ignoreNewlines" value="true"/>
        </properties>
    </rule>
    <!-- Loose comparison operators SHOULD NOT be used, use strict comparison
         operators instead. -->
    <rule ref="SlevomatCodingStandard.Operators.DisallowEqualOperators" phpcs-only="true"/>
    <!-- The null coalesce operator MUST be used when possible. -->
    <rule ref="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceOperator"/>
    <!-- Assignment operators SHOULD be used when possible. -->
    <rule ref="SlevomatCodingStandard.Operators.RequireCombinedAssignmentOperator"/>
    <!-- The `&&` and `||` operators SHOULD be used instead of `and` and `or`. -->
    <rule ref="Squiz.Operators.ValidLogicalOperators"/>

    <!-- 6.1. Unary operators -->

    <!-- The increment/decrement operators MUST NOT have any space between the
         operator and operand. -->
    <!-- checked by Generic.WhiteSpace.IncrementDecrementSpacing -->

    <!-- Type casting operators MUST NOT have any space within the parentheses. -->
    <!-- checked by Squiz.WhiteSpace.CastSpacing -->

    <!-- Additional Laminas rules -->

    <!-- There MUST be one whitespace after a type casting operator. -->
    <rule ref="Generic.Formatting.SpaceAfterCast"/>
    <!-- There MUST be one whitespace after unary not. -->
    <rule ref="Generic.Formatting.SpaceAfterNot"/>

    <!-- 6.2. Binary operators -->

    <!-- All binary arithmetic, comparison, assignment, bitwise, logical,
         string, and type operators MUST be preceded and followed by at least
         one space. -->
    <!-- checked by PSR12.Operators.OperatorSpacing -->

    <!-- 6.3. Ternary operators -->

    <!-- The conditional operator, also known simply as the ternary operator,
         MUST be preceded and followed by at least one space around both the ?
         and : characters. -->
    <!-- When the middle operand of the conditional operator is omitted, the
         operator MUST follow the same style rules as other binary comparison
         operators. -->
    <!-- checked by PSR12.Operators.OperatorSpacing -->

    <!-- 7. Closures -->

    <!-- Closures MUST be declared with a space after the function keyword, and
         a space before and after the use keyword. -->
    <!-- The opening brace MUST go on the same line, and the closing brace MUST
         go on the next line following the body. -->
    <!-- There MUST NOT be a space after the opening parenthesis of the argument
         list or variable list, and there MUST NOT be a space before the closing
         parenthesis of the argument list or variable list. -->
    <!-- In the argument list and variable list, there MUST NOT be a space
         before each comma, and there MUST be one space after each comma. -->
    <!-- Closure arguments with default values MUST go at the end of the
         argument list. -->
    <!-- Argument lists and variable lists MAY be split across multiple lines,
         where each subsequent line is indented once. When doing so, the first
         item in the list MUST be on the next line, and there MUST be only one
         argument or variable per line. -->
    <!-- When the ending list (whether of arguments or variables) is split
         across multiple lines, the closing parenthesis and opening brace MUST
         be placed together on their own line with one space between them. -->
    <!-- checked by Squiz.Functions.MultiLineFunctionDeclaration -->

    <!-- If a return type is present, it MUST follow the same rules as with
         normal functions and methods; if the use keyword is present, the colon
         MUST follow the use list closing parentheses with no spaces between
         the two characters. -->
    <!-- checked by PSR12.Functions.ReturnTypeDeclaration -->

    <!-- Additional Laminas rules -->

    <!-- Inherited variables passed via `use` MUST be used in closures. -->
    <rule ref="SlevomatCodingStandard.Functions.UnusedInheritedVariablePassedToClosure"/>

    <!-- 8. Anonymous Classes -->

    <!-- Anonymous Classes MUST follow the same guidelines and principles as
         closures in the above section. -->
    <!-- The opening brace MAY be on the same line as the `class` keyword so long
         as the list of `implements` interfaces does not wrap. If the list of
         interfaces wraps, the brace MUST be placed on the line immediately
         following the last interface. -->
    <!-- checked by PSR12.Classes.AnonClassDeclaration -->

    <!-- 9. Commenting and DocBlocks -->

    <!-- Additional Laminas rules -->

    <!-- DocBlocks and comments SHOULD only be used if necessary. Code SHOULD
         be written so it explains itself. They MUST NOT start with `#` and MUST
         NOT be empty. They MAY be omitted and SHOULD NOT be used for already
         typehinted arguments, except arrays.

         PHPDoc tags `@param`, `@throws` and `@return` SHOULD not be aligned or
         contain multiple spaces between the tag, type and description.

         If a function throws any exceptions, it SHOULD be documented with
         `@throws` tags.

         -->
    <rule ref="PEAR.Commenting.InlineComment"/>
    <rule ref="SlevomatCodingStandard.Commenting.EmptyComment"/>
    <rule ref="Squiz.Commenting.FunctionComment">
        <!-- Allow `@throws` without description -->
        <exclude name="Squiz.Commenting.FunctionComment.EmptyThrows"/>
        <!-- Does not work properly with PHP 7 / short-named types -->
        <exclude name="Squiz.Commenting.FunctionComment.IncorrectParamVarName"/>
        <!-- Does not support collections, i.e. `string[]` -->
        <exclude name="Squiz.Commenting.FunctionComment.IncorrectTypeHint"/>
        <!-- Forces incorrect types -->
        <exclude name="Squiz.Commenting.FunctionComment.InvalidReturn"/>
        <!-- Breaks with compound return types, i.e. `string|null` -->
        <exclude name="Squiz.Commenting.FunctionComment.InvalidReturnNotVoid"/>
        <!-- Breaks when all params are not documented -->
        <exclude name="Squiz.Commenting.FunctionComment.InvalidTypeHint"/>
        <!-- Doc comment is not required for every method -->
        <exclude name="Squiz.Commenting.FunctionComment.Missing"/>
        <!-- Do not require comments for `@param` -->
        <exclude name="Squiz.Commenting.FunctionComment.MissingParamComment"/>
        <!-- Do not require `@param` for all parameters -->
        <exclude name="Squiz.Commenting.FunctionComment.MissingParamTag"/>
        <!-- Do not require `@return` for void methods -->
        <exclude name="Squiz.Commenting.FunctionComment.MissingReturn"/>
        <!-- Comments don't have to be sentences -->
        <exclude name="Squiz.Commenting.FunctionComment.ParamCommentFullStop"/>
        <!-- Comments don't have to be sentences -->
        <exclude name="Squiz.Commenting.FunctionComment.ParamCommentNotCapital"/>
        <!-- Breaks when all params are not documented -->
        <exclude name="Squiz.Commenting.FunctionComment.ParamNameNoMatch"/>
        <!-- Doesn't respect inheritance -->
        <exclude name="Squiz.Commenting.FunctionComment.ScalarTypeHintMissing"/>
        <!-- Throws comments can start without a capital and doesn't need a full stop -->
        <exclude name="PEAR.Commenting.FunctionComment.ThrowsNoFullStop"/>
        <exclude name="PEAR.Commenting.FunctionComment.ThrowsNotCapital"/>
        <!-- Doesn't work with self as typehint -->
        <exclude name="Squiz.Commenting.FunctionComment.TypeHintMissing"/>
        <!-- May use excessive whitespace to align comments after parameter names -->
        <exclude name="Squiz.Commenting.FunctionComment.SpacingAfterParamName"/>
        <!-- Adds space between intersection types -->
        <exclude name="Squiz.Commenting.FunctionComment.SpacingAfterParamType"/>
    </rule>

    <!-- DocBlocks and comments SHOULD NOT be used for already typehinted arguments,
         except arrays. -->
    <rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHintSpacing"/>
    <rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint">
        <properties>
            <property name="enableNativeTypeHint" value="false"/>
        </properties>
        <exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint"/>
        <exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification"/>
    </rule>
    <rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHintSpacing"/>
    <rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint">
        <exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint"/>
        <exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification"/>
    </rule>
    <rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing"/>
    <rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
        <exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"/>
        <exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification"/>
    </rule>

    <!-- The asterisks in a DocBlock should align, and there should be one
         space between the asterisk and tag. -->
    <rule ref="Squiz.Commenting.DocCommentAlignment">
        <exclude name="Squiz.Commenting.DocCommentAlignment.SpaceAfterStar"/>
    </rule>

    <!-- DocBlocks MUST follow this specific order of annotations with empty
         newline between specific groups:

         /**
          * <Summary>
          *
          * <Description>
          *
          * @internal
          * @deprecated
          *
          * @link
          * @see
          * @uses
          *
          * @param
          * @return
          * @throws
          */
    -->
    <rule ref="SlevomatCodingStandard.Commenting.DocCommentSpacing">
        <properties>
            <property name="linesCountBeforeFirstContent" value="0"/>
            <property name="linesCountAfterLastContent" value="0"/>
            <property name="linesCountBetweenDescriptionAndAnnotations" value="1"/>
            <property name="linesCountBetweenAnnotationsGroups" value="1"/>
            <property name="annotationsGroups" type="array">
                <element value="
                    @internal,
                    @deprecated,
                "/>
                <element value="
                    @link,
                    @uses,
                    @see,
                    @copyright,
                    @license,
                "/>
                <element value="
                    @ORM\,
                    @ODM\,
                    @PHPCR\,
                "/>
                <element value="
                    @param\,
                    @return\,
                    @throws\,
                "/>
            </property>
        </properties>
    </rule>

    <!-- The annotations `@api`, `@author`, `@category`, `@created`, `@package`,
         `@subpackage` and `@version` MUST NOT be used in comments. Git commits
         provide accurate information. -->
    <rule ref="SlevomatCodingStandard.Commenting.ForbiddenAnnotations">
        <properties>
            <property name="forbiddenAnnotations" type="array">
                <element value="@api"/>
                <element value="@author"/>
                <element value="@category"/>
                <element value="@copyright"/>
                <element value="@created"/>
                <element value="@license"/>
                <element value="@package"/>
                <element value="@subpackage"/>
                <element value="@version"/>
                <element value="@expectedException"/>
                <element value="@expectedExceptionCode"/>
                <element value="@expectedExceptionMessage"/>
                <element value="@expectedExceptionMessageRegExp"/>
            </property>
        </properties>
    </rule>

    <!-- The words _private_, _protected_, _static_, _constructor_, _deconstructor_,
         _Created by_, _getter_ and _setter_, MUST NOT be used in comments. -->
    <rule ref="SlevomatCodingStandard.Commenting.ForbiddenComments">
        <properties>
            <property name="forbiddenCommentPatterns" type="array">
                <element value="~^(?:(?!private|protected|static)\S+ )?(?:con|de)structor\.\z~i"/>
                <element value="~^Created by .+\.\z~i"/>
                <element value="~^(User|Date|Time): \S+\z~i"/>
                <element value="~^\S+ [gs]etter\.\z~i"/>
                <element value="~^Class \S+\z~i"/>
            </property>
        </properties>
    </rule>

    <!-- The `@var` tag MAY be used in inline comments to document the _Type_
         of properties. Single-line property comments with a `@var` tag SHOULD
         be written as one-liners. The `@var` MAY NOT be used for constants. -->
    <rule ref="SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration"/>
    <rule ref="SlevomatCodingStandard.Commenting.RequireOneLinePropertyDocComment"/>

    <!-- The correct tag case of PHPDocs and PHPUnit tags MUST be used. -->
    <rule ref="WebimpressCodingStandard.Commenting.TagCase"/>

    <!-- Inline DocComments MAY be used at the end of the line, with at least a
         single space preceding. Inline DocComments MUST NOT be placed after
         curly brackets. -->
    <rule ref="WebimpressCodingStandard.Commenting.Placement"/>
    <rule ref="WebimpressCodingStandard.Commenting.NoInlineCommentAfterCurlyClose"/>

    <!-- Heredoc and nowdoc tags MUST be uppercase without spaces. -->
    <rule ref="WebimpressCodingStandard.Formatting.Heredoc"/>
</ruleset>
