diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..eaac2e1e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,101 @@ +// https://aka.ms/devcontainer.json +{ + "name": "Existing Docker Compose (Extend)", + "dockerComposeFile": [ + "../docker-compose.yml" + ], + "features": { + "ghcr.io/devcontainers/features/sshd:1": { + "version": "latest" + } + }, + "service": "laravel.test", + "workspaceFolder": "/var/www/html", + "customizations": { + "vscode": { + "settings": {}, + "extensions": [ + "aaron-bond.better-comments", + "adrianwilczynski.alpine-js-intellisense", + "amiralizadeh9480.laravel-extra-intellisense", + "austenc.laravel-blade-spacer", + "beyondcode.tinkerwell", + "bmewburn.vscode-intelephense-client", + "bradlc.vscode-tailwindcss", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "cierra.livewire-vscode", + "codingyu.laravel-goto-view", + "davidanson.vscode-markdownlint", + "davidbwaters.macos-modern-theme", + "eamodio.gitlens", + "editorconfig.editorconfig", + "ericcheng.codesongclear", + "faelv.composer-companion", + "file-icons.file-icons", + "foxundermoon.shell-format", + "georgykurian.laravel-ide-helper", + "github.codespaces", + "GitHub.copilot-chat", + "GitHub.copilot-nightly", + "github.vscode-github-actions", + "github.vscode-pull-request-github", + "Gruntfuggly.activitusbar", + "heissenbergerlab.php-array-from-json", + "heybourn.headwind", + "huibizhang.codesnap-plus", + "irongeek.vscode-env", + "kencocaceo.customvscodeuicss", + "m4ns0ur.base64", + "maciejdems.add-to-gitignore", + "mahmoudshahin.laravel-routes", + "markis.code-coverage", + "martybegood.single-editor-tabs", + "mechatroner.rainbow-csv", + "mehedidracula.php-namespace-resolver", + "mhutchie.git-graph", + "mikestead.dotenv", + "mohamedbenhida.laravel-intellisense", + "mrmlnc.vscode-duplicate", + "naoray.laravel-goto-components", + "oderwat.indent-rainbow", + "pcbowers.alpine-intellisense", + "recca0120.vscode-phpunit", + "redhat.vscode-yaml", + "rifi2k.format-html-in-php", + "shevaua.phpcs", + "shufo.vscode-blade-formatter", + "sperovita.alpinejs-syntax-highlight", + "streetsidesoftware.code-spell-checker", + "syler.ignore", + "teabyii.ayu", + "usernamehw.errorlens", + "vincaslt.highlight-matching-tag", + "WakaTime.vscode-wakatime", + "withfig.fig", + "wongjn.php-sniffer", + "xdebug.php-debug", + "codecov.codecov" + ] + } + }, + "remoteUser": "sail", + "postCreateCommand": "sudo chown -R 1000:1000 /var/www/html", + "forwardPorts": [ + 5432, + 6379 + ], + "portsAttributes": { + "5432": { + "label": "Postgres" + }, + "6379": { + "label": "Redis" + } + }, + "mounts": [ + "source=${localEnv:HOME}/.wakatime.cfg,target=/home/sail/.wakatime.cfg,type=bind,consistency=delegated" + ] + // "runServices": [], + // "shutdownAction": "none", +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..bc1105dc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false +indent_size = 2 + +[*.{yml,yaml}] +indent_size = 2 + +[.blackfire.yaml] +indent_size = 4 diff --git a/.github/workflows/laravel.yml b/.github/workflows/laravel.yml index a169f2bb..f5bcd953 100644 --- a/.github/workflows/laravel.yml +++ b/.github/workflows/laravel.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - php: [8.2, 8.1] + php: [8.4, 8.3, 8.2] name: PHP ${{ matrix.php }} @@ -42,9 +42,9 @@ jobs: - uses: harmon758/postgresql-action@v1 with: - postgresql version: '11' + postgresql version: '15' postgresql db: 'testing' - postgresql user: 'homestead' + postgresql user: 'forge' postgresql password: 'secret' - name: Remove Nova on a pull request @@ -56,7 +56,7 @@ jobs: - name: Install Dependencies run: | - composer config "http-basic.nova.laravel.com" "${{ secrets.NOVA_USERNAME }}" "${{ secrets.NOVA_PASSWORD }}" + composer config "http-basic.nova.laravel.com" "${{ secrets.NOVA_USERNAME }}" "${{ secrets.NOVA_LICENSE_KEY }}" composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - name: Execute Integration and Feature tests via PHPUnit diff --git a/.gitignore b/.gitignore index c2d4570f..8fbb4834 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ +.idea +.phpunit.result.cache +/.phpunit* /build /vendor composer.lock -.phpunit.result.cache -phpunit.xml -.idea diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..757b5a7d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,69 @@ +{ + "recommendations": [ + "aaron-bond.better-comments", + "adrianwilczynski.alpine-js-intellisense", + "amiralizadeh9480.laravel-extra-intellisense", + "austenc.laravel-blade-spacer", + "beyondcode.tinkerwell", + "bmewburn.vscode-intelephense-client", + "bradlc.vscode-tailwindcss", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "cierra.livewire-vscode", + "codingyu.laravel-goto-view", + "davidanson.vscode-markdownlint", + "davidbwaters.macos-modern-theme", + "eamodio.gitlens", + "editorconfig.editorconfig", + "ericcheng.codesongclear", + "faelv.composer-companion", + "file-icons.file-icons", + "foxundermoon.shell-format", + "georgykurian.laravel-ide-helper", + "github.codespaces", + "GitHub.copilot-chat", + "GitHub.copilot-nightly", + "github.vscode-github-actions", + "github.vscode-pull-request-github", + "Gruntfuggly.activitusbar", + "heissenbergerlab.php-array-from-json", + "heybourn.headwind", + "huibizhang.codesnap-plus", + "irongeek.vscode-env", + "kencocaceo.customvscodeuicss", + "m4ns0ur.base64", + "maciejdems.add-to-gitignore", + "mahmoudshahin.laravel-routes", + "markis.code-coverage", + "martybegood.single-editor-tabs", + "mechatroner.rainbow-csv", + "mehedidracula.php-namespace-resolver", + "mhutchie.git-graph", + "mikestead.dotenv", + "mohamedbenhida.laravel-intellisense", + "mrmlnc.vscode-duplicate", + "naoray.laravel-goto-components", + "oderwat.indent-rainbow", + "pcbowers.alpine-intellisense", + "recca0120.vscode-phpunit", + "redhat.vscode-yaml", + "rifi2k.format-html-in-php", + "shevaua.phpcs", + "shufo.vscode-blade-formatter", + "sperovita.alpinejs-syntax-highlight", + "streetsidesoftware.code-spell-checker", + "syler.ignore", + "teabyii.ayu", + "usernamehw.errorlens", + "vincaslt.highlight-matching-tag", + "WakaTime.vscode-wakatime", + "withfig.fig", + "wongjn.php-sniffer", + "xdebug.php-debug", + "codecov.codecov" + ], + "unwantedRecommendations": [ + "ikappas.phpcs", + "linyang95.phpmd" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e614d03c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,318 @@ +{ + "activitusbar.combineWorkspaceSettings": true, + "activitusbar.searchViewInPanel": false, + "activitusbar.showSourceControlCounter": true, + "activitusbar.views": [ + { + "name": "command.workbench.panel.chatSidebar.copilot", + "codicon": "octoface" + }, + { + "name": "explorer", + "codicon": "explorer-view-icon" + }, + { + "name": "search", + "codicon": "search-view-icon" + }, + { + "name": "pr:github", + "codicon": "github" + }, + { + "name": "scm", + "codicon": "source-control-view-icon" + }, + { + "name": "command.workbench.panel.chatSidebar.copilot", + "codicon": "octoface" + }, + { + "name": "debug", + "codicon": "run-view-icon" + }, + { + "name": "github.codespaces.explorer", + "codicon": "remote-explorer" + }, + { + "name": "extensions", + "codicon": "extensions-view-icon" + }, + { + "codicon": "kebab-vertical" + } + ], + "alpine-intellisense.settings.languageScopes": "html,blade,php", + "better-comments.tags": [ + { + "tag": "!", + "color": "#FF2D00", + "strikethrough": false, + "underline": false, + "backgroundColor": "transparent", + "bold": false, + "italic": false + }, + { + "tag": "?", + "color": "#3498DB", + "strikethrough": false, + "underline": false, + "backgroundColor": "transparent", + "bold": false, + "italic": false + }, + { + "tag": "//", + "color": "#474747", + "strikethrough": true, + "underline": false, + "backgroundColor": "transparent", + "bold": false, + "italic": false + }, + { + "tag": "todo", + "color": "#FF8C00", + "strikethrough": false, + "underline": false, + "backgroundColor": "transparent", + "bold": false, + "italic": false + }, + { + "tag": "*", + "color": "#98C379", + "strikethrough": false, + "underline": false, + "backgroundColor": "transparent", + "bold": false, + "italic": false + } + ], + "blade.format.enable": true, + "blade.newLine": true, + "bladeFormatter.format.enabled": true, + "bladeFormatter.format.noMultipleEmptyLines": true, + "bladeFormatter.format.sortHtmlAttributes": "alphabetical", + "bladeFormatter.format.sortTailwindcssClasses": true, + "bladeFormatter.format.wrapAttributes": "force-expand-multiline", + "bladeFormatter.format.wrapLineLength": 100, + "breadcrumbs.enabled": true, + "composerCompanion.executablePath": "composer", + "cSpell.spellCheckOnlyWorkspaceFiles": true, + "cSpell.autoFormatConfigFile": true, + "css.validate": false, + "debug.allowBreakpointsEverywhere": true, + "debug.showBreakpointsInOverviewRuler": true, + "diffEditor.ignoreTrimWhitespace": false, + "diffEditor.wordWrap": "off", + "editor.acceptSuggestionOnEnter": "off", + "editor.accessibilitySupport": "off", + "editor.autoClosingBrackets": "always", + "editor.codeLensFontFamily": "JetBrains Mono", + "editor.cursorBlinking": "expand", + "editor.cursorSmoothCaretAnimation": "on", + "editor.detectIndentation": true, + "editor.emptySelectionClipboard": false, + "editor.fontFamily": "JetBrains Mono", + "editor.fontLigatures": true, + "editor.formatOnPaste": false, + "editor.formatOnType": true, + "editor.gotoLocation.multipleDeclarations": "goto", + "editor.gotoLocation.multipleDefinitions": "goto", + "editor.gotoLocation.multipleImplementations": "goto", + "editor.gotoLocation.multipleReferences": "goto", + "editor.gotoLocation.multipleTypeDefinitions": "goto", + "editor.inlayHints.fontFamily": "JetBrains Mono", + "editor.inlineSuggest.enabled": true, + "editor.insertSpaces": true, + "editor.lightbulb.enabled": "off", + "editor.linkedEditing": true, + "editor.minimap.maxColumn": 100, + "editor.parameterHints.enabled": false, + "editor.quickSuggestions": { + "strings": true + }, + "editor.renderFinalNewline": "on", + "editor.renderWhitespace": "none", + "editor.roundedSelection": true, + "editor.rulers": [ + 100, + ], + "editor.stickyScroll.enabled": true, + "editor.suggest.localityBonus": true, + "editor.suggest.showValues": false, + "editor.trimAutoWhitespace": true, + "editor.wordBasedSuggestions": "off", + "editor.wordSeparators": "`~!@#%^&*()-=+[{]}\\|;:'\",.<>/?", + "editor.wordWrapColumn": 100, + "editor.wrappingIndent": "none", + "errorLens.enableOnDiffView": true, + "errorLens.fontFamily": "JetBrains Mono", + "errorLens.messageTemplate": "$message $source $code", + "explorer.confirmDelete": false, + "explorer.confirmDragAndDrop": false, + "extensions.ignoreRecommendations": false, + "files.autoGuessEncoding": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true, + "git.allowForcePush": true, + "git.autofetch": true, + "git.confirmSync": false, + "git.enableCommitSigning": false, + "git.enableSmartCommit": true, + "git.fetchOnPull": true, + "git.ignoreRebaseWarning": true, + "git.mergeEditor": false, + "git.showPushSuccessNotification": true, + "github.copilot.enable": { + "*": true, + "yaml": false, + "plaintext": false, + "markdown": false + }, + "github.copilot.inlineSuggest.enable": true, + "githubIssues.issueBranchTitle": "${user}/${sanitizedIssueTitle}", + "githubIssues.queries": [ + { + "label": "My Issues", + "query": "default" + }, + { + "label": "Created Issues", + "query": "author:${user} state:open repo:${owner}\/${repository} sort:created-desc" + }, + { + "label": "Recent Issues", + "query": "state:open repo:${owner}\/${repository} sort:updated-desc" + } + ], + "githubIssues.workingIssueFormatScm": "", + "githubPullRequests.assignCreated": "${user}", + "githubPullRequests.createDraft": true, + "githubPullRequests.defaultMergeMethod": "squash", + "githubPullRequests.fileListLayout": "tree", + "githubPullRequests.ignoredPullRequestBranches": [ + "develop", + "master" + ], + "githubPullRequests.pullBranch": "never", + "githubPullRequests.showPullRequestNumberInTree": true, + "githubPullRequests.terminalLinksHandler": "vscode", + "gitlens.showWelcomeOnInstall": false, + "gitlens.showWhatsNewAfterUpgrades": false, + "gitlens.outputLevel": "silent", + "gitlens.plusFeatures.enabled": false, + "gitlens.virtualRepositories.enabled": false, + "gitlens.codeLens.enabled": false, + "gitlens.codeLens.recentChange.enabled": false, + "gitlens.codeLens.authors.enabled": false, + "gitlens.statusBar.enabled": false, + "gitlens.statusBar.pullRequests.enabled": false, + "gitlens.hovers.enabled": false, + "gitlens.hovers.avatars": false, + "gitlens.hovers.pullRequests.enabled": false, + "gitlens.hovers.autolinks.enabled": false, + "gitlens.hovers.currentLine.enabled": false, + "gitlens.hovers.autolinks.enhanced": false, + "gitlens.hovers.currentLine.details": false, + "gitlens.hovers.currentLine.changes": false, + "gitlens.hovers.annotations.enabled": false, + "gitlens.hovers.annotations.changes": false, + "gitlens.hovers.annotations.details": false, + "headwind.runOnSave": true, + "html.format.indentHandlebars": true, + "html.format.indentInnerHtml": true, + "html.format.preserveNewLines": true, + "html.format.wrapAttributes": "force", + "html.format.wrapLineLength": 100, + "indentRainbow.colorOnWhiteSpaceOnly": true, + "intelephense.environment.documentRoot": "public/index.php", + "intelephense.files.exclude": [ + "**/.git/**", + "**/.svn/**", + "**/.hg/**", + "**/CVS/**", + "**/.DS_Store/**", + "**/node_modules/**", + "**/bower_components/**", + "**/vendor/**/{Tests,tests}/**", + "**/.history/**" + ], + "intelephense.phpdoc.returnVoid": false, + "javascript.format.placeOpenBraceOnNewLineForControlBlocks": true, + "LaravelExtraIntellisense.modelAccessorCase": "camel", + "LaravelExtraIntellisense.modelAttributeCase": "camel", + "LaravelExtraIntellisense.modelsPaths": [ + "app", + "app/Models" + ], + "LaravelExtraIntellisense.modelVariables": { + "user": "App\\Models\\User" + }, + "LaravelIntellisense.model": "App\\Models", + "markdown.preview.fontFamily": "JetBrains Mono", + "markdownlint.config": { + "default": true, + "MD024": false, + "MD022": false, + "MD032": false, + }, + "namespaceResolver.leadingSeparator": false, + "namespaceResolver.showMessageOnStatusBar": true, + "namespaceResolver.sortAlphabetically": true, + "namespaceResolver.sortOnSave": true, + "php.suggest.basic": false, + "php.validate.enable": false, + "php.validate.run": "onType", + "phpcs.executablePath": "vendor/bin/phpcs", + "phpcs.showSources": true, + "phpunit.args": [ + "--coverage-clover=coverage.xml", + ], + "redhat.telemetry.enabled": false, + "search.exclude": { + // Hide everything in /vendor, except "laravel" and "livewire" folders. + "**/vendor/{[^l],?[^ai]}*": true, + // Hide everything in /public, except "index.php" + "**/public/{[^i],?[^n]}*": true, + "**/node_modules": true, + "**/dist": true, + "**/_ide_helper.php": true, + "**/composer.lock": true, + "**/package-lock.json": true, + "storage": true, + ".phpunit.result.cache": true + }, + "tailwindCSS.validate": true, + "terminal.explorerKind": "external", + "terminal.integrated.drawBoldTextInBrightColors": false, + "terminal.integrated.enableMultiLinePasteWarning": false, + "terminal.integrated.fontFamily": "MesloLGS NF", + "terminal.integrated.gpuAcceleration": "off", + "terminal.integrated.scrollback": 5000, + "typescript.suggest.enabled": false, + "window.commandCenter": true, + "workbench.editor.enablePreview": false, + "workbench.editor.showIcons": false, + "workbench.editor.showTabs": "single", + "workbench.editor.tabCloseButton": "left", + "workbench.fontAliasing": "auto", + "workbench.iconTheme": "file-icons", + "workbench.productIconTheme": "macos-modern", + "workbench.startupEditor": "none", + "zenMode.fullScreen": false, + "zenMode.hideLineNumbers": false, + // formaters + "[blade]": { + "editor.defaultFormatter": "shufo.vscode-blade-formatter" + }, + "[php]": { + "editor.defaultFormatter": "bmewburn.vscode-intelephense-client" + }, + "window.title": "laravel-model-caching", + "workbench.editor.tabActionLocation": "left" +} diff --git a/README.md b/README.md index 86d86357..f8c04ce7 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ The following are packages we have identified as conflicting: - [spatie/laravel-query-builder](https://github.com/spatie/laravel-query-builder) - [dwightwatson/rememberable](https://github.com/dwightwatson/rememberable) - [kalnoy/nestedset](https://github.com/lazychaser/laravel-nestedset) +- [laravel-adjacency-list](https://github.com/staudenmeir/laravel-adjacency-list) ### Things That Don't Work Currently The following items currently do no work with this package: @@ -81,7 +82,7 @@ The following items currently do no work with this package: ## Installation Be sure to not require a specific version of this package when requiring it: ``` -composer require genealabs/laravel-model-caching +composer require mikebronner/laravel-model-caching ``` ### Gotchas If Using With Lumen diff --git a/composer.json b/composer.json index 0460718b..de5669c6 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "genealabs/laravel-model-caching", + "name": "mikebronner/laravel-model-caching", "description": "Automatic caching for Eloquent models.", "license": "MIT", "authors": [ @@ -15,26 +15,25 @@ } ], "require": { - "php": "^8.1", - "genealabs/laravel-pivot-events": "^10.0", - "illuminate/cache": "^10.0", - "illuminate/config": "^10.0", - "illuminate/console": "^10.0", - "illuminate/container": "^10.0", - "illuminate/database": "^10.0", - "illuminate/http": "^10.0", - "illuminate/support": "^10.0" + "php": ">=8.1", + "mikebronner/laravel-pivot-events": "^10.0|^11.0|^12.0", + "illuminate/cache": "^10.0|^11.0|^12.0", + "illuminate/config": "^10.0|^11.0|^12.0", + "illuminate/console": "^10.0|^11.0|^12.0", + "illuminate/container": "^10.0|^11.0|^12.0", + "illuminate/database": "^10.0|^11.0|^12.0", + "illuminate/http": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0" }, "require-dev": { - "doctrine/dbal": "^3.3", + "doctrine/dbal": "^3.3|^4.2", "fakerphp/faker": "^1.11", - "laravel/nova": "^3.9", - "orchestra/testbench-browser-kit": "^8.0", - "orchestra/testbench": "^8.0", - "php-coveralls/php-coveralls" : "^2.2", - "phpmd/phpmd": "^2.11", - "phpunit/phpunit": "^9.5", - "slevomat/coding-standard": "^7.0", + "laravel/nova": "^5.0", + "orchestra/testbench-browser-kit": "^9.0|^10.0", + "orchestra/testbench": "^9.0|^10.0", + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^10.5|^11.5.3", + "slevomat/coding-standard": "^7.0|^8.14", "squizlabs/php_codesniffer": "^3.6", "symfony/thanks": "^1.2", "laravel/legacy-factories": "^1.3" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..91897e8c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,59 @@ +# For more information: https://laravel.com/docs/sail +version: '3' +services: + laravel.test: + image: ghcr.io/mikebronner/sail/php-8.2:latest + extra_hosts: + - 'host.docker.internal:host-gateway' + ports: + - '${APP_PORT:-80}:80' + - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' + environment: + WWWUSER: '${WWWUSER}' + LARAVEL_SAIL: 1 + XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' + XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' + volumes: + - '.:/var/www/html' + networks: + - sail + depends_on: + - redis + pgsql: + image: 'postgres:15' + ports: + - '${FORWARD_DB_PORT:-5432}:5432' + environment: + PGPASSWORD: '${DB_PASSWORD:-secret}' + POSTGRES_DB: '${DB_DATABASE:-testing}' + POSTGRES_USER: '${DB_USERNAME:-forge}' + POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' + volumes: + - 'sail-pgsql:/var/lib/postgresql/data' + - './vendor/laravel/sail/database/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql' + networks: + - sail + healthcheck: + test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] + retries: 3 + timeout: 5s + redis: + image: 'redis:alpine' + ports: + - '${FORWARD_REDIS_PORT:-6379}:6379' + volumes: + - 'sail-redis:/data' + networks: + - sail + healthcheck: + test: ["CMD", "redis-cli", "ping"] + retries: 3 + timeout: 5s +networks: + sail: + driver: bridge +volumes: + sail-pgsql: + driver: local + sail-redis: + driver: local diff --git a/phpmd.xml b/phpmd.xml deleted file mode 100644 index 45449165..00000000 --- a/phpmd.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - Custom ruleset for Laravel. - - - - - - - - - - - - - - - - - 36 - - - - - - - 2 - - - - - - - 2 - - - - - - diff --git a/phpunit.xml b/phpunit.xml index 638c1866..c26ddd53 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,34 +1,45 @@ - - - - ./src - - - - - ./tests/Feature - - - ./tests/Integration - - - ./tests/Nova - - - - - - - - - - - - - - - - - + + + + + ./tests/Feature + + + ./tests/Integration + + + ./tests/Nova + + + + + + + + + + + + + + + + + + + + ./src + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3c8ff2dd..45a3ad26 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,14 +1,14 @@ @@ -21,21 +21,21 @@ ./tests/Nova - - - ./src - - - - - - - - - - - - + + + + + + + + + + + + + ./src + + diff --git a/src/CacheKey.php b/src/CacheKey.php index 3258e288..84c1fc97 100644 --- a/src/CacheKey.php +++ b/src/CacheKey.php @@ -1,5 +1,8 @@ -query->havings)->reduce(function ($carry, $having) { - $value = $carry; - $value .= $this->getHavingClause($having); - - return $value; - }); - } - - protected function getHavingClause(array $having): string - { - $return = '-having'; - - foreach ($having as $key => $value) { - $return .= '_' . $key . '_' . str_replace(' ', '_', $value); - } - - return $return; - } - protected function getBindingsSlug() : string { if (! method_exists($this->model, 'query')) { @@ -102,7 +85,7 @@ protected function getColumnClauses(array $where) : string if ($where["type"] !== "Column") { return ""; } - + if ($where["first"] instanceof Expression) { $where["first"] = $this->expressionToString($where["first"]); } @@ -119,6 +102,27 @@ protected function getCurrentBinding(string $type, $bindingFallback = null) return data_get($this->query->bindings, "{$type}.{$this->currentBinding}", $bindingFallback); } + protected function getHavingClauses() + { + return Collection::make($this->query->havings)->reduce(function ($carry, $having) { + $value = $carry; + $value .= $this->getHavingClause($having); + + return $value; + }); + } + + protected function getHavingClause(array $having): string + { + $return = '-having'; + + foreach ($having as $key => $value) { + $return .= '_' . $key . '_' . str_replace(' ', '_', $value); + } + + return $return; + } + protected function getIdColumn(string $idColumn) : string { return $idColumn ? "_{$idColumn}" : ""; @@ -214,7 +218,7 @@ protected function getOrderByClauses() : string } $orders = collect($this->query->orders); - + return $orders ->reduce(function ($carry, $order) { if (($order["type"] ?? "") === "Raw") { @@ -241,7 +245,12 @@ protected function getOtherClauses(array $where) : string $value .= $this->getValuesClause($where); $column = ""; - $column .= isset($where["column"]) ? $this->expressionToString($where["column"]) : ""; + + if (data_get($where, "column") instanceof Expression) { + $where["column"] = $this->expressionToString(data_get($where, "column")); + } + + $column .= isset($where["column"]) ? $where["column"] : ""; $column .= isset($where["columns"]) ? implode("-", $where["columns"]) : ""; return "-{$column}_{$value}"; @@ -260,16 +269,18 @@ protected function getQueryColumns(array $columns) : string if (property_exists($this->query, "columns") && $this->query->columns ) { - $columns = array_map(function ($column) { + $columns = array_map(function ($column) { return $this->expressionToString($column); }, $this->query->columns); return "_" . implode("_", $columns); } - return "_" . implode("_", array_map(function ($column) { + $columns = array_map(function ($column) { return $this->expressionToString($column); - }, $columns)); + }, $columns); + + return "_" . implode("_", $columns); } protected function getRawClauses(array $where) : string @@ -304,7 +315,7 @@ protected function getTableSlug() : string protected function getTypeClause($where) : string { - $type = in_array($where["type"], ["InRaw", "In", "NotIn", "Null", "NotNull", "between", "NotInSub", "InSub", "JsonContains", "Fulltext"]) + $type = in_array($where["type"], ["InRaw", "In", "NotIn", "Null", "NotNull", "between", "NotInSub", "InSub", "JsonContains", "Fulltext", "JsonContainsKey"]) ? strtolower($where["type"]) : strtolower($where["operator"]); @@ -448,11 +459,11 @@ protected function recursiveImplode(array $items, string $glue = ",") : string return $result; } - private function processEnum(\BackedEnum|\UnitEnum|Expression|string|null $value): string + private function processEnum(BackedEnum|UnitEnum|Expression|string|null $value): ?string { - if ($value instanceof \BackedEnum) { + if ($value instanceof BackedEnum) { return $value->value; - } elseif ($value instanceof \UnitEnum) { + } elseif ($value instanceof UnitEnum) { return $value->name; } elseif ($value instanceof Expression) { return $this->expressionToString($value); diff --git a/src/Traits/Buildable.php b/src/Traits/Buildable.php index 0fcf5bde..34af7002 100644 --- a/src/Traits/Buildable.php +++ b/src/Traits/Buildable.php @@ -176,7 +176,7 @@ public function paginate( if (is_array($page)) { $page = $this->recursiveImplodeWithKey($page); } - + $columns = collect($columns)->toArray(); $keyDifferentiator = "-paginate_by_{$perPage}_{$pageName}_{$page}"; @@ -325,12 +325,12 @@ function () use ($arguments, $cacheKey, $method) { * The risk of this change is if any application code is dependent on the `pivotParent` property * of a cached Pivot record, then you're a bit out of luck and would need to have a fallback. */ - if (is_iterable($value) && !empty($value)) { - foreach ($value as $index => $model) { - if (!empty($model) && is_object($model) && $model?->pivot?->pivotParent) { + if (is_iterable($value) && ! empty($value)) { + foreach ($value as $model) { + if (! empty($model) && is_object($model) && $model?->pivot?->pivotParent) { unset($model->pivot->pivotParent); - } - } + } + } } return [ "key" => $cacheKey, diff --git a/src/Traits/BuilderCaching.php b/src/Traits/BuilderCaching.php index e3cc90f0..f51d247d 100644 --- a/src/Traits/BuilderCaching.php +++ b/src/Traits/BuilderCaching.php @@ -31,7 +31,7 @@ public function withoutGlobalScope($scope) return parent::withoutGlobalScope($scope); } - public function withoutGlobalScopes(array $scopes = null) + public function withoutGlobalScopes(?array $scopes = null) { if ($scopes !== null) { $this->withoutGlobalScopes = $scopes; diff --git a/src/Traits/Caching.php b/src/Traits/Caching.php index 5d5fccb9..fcf85247 100644 --- a/src/Traits/Caching.php +++ b/src/Traits/Caching.php @@ -41,7 +41,7 @@ public function applyScopes() if ($this->scopesAreApplied) { return $this; } - + return parent::applyScopes(); } @@ -170,7 +170,7 @@ protected function makeCacheKey( ?? Container::getInstance() ->make("db") ->query(); - + if ( $this->query && method_exists($this->query, "getQuery") @@ -241,7 +241,7 @@ protected function checkCooldownAndRemoveIfExpired(Model $instance) if ( ! $cacheCooldown - || (new Carbon)->now()->diffInSeconds($invalidatedAt) < $cacheCooldown + || (new Carbon)->now()->diffInSeconds($invalidatedAt, true) < $cacheCooldown ) { return; } @@ -263,6 +263,15 @@ protected function checkCooldownAndRemoveIfExpired(Model $instance) protected function checkCooldownAndFlushAfterPersisting(Model $instance, string $relationship = "") { + /** + * Our usage of the library currently expects model caches to be flushed in the usual way, even + * whilst code is run in a `runDisabled` callback. Leaving this check in place introduced all + * sorts of issues where caches weren't being flushed where they needed to be. + */ + // if (! $this->isCachable()) { + // return; + // } + [$cacheCooldown, $invalidatedAt] = $instance->getModelCacheCooldown($instance); if (! $cacheCooldown) { @@ -281,7 +290,7 @@ protected function checkCooldownAndFlushAfterPersisting(Model $instance, string $this->setCacheCooldownSavedAtTimestamp($instance); - if ((new Carbon)->now()->diffInSeconds($invalidatedAt) >= $cacheCooldown) { + if ((new Carbon)->now()->diffInSeconds($invalidatedAt, true) >= $cacheCooldown) { $instance->flushCache(); if ($relationship) { @@ -295,6 +304,11 @@ public function isCachable() : bool $isCacheDisabled = ! Container::getInstance() ->make("config") ->get("laravel-model-caching.enabled"); + + if ($isCacheDisabled) { + return false; + } + $allRelationshipsAreCachable = true; if ( @@ -311,7 +325,7 @@ public function isCachable() : bool ) { return $carry; } - + $relatedModel = $this->model->$related()->getRelated(); if ( @@ -327,7 +341,6 @@ public function isCachable() : bool } return $this->isCachable - && ! $isCacheDisabled && $allRelationshipsAreCachable; } diff --git a/src/Traits/ModelCaching.php b/src/Traits/ModelCaching.php index 1f428c36..b18927d7 100644 --- a/src/Traits/ModelCaching.php +++ b/src/Traits/ModelCaching.php @@ -22,6 +22,11 @@ public function __get($key) ?? 0; } + if ($key === "query") { + return $this->query + ?? $this->newModelQuery(); + } + return parent::__get($key); } @@ -160,7 +165,7 @@ public function scopeDisableCache(EloquentBuilder $query) : EloquentBuilder public function scopeWithCacheCooldownSeconds( EloquentBuilder $query, - int $seconds = null + ?int $seconds = null ) : EloquentBuilder { if (! $seconds) { $seconds = $this->cacheCooldownSeconds; diff --git a/tests/CreatesApplication.php b/tests/CreatesApplication.php index b402ab3a..7b70d647 100644 --- a/tests/CreatesApplication.php +++ b/tests/CreatesApplication.php @@ -139,18 +139,26 @@ protected function getEnvironmentSetUp($app) ]); } - public function appVersionEightAndUp(): bool + public function appVersionEightAndNine(): bool { - return version_compare(app()->version(), '8.0.0', '>='); + return version_compare(app()->version(), '8.0.0', '>=') + && version_compare(app()->version(), '10.0.0', '<'); } public function appVersionFiveBetweenSeven(): bool { - return version_compare(app()->version(), '5.6.0', '>=') && version_compare(app()->version(), '8.0.0', '<'); + return version_compare(app()->version(), '5.6.0', '>=') + && version_compare(app()->version(), '8.0.0', '<'); } public function appVersionOld(): bool { - return version_compare(app()->version(), '5.4.0', '>=') && version_compare(app()->version(), '5.6.0', '<'); + return version_compare(app()->version(), '5.4.0', '>=') + && version_compare(app()->version(), '5.6.0', '<'); + } + + public function appVersionTen(): bool + { + return version_compare(app()->version(), '10.0.0', '>='); } } diff --git a/tests/Feature/PaginationTest.php b/tests/Feature/PaginationTest.php index 465ec823..ab8e751c 100644 --- a/tests/Feature/PaginationTest.php +++ b/tests/Feature/PaginationTest.php @@ -7,8 +7,14 @@ class PaginationTest extends FeatureTestCase { public function testPaginationProvidesDifferentLinksOnDifferentPages() { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + } + // Checking the version start with 8.0. - if ($this->appVersionEightAndUp()) { + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; } @@ -39,8 +45,14 @@ public function testPaginationProvidesDifferentLinksOnDifferentPages() public function testAdvancedPagination() { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + } + // Checking the version start with 8.0. - if ($this->appVersionEightAndUp()) { + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; } @@ -62,8 +74,14 @@ public function testAdvancedPagination() public function testCustomPagination() { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + } + // Checking the version start with 8.0. - if ($this->appVersionEightAndUp()) { + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; } diff --git a/tests/Integration/CachedBuilder/PaginateTest.php b/tests/Integration/CachedBuilder/PaginateTest.php index 0ac4ead0..5d95b3d3 100644 --- a/tests/Integration/CachedBuilder/PaginateTest.php +++ b/tests/Integration/CachedBuilder/PaginateTest.php @@ -36,7 +36,14 @@ public function testPaginationIsCached() public function testPaginationReturnsCorrectLinks() { - if ($this->appVersionEightAndUp()) { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + $page24ActiveLink = '24'; + } + + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; $page24ActiveLink = '24'; @@ -71,7 +78,14 @@ public function testPaginationReturnsCorrectLinks() public function testPaginationWithOptionsReturnsCorrectLinks() { - if ($this->appVersionEightAndUp()) { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + $page24ActiveLink = '24'; + } + + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; $page24ActiveLink = '24'; @@ -106,7 +120,14 @@ public function testPaginationWithOptionsReturnsCorrectLinks() public function testPaginationWithCustomOptionsReturnsCorrectLinks() { - if ($this->appVersionEightAndUp()) { + // Checking the version start with 10.0. + if ($this->appVersionTen()) { + $page1ActiveLink = '1'; + $page2ActiveLink = '2'; + $page24ActiveLink = '24'; + } + + if ($this->appVersionEightAndNine()) { $page1ActiveLink = '1'; $page2ActiveLink = '2'; $page24ActiveLink = '24'; diff --git a/tests/Integration/CachedBuilder/WhereJsonContainsTest.php b/tests/Integration/CachedBuilder/WhereJsonContainsTest.php index 3dd62c8c..3811d6f6 100644 --- a/tests/Integration/CachedBuilder/WhereJsonContainsTest.php +++ b/tests/Integration/CachedBuilder/WhereJsonContainsTest.php @@ -17,9 +17,9 @@ protected function getEnvironmentSetUp($app) parent::getEnvironmentSetUp($app); $app['config']->set('database.default', 'pgsql'); - $app['config']->set('database.connections.pgsql.host', env("PGSQL_HOST", "127.0.0.1")); + $app['config']->set('database.connections.pgsql.host', env("PGSQL_HOST", "pgsql")); $app['config']->set('database.connections.pgsql.database', env("PGSQL_DATABASE", "testing")); - $app['config']->set('database.connections.pgsql.username', env("PGSQL_USERNAME", "homestead")); + $app['config']->set('database.connections.pgsql.username', env("PGSQL_USERNAME", "forge")); $app['config']->set('database.connections.pgsql.password', env("PGSQL_PASSWORD", "secret")); } diff --git a/tests/Integration/CachedModelTest.php b/tests/Integration/CachedModelTest.php index af6e2524..dc932645 100644 --- a/tests/Integration/CachedModelTest.php +++ b/tests/Integration/CachedModelTest.php @@ -1,11 +1,11 @@ withCacheCooldownSeconds(1) ->first(); - + [$usesCacheCooldown, $expiresAt, $savedAt] = $method->invokeArgs($author, [$author]); $this->assertEquals($usesCacheCooldown, 1); @@ -188,7 +188,7 @@ public function testModelCacheDoesntInvalidateDuringCooldownPeriod() ->get(); $uncachedAuthors = (new UncachedAuthor) ->get(); - sleep(2); + sleep(3); $authorsAfterCooldown = (new AuthorWithCooldown) ->get(); diff --git a/tests/NovaTestCase.php b/tests/NovaTestCase.php index 9a25ec4b..d1885ade 100644 --- a/tests/NovaTestCase.php +++ b/tests/NovaTestCase.php @@ -1,5 +1,7 @@ authenticate(); + $this->withoutMiddleware(); + + Artisan::call("nova:publish"); } protected function authenticate() @@ -54,6 +61,7 @@ protected function getPackageProviders($app) NovaCoreServiceProvider::class, \Laravel\Nova\NovaServiceProvider::class, NovaServiceProvider::class, + ServiceProvider::class, ] ); } diff --git a/tools/phpcs b/tools/phpcs deleted file mode 120000 index 9a822ebb..00000000 --- a/tools/phpcs +++ /dev/null @@ -1 +0,0 @@ -/home/forge/.phive/phars/phpcs-3.5.6.phar \ No newline at end of file diff --git a/tools/phpmd b/tools/phpmd deleted file mode 120000 index 7649801a..00000000 --- a/tools/phpmd +++ /dev/null @@ -1 +0,0 @@ -/home/forge/.phive/phars/phpmd-2.7.0.phar \ No newline at end of file diff --git a/tools/phpunit b/tools/phpunit deleted file mode 120000 index c8a2e31f..00000000 --- a/tools/phpunit +++ /dev/null @@ -1 +0,0 @@ -/home/forge/.phive/phars/phpunit-9.3.10.phar \ No newline at end of file