diff --git a/.Specs/InfoBoxSystem.md b/.Specs/InfoBoxSystem.md index 1d93b81..37c7bf7 100644 --- a/.Specs/InfoBoxSystem.md +++ b/.Specs/InfoBoxSystem.md @@ -4,44 +4,41 @@ This document specifies the internal "InfoBox" rendering system. It is a reusabl ## Overview -The system is designed to decouple data fetching and rendering from the controllers. Instead of a controller fetching all data and passing it to a monolithic Fluid template, the responsibility is distributed among several smaller, specialized `InfoBox` classes. +The system is designed to decouple database data fetching and rendering from the controllers. Instead of a controller fetching all data and passing it to a monolithic Fluid template, the responsibility is distributed among several smaller, specialized `InfoBox` classes. The core components of this system are: -1. **`Page` Service**: A DTO that acts as a container for a collection of InfoBoxes for a specific topic (e.g., "InnoDB"). -2. **`AbstractInfoBox`**: A base class that defines the contract for all InfoBox objects. -3. **Concrete InfoBox Implementations**: Specific classes (e.g., `UptimeInfoBox`) that extend `AbstractInfoBox` and contain the logic to fetch and prepare data for a single panel. -4. **Service Tagging**: The Symfony Dependency Injection container uses tags to collect all relevant InfoBox implementations and inject them into the correct `Page` service. +1. **`InfoBoxInterface`**: The interface (`Classes/InfoBox/InfoBoxInterface.php`) defining the contract for all InfoBoxes. It requires a `TITLE` constant and a `getBody(): string` method. +2. **Concrete InfoBox Implementations**: Specific `final readonly` classes (e.g., `UptimeInfoBox`) that implement `InfoBoxInterface` (and optional interfaces like `InfoBoxUnorderedListInterface` or `InfoBoxStateInterface`) and contain the logic to calculate and format data. +3. **`RenderInfoBoxFactory`**: A stateless rendering service (`Classes/InfoBox/RenderInfoBoxFactory.php`) that maps the structured InfoBox properties to a Fluid view and generates the final HTML output. +4. **Service Tagging**: InfoBox implementations are tagged with their respective topic tags (e.g., `mysqlreport.infobox.status`) using the PHP attribute `#[AutoconfigureTag]`. +5. **Constructor Autowiring**: The DI container instantiates the models `StatusValues` and `Variables` using repositories and caches them. They are autowired directly to the InfoBox constructors via the global `bind` configuration in `Services.yaml`. ## Component Analysis -### 1. `Page` Service (`Classes/Menu/Page.php`) +### 1. `InfoBoxInterface` (`Classes/InfoBox/InfoBoxInterface.php`) -- A `readonly` DTO that receives an iterable of `AbstractInfoBox` objects via its constructor. -- The `getRenderedInfoBoxes()` method iterates through all its InfoBoxes. -- For each InfoBox, it calls the `updateView()` method, which returns a configured `ViewInterface` object. -- It then calls `render()` on that view and concatenates the resulting HTML strings. -- The final, combined HTML of all InfoBoxes is returned to the controller. +- Defines the contract: + - `public const TITLE = '';` + - `public function getBody(): string;` -### 2. `AbstractInfoBox` (`Classes/InfoBox/AbstractInfoBox.php`) +### 2. `RenderInfoBoxFactory` (`Classes/InfoBox/RenderInfoBoxFactory.php`) -- Defines the basic structure of an InfoBox, including methods for rendering a title, body, and footer. -- Crucially, it contains the `updateView()` method, where the concrete class assigns its fetched data to the view. -- Many InfoBoxes use the `GetStatusValuesAndVariablesTrait` to easily access the `StatusRepository` and `VariablesRepository`. +- Takes the `ViewFactoryInterface` in the constructor. +- The `render(iterable $infoBoxes): string` method iterates over the InfoBoxes, extracts their structured data, assigns them to a Fluid view, and compiles the final HTML. +- It keeps the InfoBox classes completely independent of the view layer (fully headless-ready). ### 3. Service Configuration (`Configuration/Services.yaml`) This is where the system is wired together. -- **InfoBox Tagging**: Concrete InfoBox classes are automatically tagged using the `#[AutoconfigureTag]` PHP attribute. For example, an InfoBox for the "Status" page will have `#[AutoconfigureTag('mysqlreport.infobox.status')]`. -- **`Page` Service Definition**: For each sub-module that uses this pattern, a dedicated `Page` service is defined. -- **`!tagged_iterator`**: The `arguments` of the `Page` service use the `!tagged_iterator` directive to collect all services with a specific tag. For example, the `mysqlreport.page.information` service receives all InfoBoxes tagged with `mysqlreport.infobox.status`. -- **Controller Injection**: The corresponding controller (e.g., `StatusController`) then gets the correctly configured `Page` service injected. +- **Factories**: `StatusValues` and `Variables` are registered as factory services calling the `findAll` repository methods. +- **Autowiring Bindings**: The types are globally bound to the factory services under `_defaults.bind`. +- **Direct Controller Injection**: The controller (e.g., `StatusController`) is configured to receive the tagged iterator of InfoBoxes directly via `!tagged_iterator`. ## Workflow Example (`StatusController`) -1. `StatusController` has `@mysqlreport.page.information` injected as `$this->page`. -2. The `indexAction` calls `$this->page->getRenderedInfoBoxes()`. -3. The `Page` object iterates through all InfoBoxes tagged with `mysqlreport.infobox.status` (e.g., `UptimeInfoBox`, `ConnectionInfoBox`). -4. Each InfoBox fetches its data (e.g., from `StatusRepository`), prepares it, and renders its own small HTML partial (`Resources/Private/Templates/InfoBox/Default.html`). -5. The controller receives a single string of pre-rendered HTML and assigns it to the main module template (`Resources/Private/Templates/Status/Index.html`). +1. `StatusController` has `iterable $infoBoxes` (tagged with `mysqlreport.infobox.status`) and the `RenderInfoBoxFactory` injected via constructor autowiring. +2. The `indexAction` calls `$this->renderInfoBoxFactory->render($this->infoBoxes)`. +3. Inside the factory, each InfoBox's `TITLE` constant and `getBody()` content are extracted and assigned to `Resources/Private/Templates/InfoBox/Default.html`. +4. The controller receives a single string of pre-rendered HTML and assigns it to the main module template (`Resources/Private/Templates/Status/Index.html`). diff --git a/.github/workflows/typo3_13.yml b/.github/workflows/ci.yml similarity index 95% rename from .github/workflows/typo3_13.yml rename to .github/workflows/ci.yml index 8d5afb6..eca0b6a 100644 --- a/.github/workflows/typo3_13.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,11 @@ jobs: php: - '8.2' - '8.3' + - '8.4' steps: - name: 'Checkout' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Lint PHP' run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s lint diff --git a/.gitignore b/.gitignore index f31d9c3..f080a92 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ /.ddev /.Build /composer.lock +/packages/ +/scratch/ *GENERATED* /Build/testing-docker/.env /.php-cs-fixer.cache diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index 5fe43e6..5cac7c6 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -60,8 +60,8 @@ handleDbmsOptions() { echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 exit 1 fi - [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.11" - if ! [[ ${DBMS_VERSION} =~ ^(10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.5" + if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 echo >&2 echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 @@ -125,7 +125,7 @@ handleDbmsOptions() { loadHelp() { # Load help text into $HELP read -r -d '' HELP < + -p <8.1|8.2|8.3> Specifies the PHP minor version to be used - - 8.2: (default) use PHP 8.2 + - 8.1: use PHP 8.1 + - 8.2: use PHP 8.2 - 8.3: use PHP 8.3 -x @@ -256,7 +257,7 @@ DBMS_VERSION="" PHP_VERSION="8.2" PHP_XDEBUG_ON=0 PHP_XDEBUG_PORT=9003 -CGLCHECK_DRY_RUN=0 +DRY_RUN=0 CI_PARAMS="${CI_PARAMS:-}" DOCS_PARAMS="${DOCS_PARAMS:=--pull always}" CONTAINER_BIN="" @@ -290,7 +291,7 @@ while getopts "a:b:d:i:s:p:xy:nhu" OPT; do ;; p) PHP_VERSION=${OPTARG} - if ! [[ ${PHP_VERSION} =~ ^(8.2|8.3)$ ]]; then + if ! [[ ${PHP_VERSION} =~ ^(8.1|8.2|8.3|8.4)$ ]]; then INVALID_OPTIONS+=("p ${OPTARG}") fi ;; @@ -301,7 +302,7 @@ while getopts "a:b:d:i:s:p:xy:nhu" OPT; do PHP_XDEBUG_PORT=${OPTARG} ;; n) - CGLCHECK_DRY_RUN=1 + DRY_RUN=1 ;; h) loadHelp @@ -384,7 +385,7 @@ IMAGE_DOCS="ghcr.io/typo3-documentation/render-guides:latest" shift $((OPTIND - 1)) SUFFIX=$(echo $RANDOM) -NETWORK="t3docsexamples-${SUFFIX}" +NETWORK="t3mysqlreport-${SUFFIX}" ${CONTAINER_BIN} network create ${NETWORK} >/dev/null if [ ${CONTAINER_BIN} = "docker" ]; then @@ -409,11 +410,11 @@ fi # Suite execution case ${TEST_SUITE} in cgl) - if [ "${CGLCHECK_DRY_RUN}" -eq 1 ]; then - COMMAND="php -dxdebug.mode=off .Build/bin/php-cs-fixer fix -v --dry-run --diff --config=Build/cgl/.php-cs-fixer.dist.php --using-cache=no ." - else - COMMAND="php -dxdebug.mode=off .Build/bin/php-cs-fixer fix -v --config=Build/cgl/.php-cs-fixer.dist.php --using-cache=no ." + DRY_RUN_OPTIONS='' + if [ "${DRY_RUN}" -eq 1 ]; then + DRY_RUN_OPTIONS='--dry-run --diff' fi + COMMAND="php -dxdebug.mode=off .Build/bin/php-cs-fixer fix -v ${DRY_RUN_OPTIONS} --config=Build/cgl/config.php --using-cache=no" ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-${SUFFIX} -e COMPOSER_CACHE_DIR=.Build/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" SUITE_EXIT_CODE=$? ;; @@ -433,7 +434,7 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; composerNormalize) - if [ "${CGLCHECK_DRY_RUN}" -eq 1 ]; then + if [ "${DRY_RUN}" -eq 1 ]; then COMMAND=(composer normalize -n) else COMMAND=(composer normalize) @@ -442,7 +443,7 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; composerUpdate) - rm -rf .Build/bin/ .Build/typo3 .Build/vendor .Build/Web ./composer.lock + rm -rf .Build/bin .Build/typo3 .Build/vendor ./composer.lock cp ${ROOT_DIR}/composer.json ${ROOT_DIR}/composer.json.orig if [ -f "${ROOT_DIR}/composer.json.testing" ]; then cp ${ROOT_DIR}/composer.json ${ROOT_DIR}/composer.json.orig @@ -453,18 +454,6 @@ case ${TEST_SUITE} in cp ${ROOT_DIR}/composer.json ${ROOT_DIR}/composer.json.testing mv ${ROOT_DIR}/composer.json.orig ${ROOT_DIR}/composer.json ;; - composerUpdateRector) - rm -rf Build/rector/.Build/bin/ Build/rector/.Build/vendor Build/rector/composer.lock - cp ${ROOT_DIR}/Build/rector/composer.json ${ROOT_DIR}/Build/rector/composer.json.orig - if [ -f "${ROOT_DIR}/Build/rector/composer.json.testing" ]; then - cp ${ROOT_DIR}/Build/rector/composer.json ${ROOT_DIR}/Build/rector/composer.json.orig - fi - COMMAND=(composer require --working-dir=${ROOT_DIR}/Build/rector --no-ansi --no-interaction --no-progress) - ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-${SUFFIX} -e COMPOSER_CACHE_DIR=.Build/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" - SUITE_EXIT_CODE=$? - cp ${ROOT_DIR}/Build/rector/composer.json ${ROOT_DIR}/Build/rector/composer.json.testing - mv ${ROOT_DIR}/Build/rector/composer.json.orig ${ROOT_DIR}/Build/rector/composer.json - ;; composerValidate) COMMAND=(composer validate "$@") ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-command-${SUFFIX} -e COMPOSER_CACHE_DIR=.Build/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" @@ -522,12 +511,12 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; rector) - if [ "${CGLCHECK_DRY_RUN}" -eq 1 ]; then - COMMAND=(php -dxdebug.mode=off Build/rector/.Build/bin/rector -n --config=Build/rector/rector.php --clear-cache "$@") - else - COMMAND=(php -dxdebug.mode=off Build/rector/.Build/bin/rector --config=Build/rector/rector.php --clear-cache "$@") + DRY_RUN_OPTIONS='' + if [ "${DRY_RUN}" -eq 1 ]; then + DRY_RUN_OPTIONS='--dry-run' fi - ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name rector-${SUFFIX} -e COMPOSER_CACHE_DIR=.Build/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" + COMMAND="php -dxdebug.mode=off .Build/bin/rector process ${DRY_RUN_OPTIONS} --config=Build/rector/rector.php --no-progress-bar --ansi" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name rector-${SUFFIX} -e COMPOSER_CACHE_DIR=.Build/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" SUITE_EXIT_CODE=$? ;; renderDocumentation) diff --git a/Build/cgl/.php-cs-fixer.dist.php b/Build/cgl/.php-cs-fixer.dist.php deleted file mode 100644 index 13fafa1..0000000 --- a/Build/cgl/.php-cs-fixer.dist.php +++ /dev/null @@ -1,81 +0,0 @@ -setFinder( - (new Finder()) - ->in(__DIR__ . '/../../') - ->exclude(__DIR__ . '/../../.Build') - ->exclude(__DIR__ . '/../../var') - ) - ->setRiskyAllowed(true) - ->setRules([ - '@DoctrineAnnotation' => true, - // @todo: Switch to @PER-CS2.0 once php-cs-fixer's todo list is done: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/7247 - '@PER-CS1.0' => true, - 'array_indentation' => true, - 'array_syntax' => ['syntax' => 'short'], - 'cast_spaces' => ['space' => 'none'], - // @todo: Can be dropped once we enable @PER-CS2.0 - 'concat_space' => ['spacing' => 'one'], - 'declare_equal_normalize' => ['space' => 'none'], - 'declare_parentheses' => true, - 'dir_constant' => true, - // @todo: Can be dropped once we enable @PER-CS2.0 - 'function_declaration' => [ - 'closure_fn_spacing' => 'none', - ], - 'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']], - 'type_declaration_spaces' => true, - 'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false], - 'list_syntax' => ['syntax' => 'short'], - // @todo: Can be dropped once we enable @PER-CS2.0 - 'method_argument_space' => true, - 'modernize_strpos' => true, - 'modernize_types_casting' => true, - 'native_function_casing' => true, - 'no_alias_functions' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_empty_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_blank_lines' => true, - 'no_leading_namespace_whitespace' => true, - 'no_null_property_initialization' => true, - 'no_short_bool_cast' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_superfluous_elseif' => true, - 'no_trailing_comma_in_singleline' => true, - 'no_unneeded_control_parentheses' => true, - 'no_unused_imports' => true, - 'no_useless_nullsafe_operator' => true, - 'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'], - 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], - 'php_unit_mock_short_will_return' => true, - 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], - 'phpdoc_no_access' => true, - 'phpdoc_no_empty_return' => true, - 'phpdoc_no_package' => true, - 'phpdoc_scalar' => true, - 'phpdoc_trim' => true, - 'phpdoc_types' => true, - 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], - 'return_type_declaration' => ['space_before' => 'none'], - 'single_quote' => true, - 'single_space_around_construct' => true, - 'single_line_comment_style' => ['comment_types' => ['hash']], - // @todo: Can be dropped once we enable @PER-CS2.0 - 'single_line_empty_body' => true, - 'trailing_comma_in_multiline' => ['elements' => ['arguments', 'arrays', 'match', 'parameters']], - 'whitespace_after_comma_in_array' => ['ensure_single_space' => true], - 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], - - // We need this for documentation! - 'no_useless_else' => false, // We want to preserve else with comments only - - // Add this rule to convert FQCN to use statements - 'full_opening_tag' => true, - ]); diff --git a/Build/cgl/config.php b/Build/cgl/config.php new file mode 100644 index 0000000..0e9510e --- /dev/null +++ b/Build/cgl/config.php @@ -0,0 +1,183 @@ + true, + '@PER-CS1x0' => true, + 'array_indentation' => true, + 'array_syntax' => ['syntax' => 'short'], + 'cast_spaces' => ['space' => 'none'], + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'declare_parentheses' => true, + 'dir_constant' => true, + 'function_declaration' => [ + 'closure_fn_spacing' => 'none', + ], + 'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']], + 'type_declaration_spaces' => true, + 'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false], + 'list_syntax' => ['syntax' => 'short'], + 'method_argument_space' => true, + 'modernize_strpos' => true, + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_namespace_whitespace' => true, + 'no_null_property_initialization' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_superfluous_elseif' => true, + 'no_trailing_comma_in_singleline' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_nullsafe_operator' => true, + 'nullable_type_declaration' => [ + 'syntax' => 'question_mark', + ], + 'nullable_type_declaration_for_default_null_value' => true, + 'ordered_class_elements' => ['order' => ['use_trait', 'case', 'constant', 'property']], + 'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'], + 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], + 'php_unit_mock_short_will_return' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self', + 'methods' => [ + 'any' => 'this', + 'atLeast' => 'this', + 'atLeastOnce' => 'this', + 'atMost' => 'this', + 'exactly' => 'this', + 'never' => 'this', + 'onConsecutiveCalls' => 'this', + 'once' => 'this', + 'returnArgument' => 'this', + 'returnCallback' => 'this', + 'returnSelf' => 'this', + 'returnValue' => 'this', + 'returnValueMap' => 'this', + 'throwException' => 'this', + ], + ], + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'protected_to_private' => true, + 'return_type_declaration' => ['space_before' => 'none'], + 'single_quote' => true, + 'single_space_around_construct' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + 'single_line_empty_body' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'whitespace_after_comma_in_array' => ['ensure_single_space' => true], + 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], +]; + +// 2. Custom stefanfroemken Overrides +$stefanfroemkenRules = [ + 'braces_position' => [ + 'allow_single_line_anonymous_functions' => false, + 'allow_single_line_empty_anonymous_classes' => true, + 'anonymous_classes_opening_brace' => 'same_line', + 'anonymous_functions_opening_brace' => 'same_line', + 'classes_opening_brace' => 'next_line_unless_newline_at_signature_end', + 'control_structures_opening_brace' => 'same_line', + 'functions_opening_brace' => 'next_line_unless_newline_at_signature_end', + ], + 'control_structure_braces' => true, + 'control_structure_continuation_position' => [ + 'position' => 'same_line', + ], + 'function_declaration' => [ + 'closure_fn_spacing' => 'none', + 'closure_function_spacing' => 'one', + 'trailing_comma_single_line' => false, + ], + 'method_argument_space' => [ + 'after_heredoc' => false, + 'attribute_placement' => 'same_line', + 'keep_multiple_spaces_after_comma' => false, + 'on_multiline' => 'ensure_fully_multiline', + ], + 'method_chaining_indentation' => true, + 'multiline_whitespace_before_semicolons' => [ + 'strategy' => 'no_multi_line', + ], + 'no_empty_comment' => true, + 'no_extra_blank_lines' => [ + 'tokens' => [ + 'attribute', + 'case', + 'continue', + 'curly_brace_block', + 'default', + 'extra', + 'parenthesis_brace_block', + 'square_brace_block', + 'switch', + 'throw', + 'use', + ], + ], + 'no_multiple_statements_per_line' => true, + 'operator_linebreak' => [ + 'only_booleans' => false, + 'position' => 'beginning', + ], + 'single_line_empty_body' => true, + 'single_space_around_construct' => true, + 'statement_indentation' => [ + 'stick_comment_to_next_continuous_control_statement' => false, + ], + 'trailing_comma_in_multiline' => [ + 'elements' => [ + 'arrays', + 'arguments', + 'parameters', + ], + ], +]; + +// Merge rules: stefanfroemkenRules will overwrite typo3Rules in case of conflicts +$mergedRules = array_merge($typo3Rules, $stefanfroemkenRules); + +return (new \PhpCsFixer\Config()) + ->setParallelConfig(\PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setFinder( + (new PhpCsFixer\Finder()) + ->exclude(['var', 'packages']) + ->ignoreVCSIgnored(true) + ->in(__DIR__ . '/../../'), + ) + ->setRiskyAllowed(true) + ->setRules($mergedRules); diff --git a/Build/rector/rector.php b/Build/rector/rector.php new file mode 100644 index 0000000..a3dca2b --- /dev/null +++ b/Build/rector/rector.php @@ -0,0 +1,68 @@ +withPaths([ + __DIR__ . '/../../Classes', + __DIR__ . '/../../Configuration', + __DIR__ . '/../../Tests', + __DIR__ . '/../../ext_emconf.php', + __DIR__ . '/../../ext_localconf.php', + ]) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + typeDeclarations: true, + privatization: true, + instanceOf: true, + earlyReturn: true, + ) + ->withPhpSets(php82: true) + ->withPhpVersion(PhpVersion::PHP_82) + ->withSets([ + Typo3SetList::CODE_QUALITY, + Typo3SetList::GENERAL, + Typo3LevelSetList::UP_TO_TYPO3_14, + ]) + ->withPHPStanConfigs([Typo3Option::PHPSTAN_FOR_RECTOR_PATH]) + ->withConfiguredRule(ExtEmConfRector::class, [ + ExtEmConfRector::TYPO3_VERSION_CONSTRAINT => '14.3.0-14.3.99', + ExtEmConfRector::ADDITIONAL_VALUES_TO_BE_REMOVED => [], + ]) + ->withConfiguredRule(EncapsedStringsToSprintfRector::class, [ + 'always' => true, + // force sprintf even for simple cases + ]) + ->withImportNames(importShortClasses: false, removeUnusedImports: true) + ->withSkip([ + NullToStrictStringFuncCallArgRector::class, + SafeDeclareStrictTypesRector::class => [ + '*ext_emconf.php', + ], + // Avoid stripping class types from mock properties to keep IDE autocomplete working in functional tests + TypedPropertyFromCreateMockAssignRector::class => [ + '*/Tests/Functional/*', + ], + '*Build/*', + '*Resources/*', + '*Model/*', + ]); diff --git a/Classes/Configuration/ExtConf.php b/Classes/Configuration/ExtConf.php index 85749ed..2fff753 100644 --- a/Classes/Configuration/ExtConf.php +++ b/Classes/Configuration/ExtConf.php @@ -97,14 +97,9 @@ public function isQueryLoggingActivated(): bool return false; } - if ($this->isEnableFrontendLogging() && !$this->isBackendRequest()) { + if ($this->enableFrontendLogging && !$this->isBackendRequest()) { return true; } - - if ($this->isEnableBackendLogging() && $this->isBackendRequest()) { - return true; - } - - return false; + return $this->enableBackendLogging && $this->isBackendRequest(); } } diff --git a/Classes/Controller/InnoDBController.php b/Classes/Controller/InnoDBController.php index 3285d5b..d7f2f34 100644 --- a/Classes/Controller/InnoDBController.php +++ b/Classes/Controller/InnoDBController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class InnoDBController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - InnoDB', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('InnoDB/Index'); } diff --git a/Classes/Controller/MiscController.php b/Classes/Controller/MiscController.php index f6e5ea6..6c73559 100644 --- a/Classes/Controller/MiscController.php +++ b/Classes/Controller/MiscController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class MiscController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - Misc', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('Misc/Index'); } diff --git a/Classes/Controller/ProfileController.php b/Classes/Controller/ProfileController.php index 6d740b3..969a548 100644 --- a/Classes/Controller/ProfileController.php +++ b/Classes/Controller/ProfileController.php @@ -151,7 +151,6 @@ public function downloadAction(string $uniqueIdentifier, string $downloadType): /** * @param array $headerColumns * @param array $records - * @return ResponseInterface */ private function downloadAsCsv(array $headerColumns, array $records): ResponseInterface { @@ -160,7 +159,6 @@ private function downloadAsCsv(array $headerColumns, array $records): ResponseIn /** * @param array $records - * @return ResponseInterface */ private function downloadAsJson(array $records): ResponseInterface { diff --git a/Classes/Controller/QueryCacheController.php b/Classes/Controller/QueryCacheController.php index 30fd729..bad13c2 100644 --- a/Classes/Controller/QueryCacheController.php +++ b/Classes/Controller/QueryCacheController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class QueryCacheController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - Query Cache', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('QueryCache/Index'); } diff --git a/Classes/Controller/StatusController.php b/Classes/Controller/StatusController.php index 8ef6bbc..38c834a 100644 --- a/Classes/Controller/StatusController.php +++ b/Classes/Controller/StatusController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class StatusController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - Status', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('Status/Index'); } diff --git a/Classes/Controller/TableCacheController.php b/Classes/Controller/TableCacheController.php index e224752..bd7e274 100644 --- a/Classes/Controller/TableCacheController.php +++ b/Classes/Controller/TableCacheController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class TableCacheController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - Table Cache', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('TableCache/Index'); } diff --git a/Classes/Controller/ThreadCacheController.php b/Classes/Controller/ThreadCacheController.php index 450d05e..104113d 100644 --- a/Classes/Controller/ThreadCacheController.php +++ b/Classes/Controller/ThreadCacheController.php @@ -12,14 +12,18 @@ namespace StefanFroemken\Mysqlreport\Controller; use Psr\Http\Message\ResponseInterface; -use StefanFroemken\Mysqlreport\Menu\Page; +use StefanFroemken\Mysqlreport\InfoBox\RenderInfoBoxFactory; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class ThreadCacheController extends ActionController { + /** + * @param iterable $infoBoxes + */ public function __construct( - private readonly Page $page, + private readonly iterable $infoBoxes, + private readonly RenderInfoBoxFactory $renderInfoBoxFactory, private readonly ModuleTemplateFactory $moduleTemplateFactory, ) {} @@ -31,7 +35,10 @@ public function indexAction(): ResponseInterface 'MySQL Report - Thread Cache', ); - $moduleTemplate->assign('renderedInfoBoxes', $this->page->getRenderedInfoBoxes()); + $moduleTemplate->assign( + 'renderedInfoBoxes', + $this->renderInfoBoxFactory->render($this->infoBoxes), + ); return $moduleTemplate->renderResponse('ThreadCache/Index'); } diff --git a/Classes/DependencyInjection/DashboardPass.php b/Classes/DependencyInjection/DashboardPass.php index 417fd5f..d121fb6 100644 --- a/Classes/DependencyInjection/DashboardPass.php +++ b/Classes/DependencyInjection/DashboardPass.php @@ -22,12 +22,7 @@ */ readonly class DashboardPass implements CompilerPassInterface { - private string $tagName; - - public function __construct(string $tagName) - { - $this->tagName = $tagName; - } + public function __construct(private string $tagName) {} /** * Start removing registered dashboard widgets if EXT:dashboard is not installed @@ -42,7 +37,7 @@ public function __construct(string $tagName) public function process(ContainerBuilder $container): void { if (!$container->has(DashboardController::class)) { - foreach ($container->findTaggedServiceIds($this->tagName) as $id => $tags) { + foreach (array_keys($container->findTaggedServiceIds($this->tagName)) as $id) { $container->removeDefinition($id); } } diff --git a/Classes/Doctrine/Middleware/LoggerStatement.php b/Classes/Doctrine/Middleware/LoggerStatement.php index bdfdc0a..c42932a 100644 --- a/Classes/Doctrine/Middleware/LoggerStatement.php +++ b/Classes/Doctrine/Middleware/LoggerStatement.php @@ -12,7 +12,6 @@ namespace StefanFroemken\Mysqlreport\Doctrine\Middleware; use Doctrine\DBAL\Driver\Result as ResultInterface; -use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\Statement as StatementInterface; use Doctrine\DBAL\ParameterType; use StefanFroemken\Mysqlreport\Domain\Model\QueryInformation; @@ -21,7 +20,7 @@ /** * Here in the connection, we can wrap our logger around the queries and commands. */ -class LoggerStatement implements Statement +class LoggerStatement implements StatementInterface { /** * @var array diff --git a/Classes/Doctrine/Middleware/LoggerWithQueryTimeConnection.php b/Classes/Doctrine/Middleware/LoggerWithQueryTimeConnection.php index 1b41b70..e7214cb 100644 --- a/Classes/Doctrine/Middleware/LoggerWithQueryTimeConnection.php +++ b/Classes/Doctrine/Middleware/LoggerWithQueryTimeConnection.php @@ -30,13 +30,13 @@ class LoggerWithQueryTimeConnection extends AbstractConnectionMiddleware /** * @var \SplQueue */ - private \SplQueue $queries; + private readonly \SplQueue $queries; - private MySqlReportSqlLogger $logger; + private readonly MySqlReportSqlLogger $logger; - private ExplainQueryHelper $explainQueryHelper; + private readonly ExplainQueryHelper $explainQueryHelper; - private QueryInformationRepository $queryInformationRepository; + private readonly QueryInformationRepository $queryInformationRepository; public function __construct(Connection $connection) { diff --git a/Classes/Domain/Factory/QueryInformationFactory.php b/Classes/Domain/Factory/QueryInformationFactory.php index 154d2f6..d654329 100644 --- a/Classes/Domain/Factory/QueryInformationFactory.php +++ b/Classes/Domain/Factory/QueryInformationFactory.php @@ -14,7 +14,9 @@ use Psr\Http\Message\ServerRequestInterface; use StefanFroemken\Mysqlreport\Domain\Model\QueryInformation; use StefanFroemken\Mysqlreport\Traits\Typo3RequestTrait; +use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Core\Environment; +use TYPO3\CMS\Core\Http\NormalizedParams; use TYPO3\CMS\Core\Routing\PageArguments; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -43,12 +45,24 @@ public function __construct() { $this->pageUid = $this->getPageUid(); - $this->ip = (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'); - $this->referer = (string)GeneralUtility::getIndpEnv('HTTP_REFERER'); - $this->request = (string)GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'); + $ip = ''; + $referer = ''; + $requestUrl = ''; + $request = $GLOBALS['TYPO3_REQUEST'] ?? null; + if ($request instanceof ServerRequestInterface) { + $normalizedParams = $request->getAttribute('normalizedParams'); + if ($normalizedParams instanceof NormalizedParams) { + $ip = (string)$normalizedParams->getRemoteAddress(); + $referer = (string)$normalizedParams->getHttpReferer(); + $requestUrl = (string)$normalizedParams->getRequestUrl(); + } + } + $this->ip = $ip; + $this->referer = $referer; + $this->request = $requestUrl; $this->mode = $this->getTypo3Mode(); $this->uniqueCallIdentifier = uniqid('', true); - $this->crdate = (int)$GLOBALS['EXEC_TIME']; + $this->crdate = (int)GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('date', 'timestamp'); } public function createNewQueryInformation(): QueryInformation diff --git a/Classes/Event/ModifyQueryInformationRecordsEvent.php b/Classes/Event/ModifyQueryInformationRecordsEvent.php index 5b9fb65..03fb200 100644 --- a/Classes/Event/ModifyQueryInformationRecordsEvent.php +++ b/Classes/Event/ModifyQueryInformationRecordsEvent.php @@ -17,22 +17,10 @@ */ class ModifyQueryInformationRecordsEvent { - private string $methodName; - - /** - * @var array - */ - private array $queryInformationRecords; - /** - * @param string $methodName * @param array $queryInformationRecords */ - public function __construct(string $methodName, array $queryInformationRecords) - { - $this->methodName = $methodName; - $this->queryInformationRecords = $queryInformationRecords; - } + public function __construct(private readonly string $methodName, private array $queryInformationRecords) {} public function getMethodName(): string { diff --git a/Classes/EventListener/CacheAction.php b/Classes/EventListener/CacheAction.php index 3348d98..c209fa9 100644 --- a/Classes/EventListener/CacheAction.php +++ b/Classes/EventListener/CacheAction.php @@ -30,7 +30,6 @@ public function __construct( /** * Add clear cache menu entry * - * @param ModifyClearCacheActionsEvent $modifyClearCacheActionsEvent * @throws RouteNotFoundException */ public function __invoke(ModifyClearCacheActionsEvent $modifyClearCacheActionsEvent): void @@ -40,7 +39,7 @@ public function __invoke(ModifyClearCacheActionsEvent $modifyClearCacheActionsEv 'id' => 'mysqlprofile', 'title' => 'LLL:EXT:mysqlreport/Resources/Private/Language/locallang.xlf:clearCache.title', 'description' => 'LLL:EXT:mysqlreport/Resources/Private/Language/locallang.xlf:clearCache.description', - 'href' => (string)$this->uriBuilder->buildUriFromRoute('tce_db', ['cacheCmd' => 'mysqlprofiles']), + 'endpoint' => (string)$this->uriBuilder->buildUriFromRoute('tce_db', ['cacheCmd' => 'mysqlprofiles']), 'iconIdentifier' => 'actions-system-cache-clear-impact-high', ]); } diff --git a/Classes/Helper/ExplainQueryHelper.php b/Classes/Helper/ExplainQueryHelper.php index 825f924..2f23ef9 100644 --- a/Classes/Helper/ExplainQueryHelper.php +++ b/Classes/Helper/ExplainQueryHelper.php @@ -29,9 +29,6 @@ public function __construct( private LoggerInterface $logger, ) {} - /** - * @param QueryInformation $queryInformation - */ public function updateQueryInformation(QueryInformation $queryInformation): void { if (!$this->extConf->isActivateExplainQuery()) { diff --git a/Classes/InfoBox/AbstractInfoBox.php b/Classes/InfoBox/AbstractInfoBox.php deleted file mode 100644 index de9d523..0000000 --- a/Classes/InfoBox/AbstractInfoBox.php +++ /dev/null @@ -1,44 +0,0 @@ -renderBody()) === '') { - return null; - } - - $view->assign('title', static::TITLE); - $view->assign('body', $body); - - if ($this instanceof InfoBoxUnorderedListInterface) { - $view->assign('unorderedList', $this->getUnorderedList()); - } - - if ($this instanceof InfoBoxStateInterface) { - $view->assign('state', $this->getState()->value); - } - - return $view; - } -} diff --git a/Classes/InfoBox/InfoBoxInterface.php b/Classes/InfoBox/InfoBoxInterface.php new file mode 100644 index 0000000..47a12cf --- /dev/null +++ b/Classes/InfoBox/InfoBoxInterface.php @@ -0,0 +1,19 @@ + 30], )] -class ConnectionInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface, InfoBoxStateInterface +final readonly class ConnectionInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Connections'; - protected const TITLE = 'Connections'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - return 'Have an eye on your servers connections. ' - . 'It is a first indicator how much your server has to do. ' - . 'If the percentage usage of max simultaneous connections is high you should consider ' - . 'to increase the value for max_connections'; + return 'Keep an eye on your server\'s connections. ' + . 'It is a first indicator of how much work your server has to do. ' + . 'If the percentage usage of max simultaneous connections is high, you should consider ' + . 'optimizing your queries, checking connection lifetimes, or increasing the max_connections value (if privileges allow).'; } private function getAverage(int $value, int $uptime): string @@ -52,28 +56,29 @@ public function getUnorderedList(): \SplQueue { $unorderedList = new \SplQueue(); - if (isset($this->getStatusValues()['Connections'])) { + if (isset($this->statusValues['Connections'])) { $unorderedList->enqueue(new ListElement( title: 'Connections in total (Connections)', - value: $this->getStatusValues()['Connections'], + value: $this->statusValues['Connections'], )); $unorderedList->enqueue(new ListElement( title: 'Average connections each second', value: $this->getAverage( - (int)$this->getStatusValues()['Connections'], - (int)$this->getStatusValues()['Uptime'], + (int)$this->statusValues['Connections'], + (int)$this->statusValues['Uptime'], ), )); } - if (isset($this->getStatusValues()['Max_used_connections'])) { + if (isset($this->statusValues['Max_used_connections'])) { $unorderedList->enqueue(new ListElement( title: 'Max used simultaneous connections (Max_used_connections)', - value: $this->getStatusValues()['Max_used_connections'], + value: $this->statusValues['Max_used_connections'], )); - if (isset($this->getVariables()['max_connections'])) { - $percent = 100 / (int)$this->getVariables()['max_connections'] * (int)$this->getStatusValues()['Max_used_connections']; + $maxConnections = (int)($this->variables['max_connections'] ?? 0); + if ($maxConnections > 0) { + $percent = 100 / $maxConnections * (int)$this->statusValues['Max_used_connections']; $unorderedList->enqueue(new ListElement( title: 'Max used simultaneous connections in percent', value: number_format($percent, 2, ',', '.') . '%', @@ -81,30 +86,30 @@ public function getUnorderedList(): \SplQueue } } - if (isset($this->getVariables()['max_connections'])) { + if (isset($this->variables['max_connections'])) { $unorderedList->enqueue(new ListElement( title: 'Max allowed simultaneous connections (max_connections)', - value: $this->getVariables()['max_connections'], + value: $this->variables['max_connections'], )); } - if (isset($this->getVariables()['extra_max_connections'])) { + if (isset($this->variables['extra_max_connections'])) { $unorderedList->enqueue(new ListElement( title: 'Extra connections (extra_max_connections)', - value: $this->getVariables()['extra_max_connections'], + value: $this->variables['extra_max_connections'], )); } - if (isset($this->getVariables()['max_user_connections'])) { - if ((int)$this->getVariables()['max_user_connections'] === 0) { + if (isset($this->variables['max_user_connections'])) { + if ((int)$this->variables['max_user_connections'] === 0) { $unorderedList->enqueue(new ListElement( title: 'Max allowed user connections (max_user_connections)', - value: 'No limit. Using value from max_connections', + value: 'No per-user limit (applies global max_connections limit)', )); } else { $unorderedList->enqueue(new ListElement( title: 'Max allowed user connections (max_user_connections)', - value: $this->getVariables()['max_user_connections'], + value: $this->variables['max_user_connections'], )); } } @@ -116,11 +121,12 @@ public function getState(): StateEnumeration { $state = StateEnumeration::STATE_NOTICE; + $maxConnections = (int)($this->variables['max_connections'] ?? 0); if ( - isset($this->getStatusValues()['Max_used_connections']) - && isset($this->getVariables()['max_connections']) + $maxConnections > 0 + && isset($this->statusValues['Max_used_connections']) ) { - $percent = 100 / (int)$this->getVariables()['max_connections'] * (int)$this->getStatusValues()['Max_used_connections']; + $percent = 100 / $maxConnections * (int)$this->statusValues['Max_used_connections']; if ($percent > 90) { $state = StateEnumeration::STATE_ERROR; } elseif ($percent > 70) { diff --git a/Classes/InfoBox/Information/ServerVersionInfoBox.php b/Classes/InfoBox/Information/ServerVersionInfoBox.php index f52eb32..bf56446 100644 --- a/Classes/InfoBox/Information/ServerVersionInfoBox.php +++ b/Classes/InfoBox/Information/ServerVersionInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Information; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,15 +24,17 @@ name: 'mysqlreport.infobox.status', attributes: ['priority' => 90], )] -class ServerVersionInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class ServerVersionInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Server Information'; - protected const TITLE = 'Server Information'; + public function __construct( + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - return 'Following server information have been found:'; + return 'The following server information was found:'; } /** @@ -42,31 +44,31 @@ public function getUnorderedList(): \SplQueue { $unorderedList = new \SplQueue(); - if (isset($this->getVariables()['version'])) { + if (isset($this->variables['version'])) { $unorderedList->enqueue(new ListElement( title: 'Version', - value: $this->getVariables()['version'], + value: $this->variables['version'], )); } - if (isset($this->getVariables()['version_comment'])) { + if (isset($this->variables['version_comment'])) { $unorderedList->enqueue(new ListElement( title: 'Version comment', - value: $this->getVariables()['version_comment'], + value: $this->variables['version_comment'], )); } - if (isset($this->getVariables()['version_compile_machine'])) { + if (isset($this->variables['version_compile_machine'])) { $unorderedList->enqueue(new ListElement( title: 'Version compile machine', - value: $this->getVariables()['version_compile_machine'], + value: $this->variables['version_compile_machine'], )); } - if (isset($this->getVariables()['version_compile_os'])) { + if (isset($this->variables['version_compile_os'])) { $unorderedList->enqueue(new ListElement( title: 'Version compile OS', - value: $this->getVariables()['version_compile_os'], + value: $this->variables['version_compile_os'], )); } diff --git a/Classes/InfoBox/Information/UptimeInfoBox.php b/Classes/InfoBox/Information/UptimeInfoBox.php index e31317f..0fc2fd0 100644 --- a/Classes/InfoBox/Information/UptimeInfoBox.php +++ b/Classes/InfoBox/Information/UptimeInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Information; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,18 +24,20 @@ name: 'mysqlreport.infobox.status', attributes: ['priority' => 80], )] -class UptimeInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class UptimeInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Uptime'; - protected const TITLE = 'Uptime'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { - return '"Uptime" shows time since server start or last restart. ' - . 'As a server admin you can FLUSH STATUS to reset various status variables. ' - . 'This is good for temporary debugging, but breaks analysis of server over full time.' - . 'If "Uptime_since_flush_status" is lower than "Uptime" an admin has reset the status variables.'; + return '"Uptime" shows the time since the server was started or restarted. ' + . 'Database administrators can execute "FLUSH STATUS" to reset various status variables. ' + . 'While useful for temporary debugging, resetting the status variables interrupts long-term profiling analysis. ' + . 'If "Uptime_since_flush_status" is lower than "Uptime", the status variables have been reset since the server started.'; } private function convertSecondsToDays(int $seconds): string @@ -50,27 +52,27 @@ public function getUnorderedList(): \SplQueue { $unorderedList = new \SplQueue(); - if (isset($this->getStatusValues()['Uptime'])) { + if (isset($this->statusValues['Uptime'])) { $unorderedList->enqueue(new ListElement( title: 'Uptime', - value: $this->getStatusValues()['Uptime'] . ' seconds', + value: $this->statusValues['Uptime'] . ' seconds', )); $unorderedList->enqueue(new ListElement( title: 'Uptime in days', - value: $this->convertSecondsToDays((int)$this->getStatusValues()['Uptime']) . ' days', + value: $this->convertSecondsToDays((int)$this->statusValues['Uptime']) . ' days', )); } - if (isset($this->getStatusValues()['Uptime_since_flush_status'])) { + if (isset($this->statusValues['Uptime_since_flush_status'])) { $unorderedList->enqueue(new ListElement( - title: 'Uptime since last flush', - value: $this->getStatusValues()['Uptime_since_flush_status'] . ' seconds', + title: 'Uptime since status variables reset', + value: $this->statusValues['Uptime_since_flush_status'] . ' seconds', )); $unorderedList->enqueue(new ListElement( - title: 'Uptime since last flush in days', - value: $this->convertSecondsToDays((int)$this->getStatusValues()['Uptime_since_flush_status']) . ' days', + title: 'Uptime since status variables reset in days', + value: $this->convertSecondsToDays((int)$this->statusValues['Uptime_since_flush_status']) . ' days', )); } diff --git a/Classes/InfoBox/InnoDb/HitRatioBySFInfoBox.php b/Classes/InfoBox/InnoDb/HitRatioBySFInfoBox.php index c51fbab..89b192d 100644 --- a/Classes/InfoBox/InnoDb/HitRatioBySFInfoBox.php +++ b/Classes/InfoBox/InnoDb/HitRatioBySFInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,19 +24,21 @@ name: 'mysqlreport.infobox.innodb', attributes: ['priority' => 40], )] -class HitRatioBySFInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class HitRatioBySFInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Hit Ratio by SF'; - protected const TITLE = 'Hit Ratio by SF'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { if ( !isset( - $this->getStatusValues()['Innodb_page_size'], - $this->getStatusValues()['Innodb_buffer_pool_reads'], - $this->getStatusValues()['Innodb_buffer_pool_read_requests'], + $this->statusValues['Innodb_page_size'], + $this->statusValues['Innodb_buffer_pool_reads'], + $this->statusValues['Innodb_buffer_pool_read_requests'], ) ) { return ''; @@ -58,9 +60,9 @@ public function renderBody(): string /** * get hit ratio of innoDb Buffer by SF */ - protected function getHitRatioBySF(): float + private function getHitRatioBySF(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $niceToHave = $status['Innodb_buffer_pool_reads'] * 1000; $hitRatio = 100 / $niceToHave * $status['Innodb_buffer_pool_read_requests']; @@ -70,7 +72,7 @@ protected function getHitRatioBySF(): float public function getState(): StateEnumeration { - $status = $this->getStatusValues(); + $status = $this->statusValues; // We always want a factor of 1/1000. $niceToHave = $status['Innodb_buffer_pool_reads'] * 1000; diff --git a/Classes/InfoBox/InnoDb/HitRatioInfoBox.php b/Classes/InfoBox/InnoDb/HitRatioInfoBox.php index d8488c7..cbd92ac 100644 --- a/Classes/InfoBox/InnoDb/HitRatioInfoBox.php +++ b/Classes/InfoBox/InnoDb/HitRatioInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,19 +24,21 @@ name: 'mysqlreport.infobox.innodb', attributes: ['priority' => 50], )] -class HitRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class HitRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Hit Ratio'; - protected const TITLE = 'Hit Ratio'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { if ( !isset( - $this->getStatusValues()['Innodb_page_size'], - $this->getStatusValues()['Innodb_buffer_pool_read_requests'], - $this->getStatusValues()['Innodb_buffer_pool_reads'], + $this->statusValues['Innodb_page_size'], + $this->statusValues['Innodb_buffer_pool_read_requests'], + $this->statusValues['Innodb_buffer_pool_reads'], ) ) { return ''; @@ -59,9 +61,9 @@ public function renderBody(): string * get hit ratio of innoDb Buffer * A ratio of 99.9 equals 1/1000 */ - protected function getHitRatio(): float + private function getHitRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $hitRatio = ($status['Innodb_buffer_pool_read_requests'] / ($status['Innodb_buffer_pool_read_requests'] + $status['Innodb_buffer_pool_reads'])) * 100; diff --git a/Classes/InfoBox/InnoDb/InnoDbBufferLoadInfoBox.php b/Classes/InfoBox/InnoDb/InnoDbBufferLoadInfoBox.php index 584e3ef..f5d101d 100644 --- a/Classes/InfoBox/InnoDb/InnoDbBufferLoadInfoBox.php +++ b/Classes/InfoBox/InnoDb/InnoDbBufferLoadInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -25,15 +25,17 @@ name: 'mysqlreport.infobox.innodb', attributes: ['priority' => 90], )] -class InnoDbBufferLoadInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class InnoDbBufferLoadInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'InnoDB Buffer Load'; - protected const TITLE = 'InnoDB Buffer Load'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Innodb_page_size'])) { + if (!isset($this->statusValues['Innodb_page_size'])) { return ''; } @@ -44,7 +46,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), - $this->getStatusValues()['Innodb_page_size'], + $this->statusValues['Innodb_page_size'], ); } @@ -53,10 +55,10 @@ public function renderBody(): string * * @return array */ - protected function getLoad(): array + private function getLoad(): array { $load = []; - $status = $this->getStatusValues(); + $status = $this->statusValues; // in Bytes $total = $status['Innodb_buffer_pool_pages_total'] * $status['Innodb_page_size']; diff --git a/Classes/InfoBox/InnoDb/InstancesInfoBox.php b/Classes/InfoBox/InnoDb/InstancesInfoBox.php index c7c482d..f40935a 100644 --- a/Classes/InfoBox/InnoDb/InstancesInfoBox.php +++ b/Classes/InfoBox/InnoDb/InstancesInfoBox.php @@ -11,10 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -23,19 +24,22 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.innodb', )] -class InstancesInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class InstancesInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Instances'; - protected const TITLE = 'Instances'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Innodb_page_size'])) { + if (!isset($this->statusValues['Innodb_page_size'])) { return ''; } - if (!isset($this->getVariables()['innodb_buffer_pool_instances'])) { + if (!isset($this->variables['innodb_buffer_pool_instances'])) { return ''; } @@ -54,20 +58,20 @@ public function renderBody(): string ); } - protected function getInstances(): int + private function getInstances(): int { - $variables = $this->getVariables(); + $variables = $this->variables; return (int)$variables['innodb_buffer_pool_instances']; } public function getState(): StateEnumeration { - $variables = $this->getVariables(); + $variables = $this->variables; - $innodbBufferShouldBe = $variables['innodb_buffer_pool_instances'] * (1 * 1024 * 1024 * 1024); // Instances * 1 GB + $innodbBufferShouldBe = $variables['innodb_buffer_pool_instances'] * (1024 * 1024 * 1024); // Instances * 1 GB if ( - $variables['innodb_buffer_pool_size'] < (1 * 1024 * 1024 * 1024) + $variables['innodb_buffer_pool_size'] < (1024 * 1024 * 1024) && $variables['innodb_buffer_pool_instances'] === 1 ) { $state = StateEnumeration::STATE_OK; diff --git a/Classes/InfoBox/InnoDb/LogFileSizeInfoBox.php b/Classes/InfoBox/InnoDb/LogFileSizeInfoBox.php index fae9558..b380e40 100644 --- a/Classes/InfoBox/InnoDb/LogFileSizeInfoBox.php +++ b/Classes/InfoBox/InnoDb/LogFileSizeInfoBox.php @@ -11,10 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -23,20 +24,23 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.innodb', )] -class LogFileSizeInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class LogFileSizeInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Log File Size'; - protected const TITLE = 'Log File Size'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { if ( !isset( - $this->getStatusValues()['Innodb_page_size'], - $this->getVariables()['innodb_log_files_in_group'], + $this->statusValues['Innodb_page_size'], + $this->variables['innodb_log_files_in_group'], ) - || (int)$this->getVariables()['innodb_log_files_in_group'] === 0 + || (int)$this->variables['innodb_log_files_in_group'] === 0 ) { return ''; } @@ -65,9 +69,9 @@ public function renderBody(): string * * @return array */ - protected function getLogFileSize(): array + private function getLogFileSize(): array { - $variables = $this->getVariables(); + $variables = $this->variables; return [ 'value' => $variables['innodb_log_file_size'], @@ -77,8 +81,8 @@ protected function getLogFileSize(): array private function getSizeOfEachLogFile(): int { - $variables = $this->getVariables(); - $status = $this->getStatusValues(); + $variables = $this->variables; + $status = $this->statusValues; $bytesWrittenEachSecond = $status['Innodb_os_log_written'] / $status['Uptime']; $bytesWrittenEachHour = $bytesWrittenEachSecond * 60 * 60; @@ -88,15 +92,13 @@ private function getSizeOfEachLogFile(): int public function getState(): StateEnumeration { - $variables = $this->getVariables(); + $variables = $this->variables; $sizeOfEachLogFile = $this->getSizeOfEachLogFile(); if ($sizeOfEachLogFile < 5242880 || $sizeOfEachLogFile < $variables['innodb_log_file_size']) { - $state = StateEnumeration::STATE_OK; - } else { - $state = StateEnumeration::STATE_ERROR; + return StateEnumeration::STATE_OK; } - return $state; + return StateEnumeration::STATE_ERROR; } } diff --git a/Classes/InfoBox/InnoDb/WriteRatioInfoBox.php b/Classes/InfoBox/InnoDb/WriteRatioInfoBox.php index b7b4582..6bccbaf 100644 --- a/Classes/InfoBox/InnoDb/WriteRatioInfoBox.php +++ b/Classes/InfoBox/InnoDb/WriteRatioInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\InnoDb; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -23,21 +23,23 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.innodb', )] -class WriteRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class WriteRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Write Ratio'; - protected const TITLE = 'Write Ratio'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { if ( !isset( - $this->getStatusValues()['Innodb_page_size'], - $this->getStatusValues()['Innodb_buffer_pool_write_requests'], - $this->getStatusValues()['Innodb_buffer_pool_pages_flushed'], + $this->statusValues['Innodb_page_size'], + $this->statusValues['Innodb_buffer_pool_write_requests'], + $this->statusValues['Innodb_buffer_pool_pages_flushed'], ) - || (int)$this->getStatusValues()['Innodb_buffer_pool_pages_flushed'] === 0 + || (int)$this->statusValues['Innodb_buffer_pool_pages_flushed'] === 0 ) { return ''; } @@ -57,9 +59,9 @@ public function renderBody(): string * get write ratio of innoDb Buffer * A value higher than 1 is good */ - protected function getWriteRatio(): float + private function getWriteRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $writeRatio = $status['Innodb_buffer_pool_write_requests'] / $status['Innodb_buffer_pool_pages_flushed']; diff --git a/Classes/InfoBox/ListElement.php b/Classes/InfoBox/ListElement.php index 34d7c99..9dec842 100644 --- a/Classes/InfoBox/ListElement.php +++ b/Classes/InfoBox/ListElement.php @@ -11,7 +11,7 @@ namespace StefanFroemken\Mysqlreport\InfoBox; -readonly class ListElement +final readonly class ListElement { public function __construct( public string $title, diff --git a/Classes/InfoBox/Misc/AbortedConnectsInfoBox.php b/Classes/InfoBox/Misc/AbortedConnectsInfoBox.php index d7e676f..5f47ada 100644 --- a/Classes/InfoBox/Misc/AbortedConnectsInfoBox.php +++ b/Classes/InfoBox/Misc/AbortedConnectsInfoBox.php @@ -11,8 +11,8 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -22,15 +22,17 @@ name: 'mysqlreport.infobox.misc', attributes: ['priority' => 50], )] -class AbortedConnectsInfoBox extends AbstractInfoBox +final readonly class AbortedConnectsInfoBox implements InfoBoxInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Aborted Connects'; - protected const TITLE = 'Aborted Connects'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Aborted_connects'])) { + if (!isset($this->statusValues['Aborted_connects'])) { return ''; } @@ -41,7 +43,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), - $this->getStatusValues()['Aborted_connects'], + $this->statusValues['Aborted_connects'], ); } } diff --git a/Classes/InfoBox/Misc/BackLogInfoBox.php b/Classes/InfoBox/Misc/BackLogInfoBox.php index 38105f5..e0aa464 100644 --- a/Classes/InfoBox/Misc/BackLogInfoBox.php +++ b/Classes/InfoBox/Misc/BackLogInfoBox.php @@ -11,8 +11,8 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; use TYPO3\CMS\Core\Utility\CommandUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -23,15 +23,17 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.misc', )] -class BackLogInfoBox extends AbstractInfoBox +final readonly class BackLogInfoBox implements InfoBoxInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Back Log'; - protected const TITLE = 'Back Log'; + public function __construct( + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getVariables()['back_log'])) { + if (!isset($this->variables['back_log'])) { return ''; } @@ -46,7 +48,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), - $this->getVariables()['back_log'], + $this->variables['back_log'], $this->getMaxNetworkRequests(), ); } @@ -54,7 +56,7 @@ public function renderBody(): string /** * Execute shell command to get amount of max network requests by OS */ - protected function getMaxNetworkRequests(): string + private function getMaxNetworkRequests(): string { $value = ''; $command = CommandUtility::getCommand('sysctl'); diff --git a/Classes/InfoBox/Misc/BinaryLogInfoBox.php b/Classes/InfoBox/Misc/BinaryLogInfoBox.php index dd4f636..0f5a850 100644 --- a/Classes/InfoBox/Misc/BinaryLogInfoBox.php +++ b/Classes/InfoBox/Misc/BinaryLogInfoBox.php @@ -11,8 +11,8 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -21,19 +21,21 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.misc', )] -class BinaryLogInfoBox extends AbstractInfoBox +final readonly class BinaryLogInfoBox implements InfoBoxInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Binary Log'; - protected const TITLE = 'Binary Log'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { if ( - isset($this->getStatusValues()['Slave_running']) + isset($this->statusValues['Slave_running']) && ( - strtolower($this->getStatusValues()['Slave_running']) === 'off' - || (int)$this->getStatusValues()['Slave_running'] === 0 + strtolower($this->statusValues['Slave_running']) === 'off' + || (int)$this->statusValues['Slave_running'] === 0 ) ) { $content = []; diff --git a/Classes/InfoBox/Misc/MaxAllowedPacketInfoBox.php b/Classes/InfoBox/Misc/MaxAllowedPacketInfoBox.php index 96b6776..373f0dc 100644 --- a/Classes/InfoBox/Misc/MaxAllowedPacketInfoBox.php +++ b/Classes/InfoBox/Misc/MaxAllowedPacketInfoBox.php @@ -11,10 +11,10 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,15 +24,17 @@ name: 'mysqlreport.infobox.misc', attributes: ['priority' => 90], )] -class MaxAllowedPacketInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class MaxAllowedPacketInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Max Packet Size'; - protected const TITLE = 'Max Packet Size'; + public function __construct( + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getVariables()['max_allowed_packet'])) { + if (!isset($this->variables['max_allowed_packet'])) { return ''; } @@ -54,7 +56,7 @@ public function getUnorderedList(): \SplQueue $unorderedList->enqueue(new ListElement( title: 'Max allowed packet size in bytes (max_allowed_packet)', - value: $this->getVariables()['max_allowed_packet'], + value: $this->variables['max_allowed_packet'], )); return $unorderedList; diff --git a/Classes/InfoBox/Misc/StandaloneReplicationInfoBox.php b/Classes/InfoBox/Misc/StandaloneReplicationInfoBox.php index a748d08..4ae9629 100644 --- a/Classes/InfoBox/Misc/StandaloneReplicationInfoBox.php +++ b/Classes/InfoBox/Misc/StandaloneReplicationInfoBox.php @@ -11,8 +11,8 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -21,15 +21,17 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.misc', )] -class StandaloneReplicationInfoBox extends AbstractInfoBox +final readonly class StandaloneReplicationInfoBox implements InfoBoxInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Standalone or Replication'; - protected const TITLE = 'Standalone or Replication'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Slave_running'])) { + if (!isset($this->statusValues['Slave_running'])) { return ''; } @@ -41,7 +43,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), - $this->getStatusValues()['Slave_running'], + $this->statusValues['Slave_running'], ); } } diff --git a/Classes/InfoBox/Misc/SyncBinaryLogInfoBox.php b/Classes/InfoBox/Misc/SyncBinaryLogInfoBox.php index efc57e2..e740de1 100644 --- a/Classes/InfoBox/Misc/SyncBinaryLogInfoBox.php +++ b/Classes/InfoBox/Misc/SyncBinaryLogInfoBox.php @@ -11,8 +11,8 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -21,16 +21,18 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.misc', )] -class SyncBinaryLogInfoBox extends AbstractInfoBox +final readonly class SyncBinaryLogInfoBox implements InfoBoxInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Sync Binary Log'; - protected const TITLE = 'Sync Binary Log'; + public function __construct( + private StatusValues $statusValues, + ) {} - public function renderBody(): string + public function getBody(): string { // Sync_binlog does not exist on MariaDB - if (!isset($this->getStatusValues()['Sync_binlog'])) { + if (!isset($this->statusValues['Sync_binlog'])) { return ''; } @@ -43,7 +45,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), - $this->getStatusValues()['Sync_binlog'] ? 'ON' : 'OFF', + $this->statusValues['Sync_binlog'] ? 'ON' : 'OFF', ); } } diff --git a/Classes/InfoBox/Misc/TempTablesInfoBox.php b/Classes/InfoBox/Misc/TempTablesInfoBox.php index 8c21800..8326a88 100644 --- a/Classes/InfoBox/Misc/TempTablesInfoBox.php +++ b/Classes/InfoBox/Misc/TempTablesInfoBox.php @@ -11,10 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\Misc; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,13 +25,16 @@ name: 'mysqlreport.infobox.misc', attributes: ['priority' => 80], )] -class TempTablesInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class TempTablesInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Temporary Tables'; - protected const TITLE = 'Temporary Tables'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { $content = []; $content[] = 'While JOIN and GROUP BY the server needs a lot of memory to manage the requested data.'; @@ -49,34 +53,34 @@ public function getUnorderedList(): \SplQueue $unorderedList = new \SplQueue(); if (isset( - $this->getVariables()['tmp_table_size'], - $this->getVariables()['max_heap_table_size'], + $this->variables['tmp_table_size'], + $this->variables['max_heap_table_size'], )) { $unorderedList->enqueue(new ListElement( title: 'Configured max size of temp table while query (tmp_table_size)', - value: $this->getVariables()['tmp_table_size'], + value: $this->variables['tmp_table_size'], )); $unorderedList->enqueue(new ListElement( title: 'Configured max size of in-memory table YOU can create (max_heap_table_size)', - value: $this->getVariables()['max_heap_table_size'], + value: $this->variables['max_heap_table_size'], )); $unorderedList->enqueue(new ListElement( title: 'Real max size. Lowest value of tmp_table_size/max_heap_table_size wins', - value: $this->getVariables()['max_heap_table_size'] < $this->getVariables()['tmp_table_size'] - ? $this->getVariables()['max_heap_table_size'] - : $this->getVariables()['tmp_table_size'], + value: $this->variables['max_heap_table_size'] < $this->variables['tmp_table_size'] + ? $this->variables['max_heap_table_size'] + : $this->variables['tmp_table_size'], )); } - if (isset($this->getStatusValues()['Created_tmp_disk_tables'])) { + if (isset($this->statusValues['Created_tmp_disk_tables'])) { $unorderedList->enqueue(new ListElement( title: 'Created temporary tables on disk since server start', - value: $this->getStatusValues()['Created_tmp_disk_tables'], + value: $this->statusValues['Created_tmp_disk_tables'], )); $unorderedList->enqueue(new ListElement( title: 'Created temporary tables on disk in seconds', value: number_format( - $this->getStatusValues()['Created_tmp_disk_tables'] / $this->getStatusValues()['Uptime'], + $this->statusValues['Created_tmp_disk_tables'] / $this->statusValues['Uptime'], 2, ',', '.', @@ -84,15 +88,15 @@ public function getUnorderedList(): \SplQueue )); } - if (isset($this->getStatusValues()['Created_tmp_tables'])) { + if (isset($this->statusValues['Created_tmp_tables'])) { $unorderedList->enqueue(new ListElement( title: 'Created temporary tables on disk and ram since server start', - value: $this->getStatusValues()['Created_tmp_tables'], + value: $this->statusValues['Created_tmp_tables'], )); $unorderedList->enqueue(new ListElement( title: 'Created temporary tables on disk and ram in seconds', value: number_format( - $this->getStatusValues()['Created_tmp_tables'] / $this->getStatusValues()['Uptime'], + $this->statusValues['Created_tmp_tables'] / $this->statusValues['Uptime'], 2, ',', '.', @@ -103,13 +107,13 @@ public function getUnorderedList(): \SplQueue // If not set, InnoDB is the new default $unorderedList->enqueue(new ListElement( title: 'Storage engine for temp. tables on disk', - value: $this->getVariables()['internal_tmp_disk_storage_engine'] ?? 'InnoDB', + value: $this->variables['internal_tmp_disk_storage_engine'] ?? 'InnoDB', )); // If not set, MEMORY was the old default $unorderedList->enqueue(new ListElement( title: 'Storage engine for temp. tables in ram', - value: $this->getVariables()['internal_tmp_mem_storage_engine'] ?? 'MEMORY', + value: $this->variables['internal_tmp_mem_storage_engine'] ?? 'MEMORY', )); return $unorderedList; diff --git a/Classes/InfoBox/QueryCache/AverageQuerySizeInfoBox.php b/Classes/InfoBox/QueryCache/AverageQuerySizeInfoBox.php index d076a3f..3ab5058 100644 --- a/Classes/InfoBox/QueryCache/AverageQuerySizeInfoBox.php +++ b/Classes/InfoBox/QueryCache/AverageQuerySizeInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,25 +25,22 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.query_cache', )] -class AverageQuerySizeInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class AverageQuerySizeInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Average Query Size'; - protected const TITLE = 'Average Query Size'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_queries_in_cache']) - || (int)$this->getStatusValues()['Qcache_queries_in_cache'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_queries_in_cache']) + || (int)$this->statusValues['Qcache_queries_in_cache'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -53,13 +51,13 @@ public function renderBody(): string return sprintf( implode(' ', $content), $this->getAvgQuerySize(), - $this->getVariables()['query_cache_min_res_unit'], + $this->variables['query_cache_min_res_unit'], ); } - protected function getAvgQuerySize(): float + private function getAvgQuerySize(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $avgQuerySize = 0; if ($status['Qcache_queries_in_cache']) { @@ -69,10 +67,10 @@ protected function getAvgQuerySize(): float return round($avgQuerySize, 4); } - protected function getUsedQueryCacheSize(): int + private function getUsedQueryCacheSize(): int { - $status = $this->getStatusValues(); - $variables = $this->getVariables(); + $status = $this->statusValues; + $variables = $this->variables; // ~40KB are reserved by the operating system $queryCacheSize = $variables['query_cache_size'] - (40 * 1024); @@ -82,15 +80,13 @@ protected function getUsedQueryCacheSize(): int public function getState(): StateEnumeration { - $variables = $this->getVariables(); + $variables = $this->variables; $avgQuerySize = $this->getAvgQuerySize(); if ($avgQuerySize > $variables['query_cache_min_res_unit']) { - $state = StateEnumeration::STATE_ERROR; - } else { - $state = StateEnumeration::STATE_OK; + return StateEnumeration::STATE_ERROR; } - return $state; + return StateEnumeration::STATE_OK; } } diff --git a/Classes/InfoBox/QueryCache/AverageUsedBlocksInfoBox.php b/Classes/InfoBox/QueryCache/AverageUsedBlocksInfoBox.php index be9905d..419e967 100644 --- a/Classes/InfoBox/QueryCache/AverageUsedBlocksInfoBox.php +++ b/Classes/InfoBox/QueryCache/AverageUsedBlocksInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,25 +25,22 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.query_cache', )] -class AverageUsedBlocksInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface +final readonly class AverageUsedBlocksInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Average Used Blocks'; - protected const TITLE = 'Average Used Blocks'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_queries_in_cache']) - || (int)$this->getStatusValues()['Qcache_queries_in_cache'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_queries_in_cache']) + || (int)$this->statusValues['Qcache_queries_in_cache'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -54,7 +52,7 @@ public function renderBody(): string return sprintf( implode(' ', $content), $this->getAvgUsedBlocks(), - $this->getVariables()['query_cache_limit'], + $this->variables['query_cache_limit'], ); } @@ -65,9 +63,9 @@ public function renderBody(): string * * @link: http://dev.mysql.com/doc/refman/5.0/en/query-cache-status-and-maintenance.html */ - protected function getAvgUsedBlocks(): float + private function getAvgUsedBlocks(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $avgUsedBlocks = 0; $usedBlocks = $status['Qcache_total_blocks'] - $status['Qcache_free_blocks']; diff --git a/Classes/InfoBox/QueryCache/FragmentationRatioInfoBox.php b/Classes/InfoBox/QueryCache/FragmentationRatioInfoBox.php index 79a941e..32aaab8 100644 --- a/Classes/InfoBox/QueryCache/FragmentationRatioInfoBox.php +++ b/Classes/InfoBox/QueryCache/FragmentationRatioInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,25 +25,22 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.query_cache', )] -class FragmentationRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class FragmentationRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Fragmentation Ratio'; - protected const TITLE = 'Fragmentation Ratio'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_total_blocks']) - || (int)$this->getStatusValues()['Qcache_total_blocks'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_total_blocks']) + || (int)$this->statusValues['Qcache_total_blocks'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -61,9 +59,9 @@ public function renderBody(): string ); } - protected function getFragmentationRatio(): float + private function getFragmentationRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; // total blocks / 2 = maximum fragmentation $fragmentation = ($status['Qcache_free_blocks'] / ($status['Qcache_total_blocks'] / 2)) * 100; diff --git a/Classes/InfoBox/QueryCache/HitRatioInfoBox.php b/Classes/InfoBox/QueryCache/HitRatioInfoBox.php index 6690108..9584ca6 100644 --- a/Classes/InfoBox/QueryCache/HitRatioInfoBox.php +++ b/Classes/InfoBox/QueryCache/HitRatioInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -25,25 +26,22 @@ name: 'mysqlreport.infobox.query_cache', attributes: ['priority' => 80], )] -class HitRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class HitRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Hit Ratio'; - protected const TITLE = 'Hit Ratio'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_hits']) - || (int)$this->getStatusValues()['Qcache_hits'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_hits']) + || (int)$this->statusValues['Qcache_hits'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -59,9 +57,9 @@ public function renderBody(): string ); } - protected function getHitRatio(): float + private function getHitRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $hitRatio = ($status['Qcache_hits'] / ($status['Qcache_hits'] + $status['Com_select'])) * 100; diff --git a/Classes/InfoBox/QueryCache/InsertRatioInfoBox.php b/Classes/InfoBox/QueryCache/InsertRatioInfoBox.php index 52b1e04..7d99d1c 100644 --- a/Classes/InfoBox/QueryCache/InsertRatioInfoBox.php +++ b/Classes/InfoBox/QueryCache/InsertRatioInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -25,25 +26,22 @@ name: 'mysqlreport.infobox.query_cache', attributes: ['priority' => 80], )] -class InsertRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class InsertRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Insert Ratio'; - protected const TITLE = 'Insert Ratio'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_hits']) - || (int)$this->getStatusValues()['Qcache_hits'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_hits']) + || (int)$this->statusValues['Qcache_hits'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -61,9 +59,9 @@ public function renderBody(): string ); } - protected function getInsertRatio(): float + private function getInsertRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $insertRatio = ($status['Qcache_inserts'] / ($status['Qcache_hits'] + $status['Com_select'])) * 100; diff --git a/Classes/InfoBox/QueryCache/PruneRatioInfoBox.php b/Classes/InfoBox/QueryCache/PruneRatioInfoBox.php index a479145..10a17e5 100644 --- a/Classes/InfoBox/QueryCache/PruneRatioInfoBox.php +++ b/Classes/InfoBox/QueryCache/PruneRatioInfoBox.php @@ -11,11 +11,12 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -25,25 +26,22 @@ name: 'mysqlreport.infobox.query_cache', attributes: ['priority' => 80], )] -class PruneRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class PruneRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Prune Ratio'; - protected const TITLE = 'Prune Ratio'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getStatusValues()['Qcache_inserts']) - || (int)$this->getStatusValues()['Qcache_inserts'] === 0 - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->statusValues['Qcache_inserts']) + || (int)$this->statusValues['Qcache_inserts'] === 0 + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } @@ -69,9 +67,9 @@ public function renderBody(): string ); } - protected function getPruneRatio(): float + private function getPruneRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $pruneRatio = 0; if ($status['Qcache_inserts']) { diff --git a/Classes/InfoBox/QueryCache/QueryCacheSizeTooHighInfoBox.php b/Classes/InfoBox/QueryCache/QueryCacheSizeTooHighInfoBox.php index bc596df..de031bc 100644 --- a/Classes/InfoBox/QueryCache/QueryCacheSizeTooHighInfoBox.php +++ b/Classes/InfoBox/QueryCache/QueryCacheSizeTooHighInfoBox.php @@ -11,11 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -24,29 +24,25 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.query_cache', )] -class QueryCacheSizeTooHighInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class QueryCacheSizeTooHighInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Query Cache too high'; - protected const TITLE = 'Query Cache too high'; + public function __construct( + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { if ( - !isset($this->getVariables()['query_cache_size']) - || !$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables()) + !isset($this->variables['query_cache_size']) + || !$this->queryCacheHelper->isQueryCacheEnabled($this->variables) ) { return ''; } - if ($this->getVariables()['query_cache_size'] < 268435456) { + if ($this->variables['query_cache_size'] < 268435456) { return ''; } diff --git a/Classes/InfoBox/QueryCache/QueryCacheStatusInfoBox.php b/Classes/InfoBox/QueryCache/QueryCacheStatusInfoBox.php index bdf0d2d..a6871fc 100644 --- a/Classes/InfoBox/QueryCache/QueryCacheStatusInfoBox.php +++ b/Classes/InfoBox/QueryCache/QueryCacheStatusInfoBox.php @@ -11,11 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\QueryCache; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; use StefanFroemken\Mysqlreport\Helper\QueryCacheHelper; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -25,26 +25,22 @@ name: 'mysqlreport.infobox.query_cache', attributes: ['priority' => 90], )] -class QueryCacheStatusInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class QueryCacheStatusInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Query Cache Status'; - protected const TITLE = 'Query Cache Status'; + public function __construct( + private Variables $variables, + private QueryCacheHelper $queryCacheHelper, + ) {} - private QueryCacheHelper $queryCacheHelper; - - public function injectQueryCacheHelper(QueryCacheHelper $queryCacheHelper): void - { - $this->queryCacheHelper = $queryCacheHelper; - } - - public function renderBody(): string + public function getBody(): string { - if (!$this->queryCacheHelper->isQueryCacheEnabled($this->getVariables())) { + if (!$this->queryCacheHelper->isQueryCacheEnabled($this->variables)) { return 'Query Cache is not activated'; } - if ((int)($this->getVariables()['query_cache_size']) === 0) { + if ((int)($this->variables['query_cache_size']) === 0) { return 'Query Cache is activated, but query_cache_size can not be 0'; } diff --git a/Classes/InfoBox/RenderInfoBoxFactory.php b/Classes/InfoBox/RenderInfoBoxFactory.php new file mode 100644 index 0000000..2efd6e3 --- /dev/null +++ b/Classes/InfoBox/RenderInfoBoxFactory.php @@ -0,0 +1,64 @@ + $infoBoxes + */ + public function render(iterable $infoBoxes): string + { + $renderedInfoBoxes = ''; + foreach ($infoBoxes as $infoBox) { + $body = $infoBox->getBody(); + if ($body === '') { + continue; + } + + $view = $this->getViewForInfoBox(); + $view->assign('title', $infoBox::TITLE); + $view->assign('body', $body); + + if ($infoBox instanceof InfoBoxUnorderedListInterface) { + $view->assign('unorderedList', $infoBox->getUnorderedList()); + } + + if ($infoBox instanceof InfoBoxStateInterface) { + $view->assign('state', $infoBox->getState()->value); + } + + $renderedInfoBoxes .= $view->render(); + } + + return $renderedInfoBoxes; + } + + private function getViewForInfoBox(): ViewInterface + { + $viewFactoryData = new ViewFactoryData( + templatePathAndFilename: self::TEMPLATE_FILE, + ); + + return $this->viewFactory->create($viewFactoryData); + } +} diff --git a/Classes/InfoBox/TableCache/OpenedTableDefinitionsInfoBox.php b/Classes/InfoBox/TableCache/OpenedTableDefinitionsInfoBox.php index f30fa70..cebda20 100644 --- a/Classes/InfoBox/TableCache/OpenedTableDefinitionsInfoBox.php +++ b/Classes/InfoBox/TableCache/OpenedTableDefinitionsInfoBox.php @@ -11,12 +11,13 @@ namespace StefanFroemken\Mysqlreport\InfoBox\TableCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -28,15 +29,18 @@ name: 'mysqlreport.infobox.table_cache', attributes: ['priority' => 80], )] -class OpenedTableDefinitionsInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface, InfoBoxStateInterface +final readonly class OpenedTableDefinitionsInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Opened Table Definitions'; - protected const TITLE = 'Opened Table Definitions'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Opened_table_definitions'])) { + if (!isset($this->statusValues['Opened_table_definitions'])) { return ''; } @@ -47,9 +51,9 @@ public function renderBody(): string /** * Get the number of opened table definitions each second */ - protected function getOpenedTableDefinitionsEachSecond(): float + private function getOpenedTableDefinitionsEachSecond(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $openedTableDefinitions = $status['Opened_table_definitions'] / $status['Uptime']; @@ -65,17 +69,17 @@ public function getUnorderedList(): \SplQueue $unorderedList->enqueue(new ListElement( title: 'Opened tables since server start (Opened_table_definitions)', - value: $this->getStatusValues()['Opened_table_definitions'], + value: $this->statusValues['Opened_table_definitions'], )); $unorderedList->enqueue(new ListElement( title: 'Open tables in cache (Open_table_definitions)', - value: $this->getStatusValues()['Open_table_definitions'], + value: $this->statusValues['Open_table_definitions'], )); $unorderedList->enqueue(new ListElement( title: 'Max allowed tables in cache (table_definition_cache)', - value: $this->getVariables()['table_definition_cache'], + value: $this->variables['table_definition_cache'], )); $unorderedList->enqueue(new ListElement( diff --git a/Classes/InfoBox/TableCache/OpenedTablesInfoBox.php b/Classes/InfoBox/TableCache/OpenedTablesInfoBox.php index c667365..e19e206 100644 --- a/Classes/InfoBox/TableCache/OpenedTablesInfoBox.php +++ b/Classes/InfoBox/TableCache/OpenedTablesInfoBox.php @@ -11,12 +11,13 @@ namespace StefanFroemken\Mysqlreport\InfoBox\TableCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxUnorderedListInterface; use StefanFroemken\Mysqlreport\InfoBox\ListElement; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -28,15 +29,18 @@ name: 'mysqlreport.infobox.table_cache', attributes: ['priority' => 90], )] -class OpenedTablesInfoBox extends AbstractInfoBox implements InfoBoxUnorderedListInterface, InfoBoxStateInterface +final readonly class OpenedTablesInfoBox implements InfoBoxInterface, InfoBoxUnorderedListInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Opened Tables'; - protected const TITLE = 'Opened Tables'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getStatusValues()['Opened_tables'])) { + if (!isset($this->statusValues['Opened_tables'])) { return ''; } @@ -50,9 +54,9 @@ public function renderBody(): string /** * get number of opened tables each second */ - protected function getOpenedTablesEachSecond(): float + private function getOpenedTablesEachSecond(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $openedTables = $status['Opened_tables'] / $status['Uptime']; return round($openedTables, 4); @@ -67,28 +71,28 @@ public function getUnorderedList(): \SplQueue $unorderedList->enqueue(new ListElement( title: 'Opened tables since server start (Opened_tables)', - value: $this->getStatusValues()['Opened_tables'], + value: $this->statusValues['Opened_tables'], )); $unorderedList->enqueue(new ListElement( title: 'Open tables in cache (Open_tables)', - value: $this->getStatusValues()['Open_tables'], + value: $this->statusValues['Open_tables'], )); $unorderedList->enqueue(new ListElement( title: 'Max allowed tables in cache (table_open_cache)', - value: $this->getVariables()['table_open_cache'], + value: $this->variables['table_open_cache'], )); $unorderedList->enqueue(new ListElement( title: 'Max file descriptors the mysqld process can use (open_files_limit)', - value: $this->getVariables()['open_files_limit'], + value: $this->variables['open_files_limit'], )); $unorderedList->enqueue(new ListElement( title: 'Calculated table_open_cache with 5 tables and 2 reserved file descriptors', value: number_format( - $this->getVariables()['max_connections'] * (5 + 2), + $this->variables['max_connections'] * (5 + 2), 0, ',', '.', @@ -98,7 +102,7 @@ public function getUnorderedList(): \SplQueue $unorderedList->enqueue(new ListElement( title: 'Calculated table_open_cache with 8 tables and 3 reserved file descriptors', value: number_format( - $this->getVariables()['max_connections'] * (8 + 3), + $this->variables['max_connections'] * (8 + 3), 0, ',', '.', diff --git a/Classes/InfoBox/ThreadCache/HitRatioInfoBox.php b/Classes/InfoBox/ThreadCache/HitRatioInfoBox.php index 253a224..12464d8 100644 --- a/Classes/InfoBox/ThreadCache/HitRatioInfoBox.php +++ b/Classes/InfoBox/ThreadCache/HitRatioInfoBox.php @@ -11,10 +11,11 @@ namespace StefanFroemken\Mysqlreport\InfoBox\ThreadCache; +use StefanFroemken\Mysqlreport\Domain\Model\StatusValues; +use StefanFroemken\Mysqlreport\Domain\Model\Variables; use StefanFroemken\Mysqlreport\Enumeration\StateEnumeration; -use StefanFroemken\Mysqlreport\InfoBox\AbstractInfoBox; +use StefanFroemken\Mysqlreport\InfoBox\InfoBoxInterface; use StefanFroemken\Mysqlreport\InfoBox\InfoBoxStateInterface; -use StefanFroemken\Mysqlreport\Traits\GetStatusValuesAndVariablesTrait; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; /** @@ -23,15 +24,18 @@ #[AutoconfigureTag( name: 'mysqlreport.infobox.thread_cache', )] -class HitRatioInfoBox extends AbstractInfoBox implements InfoBoxStateInterface +final readonly class HitRatioInfoBox implements InfoBoxInterface, InfoBoxStateInterface { - use GetStatusValuesAndVariablesTrait; + public const TITLE = 'Hit Ratio'; - protected const TITLE = 'Hit Ratio'; + public function __construct( + private StatusValues $statusValues, + private Variables $variables, + ) {} - public function renderBody(): string + public function getBody(): string { - if (!isset($this->getVariables()['thread_cache_size'])) { + if (!isset($this->variables['thread_cache_size'])) { return ''; } @@ -39,12 +43,12 @@ public function renderBody(): string $content[] = 'As closer to 100%% as better.'; $content[] = "\n\n"; - if ((int)$this->getVariables()['thread_cache_size'] === 0) { + if ((int)$this->variables['thread_cache_size'] === 0) { $content[] = 'Your thread_cache_size (0) is not activated. Please set this value 10.'; - } elseif ($this->getStatusValues()['Threads_connected'] < $this->getVariables()['thread_cache_size']) { + } elseif ($this->statusValues['Threads_connected'] < $this->variables['thread_cache_size']) { $content[] = 'It seems that you are the only person on this MySQL-Server, so this value should be OK.'; } else { - $content[] = 'It seems that your thread_cache_size (' . $this->getVariables()['thread_cache_size'] . ') is too low.'; + $content[] = 'It seems that your thread_cache_size (' . $this->variables['thread_cache_size'] . ') is too low.'; $content[] = 'Please increase this value in 10th steps.'; } @@ -61,9 +65,9 @@ public function renderBody(): string * get hit ratio of threads cache * A ratio nearly 100 would be cool */ - protected function getHitRatio(): float + private function getHitRatio(): float { - $status = $this->getStatusValues(); + $status = $this->statusValues; $hitRatio = 100 - (($status['Threads_created'] / $status['Connections']) * 100); diff --git a/Classes/Menu/Page.php b/Classes/Menu/Page.php deleted file mode 100644 index b8431e6..0000000 --- a/Classes/Menu/Page.php +++ /dev/null @@ -1,74 +0,0 @@ - $infoBoxes - */ - public function __construct( - private iterable $infoBoxes, - private ViewFactoryInterface $viewFactory, - ) {} - - public function getRenderedInfoBoxes(): string - { - $renderedInfoBoxes = ''; - foreach ($this->infoBoxes as $infoBox) { - if ($view = $infoBox->updateView($this->getViewForInfoBox())) { - $renderedInfoBoxes .= $view->render(); - } - } - - return $renderedInfoBoxes; - } - - private function getViewForInfoBox(): ViewInterface - { - $viewFactoryData = new ViewFactoryData( - templatePathAndFilename: self::TEMPLATE_FILE, - ); - - return $this->viewFactory->create($viewFactoryData); - } -} diff --git a/Classes/Traits/GetStatusValuesAndVariablesTrait.php b/Classes/Traits/GetStatusValuesAndVariablesTrait.php deleted file mode 100644 index 289553a..0000000 --- a/Classes/Traits/GetStatusValuesAndVariablesTrait.php +++ /dev/null @@ -1,47 +0,0 @@ -statusRepository = $statusRepository; - } - - public function injectVariablesRepository(VariablesRepository $variablesRepository): void - { - $this->variablesRepository = $variablesRepository; - } - - private function getStatusValues(): StatusValues - { - return $this->statusRepository->findAll(); - } - - private function getVariables(): Variables - { - return $this->variablesRepository->findAll(); - } -} diff --git a/Configuration/Backend/DashboardPresets.php b/Configuration/Backend/DashboardPresets.php index 80f2ff9..f310f19 100644 --- a/Configuration/Backend/DashboardPresets.php +++ b/Configuration/Backend/DashboardPresets.php @@ -2,6 +2,8 @@ declare(strict_types=1); +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; + /* * This file is part of the package stefanfroemken/mysqlreport. * @@ -9,7 +11,7 @@ * LICENSE file that was distributed with this source code. */ -if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dashboard')) { +if (ExtensionManagementUtility::isLoaded('dashboard')) { return [ 'mysqlreport' => [ 'title' => 'LLL:EXT:mysqlreport/Resources/Private/Language/locallang.xlf:dashboard.mysqlreport.title', @@ -25,6 +27,5 @@ 'showInWizard' => true, ], ]; -} else { - return []; } +return []; diff --git a/Configuration/Backend/DashboardWidgetGroups.php b/Configuration/Backend/DashboardWidgetGroups.php index e2e639e..c07c252 100644 --- a/Configuration/Backend/DashboardWidgetGroups.php +++ b/Configuration/Backend/DashboardWidgetGroups.php @@ -2,6 +2,8 @@ declare(strict_types=1); +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; + /* * This file is part of the package stefanfroemken/mysqlreport. * @@ -9,12 +11,11 @@ * LICENSE file that was distributed with this source code. */ -if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dashboard')) { +if (ExtensionManagementUtility::isLoaded('dashboard')) { return [ 'mysqlreport' => [ 'title' => 'LLL:EXT:mysqlreport/Resources/Private/Language/locallang.xlf:widget.group.mysqlreport', ], ]; -} else { - return []; } +return []; diff --git a/Configuration/Services.php b/Configuration/Services.php index bd31e4e..83c5044 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -2,14 +2,15 @@ declare(strict_types=1); -use StefanFroemken\Mysqlreport\DependencyInjection; +use StefanFroemken\Mysqlreport\DependencyInjection\DashboardPass; +use Symfony\Component\Config\Resource\ComposerResource; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -return static function (ContainerConfigurator $container, ContainerBuilder $containerBuilder) { - $containerBuilder->addCompilerPass(new DependencyInjection\DashboardPass('dashboard.widget')); +return static function (ContainerConfigurator $container, ContainerBuilder $containerBuilder): void { + $containerBuilder->addCompilerPass(new DashboardPass('dashboard.widget')); - $composerResource = new \Symfony\Component\Config\Resource\ComposerResource(); + $composerResource = new ComposerResource(); foreach ($composerResource->getVendors() as $vendorPath) { $sqlFormatterDir = $vendorPath . '/doctrine/sql-formatter/src'; if (is_dir($sqlFormatterDir)) { diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 6e7d78b..bfdbb9e 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -9,6 +9,9 @@ services: autowire: true autoconfigure: true public: false + bind: + StefanFroemken\Mysqlreport\Domain\Model\StatusValues: '@mysqlreport.status' + StefanFroemken\Mysqlreport\Domain\Model\Variables: '@mysqlreport.variables' StefanFroemken\Mysqlreport\: resource: '../Classes/*' @@ -16,29 +19,13 @@ services: - '../Classes/Domain/Model/*' - '../Classes/InfoBox/ListElement.php' - mysqlreport.page.information: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.status' }] + mysqlreport.status: + class: StefanFroemken\Mysqlreport\Domain\Model\StatusValues + factory: ['@StefanFroemken\Mysqlreport\Domain\Repository\StatusRepository', 'findAll'] - mysqlreport.page.innodb: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.innodb' }] - - mysqlreport.page.misc: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.misc' }] - - mysqlreport.page.query_cache: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.query_cache' }] - - mysqlreport.page.table_cache: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.table_cache' }] - - mysqlreport.page.thread_cache: - class: StefanFroemken\Mysqlreport\Menu\Page - arguments: [!tagged_iterator { tag: 'mysqlreport.infobox.thread_cache' }] + mysqlreport.variables: + class: StefanFroemken\Mysqlreport\Domain\Model\Variables + factory: ['@StefanFroemken\Mysqlreport\Domain\Repository\VariablesRepository', 'findAll'] # Will be called via GeneralUtility::makeInstance in LoggerWithQueryTimeMiddleware and LoggerWithQueryTimeConnection StefanFroemken\Mysqlreport\Configuration\ExtConf: @@ -46,27 +33,27 @@ services: StefanFroemken\Mysqlreport\Controller\InnoDBController: arguments: - $page: '@mysqlreport.page.innodb' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.innodb' } StefanFroemken\Mysqlreport\Controller\MiscController: arguments: - $page: '@mysqlreport.page.misc' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.misc' } StefanFroemken\Mysqlreport\Controller\QueryCacheController: arguments: - $page: '@mysqlreport.page.query_cache' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.query_cache' } StefanFroemken\Mysqlreport\Controller\StatusController: arguments: - $page: '@mysqlreport.page.information' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.status' } StefanFroemken\Mysqlreport\Controller\TableCacheController: arguments: - $page: '@mysqlreport.page.table_cache' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.table_cache' } StefanFroemken\Mysqlreport\Controller\ThreadCacheController: arguments: - $page: '@mysqlreport.page.thread_cache' + $infoBoxes: !tagged_iterator { tag: 'mysqlreport.infobox.thread_cache' } # Will be called via GeneralUtility::makeInstance in ConnectionPool StefanFroemken\Mysqlreport\Doctrine\Middleware\LoggerWithQueryTimeMiddleware: @@ -97,8 +84,6 @@ services: StefanFroemken\Mysqlreport\Controller\ProfileController: public: true - StefanFroemken\Mysqlreport\Controller\QueryController: - public: true # Will be called via GeneralUtility::makeInstance in LoggerWithQueryTimeConnection StefanFroemken\Mysqlreport\Domain\Repository\QueryInformationRepository: diff --git a/Configuration/TCA/tx_mysqlreport_query_information.php b/Configuration/TCA/tx_mysqlreport_query_information.php index 0b31dce..9d834f9 100644 --- a/Configuration/TCA/tx_mysqlreport_query_information.php +++ b/Configuration/TCA/tx_mysqlreport_query_information.php @@ -1,5 +1,7 @@ extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([]); @@ -64,7 +64,7 @@ public function isEnableFrontendLoggingInitiallyReturnsFalse(): void public function setEnableFrontendLoggingSetsEnableFrontendLogging(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ @@ -82,7 +82,7 @@ public function setEnableFrontendLoggingSetsEnableFrontendLogging(): void public function isEnableBackendLoggingInitiallyReturnsFalse(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([]); @@ -98,7 +98,7 @@ public function isEnableBackendLoggingInitiallyReturnsFalse(): void public function setEnableBackendLoggingSetsEnableBackendLogging(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ @@ -116,7 +116,7 @@ public function setEnableBackendLoggingSetsEnableBackendLogging(): void public function isActivateExplainQueryInitiallyReturnsFalse(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([]); @@ -132,7 +132,7 @@ public function isActivateExplainQueryInitiallyReturnsFalse(): void public function setActivateExplainQuerySetsActivateExplainQuery(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ @@ -150,7 +150,7 @@ public function setActivateExplainQuerySetsActivateExplainQuery(): void public function getSlowQueryThresholdInitiallyReturns10Seconds(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([]); @@ -167,7 +167,7 @@ public function getSlowQueryThresholdInitiallyReturns10Seconds(): void public function setSlowQueryThresholdWithIntegerSetsSlowQueryThreshold(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ @@ -186,7 +186,7 @@ public function setSlowQueryThresholdWithIntegerSetsSlowQueryThreshold(): void public function setSlowQueryThresholdWithFloatSetsSlowQueryThreshold(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ @@ -205,7 +205,7 @@ public function setSlowQueryThresholdWithFloatSetsSlowQueryThreshold(): void public function setSlowQueryThresholdWithCommaFloatSetsSlowQueryThreshold(): void { $this->extensionConfigurationMock - ->expects(self::once()) + ->expects($this->once()) ->method('get') ->with('mysqlreport') ->willReturn([ diff --git a/Tests/Unit/Domain/Factory/QueryInformationFactoryTest.php b/Tests/Unit/Domain/Factory/QueryInformationFactoryTest.php index b4812aa..fd2d61f 100644 --- a/Tests/Unit/Domain/Factory/QueryInformationFactoryTest.php +++ b/Tests/Unit/Domain/Factory/QueryInformationFactoryTest.php @@ -13,10 +13,14 @@ use PHPUnit\Framework\Attributes\Test; use StefanFroemken\Mysqlreport\Domain\Factory\QueryInformationFactory; +use TYPO3\CMS\Core\Context\Context; +use TYPO3\CMS\Core\Context\DateTimeAspect; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder; +use TYPO3\CMS\Core\Http\NormalizedParams; use TYPO3\CMS\Core\Http\ServerRequest; use TYPO3\CMS\Core\Routing\PageArguments; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; /** @@ -32,7 +36,8 @@ protected function setUp(): void { $this->time = time(); - $GLOBALS['EXEC_TIME'] = $this->time; + $context = GeneralUtility::makeInstance(Context::class); + $context->setAspect('date', new DateTimeAspect(new \DateTimeImmutable('@' . $this->time))); $_SERVER = array_merge($_SERVER, [ 'REMOTE_ADDR' => '123.124.125.126', @@ -44,7 +49,8 @@ protected function setUp(): void $GLOBALS['TYPO3_REQUEST'] = (new ServerRequest('https://www.example.com/', 'GET', 'php://input', [], $_SERVER)) ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE) - ->withAttribute('routing', new PageArguments(1, '0', [])); + ->withAttribute('routing', new PageArguments(1, '0', [])) + ->withAttribute('normalizedParams', NormalizedParams::createFromServerParams($_SERVER)); Environment::initialize( Environment::getContext(), @@ -66,8 +72,8 @@ protected function tearDown(): void unset( $this->subject, $GLOBALS['TYPO3_REQUEST'], - $GLOBALS['EXEC_TIME'], ); + GeneralUtility::purgeInstances(); } #[Test] diff --git a/composer.json b/composer.json index 9352923..8a21f7b 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "stefanfroemken/mysqlreport", - "description": "Analyze and profile your TYPO3 databases queries", + "description": "MySQL Report - Analyze and profile your TYPO3 database queries", "license": "GPL-2.0-or-later", "type": "typo3-cms-extension", "keywords": [ @@ -35,6 +35,7 @@ "friendsofphp/php-cs-fixer": "^3.88", "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^11.5", + "ssch/typo3-rector": "^3.6", "typo3/cms-dashboard": "^14.0", "typo3/cms-install": "^14.0", "typo3/cms-reports": "^14.0", @@ -71,7 +72,11 @@ }, "extra": { "typo3/cms": { + "Package": { + "providesPackages": {} + }, "extension-key": "mysqlreport", + "version": "5.1.0", "web-dir": ".Build/web" } } diff --git a/ext_emconf.php b/ext_emconf.php index 6030b3d..10e9237 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -11,7 +11,7 @@ 'version' => '5.1.0', 'constraints' => [ 'depends' => [ - 'typo3' => '14.1.0-14.99.99', + 'typo3' => '14.3.0-14.3.99', ], 'conflicts' => [ 'adminpanel' => '', diff --git a/ext_localconf.php b/ext_localconf.php index 3f62f8f..b59f4fc 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,29 +1,34 @@ clearProfiles'; +use Psr\Log\LogLevel; +use StefanFroemken\Mysqlreport\Doctrine\Middleware\LoggerWithQueryTimeMiddleware; +use StefanFroemken\Mysqlreport\EventListener\CacheAction; +use TYPO3\CMS\Core\Log\Writer\FileWriter; - // Register our logger in Doctrine Middleware - $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driverMiddlewares']['mysqlreport-dbal-middleware'] = [ - 'target' => \StefanFroemken\Mysqlreport\Doctrine\Middleware\LoggerWithQueryTimeMiddleware::class, - 'after' => [ - 'typo3/core/custom-platform-driver-middleware', - ], - ]; +// TRUNCATE table tx_mysqlreport_query_information on clear cache action +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'][] + = CacheAction::class . '->clearProfiles'; + +// Register our logger in Doctrine Middleware +$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driverMiddlewares']['mysqlreport-dbal-middleware'] = [ + 'target' => LoggerWithQueryTimeMiddleware::class, + 'after' => [ + 'typo3/core/custom-platform-driver-middleware', + ], +]; - if (!isset($GLOBALS['TYPO3_CONF_VARS']['LOG']['StefanFroemken']['Mysqlreport']['writerConfiguration'])) { - $GLOBALS['TYPO3_CONF_VARS']['LOG']['StefanFroemken']['Mysqlreport']['writerConfiguration'] = [ - \Psr\Log\LogLevel::INFO => [ - \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [ - 'logFileInfix' => 'mysqlreport', - ], +if (!isset($GLOBALS['TYPO3_CONF_VARS']['LOG']['StefanFroemken']['Mysqlreport']['writerConfiguration'])) { + $GLOBALS['TYPO3_CONF_VARS']['LOG']['StefanFroemken']['Mysqlreport']['writerConfiguration'] = [ + LogLevel::INFO => [ + FileWriter::class => [ + 'logFileInfix' => 'mysqlreport', ], - ]; - } -}); + ], + ]; +}