Showing preview only (922K chars total). Download the full file or copy to clipboard to get everything.
Repository: mongodb/laravel-mongodb
Branch: 5.x
Commit: 0071a45e7974
Files: 171
Total size: 872.5 KB
Directory structure:
gitextract_2jedx5y6/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── BUG_REPORT.md
│ │ ├── FEATURE-REQUEST.md
│ │ └── config.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependabot.yml
│ ├── labeler.yml
│ ├── release.yml
│ └── workflows/
│ ├── build-ci-atlas.yml
│ ├── build-ci.yml
│ ├── coding-standards.yml
│ ├── labeler.yml
│ ├── merge-up.yml
│ ├── release.yml
│ └── static-analysis.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── RELEASING.md
├── composer.json
├── docker-compose.yml
├── phpcs.xml.dist
├── phpstan-baseline.neon
├── phpstan.neon.dist
├── phpunit.xml.dist
├── rector.php
├── sbom.json
├── src/
│ ├── Auth/
│ │ └── User.php
│ ├── Bus/
│ │ └── MongoBatchRepository.php
│ ├── Cache/
│ │ ├── MongoLock.php
│ │ └── MongoStore.php
│ ├── CommandSubscriber.php
│ ├── Concerns/
│ │ └── ManagesTransactions.php
│ ├── Connection.php
│ ├── Eloquent/
│ │ ├── Builder.php
│ │ ├── Casts/
│ │ │ ├── BinaryUuid.php
│ │ │ └── ObjectId.php
│ │ ├── DocumentModel.php
│ │ ├── EmbedsRelations.php
│ │ ├── HasSchemaVersion.php
│ │ ├── HybridRelations.php
│ │ ├── MassPrunable.php
│ │ ├── Model.php
│ │ └── SoftDeletes.php
│ ├── Helpers/
│ │ ├── EloquentBuilder.php
│ │ └── QueriesRelationships.php
│ ├── MongoDBBusServiceProvider.php
│ ├── MongoDBServiceProvider.php
│ ├── Query/
│ │ ├── AggregationBuilder.php
│ │ ├── Builder.php
│ │ ├── BuilderTimeout.php
│ │ ├── Grammar.php
│ │ └── Processor.php
│ ├── Queue/
│ │ ├── MongoConnector.php
│ │ ├── MongoJob.php
│ │ └── MongoQueue.php
│ ├── Relations/
│ │ ├── BelongsTo.php
│ │ ├── BelongsToMany.php
│ │ ├── EmbedsMany.php
│ │ ├── EmbedsOne.php
│ │ ├── EmbedsOneOrMany.php
│ │ ├── HasMany.php
│ │ ├── HasOne.php
│ │ ├── MorphMany.php
│ │ ├── MorphTo.php
│ │ └── MorphToMany.php
│ ├── Schema/
│ │ ├── Blueprint.php
│ │ ├── BlueprintLaravelCompatibility.php
│ │ ├── Builder.php
│ │ └── Grammar.php
│ ├── Scout/
│ │ └── ScoutEngine.php
│ ├── Session/
│ │ └── MongoDbSessionHandler.php
│ └── Validation/
│ ├── DatabasePresenceVerifier.php
│ └── ValidationServiceProvider.php
└── tests/
├── AtlasSearchIndexManagement.php
├── AtlasSearchTest.php
├── AuthTest.php
├── Bus/
│ ├── Fixtures/
│ │ ├── ChainHeadJob.php
│ │ ├── SecondTestJob.php
│ │ └── ThirdTestJob.php
│ └── MongoBatchRepositoryTest.php
├── Cache/
│ ├── MongoCacheStoreTest.php
│ └── MongoLockTest.php
├── Casts/
│ ├── BinaryUuidTest.php
│ ├── BooleanTest.php
│ ├── CollectionTest.php
│ ├── DateTest.php
│ ├── DatetimeTest.php
│ ├── DecimalTest.php
│ ├── EncryptionTest.php
│ ├── FloatTest.php
│ ├── IntegerTest.php
│ ├── JsonTest.php
│ ├── ObjectIdTest.php
│ ├── ObjectTest.php
│ └── StringTest.php
├── ConnectionTest.php
├── DateTimeImmutableTest.php
├── Eloquent/
│ ├── CallBuilderTest.php
│ ├── MassPrunableTest.php
│ └── ModelTest.php
├── EmbeddedRelationsTest.php
├── ExternalPackageTest.php
├── FilesystemsTest.php
├── GeospatialTest.php
├── HybridRelationsTest.php
├── ModelTest.php
├── Models/
│ ├── Address.php
│ ├── Anniversary.php
│ ├── Birthday.php
│ ├── Book.php
│ ├── CastObjectId.php
│ ├── Casting.php
│ ├── Client.php
│ ├── Experience.php
│ ├── Group.php
│ ├── Guarded.php
│ ├── HiddenAnimal.php
│ ├── IdIsBinaryUuid.php
│ ├── IdIsInt.php
│ ├── IdIsString.php
│ ├── Item.php
│ ├── Label.php
│ ├── Location.php
│ ├── MemberStatus.php
│ ├── NonIncrementing.php
│ ├── Photo.php
│ ├── Role.php
│ ├── SchemaVersion.php
│ ├── Scoped.php
│ ├── Skill.php
│ ├── Soft.php
│ ├── SqlBook.php
│ ├── SqlRole.php
│ ├── SqlUser.php
│ └── User.php
├── PHPStan/
│ └── SarifErrorFormatter.php
├── PropertyTest.php
├── Query/
│ ├── AggregationBuilderTest.php
│ └── BuilderTest.php
├── QueryBuilderTest.php
├── QueryTest.php
├── Queue/
│ └── Failed/
│ └── DatabaseFailedJobProviderTest.php
├── QueueTest.php
├── RelationsTest.php
├── SchemaTest.php
├── SchemaVersionTest.php
├── Scout/
│ ├── Models/
│ │ ├── ScoutUser.php
│ │ ├── SearchableInSameNamespace.php
│ │ └── SearchableModel.php
│ ├── ScoutEngineTest.php
│ └── ScoutIntegrationTest.php
├── Seeder/
│ ├── DatabaseSeeder.php
│ └── UserTableSeeder.php
├── SeederTest.php
├── SessionTest.php
├── TestCase.php
├── Ticket/
│ ├── GH2489Test.php
│ ├── GH2783Test.php
│ ├── GH3326Test.php
│ ├── GH3328Test.php
│ └── GH3335Test.php
├── TransactionTest.php
├── ValidationTest.php
└── config/
├── database.php
└── queue.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.yml]
indent_size = 2
================================================
FILE: .gitattributes
================================================
/.github export-ignore
/.phpunit.cache export-ignore
/tests export-ignore
*.md export-ignore
*.dist export-ignore
.editorconfig export-ignore
.gitattributes export-ignore
.gitignore export-ignore
docker-compose.yml export-ignore
Dockerfile export-ignore
phpstan-baseline.neon export-ignore
================================================
FILE: .github/CODEOWNERS
================================================
* @mongodb/dbx-php
================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.md
================================================
---
name: "Bug report"
about: 'Report errors or unexpected behavior.'
---
- Laravel-mongodb Version: #.#.#
- PHP Version: #.#.#
- Database Driver & Version:
### Description:
### Steps to reproduce
1.
2.
3.
### Expected behaviour
Tell us what should happen
### Actual behaviour
Tell us what happens instead
<details><summary><b>Logs</b>:</summary>
Insert log.txt here (if necessary)
</details>
================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE-REQUEST.md
================================================
---
name: Feature request
about: Suggest an idea.
title: "[Feature Request] "
---
### Is your feature request related to a problem?
A clear and concise description of what the problem is.
### Describe the solution you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Discussions
url: https://github.com/mongodb/laravel-mongodb/discussions/new/choose
about: For questions, discussions, or general technical support from other Laravel users, visit the Discussions page.
- name: MongoDB Developer Community Forums
url: https://developer.mongodb.com/community/forums/
about: For questions, discussions, or general technical support, visit the MongoDB Community Forums. The MongoDB Community Forums are a centralized place to connect with other MongoDB users, ask questions, and get answers.
- name: Report a Security Vulnerability
url: https://mongodb.com/docs/manual/tutorial/create-a-vulnerability-report
about: If you believe you have discovered a vulnerability in MongoDB products or have experienced a security incident related to MongoDB products, please report the issue to aid in its resolution.
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.
-->
### Checklist
- [ ] Add tests and ensure they pass
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
================================================
FILE: .github/labeler.yml
================================================
# https://github.com/actions/labeler
github:
- changed-files:
- any-glob-to-any-file: '.github/**'
================================================
FILE: .github/release.yml
================================================
changelog:
exclude:
labels:
- ignore-for-release
- minor
authors:
- mongodb-php-bot
categories:
- title: Breaking Changes 🛠
labels:
- breaking-change
- title: New Features
labels:
- enhancement
- feature
- title: Fixed
labels:
- bug
- fixed
- title: Other Changes
labels:
- '*'
================================================
FILE: .github/workflows/build-ci-atlas.yml
================================================
name: Atlas CI
on:
push:
branches:
- '[0-9]+.[0-9x]+'
pull_request:
branches:
- '[0-9]+.[0-9x]+'
- feature/*
env:
MONGODB_EXT_V1: mongodb-1.21.0
MONGODB_EXT_V2: stable
jobs:
build:
runs-on: ubuntu-latest
name: PHP/${{ matrix.php }} Laravel/${{ matrix.laravel }} Driver/${{ matrix.driver }}
strategy:
matrix:
php: ['8.2', '8.3', '8.4', '8.5']
laravel: ['12.*', '13.*']
driver: [2]
include:
- php: '8.1'
laravel: 10.*
driver: 1
- php: '8.2'
laravel: 11.*
driver: 1
- php: '8.4'
laravel: 12.*
driver: 1
exclude:
- laravel: 13.*
php: '8.2'
steps:
- uses: actions/checkout@v6
- name: Create MongoDB Atlas Local
run: |
docker run --name mongodb -p 27017:27017 --detach mongodb/mongodb-atlas-local:latest
until docker exec --tty mongodb mongosh --eval "db.runCommand({ ping: 1 })"; do
sleep 1
done
until docker exec --tty mongodb mongosh --eval "db.createCollection('connection_test') && db.getCollection('connection_test').createSearchIndex({mappings:{dynamic: true}})"; do
sleep 1
done
- name: Show MongoDB server status
run: |
docker exec --tty mongodb mongosh --eval "db.runCommand({ serverStatus: 1 })"
- name: Setup cache environment
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
key: extcache-v1
- name: Installing php
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: curl,mbstring,xdebug,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
coverage: xdebug
tools: composer
- name: Show Docker version
if: ${{ runner.debug }}
run: docker version && env
- name: Restrict Laravel version
run: composer require --dev --no-update 'laravel/framework:${{ matrix.laravel }}'
- name: Download Composer cache dependencies from cache
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ matrix.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ matrix.os }}-composer-
- name: Install dependencies
run: |
composer update --no-interaction
- name: Run tests
run: |
export MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true"
php -d zend.assertions=1 ./vendor/bin/phpunit --coverage-clover coverage.xml --group atlas-search
================================================
FILE: .github/workflows/build-ci.yml
================================================
name: CI
on:
push:
branches:
- '[0-9]+.[0-9x]+'
pull_request:
branches:
- '[0-9]+.[0-9x]+'
- feature/*
env:
MONGODB_EXT_V1: mongodb-1.21.0
MONGODB_EXT_V2: stable
jobs:
build:
runs-on: ubuntu-latest
name: PHP/${{ matrix.php }} Laravel/${{ matrix.laravel }} Driver/${{ matrix.driver }} Server/${{ matrix.mongodb }} ${{ matrix.mode }}
strategy:
matrix:
mongodb: ['8.0']
php: ['8.2', '8.3', '8.4', '8.5']
laravel: ['12.*', '13.*']
driver: [2]
include:
- php: '8.1'
laravel: 10.*
mongodb: '5.0'
mode: low-deps
driver: 1
- php: '8.3'
laravel: 10.*
mongodb: '4.4'
driver: 1
- php: '8.4'
laravel: 12.*
mongodb: '8.0'
driver: 1
- php: '8.5'
laravel: 10.*
mongodb: '8.0'
- php: '8.5'
laravel: 11.*
mongodb: '8.0'
- php: '8.2'
laravel: 12.*
mongodb: '4.4'
- php: '8.2'
laravel: 12.*
mongodb: '5.0'
- php: '8.2'
laravel: 12.*
mongodb: '6.0'
- php: '8.2'
laravel: 12.*
mongodb: '7.0'
- php: '8.2'
laravel: 12.*
mongodb: '8.0'
exclude:
- laravel: 13.*
php: '8.2'
steps:
- uses: actions/checkout@v6
- name: Create MongoDB Replica Set
run: |
docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5
if [ "${{ matrix.mongodb }}" = "4.4" ]; then MONGOSH_BIN="mongo"; else MONGOSH_BIN="mongosh"; fi
until docker exec --tty mongodb $MONGOSH_BIN --eval "db.runCommand({ ping: 1 })"; do
sleep 1
done
sudo docker exec --tty mongodb $MONGOSH_BIN --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})"
- name: Show MongoDB server status
run: |
if [ "${{ matrix.mongodb }}" = "4.4" ]; then MONGOSH_BIN="mongo"; else MONGOSH_BIN="mongosh"; fi
docker exec --tty mongodb $MONGOSH_BIN --eval "db.runCommand({ serverStatus: 1 })"
- name: Setup cache environment
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
key: extcache-v1
- name: Installing php
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: curl,mbstring,xdebug,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
coverage: xdebug
tools: composer
- name: Show Docker version
if: ${{ runner.debug }}
run: docker version && env
- name: Restrict Laravel version
run: composer require --dev --no-update 'laravel/framework:${{ matrix.laravel }}'
- name: Download Composer cache dependencies from cache
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ matrix.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ matrix.os }}-composer-
- name: Install dependencies
run: |
composer update --no-interaction \
$([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest') \
$([[ "${{ matrix.mode }}" == ignore-php-req ]] && echo ' --ignore-platform-req=php+')
- name: Run tests
run: |
export MONGODB_URI="mongodb://127.0.0.1:27017/?replicaSet=rs"
php -d zend.assertions=1 ./vendor/bin/phpunit --coverage-clover coverage.xml --exclude-group atlas-search --testdox
================================================
FILE: .github/workflows/coding-standards.yml
================================================
name: Coding Standards
on:
push:
branches:
- '[0-9]+.[0-9x]+'
pull_request:
branches:
- '[0-9]+.[0-9x]+'
- feature/*
env:
PHP_VERSION: '8.4'
DRIVER_VERSION: stable
jobs:
phpcs:
name: phpcs
runs-on: ubuntu-22.04
permissions:
# Give the default GITHUB_TOKEN write permission to commit and push the
# added or changed files to the repository.
contents: write
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup cache environment
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ env.PHP_VERSION }}
extensions: mongodb-${{ env.DRIVER_VERSION }}
key: extcache-v1
- name: Cache extensions
uses: actions/cache@v5
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
restore-keys: ${{ steps.extcache.outputs.key }}
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
coverage: none
extensions: mongodb-${{ env.DRIVER_VERSION }}
php-version: ${{ env.PHP_VERSION }}
tools: cs2pr
- name: Show driver information
run: php --ri mongodb
- name: Install dependencies with Composer
uses: ramsey/composer-install@4.0.0
with:
composer-options: --no-suggest
- name: Validate PSR class names
run: composer dump-autoload --optimize --strict-psr
# The -q option is required until phpcs v4 is released
- name: Run PHP_CodeSniffer
run: |
mkdir .cache
vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr
================================================
FILE: .github/workflows/labeler.yml
================================================
name: Pull Request Labeler
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
================================================
FILE: .github/workflows/merge-up.yml
================================================
name: Merge up
on:
push:
branches:
- '[0-9]+.[0-9x]+'
env:
GH_TOKEN: ${{ secrets.MERGE_UP_TOKEN }}
jobs:
merge-up:
name: Create merge up pull request
runs-on: ubuntu-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v6
with:
# fetch-depth 0 is required to fetch all branches, not just the branch being built
fetch-depth: 0
token: ${{ secrets.MERGE_UP_TOKEN }}
- name: Create pull request
id: create-pull-request
uses: alcaeus/automatic-merge-up-action@main
with:
ref: ${{ github.ref_name }}
branchNamePattern: '<major>.<minor>'
devBranchNamePattern: '<major>.x'
enableAutoMerge: true
================================================
FILE: .github/workflows/release.yml
================================================
name: "Release New Version"
run-name: "Release ${{ inputs.version }}"
on:
workflow_dispatch:
inputs:
version:
description: "The version to be released. This is checked for consistency with the branch name and configuration"
required: true
type: "string"
jobs:
prepare-release:
environment: release
name: "Prepare release"
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- name: "Create release output"
run: echo '🎬 Release process for version ${{ inputs.version }} started by @${{ github.triggering_actor }}' >> $GITHUB_STEP_SUMMARY
- name: "Generate token and checkout repository"
uses: mongodb-labs/drivers-github-tools/secure-checkout@v3
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.APP_PRIVATE_KEY }}
- name: "Store version numbers in env variables"
run: |
echo RELEASE_VERSION=${{ inputs.version }} >> $GITHUB_ENV
echo RELEASE_BRANCH=$(echo ${{ inputs.version }} | cut -d '.' -f-2) >> $GITHUB_ENV
echo DEV_BRANCH=$(echo ${{ inputs.version }} | cut -d '.' -f-1).x >> $GITHUB_ENV
- name: "Ensure release tag does not already exist"
run: |
if [[ $(git tag -l ${RELEASE_VERSION}) == ${RELEASE_VERSION} ]]; then
echo '❌ Release failed: tag for version ${{ inputs.version }} already exists' >> $GITHUB_STEP_SUMMARY
exit 1
fi
# For patch releases (A.B.C where C != 0), we expect the release to be
# triggered from the A.B maintenance branch
- name: "Fail if patch release is created from wrong release branch"
if: ${{ !endsWith(inputs.version, '.0') && env.RELEASE_BRANCH != github.ref_name }}
run: |
echo '❌ Release failed due to branch mismatch: expected ${{ inputs.version }} to be released from ${{ env.RELEASE_BRANCH }}, got ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
exit 1
# For non-patch releases (A.B.C where C == 0), we expect the release to
# be triggered from the A.x maintenance branch or A.x development branch
- name: "Fail if non-patch release is created from wrong release branch"
if: ${{ endsWith(inputs.version, '.0') && env.RELEASE_BRANCH != github.ref_name && env.DEV_BRANCH != github.ref_name }}
run: |
echo '❌ Release failed due to branch mismatch: expected ${{ inputs.version }} to be released from ${{ env.RELEASE_BRANCH }} or ${{ env.DEV_BRANCH }}, got ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
exit 1
# If a non-patch release is created from its A.x development branch,
# create the A.B maintenance branch from the current one and push it
- name: "Create and push new release branch for non-patch release"
if: ${{ endsWith(inputs.version, '.0') && env.DEV_BRANCH == github.ref_name }}
run: |
echo '🆕 Creating new release branch ${RELEASE_BRANCH} from ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
git checkout -b ${RELEASE_BRANCH}
git push origin ${RELEASE_BRANCH}
#
# Preliminary checks done - commence the release process
#
- name: "Set up drivers-github-tools"
uses: mongodb-labs/drivers-github-tools/setup@v3
with:
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
aws_region_name: ${{ vars.AWS_REGION_NAME }}
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
# Create draft release with release notes
- name: "Create draft release"
run: echo "RELEASE_URL=$(gh release create ${{ inputs.version }} --target ${{ github.ref_name }} --title "${{ inputs.version }}" --generate-notes --draft)" >> "$GITHUB_ENV"
- name: "Create release tag"
uses: mongodb-labs/drivers-github-tools/tag-version@v3
with:
version: ${{ inputs.version }}
tag_message_template: 'Release ${VERSION}'
# TODO: Manually merge using ours strategy. This avoids merge-up pull requests being created
# Process is:
# 1. switch to next branch (according to merge-up action)
# 2. merge release branch using --strategy=ours
# 3. push next branch
# 4. switch back to release branch, then push
- name: "Set summary"
run: |
echo '🚀 Created tag and drafted release for version [${{ inputs.version }}](${{ env.RELEASE_URL }})' >> $GITHUB_STEP_SUMMARY
echo '✍️ You may now update the release notes and publish the release when ready' >> $GITHUB_STEP_SUMMARY
static-analysis:
needs: prepare-release
name: "Run Static Analysis"
uses: ./.github/workflows/static-analysis.yml
with:
ref: refs/tags/${{ inputs.version }}
permissions:
security-events: write
id-token: write
publish-ssdlc-assets:
needs: static-analysis
environment: release
name: "Publish SSDLC Assets"
runs-on: ubuntu-latest
permissions:
security-events: read
id-token: write
contents: write
steps:
- name: "Generate token and checkout repository"
uses: mongodb-labs/drivers-github-tools/secure-checkout@v3
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.APP_PRIVATE_KEY }}
ref: refs/tags/${{ inputs.version }}
# Sets the S3_ASSETS environment variable used later
- name: "Set up drivers-github-tools"
uses: mongodb-labs/drivers-github-tools/setup@v3
with:
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
aws_region_name: ${{ vars.AWS_REGION_NAME }}
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
- name: "Generate SSDLC Reports"
uses: mongodb-labs/drivers-github-tools/full-report@v3
with:
product_name: "MongoDB Laravel Integration"
release_version: ${{ inputs.version }}
silk_asset_group: mongodb-laravel-integration
- name: "Upload SBOM as release artifact"
run: gh release upload ${{ inputs.version }} ${{ env.S3_ASSETS }}/cyclonedx.sbom.json
continue-on-error: true
- name: Upload S3 assets
uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v3
with:
version: ${{ inputs.version }}
product_name: laravel-mongodb
================================================
FILE: .github/workflows/static-analysis.yml
================================================
name: Static Analysis
on:
push:
branches:
- '[0-9]+.[0-9x]+'
pull_request:
branches:
- '[0-9]+.[0-9x]+'
- feature/*
workflow_call:
inputs:
ref:
description: The git ref to check
type: string
required: true
env:
PHP_VERSION: '8.5'
DRIVER_VERSION: stable
MONGODB_EXT_V1: mongodb-1.21.0
MONGODB_EXT_V2: mongodb-mongodb/mongo-php-driver@v2.x
jobs:
phpstan:
name: PHP/${{ matrix.php }} Driver/${{ matrix.driver }}
runs-on: ubuntu-22.04
continue-on-error: true
strategy:
matrix:
php: ['8.1', '8.2', '8.3', '8.4', '8.5']
driver: [2]
include:
- php: '8.4'
driver: 1
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
- name: Get SHA hash of checked out ref
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo CHECKED_OUT_SHA=$(git rev-parse HEAD) >> $GITHUB_ENV
- name: Setup cache environment
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
key: extcache-v1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: curl,mbstring,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
tools: composer:v2
coverage: none
- name: Cache dependencies
id: composer-cache
uses: actions/cache@v5
with:
path: ./vendor
key: composer-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install
- name: Restore cache PHPStan results
id: phpstan-cache-restore
uses: actions/cache/restore@v5
with:
path: .cache
key: phpstan-result-cache-${{ matrix.php }}-${{ github.run_id }}
restore-keys: |
phpstan-result-cache-
- name: Run PHPStan
run: ./vendor/bin/phpstan analyse --no-interaction --no-progress --ansi --error-format=sarif > phpstan.sarif
continue-on-error: true
- name: Upload SARIF report
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: phpstan.sarif
- name: Upload SARIF report
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: phpstan.sarif
ref: ${{ inputs.ref }}
sha: ${{ env.CHECKED_OUT_SHA }}
- name: Save cache PHPStan results
id: phpstan-cache-save
if: always()
uses: actions/cache/save@v5
with:
path: .cache
key: ${{ steps.phpstan-cache-restore.outputs.cache-primary-key }}
================================================
FILE: .gitignore
================================================
*.project
*.sublime-project
*.sublime-workspace
.DS_Store
.idea/
/vendor
composer.lock
composer.phar
phpunit.xml
phpstan.neon
/.cache/
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# MongoDB Code of Conduct
The Code of Conduct outlines the expectations for our behavior as members of the MongoDB community.
We value the participation of each member of the MongoDB community and want all participants to have an enjoyable and fulfilling experience.
Thanks for reading the [MongoDB Code of Conduct](https://www.mongodb.com/community-code-of-conduct).
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Contributions are **welcome** and will be fully **credited**.
Please read and understand the contribution guide before creating an issue or pull request.
## Etiquette
This project is open source, and as such, the maintainers give their free time to build and maintain the source code
held within. They make the code freely available in the hope that it will be of use to other developers. It would be
extremely unfair for them to suffer abuse or anger for their hard work.
Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the
world that developers are civilized and selfless people.
It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.
## Viability
When requesting or submitting new features, first consider whether it might be useful to others. Open
source projects are used by many developers, who may have entirely different needs to your own. Think about
whether or not your feature is likely to be used by other users of the project.
## Procedure
Before filing an issue:
- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your feature suggestion isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
Before submitting a pull request:
- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
## Run Tests
The full test suite requires PHP cli with mongodb extension and a running MongoDB server. A replica set is required for
testing transactions.
Duplicate the `phpunit.xml.dist` file to `phpunit.xml` and edit the environment variables to match your setup.
```bash
$ docker-compose run app
```
Docker can be slow to start. You can run the command `composer run test` locally or in a docker container.
```bash
$ docker-compose run -it tests bash
# Inside the container
$ composer install
$ composer run test
```
For fixing style issues, you can run the PHP Code Beautifier and Fixer, some issues can't be fixed automatically:
```bash
$ composer run cs:fix
$ composer run cs
```
## Requirements
If the project maintainer has any additional requirements, you will find them listed here.
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer).
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
- **Document any change in behaviour** - Make sure the documentation is kept up-to-date.
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
Happy coding!
## Releasing
The releases are created by the maintainers of the library. The process is documented in
the [RELEASING.md](RELEASING.md) file.
================================================
FILE: Dockerfile
================================================
ARG PHP_VERSION=8.2
FROM php:${PHP_VERSION}-cli
# Install extensions
RUN apt-get update && \
apt-get install -y autoconf pkg-config libssl-dev git unzip libzip-dev zlib1g-dev && \
pecl install mongodb && docker-php-ext-enable mongodb && \
pecl install xdebug && docker-php-ext-enable xdebug && \
docker-php-ext-install -j$(nproc) zip
# Create php.ini
RUN cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Install Composer
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 MongoDB, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Laravel MongoDB
===============
[](https://packagist.org/packages/mongodb/laravel-mongodb)
[](https://packagist.org/packages/mongodb/laravel-mongodb)
[](https://github.com/mongodb/laravel-mongodb/actions/workflows/build-ci.yml)
This package adds functionalities to the Eloquent model and Query builder for MongoDB, using the original Laravel API.
*This library extends the original Laravel classes, so it uses exactly the same methods.*
This package was renamed to `mongodb/laravel-mongodb` because of a transfer of ownership to MongoDB, Inc.
It is compatible with Laravel 10.x. For older versions of Laravel, please refer to the
[old versions](https://github.com/mongodb/laravel-mongodb/tree/3.9#laravel-version-compatibility).
## Documentation
- https://www.mongodb.com/docs/drivers/php/laravel-mongodb/
- https://www.mongodb.com/docs/drivers/php/
## Release Integrity
Releases are created automatically and the resulting release tag is signed using
the [PHP team's GPG key](https://pgp.mongodb.com/php-driver.asc). To verify the
tag signature, download the key and import it using `gpg`:
```shell
gpg --import php-driver.asc
```
Then, in a local clone, verify the signature of a given tag (e.g. `4.4.0`):
```shell
git show --show-signature 4.4.0
```
> [!NOTE]
> Composer does not support verifying signatures as part of its installation
> process.
## Reporting Issues
Think you’ve found a bug in the library? Want to see a new feature? Please open a case in our issue management tool, JIRA:
- [Create an account and login.](https://jira.mongodb.org/)
- Navigate to the [PHPORM](https://jira.mongodb.org/browse/PHPORM) project.
- Click Create - Please provide as much information as possible about the issue type and how to reproduce it.
Note: All reported issues in JIRA project are public.
For general questions and support requests, please use one of MongoDB's
[Technical Support](https://mongodb.com/docs/manual/support/) channels.
### Security Vulnerabilities
If you've identified a security vulnerability in a driver or any other MongoDB
project, please report it according to the instructions in
[Create a Vulnerability Report](https://mongodb.com/docs/manual/tutorial/create-a-vulnerability-report).
## Development
Development is tracked in the
[PHPORM](https://jira.mongodb.org/projects/PHPORM/summary) project in MongoDB's
JIRA. Documentation for contributing to this project may be found in
[CONTRIBUTING.md](CONTRIBUTING.md).
================================================
FILE: RELEASING.md
================================================
# Releasing
The following steps outline the release process for both new minor versions and
patch versions.
The command examples below assume that the canonical "mongodb" repository has
the remote name "mongodb". You may need to adjust these commands if you've given
the remote another name (e.g. "upstream"). The "origin" remote name was not used
as it likely refers to your personal fork.
It helps to keep your own fork in sync with the "mongodb" repository (i.e. any
branches and tags on the main repository should also exist in your fork). This
is left as an exercise to the reader.
## Ensure PHP version compatibility
Ensure that the test suite completes on supported versions of PHP.
## Transition JIRA issues and version
All issues associated with the release version should be in the "Closed" state
and have a resolution of "Fixed". Issues with other resolutions (e.g.
"Duplicate", "Works as Designed") should be removed from the release version so
that they do not appear in the release notes.
Check the corresponding "laravel-*.x" fix version to see if it contains any
issues that are resolved as "Fixed" and should be included in this release
version.
Update the version's release date and status from the
[Manage Versions](https://jira.mongodb.org/plugins/servlet/project-config/PHPORM/versions)
page.
## Trigger the release workflow
Releases are done automatically through a GitHub Action. Visit the corresponding
[Release New Version](https://github.com/mongodb/laravel-mongodb/actions/workflows/release.yml)
workflow page to trigger a new build. Select the correct branch (e.g. `v4.5`)
and trigger a new run using the "Run workflow" button. In the following prompt,
enter the version number.
The automation will then create and push the necessary commits and tag, and create
a draft release. The release is created in a draft state and can be published
once the release notes have been updated.
## Branch management
# Creating a maintenance branch and updating default branch name
When releasing a new major or minor version (e.g. 4.0.0), the default branch
should be renamed to the next version (e.g. 4.1). Renaming the default branch
using GitHub's UI ensures that all open pull request are changed to target the
new version.
Once the default branch has been renamed, create the maintenance branch for the
version to be released (e.g. 4.0):
```console
$ git checkout -b X.Y
$ git push mongodb X.Y
```
### After releasing a patch version
If this was a patch release, the maintenance branch must be merged up to the
default branch (e.g. 4.1):
```console
$ git checkout 4.1
$ git pull mongodb 4.1
$ git merge 4.0 --strategy=ours
$ git push mongodb
```
The `--strategy=ours` option ensures that all changes from the merged commits
will be ignored. This is OK because we previously ensured that the `4.1`
branch was up-to-date with all code changes in this maintenance branch before
tagging.
## Publish release notes
Use the generated release note in [this form](https://github.com/mongodb/laravel-mongodb/releases/new).
Release announcements should also be posted in the [MongoDB Product & Driver Announcements: Driver Releases](https://mongodb.com/community/forums/tags/c/announcements/driver-releases/110/php) forum and shared on Twitter.
================================================
FILE: composer.json
================================================
{
"name": "mongodb/laravel-mongodb",
"description": "A MongoDB based Eloquent model and Query builder for Laravel",
"keywords": [
"laravel",
"eloquent",
"mongodb",
"mongo",
"database",
"model"
],
"homepage": "https://github.com/mongodb/laravel-mongodb",
"support": {
"issues": "https://www.mongodb.com/support",
"security": "https://www.mongodb.com/security"
},
"authors": [
{
"name": "Andreas Braun",
"email": "andreas.braun@mongodb.com",
"role": "Leader"
},
{
"name": "Pauline Vos",
"email": "pauline.vos@mongodb.com",
"role": "Maintainer"
},
{
"name": "Jérôme Tamarelle",
"email": "jerome.tamarelle@mongodb.com",
"role": "Maintainer"
},
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com",
"role": "Maintainer"
},
{
"name": "Jens Segers",
"homepage": "https://jenssegers.com",
"role": "Creator"
}
],
"license": "MIT",
"require": {
"php": "^8.1",
"ext-mongodb": "^1.21|^2",
"composer-runtime-api": "^2.0.0",
"illuminate/cache": "^10.36|^11|^12|^13.0",
"illuminate/container": "^10.0|^11|^12|^13.0",
"illuminate/database": "^10.30|^11|^12|^13.0",
"illuminate/events": "^10.0|^11|^12|^13.0",
"illuminate/support": "^10.0|^11|^12|^13.0",
"mongodb/mongodb": "^1.21|^2"
},
"require-dev": {
"laravel/scout": "^10.3",
"league/flysystem-gridfs": "^3.28",
"league/flysystem-read-only": "^3.0",
"phpunit/phpunit": "^10.3|^11.5.3|^12.5.12",
"orchestra/testbench": "^8.0|^9.0|^10.0|^11.0",
"mockery/mockery": "^1.4.4",
"doctrine/coding-standard": "^12.0",
"spatie/laravel-query-builder": "^5.6|^6",
"phpstan/phpstan": "^1.10|^2.1",
"rector/rector": "^1.2|^2.3"
},
"conflict": {
"illuminate/bus": "< 10.37.2"
},
"suggest": {
"league/flysystem-gridfs": "Filesystem storage in MongoDB with GridFS"
},
"minimum-stability": "dev",
"prefer-stable": true,
"replace": {
"jenssegers/mongodb": "self.version"
},
"autoload": {
"psr-4": {
"MongoDB\\Laravel\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"MongoDB\\Laravel\\Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
"MongoDB\\Laravel\\MongoDBServiceProvider",
"MongoDB\\Laravel\\MongoDBBusServiceProvider"
]
}
},
"scripts": {
"test": "phpunit",
"test:coverage": "phpunit --coverage-clover ./coverage.xml",
"cs": "phpcs",
"cs:fix": "phpcbf",
"rector": "rector"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
================================================
FILE: docker-compose.yml
================================================
services:
app:
tty: true
build: .
working_dir: /var/www/laravel-mongodb
command: "bash -c 'composer install && composer run test'"
environment:
MONGODB_URI: 'mongodb://mongodb/'
volumes:
- .:/var/www/laravel-mongodb
depends_on:
mongodb:
condition: service_healthy
mongodb:
container_name: mongodb
image: mongodb/mongodb-atlas-local:8
ports:
- "27017:27017"
healthcheck:
test: mongosh --quiet --eval 'db.runCommand("ping").ok'
interval: 10s
timeout: 10s
retries: 5
================================================
FILE: phpcs.xml.dist
================================================
<?xml version="1.0"?>
<ruleset>
<arg name="basepath" value="." />
<arg name="extensions" value="php" />
<arg name="parallel" value="80" />
<arg name="cache" value=".cache/phpcs" />
<arg name="colors" />
<!-- Ignore warnings (n), show progress of the run (p), and show sniff names (s) -->
<arg value="nps"/>
<file>src</file>
<file>tests</file>
<!-- Target minimum supported PHP version -->
<config name="php_version" value="80100"/>
<!-- ****************************************** -->
<!-- Import rules from doctrine/coding-standard -->
<!-- ****************************************** -->
<rule ref="Doctrine">
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed"/>
<exclude name="SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing"/>
<exclude name="SlevomatCodingStandard.ControlStructures.NewWithParentheses"/>
<exclude name="SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly"/>
<exclude name="SlevomatCodingStandard.Functions.ArrowFunctionDeclaration"/>
<exclude name="SlevomatCodingStandard.Functions.StaticClosure"/>
<exclude name="SlevomatCodingStandard.TypeHints.UnionTypeHintFormat.DisallowedShortNullable"/>
<!-- Model properties use snake_case -->
<exclude name="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps"/>
<!-- Type changes needs to be synchronized with laravel/framework -->
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint"/>
<exclude name="Generic.Formatting.MultipleStatementAlignment" />
<exclude name="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>/tests</exclude-pattern>
</exclude>
<exclude name="SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing">
<exclude-pattern>/tests</exclude-pattern>
</exclude>
</rule>
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
<exclude-pattern>tests/Ticket/*.php</exclude-pattern>
<exclude-pattern>src/Query/BuilderTimeout.php</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.Commenting.DocCommentSpacing.IncorrectAnnotationsGroup">
<exclude-pattern>src/Schema/Blueprint.php</exclude-pattern>
</rule>
</ruleset>
================================================
FILE: phpstan-baseline.neon
================================================
parameters:
ignoreErrors:
-
message: "#^Class MongoDB\\\\Laravel\\\\Query\\\\Grammar does not have a constructor and must be instantiated without any parameters\\.$#"
count: 1
path: src/Connection.php
-
message: "#^Class MongoDB\\\\Laravel\\\\Schema\\\\Grammar does not have a constructor and must be instantiated without any parameters\\.$#"
count: 1
path: src/Connection.php
-
message: "#^Access to an undefined property Illuminate\\\\Container\\\\Container\\:\\:\\$config\\.$#"
count: 3
path: src/MongoDBBusServiceProvider.php
-
message: "#^Access to an undefined property Illuminate\\\\Foundation\\\\Application\\:\\:\\$config\\.$#"
count: 4
path: src/MongoDBServiceProvider.php
-
message: "#^Call to an undefined method TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:pull\\(\\)\\.$#"
count: 1
path: src/Relations/BelongsToMany.php
-
message: "#^Method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:push\\(\\) invoked with 3 parameters, 0 required\\.$#"
count: 3
path: src/Relations/BelongsToMany.php
-
message: "#^Call to an undefined method MongoDB\\\\Laravel\\\\Relations\\\\EmbedsMany\\<TRelatedModel of Illuminate\\\\Database\\\\Eloquent\\\\Model, TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model, TResult\\>\\:\\:contains\\(\\)\\.$#"
count: 1
path: src/Relations/EmbedsMany.php
-
message: "#^Call to an undefined method TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:getParentRelation\\(\\)\\.$#"
count: 1
path: src/Relations/EmbedsOneOrMany.php
-
message: "#^Call to an undefined method TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:setParentRelation\\(\\)\\.$#"
count: 1
path: src/Relations/EmbedsOneOrMany.php
-
message: "#^Call to an undefined method TRelatedModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:setParentRelation\\(\\)\\.$#"
count: 2
path: src/Relations/EmbedsOneOrMany.php
-
message: "#^Call to an undefined method TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:pull\\(\\)\\.$#"
count: 2
path: src/Relations/MorphToMany.php
-
message: "#^Method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:push\\(\\) invoked with 3 parameters, 0 required\\.$#"
count: 6
path: src/Relations/MorphToMany.php
-
message: "#^Method Illuminate\\\\Database\\\\Schema\\\\Blueprint\\:\\:create\\(\\) invoked with 1 parameter, 0 required\\.$#"
count: 1
path: src/Schema/Builder.php
-
message: "#^Call to an undefined method Illuminate\\\\Support\\\\HigherOrderCollectionProxy\\<\\(int\\|string\\), Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\:\\:pushSoftDeleteMetadata\\(\\)\\.$#"
count: 1
path: src/Scout/ScoutEngine.php
================================================
FILE: phpstan.neon.dist
================================================
includes:
- ./phpstan-baseline.neon
parameters:
tmpDir: .cache/phpstan
paths:
- src
level: 2
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%'
universalObjectCratesClasses:
- MongoDB\BSON\Document
ignoreErrors:
- '#Unsafe usage of new static#'
- '#Call to an undefined method [a-zA-Z0-9\\_\<\>\(\)]+::[a-zA-Z]+\(\)#'
services:
errorFormatter.sarif:
class: MongoDB\Laravel\Tests\PHPStan\SarifErrorFormatter
arguments:
relativePathHelper: @simpleRelativePathHelper
currentWorkingDirectory: %currentWorkingDirectory%
pretty: true
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheDirectory=".cache/phpunit"
executionOrder="depends,defects"
beStrictAboutCoverageMetadata="true"
beStrictAboutOutputDuringTests="true"
failOnRisky="true"
failOnWarning="true">
<testsuites>
<testsuite name="Test Suite">
<directory>tests/</directory>
</testsuite>
</testsuites>
<php>
<env name="MONGODB_URI" value="mongodb://mongodb/?directConnection=true"/>
<env name="MONGODB_DATABASE" value="unittest"/>
<env name="SQLITE_DATABASE" value=":memory:"/>
<env name="QUEUE_CONNECTION" value="database"/>
<ini name="memory_limit" value="-1"/>
<!-- Evaluate assertions, requires running with "php -d zend.assertions=1 vendor/bin/phpunit" -->
<!-- <ini name="zend.assertions=1" value="1" /> -->
</php>
<source restrictDeprecations="true"
restrictNotices="true"
restrictWarnings="true">
<include>
<directory>./src</directory>
</include>
</source>
</phpunit>
================================================
FILE: rector.php
================================================
<?php
use Rector\Config\RectorConfig;
use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector;
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
use Rector\Php80\Rector\FunctionLike\MixedTypeRector;
use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector;
use Rector\TypeDeclaration\Rector\Closure\AddClosureVoidReturnTypeWhereNoReturnRector;
return RectorConfig::configure()
->withPaths([
__FILE__,
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withPhpSets()
->withTypeCoverageLevel(0)
->withSkip([
RemoveExtraParametersRector::class,
ClosureToArrowFunctionRector::class,
NullToStrictStringFuncCallArgRector::class,
MixedTypeRector::class,
AddClosureVoidReturnTypeWhereNoReturnRector::class,
]);
================================================
FILE: sbom.json
================================================
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:0b622e40-f57d-4c6f-9f63-db415c1a1271",
"version": 1,
"metadata": {
"timestamp": "2024-05-08T09:52:55Z",
"tools": [
{
"name": "composer",
"version": "2.7.6"
},
{
"vendor": "cyclonedx",
"name": "cyclonedx-php-composer",
"version": "v5.2.0",
"externalReferences": [
{
"type": "distribution",
"url": "https://api.github.com/repos/CycloneDX/cyclonedx-php-composer/zipball/f3a3cdc1a9e34bf1d5748e4279a24569cbf31fed",
"comment": "dist reference: f3a3cdc1a9e34bf1d5748e4279a24569cbf31fed"
},
{
"type": "vcs",
"url": "https://github.com/CycloneDX/cyclonedx-php-composer.git",
"comment": "source reference: f3a3cdc1a9e34bf1d5748e4279a24569cbf31fed"
},
{
"type": "website",
"url": "https://github.com/CycloneDX/cyclonedx-php-composer/#readme",
"comment": "as detected from Composer manifest 'homepage'"
},
{
"type": "issue-tracker",
"url": "https://github.com/CycloneDX/cyclonedx-php-composer/issues",
"comment": "as detected from Composer manifest 'support.issues'"
},
{
"type": "vcs",
"url": "https://github.com/CycloneDX/cyclonedx-php-composer/",
"comment": "as detected from Composer manifest 'support.source'"
}
]
},
{
"vendor": "cyclonedx",
"name": "cyclonedx-library",
"version": "3.x-dev cad0f92",
"externalReferences": [
{
"type": "distribution",
"url": "https://api.github.com/repos/CycloneDX/cyclonedx-php-library/zipball/cad0f92b36c85f36b3d3c11ff96002af5f20cd10",
"comment": "dist reference: cad0f92b36c85f36b3d3c11ff96002af5f20cd10"
},
{
"type": "vcs",
"url": "https://github.com/CycloneDX/cyclonedx-php-library.git",
"comment": "source reference: cad0f92b36c85f36b3d3c11ff96002af5f20cd10"
},
{
"type": "website",
"url": "https://github.com/CycloneDX/cyclonedx-php-library/#readme",
"comment": "as detected from Composer manifest 'homepage'"
},
{
"type": "documentation",
"url": "https://cyclonedx-php-library.readthedocs.io",
"comment": "as detected from Composer manifest 'support.docs'"
},
{
"type": "issue-tracker",
"url": "https://github.com/CycloneDX/cyclonedx-php-library/issues",
"comment": "as detected from Composer manifest 'support.issues'"
},
{
"type": "vcs",
"url": "https://github.com/CycloneDX/cyclonedx-php-library/",
"comment": "as detected from Composer manifest 'support.source'"
}
]
}
]
}
}
================================================
FILE: src/Auth/User.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Auth;
use Illuminate\Foundation\Auth\User as BaseUser;
use MongoDB\Laravel\Eloquent\DocumentModel;
class User extends BaseUser
{
use DocumentModel;
protected $keyType = 'string';
}
================================================
FILE: src/Bus/MongoBatchRepository.php
================================================
<?php
namespace MongoDB\Laravel\Bus;
use Carbon\CarbonImmutable;
use Closure;
use DateTimeInterface;
use Illuminate\Bus\Batch;
use Illuminate\Bus\BatchFactory;
use Illuminate\Bus\DatabaseBatchRepository;
use Illuminate\Bus\PendingBatch;
use Illuminate\Bus\PrunableBatchRepository;
use Illuminate\Bus\UpdatedBatchJobCounts;
use Illuminate\Support\Carbon;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Collection;
use MongoDB\Driver\ReadPreference;
use MongoDB\Laravel\Connection;
use MongoDB\Operation\FindOneAndUpdate;
use Override;
use function is_string;
use function serialize;
use function unserialize;
// Extending DatabaseBatchRepository is necessary so methods pruneUnfinished and pruneCancelled
// are called by PruneBatchesCommand
class MongoBatchRepository extends DatabaseBatchRepository implements PrunableBatchRepository
{
private readonly Collection $collection;
public function __construct(
BatchFactory $factory,
Connection $connection,
string $collection,
) {
$this->collection = $connection->getCollection($collection);
parent::__construct($factory, $connection, $collection);
}
#[Override]
public function get($limit = 50, $before = null): array
{
if (is_string($before)) {
$before = new ObjectId($before);
}
return $this->collection->find(
$before ? ['_id' => ['$lt' => $before]] : [],
[
'limit' => $limit,
'sort' => ['_id' => -1],
'typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array'],
],
)->toArray();
}
#[Override]
public function find(string $batchId): ?Batch
{
$batchId = new ObjectId($batchId);
$batch = $this->collection->findOne(
['_id' => $batchId],
[
// If the select query is executed faster than the database replication takes place,
// then no batch is found. In that case an exception is thrown because jobs are added
// to a null batch.
'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
'typeMap' => ['root' => 'array', 'array' => 'array', 'document' => 'array'],
],
);
return $batch ? $this->toBatch($batch) : null;
}
#[Override]
public function store(PendingBatch $batch): Batch
{
$batch = [
'name' => $batch->name,
'total_jobs' => 0,
'pending_jobs' => 0,
'failed_jobs' => 0,
'failed_job_ids' => [],
// Serialization is required for Closures
'options' => serialize($batch->options),
'created_at' => $this->getUTCDateTime(),
'cancelled_at' => null,
'finished_at' => null,
];
$result = $this->collection->insertOne($batch);
return $this->toBatch(['_id' => $result->getInsertedId()] + $batch);
}
#[Override]
public function incrementTotalJobs(string $batchId, int $amount): void
{
$batchId = new ObjectId($batchId);
$this->collection->updateOne(
['_id' => $batchId],
[
'$inc' => [
'total_jobs' => $amount,
'pending_jobs' => $amount,
],
'$set' => ['finished_at' => null],
],
);
}
#[Override]
public function decrementPendingJobs(string $batchId, string $jobId): UpdatedBatchJobCounts
{
$batchId = new ObjectId($batchId);
$values = $this->collection->findOneAndUpdate(
['_id' => $batchId],
[
'$inc' => ['pending_jobs' => -1],
'$pull' => ['failed_job_ids' => $jobId],
],
[
'projection' => ['pending_jobs' => 1, 'failed_jobs' => 1],
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
],
);
return new UpdatedBatchJobCounts(
$values['pending_jobs'],
$values['failed_jobs'],
);
}
#[Override]
public function incrementFailedJobs(string $batchId, string $jobId): UpdatedBatchJobCounts
{
$batchId = new ObjectId($batchId);
$values = $this->collection->findOneAndUpdate(
['_id' => $batchId],
[
'$inc' => ['failed_jobs' => 1],
'$push' => ['failed_job_ids' => $jobId],
],
[
'projection' => ['pending_jobs' => 1, 'failed_jobs' => 1],
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
],
);
return new UpdatedBatchJobCounts(
$values['pending_jobs'],
$values['failed_jobs'],
);
}
#[Override]
public function markAsFinished(string $batchId): void
{
$batchId = new ObjectId($batchId);
$this->collection->updateOne(
['_id' => $batchId],
['$set' => ['finished_at' => $this->getUTCDateTime()]],
);
}
#[Override]
public function cancel(string $batchId): void
{
$batchId = new ObjectId($batchId);
$this->collection->updateOne(
['_id' => $batchId],
[
'$set' => [
'cancelled_at' => $this->getUTCDateTime(),
'finished_at' => $this->getUTCDateTime(),
],
],
);
}
#[Override]
public function delete(string $batchId): void
{
$batchId = new ObjectId($batchId);
$this->collection->deleteOne(['_id' => $batchId]);
}
/** Execute the given Closure within a storage specific transaction. */
#[Override]
public function transaction(Closure $callback): mixed
{
return $this->connection->transaction($callback);
}
/** Rollback the last database transaction for the connection. */
#[Override]
public function rollBack(): void
{
$this->connection->rollBack();
}
/** Prune the entries older than the given date. */
#[Override]
public function prune(DateTimeInterface $before): int
{
$result = $this->collection->deleteMany(
['finished_at' => ['$ne' => null, '$lt' => new UTCDateTime($before)]],
);
return $result->getDeletedCount();
}
/** Prune all the unfinished entries older than the given date. */
#[Override]
public function pruneUnfinished(DateTimeInterface $before): int
{
$result = $this->collection->deleteMany(
[
'finished_at' => null,
'created_at' => ['$lt' => new UTCDateTime($before)],
],
);
return $result->getDeletedCount();
}
/** Prune all the cancelled entries older than the given date. */
#[Override]
public function pruneCancelled(DateTimeInterface $before): int
{
$result = $this->collection->deleteMany(
[
'cancelled_at' => ['$ne' => null],
'created_at' => ['$lt' => new UTCDateTime($before)],
],
);
return $result->getDeletedCount();
}
/** @param array $batch */
#[Override]
protected function toBatch($batch): Batch
{
return $this->factory->make(
$this,
$batch['_id'],
$batch['name'],
$batch['total_jobs'],
$batch['pending_jobs'],
$batch['failed_jobs'],
$batch['failed_job_ids'],
unserialize($batch['options']),
$this->toCarbon($batch['created_at']),
$this->toCarbon($batch['cancelled_at']),
$this->toCarbon($batch['finished_at']),
);
}
private function getUTCDateTime(): UTCDateTime
{
// Using Carbon so the current time can be modified for tests
return new UTCDateTime(Carbon::now());
}
/** @return ($date is null ? null : CarbonImmutable) */
private function toCarbon(?UTCDateTime $date): ?CarbonImmutable
{
if ($date === null) {
return null;
}
return CarbonImmutable::createFromTimestampMsUTC((string) $date);
}
}
================================================
FILE: src/Cache/MongoLock.php
================================================
<?php
namespace MongoDB\Laravel\Cache;
use Illuminate\Cache\Lock;
use Illuminate\Support\Carbon;
use InvalidArgumentException;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Collection;
use MongoDB\Operation\FindOneAndUpdate;
use Override;
use function is_numeric;
use function random_int;
final class MongoLock extends Lock
{
/**
* Create a new lock instance.
*
* @param Collection $collection The MongoDB collection
* @param string $name Name of the lock
* @param int $seconds Time-to-live of the lock in seconds
* @param string|null $owner A unique string that identifies the owner. Random if not set
* @param array{int, int} $lottery Probability [chance, total] of pruning expired cache items. Set to [0, 0] to disable
*/
public function __construct(
private readonly Collection $collection,
string $name,
int $seconds,
?string $owner = null,
private readonly array $lottery = [2, 100],
) {
if (! is_numeric($this->lottery[0] ?? null) || ! is_numeric($this->lottery[1] ?? null) || $this->lottery[0] > $this->lottery[1]) {
throw new InvalidArgumentException('Lock lottery must be a couple of integers [$chance, $total] where $chance <= $total. Example [2, 100]');
}
parent::__construct($name, $seconds, $owner);
}
/**
* Attempt to acquire the lock.
*/
#[Override]
public function acquire(): bool
{
// The lock can be acquired if: it doesn't exist, it has expired,
// or it is already owned by the same lock instance.
$isExpiredOrAlreadyOwned = [
'$or' => [
['$lte' => ['$expires_at', $this->getUTCDateTime()]],
['$eq' => ['$owner', $this->owner]],
],
];
$result = $this->collection->findOneAndUpdate(
['_id' => $this->name],
[
[
'$set' => [
'owner' => [
'$cond' => [
'if' => $isExpiredOrAlreadyOwned,
'then' => $this->owner,
'else' => '$owner',
],
],
'expires_at' => [
'$cond' => [
'if' => $isExpiredOrAlreadyOwned,
'then' => $this->getUTCDateTime($this->seconds),
'else' => '$expires_at',
],
],
],
],
],
[
'upsert' => true,
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
'projection' => ['owner' => 1],
],
);
if ($this->lottery[0] <= 0 && random_int(1, $this->lottery[1]) <= $this->lottery[0]) {
$this->collection->deleteMany(['expires_at' => ['$lte' => $this->getUTCDateTime()]]);
}
// Compare the owner to check if the lock is owned. Acquiring the same lock
// with the same owner at the same instant would lead to not update the document
return $result['owner'] === $this->owner;
}
/**
* Release the lock.
*/
#[Override]
public function release(): bool
{
$result = $this->collection
->deleteOne([
'_id' => $this->name,
'owner' => $this->owner,
]);
return $result->getDeletedCount() > 0;
}
/**
* Releases this lock in disregard of ownership.
*/
#[Override]
public function forceRelease(): void
{
$this->collection->deleteOne([
'_id' => $this->name,
]);
}
/** Creates a TTL index that automatically deletes expired objects. */
public function createTTLIndex(): void
{
$this->collection->createIndex(
// UTCDateTime field that holds the expiration date
['expires_at' => 1],
// Delay to remove items after expiration
['expireAfterSeconds' => 0],
);
}
/**
* Returns the owner value written into the driver for this lock.
*/
#[Override]
protected function getCurrentOwner(): ?string
{
return $this->collection->findOne(
[
'_id' => $this->name,
'expires_at' => ['$gte' => $this->getUTCDateTime()],
],
['projection' => ['owner' => 1]],
)['owner'] ?? null;
}
private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
{
return new UTCDateTime(Carbon::now()->addSeconds($additionalSeconds));
}
}
================================================
FILE: src/Cache/MongoStore.php
================================================
<?php
namespace MongoDB\Laravel\Cache;
use Illuminate\Cache\RetrievesMultipleKeys;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Support\Carbon;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Collection;
use MongoDB\Laravel\Connection;
use MongoDB\Operation\FindOneAndUpdate;
use Override;
use function is_float;
use function is_int;
use function is_string;
use function serialize;
use function str_contains;
use function unserialize;
final class MongoStore implements LockProvider, Store
{
// Provides "many" and "putMany" in a non-optimized way
use RetrievesMultipleKeys;
private const TEN_YEARS_IN_SECONDS = 315360000;
private Collection $collection;
/**
* @param Connection $connection The MongoDB connection to use for the cache
* @param string $collectionName Name of the collection where cache items are stored
* @param string $prefix Prefix for the name of cache items
* @param Connection|null $lockConnection The MongoDB connection to use for the lock, if different from the cache connection
* @param string $lockCollectionName Name of the collection where locks are stored
* @param array{int, int} $lockLottery Probability [chance, total] of pruning expired cache items. Set to [0, 0] to disable
* @param int $defaultLockTimeoutInSeconds Time-to-live of the locks in seconds
*/
public function __construct(
private readonly Connection $connection,
private readonly string $collectionName = 'cache',
private readonly string $prefix = '',
private readonly ?Connection $lockConnection = null,
private readonly string $lockCollectionName = 'cache_locks',
private readonly array $lockLottery = [2, 100],
private readonly int $defaultLockTimeoutInSeconds = 86400,
) {
$this->collection = $this->connection->getCollection($this->collectionName);
}
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
*/
#[Override]
public function lock($name, $seconds = 0, $owner = null): MongoLock
{
return new MongoLock(
($this->lockConnection ?? $this->connection)->getCollection($this->lockCollectionName),
$this->prefix . $name,
$seconds ?: $this->defaultLockTimeoutInSeconds,
$owner,
$this->lockLottery,
);
}
/**
* Restore a lock instance using the owner identifier.
*/
#[Override]
public function restoreLock($name, $owner): MongoLock
{
return $this->lock($name, 0, $owner);
}
/**
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param int $seconds
*/
#[Override]
public function put($key, $value, $seconds): bool
{
$result = $this->collection->updateOne(
[
'_id' => $this->prefix . $key,
],
[
'$set' => [
'value' => $this->serialize($value),
'expires_at' => $this->getUTCDateTime($seconds),
],
],
['upsert' => true],
);
return $result->getUpsertedCount() > 0 || $result->getModifiedCount() > 0;
}
/**
* Store an item in the cache if the key doesn't exist.
*
* @param string $key
* @param mixed $value
* @param int $seconds
*/
public function add($key, $value, $seconds): bool
{
$isExpired = ['$lte' => ['$expires_at', $this->getUTCDateTime()]];
$result = $this->collection->updateOne(
[
'_id' => $this->prefix . $key,
],
[
[
'$set' => [
'value' => [
'$cond' => [
'if' => $isExpired,
'then' => $this->serialize($value),
'else' => '$value',
],
],
'expires_at' => [
'$cond' => [
'if' => $isExpired,
'then' => $this->getUTCDateTime($seconds),
'else' => '$expires_at',
],
],
],
],
],
['upsert' => true],
);
return $result->getUpsertedCount() > 0 || $result->getModifiedCount() > 0;
}
/**
* Retrieve an item from the cache by key.
*
* @param string $key
*/
#[Override]
public function get($key): mixed
{
$result = $this->collection->findOne(
['_id' => $this->prefix . $key],
['projection' => ['value' => 1, 'expires_at' => 1]],
);
if (! $result) {
return null;
}
if ($result['expires_at'] <= $this->getUTCDateTime()) {
$this->forgetIfExpired($key);
return null;
}
return $this->unserialize($result['value']);
}
/**
* Increment the value of an item in the cache.
*
* @param string $key
* @param int|float $value
*/
#[Override]
public function increment($key, $value = 1): int|float|false
{
$result = $this->collection->findOneAndUpdate(
[
'_id' => $this->prefix . $key,
],
[
'$inc' => ['value' => $value],
],
[
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
],
);
if (! $result) {
return false;
}
if ($result['expires_at'] <= $this->getUTCDateTime()) {
$this->forgetIfExpired($key);
return false;
}
return $result['value'];
}
/**
* Decrement the value of an item in the cache.
*
* @param string $key
* @param int|float $value
*/
#[Override]
public function decrement($key, $value = 1): int|float|false
{
return $this->increment($key, -1 * $value);
}
/**
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
*/
#[Override]
public function forever($key, $value): bool
{
return $this->put($key, $value, self::TEN_YEARS_IN_SECONDS);
}
/**
* Remove an item from the cache.
*
* @param string $key
*/
#[Override]
public function forget($key): bool
{
$result = $this->collection->deleteOne([
'_id' => $this->prefix . $key,
]);
return $result->getDeletedCount() > 0;
}
/**
* Remove an item from the cache if it is expired.
*
* @param string $key
*/
public function forgetIfExpired($key): bool
{
$result = $this->collection->deleteOne([
'_id' => $this->prefix . $key,
'expires_at' => ['$lte' => $this->getUTCDateTime()],
]);
return $result->getDeletedCount() > 0;
}
/**
* Extend the expiration time of an item in the cache.
*
* @param string $key
* @param int $seconds
*/
public function touch($key, $seconds): bool
{
$result = $this->collection->updateOne(
[
'_id' => $this->prefix . $key,
'expires_at' => ['$gt' => $this->getUTCDateTime()],
],
[
'$set' => ['expires_at' => $this->getUTCDateTime($seconds)],
],
);
return $result->getModifiedCount() > 0;
}
public function flush(): bool
{
$this->collection->deleteMany([]);
return true;
}
public function getPrefix(): string
{
return $this->prefix;
}
/** Creates a TTL index that automatically deletes expired objects. */
public function createTTLIndex(): void
{
$this->collection->createIndex(
// UTCDateTime field that holds the expiration date
['expires_at' => 1],
// Delay to remove items after expiration
['expireAfterSeconds' => 0],
);
}
private function serialize($value): string|int|float
{
// Don't serialize numbers, so they can be incremented
if (is_int($value) || is_float($value)) {
return $value;
}
return serialize($value);
}
private function unserialize($value): mixed
{
if (! is_string($value) || ! str_contains($value, ';')) {
return $value;
}
return unserialize($value);
}
private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
{
return new UTCDateTime(Carbon::now()->addSeconds($additionalSeconds));
}
}
================================================
FILE: src/CommandSubscriber.php
================================================
<?php
namespace MongoDB\Laravel;
use MongoDB\BSON\Document;
use MongoDB\Driver\Monitoring\CommandFailedEvent;
use MongoDB\Driver\Monitoring\CommandStartedEvent;
use MongoDB\Driver\Monitoring\CommandSubscriber as CommandSubscriberInterface;
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
use Override;
use function get_object_vars;
use function in_array;
/** @internal */
final class CommandSubscriber implements CommandSubscriberInterface
{
/** @var array<string, CommandStartedEvent> */
private array $commands = [];
public function __construct(private Connection $connection)
{
}
#[Override]
public function commandStarted(CommandStartedEvent $event): void
{
$this->commands[$event->getOperationId()] = $event;
}
#[Override]
public function commandFailed(CommandFailedEvent $event): void
{
$this->logQuery($event);
}
#[Override]
public function commandSucceeded(CommandSucceededEvent $event): void
{
$this->logQuery($event);
}
private function logQuery(CommandSucceededEvent|CommandFailedEvent $event): void
{
$startedEvent = $this->commands[$event->getOperationId()];
unset($this->commands[$event->getOperationId()]);
$command = [];
foreach (get_object_vars($startedEvent->getCommand()) as $key => $value) {
if ($key[0] !== '$' && ! in_array($key, ['lsid', 'txnNumber'])) {
$command[$key] = $value;
}
}
$this->connection->logQuery(Document::fromPHP($command)->toCanonicalExtendedJSON(), [], $event->getDurationMicros() / 1000);
}
}
================================================
FILE: src/Concerns/ManagesTransactions.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Concerns;
use Closure;
use MongoDB\Client;
use MongoDB\Driver\Exception\RuntimeException;
use MongoDB\Driver\Session;
use MongoDB\Laravel\Connection;
use Throwable;
use function max;
use function MongoDB\with_transaction;
use function property_exists;
/**
* @internal
*
* @see https://docs.mongodb.com/manual/core/transactions/
*/
trait ManagesTransactions
{
protected ?Session $session = null;
protected $transactions = 0;
abstract public function getClient(): ?Client;
public function getSession(): ?Session
{
return $this->session;
}
private function getSessionOrCreate(): Session
{
if ($this->session === null) {
$this->session = $this->getClient()->startSession();
}
return $this->session;
}
private function getSessionOrThrow(): Session
{
$session = $this->getSession();
if ($session === null) {
throw new RuntimeException('There is no active session.');
}
return $session;
}
/**
* Starts a transaction on the active session. An active session will be created if none exists.
*/
public function beginTransaction(array $options = []): void
{
$this->runCallbacksBeforeTransaction();
$this->getSessionOrCreate()->startTransaction($options);
$this->handleInitialTransactionState();
}
private function handleInitialTransactionState(): void
{
$this->transactions = 1;
$this->transactionsManager?->begin(
$this->getName(),
$this->transactions,
);
$this->fireConnectionEvent('beganTransaction');
}
/**
* Commit transaction in this session.
*/
public function commit(): void
{
$this->fireConnectionEvent('committing');
$this->getSessionOrThrow()->commitTransaction();
$this->handleCommitState();
}
private function handleCommitState(): void
{
[$levelBeingCommitted, $this->transactions] = [
$this->transactions,
max(0, $this->transactions - 1),
];
$this->transactionsManager?->commit(
$this->getName(),
$levelBeingCommitted,
$this->transactions,
);
$this->fireConnectionEvent('committed');
}
/**
* Abort transaction in this session.
*/
public function rollBack($toLevel = null): void
{
$session = $this->getSessionOrThrow();
if ($session->isInTransaction()) {
$session->abortTransaction();
}
$this->handleRollbackState();
}
private function handleRollbackState(): void
{
$this->transactions = 0;
$this->transactionsManager?->rollback(
$this->getName(),
$this->transactions,
);
$this->fireConnectionEvent('rollingBack');
}
private function runCallbacksBeforeTransaction(): void
{
// ToDo: remove conditional once we stop supporting Laravel 10.x
if (property_exists(Connection::class, 'beforeStartingTransaction')) {
foreach ($this->beforeStartingTransaction as $beforeTransactionCallback) {
$beforeTransactionCallback($this);
}
}
}
/**
* Static transaction function realize the with_transaction functionality provided by MongoDB.
*
* @param int $attempts
*
* @throws Throwable
*/
public function transaction(Closure $callback, $attempts = 1, array $options = []): mixed
{
$attemptsLeft = $attempts;
$callbackResult = null;
$throwable = null;
$callbackFunction = function (Session $session) use ($callback, &$attemptsLeft, &$callbackResult, &$throwable) {
$attemptsLeft--;
if ($attemptsLeft < 0) {
$session->abortTransaction();
$this->handleRollbackState();
return;
}
$this->runCallbacksBeforeTransaction();
$this->handleInitialTransactionState();
// Catch, store, and re-throw any exception thrown during execution
// of the callable. The last exception is re-thrown if the transaction
// was aborted because the number of callback attempts has been exceeded.
try {
$callbackResult = $callback($this);
$this->fireConnectionEvent('committing');
} catch (Throwable $throwable) {
throw $throwable;
}
};
with_transaction($this->getSessionOrCreate(), $callbackFunction, $options);
if ($attemptsLeft < 0 && $throwable) {
$this->handleRollbackState();
throw $throwable;
}
$this->handleCommitState();
return $callbackResult;
}
}
================================================
FILE: src/Connection.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel;
use Composer\InstalledVersions;
use Illuminate\Database\Connection as BaseConnection;
use InvalidArgumentException;
use MongoDB\Client;
use MongoDB\Collection;
use MongoDB\Database;
use MongoDB\Driver\Exception\AuthenticationException;
use MongoDB\Driver\Exception\ConnectionException;
use MongoDB\Driver\Exception\RuntimeException;
use MongoDB\Driver\ReadPreference;
use MongoDB\Laravel\Concerns\ManagesTransactions;
use OutOfBoundsException;
use Override;
use Throwable;
use function filter_var;
use function implode;
use function is_array;
use function preg_match;
use function sprintf;
use function str_contains;
use function trigger_error;
use const E_USER_DEPRECATED;
use const FILTER_FLAG_IPV6;
use const FILTER_VALIDATE_IP;
/** @mixin Database */
class Connection extends BaseConnection
{
use ManagesTransactions;
private static ?string $version = null;
/**
* The MongoDB database handler.
*
* @var Database
*/
protected $db;
/**
* The MongoDB connection handler.
*
* @var Client
*/
protected $connection;
private ?CommandSubscriber $commandSubscriber = null;
/** @var bool Whether to rename the rename "id" into "_id" for embedded documents. */
private bool $renameEmbeddedIdField;
/**
* Create a new database connection instance.
*/
public function __construct(array $config)
{
$this->config = $config;
// Build the connection string
$dsn = $this->getDsn($config);
// You can pass options directly to the MongoDB constructor
$options = $config['options'] ?? [];
// Create the connection
$this->connection = $this->createConnection($dsn, $config, $options);
$this->database = $this->getDefaultDatabaseName($dsn, $config);
// Select database
$this->db = $this->connection->getDatabase($this->database);
$this->tablePrefix = $config['prefix'] ?? '';
$this->useDefaultPostProcessor();
$this->useDefaultSchemaGrammar();
$this->useDefaultQueryGrammar();
$this->renameEmbeddedIdField = $config['rename_embedded_id_field'] ?? true;
}
/**
* Begin a fluent query against a database collection.
*
* @param string $table The name of the MongoDB collection
* @param string|null $as Ignored. Not supported by MongoDB
*
* @return Query\Builder
*/
#[Override]
public function table($table, $as = null)
{
$query = new Query\Builder($this, $this->getQueryGrammar(), $this->getPostProcessor());
return $query->from($table);
}
/**
* Get a MongoDB collection.
*
* @param string $name
*
* @return Collection
*/
public function getCollection($name): Collection
{
return $this->db->selectCollection($this->tablePrefix . $name);
}
/** @inheritdoc */
#[Override]
public function getSchemaBuilder()
{
return new Schema\Builder($this);
}
/**
* Get the MongoDB database object.
*
* @deprecated since mongodb/laravel-mongodb:5.2, use getDatabase() instead
*
* @return Database
*/
public function getMongoDB()
{
trigger_error(sprintf('Since mongodb/laravel-mongodb:5.2, Method "%s()" is deprecated, use "getDatabase()" instead.', __FUNCTION__), E_USER_DEPRECATED);
return $this->db;
}
/**
* Get the MongoDB database object.
*
* @param string|null $name Name of the database, if not provided the default database will be returned.
*
* @return Database
*/
public function getDatabase(?string $name = null): Database
{
if ($name && $name !== $this->database) {
return $this->connection->getDatabase($name);
}
return $this->db;
}
/**
* Return MongoDB object.
*
* @deprecated since mongodb/laravel-mongodb:5.2, use getClient() instead
*
* @return Client
*/
public function getMongoClient()
{
trigger_error(sprintf('Since mongodb/laravel-mongodb:5.2, method "%s()" is deprecated, use "getClient()" instead.', __FUNCTION__), E_USER_DEPRECATED);
return $this->getClient();
}
/**
* Get the MongoDB client.
*/
public function getClient(): ?Client
{
return $this->connection;
}
/** @inheritdoc */
#[Override]
public function enableQueryLog()
{
parent::enableQueryLog();
if (! $this->commandSubscriber) {
$this->commandSubscriber = new CommandSubscriber($this);
$this->connection->addSubscriber($this->commandSubscriber);
}
}
#[Override]
public function disableQueryLog()
{
parent::disableQueryLog();
if ($this->commandSubscriber) {
$this->connection->removeSubscriber($this->commandSubscriber);
$this->commandSubscriber = null;
}
}
#[Override]
protected function withFreshQueryLog($callback)
{
try {
return parent::withFreshQueryLog($callback);
} finally {
// The parent method enable query log using enableQueryLog()
// but disables it by setting $loggingQueries to false. We need to
// remove the subscriber for performance.
if (! $this->loggingQueries) {
$this->disableQueryLog();
}
}
}
/**
* Get the name of the default database based on db config or try to detect it from dsn.
*
* @throws InvalidArgumentException
*/
protected function getDefaultDatabaseName(string $dsn, array $config): string
{
if (empty($config['database'])) {
if (! preg_match('/^mongodb(?:[+]srv)?:\\/\\/.+?\\/([^?&]+)/s', $dsn, $matches)) {
throw new InvalidArgumentException('Database is not properly configured.');
}
$config['database'] = $matches[1];
}
return $config['database'];
}
/**
* Create a new MongoDB connection.
*/
protected function createConnection(string $dsn, array $config, array $options): Client
{
// By default driver options is an empty array.
$driverOptions = [];
if (isset($config['driver_options']) && is_array($config['driver_options'])) {
$driverOptions = $config['driver_options'];
}
$driverOptions['driver'] = [
'name' => 'laravel-mongodb',
'version' => self::getVersion(),
];
// Check if the credentials are not already set in the options
if (! isset($options['username']) && ! empty($config['username'])) {
$options['username'] = $config['username'];
}
if (! isset($options['password']) && ! empty($config['password'])) {
$options['password'] = $config['password'];
}
if (isset($config['name'])) {
$driverOptions += ['connectionName' => $config['name']];
}
return new Client($dsn, $options, $driverOptions);
}
/**
* Check the connection to the MongoDB server
*
* @throws ConnectionException if connection to the server fails (for reasons other than authentication).
* @throws AuthenticationException if authentication is needed and fails.
* @throws RuntimeException if a server matching the read preference could not be found.
*/
public function ping(): void
{
$this->getClient()->getManager()->selectServer(new ReadPreference(ReadPreference::PRIMARY_PREFERRED));
}
/** @inheritdoc */
public function disconnect()
{
$this->disableQueryLog();
$this->connection = null;
}
/**
* Determine if the given configuration array has a dsn string.
*
* @deprecated
*/
protected function hasDsnString(array $config): bool
{
return ! empty($config['dsn']);
}
/**
* Get the DSN string form configuration.
*/
protected function getDsnString(array $config): string
{
return $config['dsn'];
}
/**
* Get the DSN string for a host / port configuration.
*/
protected function getHostDsn(array $config): string
{
// Treat host option as array of hosts
$hosts = is_array($config['host']) ? $config['host'] : [$config['host']];
foreach ($hosts as &$host) {
// ipv6
if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$host = '[' . $host . ']';
if (! empty($config['port'])) {
$host .= ':' . $config['port'];
}
} else {
// Check if we need to add a port to the host
if (! str_contains($host, ':') && ! empty($config['port'])) {
$host .= ':' . $config['port'];
}
}
}
// Check if we want to authenticate against a specific database.
$authDatabase = isset($config['options']) && ! empty($config['options']['database']) ? $config['options']['database'] : null;
return 'mongodb://' . implode(',', $hosts) . ($authDatabase ? '/' . $authDatabase : '');
}
/**
* Create a DSN string from a configuration.
*/
protected function getDsn(array $config): string
{
if (! empty($config['dsn'])) {
return $this->getDsnString($config);
}
if (! empty($config['host'])) {
return $this->getHostDsn($config);
}
throw new InvalidArgumentException('MongoDB connection configuration requires "dsn" or "host" key.');
}
/** @inheritdoc */
#[Override]
public function getDriverName()
{
return 'mongodb';
}
/** @inheritdoc */
public function getDriverTitle()
{
return 'MongoDB';
}
/** @inheritdoc */
#[Override]
protected function getDefaultPostProcessor()
{
return new Query\Processor();
}
/** @inheritdoc */
#[Override]
protected function getDefaultQueryGrammar()
{
// Argument added in Laravel 12
return new Query\Grammar($this);
}
/** @inheritdoc */
#[Override]
protected function getDefaultSchemaGrammar()
{
// Argument added in Laravel 12
return new Schema\Grammar($this);
}
/**
* Set database.
*/
public function setDatabase(Database $db)
{
$this->db = $db;
}
/** @inheritdoc */
public function threadCount()
{
$status = $this->db->command(['serverStatus' => 1])->toArray();
return $status[0]['connections']['current'];
}
/**
* Dynamically pass methods to the connection.
*
* @param string $method
* @param array $parameters
*
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->db->$method(...$parameters);
}
/** Set whether to rename "id" field into "_id" for embedded documents. */
public function setRenameEmbeddedIdField(bool $rename): void
{
$this->renameEmbeddedIdField = $rename;
}
/** Get whether to rename "id" field into "_id" for embedded documents. */
public function getRenameEmbeddedIdField(): bool
{
return $this->renameEmbeddedIdField;
}
/**
* Return the server version of one of the MongoDB servers: primary for
* replica sets and standalone, and the selected server for sharded clusters.
*
* @internal
*/
public function getServerVersion(): string
{
return $this->db->command(['buildInfo' => 1])->toArray()[0]['version'];
}
private static function getVersion(): string
{
return self::$version ?? self::lookupVersion();
}
private static function lookupVersion(): string
{
try {
try {
return self::$version = InstalledVersions::getPrettyVersion('mongodb/laravel-mongodb') ?? 'unknown';
} catch (OutOfBoundsException) {
return self::$version = InstalledVersions::getPrettyVersion('jenssegers/mongodb') ?? 'unknown';
}
} catch (Throwable) {
return self::$version = 'error';
}
}
}
================================================
FILE: src/Eloquent/Builder.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Closure;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use MongoDB\BSON\Document;
use MongoDB\Builder\Expression;
use MongoDB\Builder\Type\QueryInterface;
use MongoDB\Builder\Type\SearchOperatorInterface;
use MongoDB\Driver\CursorInterface;
use MongoDB\Driver\Exception\BulkWriteException;
use MongoDB\Laravel\Connection;
use MongoDB\Laravel\Helpers\QueriesRelationships;
use MongoDB\Laravel\Query\AggregationBuilder;
use MongoDB\Model\BSONDocument;
use Override;
use function array_key_exists;
use function array_map;
use function array_replace;
use function collect;
use function is_array;
use function is_object;
use function iterator_to_array;
use function property_exists;
use function value;
/**
* @method \MongoDB\Laravel\Query\Builder toBase()
* @template TModel of Model
*/
class Builder extends EloquentBuilder
{
private const DUPLICATE_KEY_ERROR = 11000;
use QueriesRelationships;
/**
* The methods that should be returned from query builder.
*
* @var array
*/
protected $passthru = [
'average',
'avg',
'count',
'dd',
'doesntexist',
'dump',
'exists',
'getbindings',
'getconnection',
'getgrammar',
'insert',
'insertgetid',
'insertorignore',
'insertusing',
'max',
'min',
'autocomplete',
'pluck',
'pull',
'push',
'raw',
'sum',
'tomql',
];
/**
* @return ($function is null ? AggregationBuilder : $this)
*
* @inheritdoc
*/
public function aggregate($function = null, $columns = ['*'])
{
$result = $this->toBase()->aggregate($function, $columns);
return $result ?: $this;
}
/**
* Performs a full-text search of the field or fields in an Atlas collection.
*
* @see https://www.mongodb.com/docs/atlas/atlas-search/aggregation-stages/search/
*
* @return Collection<int, TModel>
*/
public function search(
SearchOperatorInterface|array $operator,
?string $index = null,
?array $highlight = null,
?bool $concurrent = null,
?string $count = null,
?string $searchAfter = null,
?string $searchBefore = null,
?bool $scoreDetails = null,
?array $sort = null,
?bool $returnStoredSource = null,
?array $tracking = null,
): Collection {
$results = $this->toBase()->search($operator, $index, $highlight, $concurrent, $count, $searchAfter, $searchBefore, $scoreDetails, $sort, $returnStoredSource, $tracking);
return $this->model->hydrate($results->all());
}
/**
* Performs a semantic search on data in your Atlas Vector Search index.
* NOTE: $vectorSearch is only available for MongoDB Atlas clusters, and is not available for self-managed deployments.
*
* @see https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/
*
* @return Collection<int, TModel>
*/
public function vectorSearch(
string $index,
string $path,
array $queryVector,
int $limit,
bool $exact = false,
QueryInterface|array $filter = [],
int|null $numCandidates = null,
): Collection {
$results = $this->toBase()->vectorSearch($index, $path, $queryVector, $limit, $exact, $filter, $numCandidates);
return $this->model->hydrate($results->all());
}
/**
* @param array $options
*
* @inheritdoc
*/
#[Override]
public function update(array $values, array $options = [])
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$relation->performUpdate($this->model, $values);
return 1;
}
return $this->toBase()->update($this->addUpdatedAtColumn($values), $options);
}
/** @inheritdoc */
public function insert(array $values)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$relation->performInsert($this->model, $values);
return true;
}
return parent::insert($values);
}
/** @inheritdoc */
public function insertGetId(array $values, $sequence = null)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$relation->performInsert($this->model, $values);
return $this->model->getKey();
}
return parent::insertGetId($values, $sequence);
}
/** @inheritdoc */
public function delete()
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$relation->performDelete($this->model);
return $this->model->getKey();
}
return parent::delete();
}
/** @inheritdoc */
public function increment($column, $amount = 1, array $extra = [])
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
return $this->model->update([$column => $value]);
}
return parent::increment($column, $amount, $extra);
}
/** @inheritdoc */
public function decrement($column, $amount = 1, array $extra = [])
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
$relation = $this->model->getParentRelation();
if ($relation) {
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
return $this->model->update([$column => $value]);
}
return parent::decrement($column, $amount, $extra);
}
/**
* @param (Closure():T)|Expression|null $value
*
* @return ($value is Closure ? T : ($value is null ? Collection : Expression))
*
* @template T
*/
public function raw($value = null)
{
// Get raw results from the query builder.
$results = $this->query->raw($value);
// Convert MongoCursor results to a collection of models.
if ($results instanceof CursorInterface) {
$results->setTypeMap(['root' => 'array', 'document' => 'array', 'array' => 'array']);
$results = array_map(fn ($document) => $this->query->aliasIdForResult($document), iterator_to_array($results));
return $this->model->hydrate($results);
}
// Convert MongoDB Document to a single object.
if (is_object($results) && (property_exists($results, '_id') || property_exists($results, 'id'))) {
$results = (array) match (true) {
$results instanceof BSONDocument => $results->getArrayCopy(),
$results instanceof Document => $results->toPHP(['root' => 'array', 'document' => 'array', 'array' => 'array']),
default => $results,
};
}
// The result is a single object.
if (is_array($results) && (array_key_exists('_id', $results) || array_key_exists('id', $results))) {
$results = $this->query->aliasIdForResult($results);
return $this->model->newFromBuilder($results);
}
return $results;
}
#[Override]
public function firstOrCreate(array $attributes = [], Closure|array $values = [])
{
$instance = (clone $this)->where($attributes)->first();
if ($instance !== null) {
return $instance;
}
// createOrFirst is not supported in transaction.
if ($this->getConnection()->getSession()?->isInTransaction()) {
return $this->create(array_replace($attributes, value($values)));
}
return $this->createOrFirst($attributes, $values);
}
#[Override]
public function createOrFirst(array $attributes = [], Closure|array $values = [])
{
// The duplicate key error would abort the transaction. Using the regular firstOrCreate in that case.
if ($this->getConnection()->getSession()?->isInTransaction()) {
return $this->firstOrCreate($attributes, $values);
}
try {
return $this->create(array_replace($attributes, value($values)));
} catch (BulkWriteException $e) {
if ($e->getCode() === self::DUPLICATE_KEY_ERROR) {
return $this->where($attributes)->first() ?? throw $e;
}
throw $e;
}
}
/**
* Add the "updated at" column to an array of values.
* TODO Remove if https://github.com/laravel/framework/commit/6484744326531829341e1ff886cc9b628b20d73e
* will be reverted
* Issue in laravel/frawework https://github.com/laravel/framework/issues/27791.
*/
#[Override]
protected function addUpdatedAtColumn(array $values)
{
if (! $this->model->usesTimestamps() || $this->model->getUpdatedAtColumn() === null) {
return $values;
}
$column = $this->model->getUpdatedAtColumn();
if (isset($values['$set'][$column])) {
return $values;
}
$values = array_replace(
[$column => $this->model->freshTimestampString()],
$values,
);
return $values;
}
public function getConnection(): Connection
{
return $this->query->getConnection();
}
/** @inheritdoc */
#[Override]
protected function ensureOrderForCursorPagination($shouldReverse = false)
{
if (empty($this->query->orders)) {
$this->enforceOrderBy();
}
if ($shouldReverse) {
$this->query->orders = collect($this->query->orders)
->map(static fn (int $direction) => $direction === 1 ? -1 : 1)
->toArray();
}
return collect($this->query->orders)
->map(static fn ($direction, $column) => [
'column' => $column,
'direction' => $direction === 1 ? 'asc' : 'desc',
])->values();
}
}
================================================
FILE: src/Eloquent/Casts/BinaryUuid.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use MongoDB\BSON\Binary;
use MongoDB\Laravel\Eloquent\Model;
use function bin2hex;
use function hex2bin;
use function is_string;
use function sprintf;
use function str_replace;
use function strlen;
use function substr;
class BinaryUuid implements CastsAttributes
{
/**
* Cast the given value.
*
* @param Model $model
* @param mixed $value
*
* @return mixed
*/
public function get($model, string $key, $value, array $attributes)
{
if (! $value instanceof Binary || $value->getType() !== Binary::TYPE_UUID) {
return $value;
}
$base16Uuid = bin2hex($value->getData());
return sprintf(
'%s-%s-%s-%s-%s',
substr($base16Uuid, 0, 8),
substr($base16Uuid, 8, 4),
substr($base16Uuid, 12, 4),
substr($base16Uuid, 16, 4),
substr($base16Uuid, 20, 12),
);
}
/**
* Prepare the given value for storage.
*
* @param Model $model
* @param mixed $value
*
* @return Binary
*/
public function set($model, string $key, $value, array $attributes)
{
if ($value instanceof Binary) {
return $value;
}
if (is_string($value) && strlen($value) === 16) {
return new Binary($value, Binary::TYPE_UUID);
}
return new Binary(hex2bin(str_replace('-', '', $value)), Binary::TYPE_UUID);
}
}
================================================
FILE: src/Eloquent/Casts/ObjectId.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use MongoDB\BSON\ObjectId as BSONObjectId;
use MongoDB\Laravel\Eloquent\Model;
class ObjectId implements CastsAttributes
{
/**
* Cast the given value.
*
* @param Model $model
* @param mixed $value
*
* @return mixed
*/
public function get($model, string $key, $value, array $attributes)
{
if (! $value instanceof BSONObjectId) {
return $value;
}
return (string) $value;
}
/**
* Prepare the given value for storage.
*
* @param Model $model
* @param mixed $value
*
* @return mixed
*/
public function set($model, string $key, $value, array $attributes)
{
if ($value instanceof BSONObjectId) {
return $value;
}
return new BSONObjectId($value);
}
}
================================================
FILE: src/Eloquent/DocumentModel.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use BackedEnum;
use Carbon\CarbonInterface;
use DateTimeInterface;
use DateTimeZone;
use Illuminate\Contracts\Queue\QueueableCollection;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Concerns\HasAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Arr;
use Illuminate\Support\Exceptions\MathException;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
use MongoDB\BSON\Binary;
use MongoDB\BSON\Decimal128;
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\Type;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Laravel\Query\Builder as QueryBuilder;
use Stringable;
use ValueError;
use function array_key_exists;
use function array_keys;
use function array_replace;
use function array_unique;
use function array_values;
use function class_basename;
use function count;
use function date_default_timezone_get;
use function explode;
use function func_get_args;
use function in_array;
use function is_array;
use function is_numeric;
use function is_string;
use function ltrim;
use function method_exists;
use function sprintf;
use function str_contains;
use function str_starts_with;
use function strcmp;
use function strlen;
use function var_export;
/** @mixin Builder */
trait DocumentModel
{
use HybridRelations;
use EmbedsRelations;
/**
* The parent relation instance.
*/
private Relation $parentRelation;
/**
* List of field names to unset from the document on save.
*
* @var array{string, true}
*/
private array $unset = [];
/**
* Custom accessor for the model's id.
*
* @param mixed $value
*
* @return mixed
*/
public function getIdAttribute($value = null)
{
// If we don't have a value for 'id', we will use the MongoDB '_id' value.
// This allows us to work with models in a more sql-like way.
$value ??= $this->attributes['id'] ?? $this->attributes['_id'] ?? null;
// Convert ObjectID to string.
if ($value instanceof ObjectID) {
return (string) $value;
}
if ($value instanceof Binary) {
return (string) $value->getData();
}
return $value;
}
/** @inheritdoc */
public function getQualifiedKeyName()
{
return $this->getKeyName();
}
/**
* Convert a DateTimeInterface (including Carbon) to a storable UTCDateTime.
*
* @see HasAttributes::fromDateTime()
*
* @param mixed $value
*/
public function fromDateTime($value): UTCDateTime
{
// If the value is already a UTCDateTime instance, we don't need to parse it.
if ($value instanceof UTCDateTime) {
return $value;
}
// Let Eloquent convert the value to a DateTime instance.
if (! $value instanceof DateTimeInterface) {
$value = parent::asDateTime($value);
}
return new UTCDateTime($value);
}
/**
* Return a timestamp as Carbon object.
*
* @see HasAttributes::asDateTime()
*
* @param mixed $value
*/
protected function asDateTime($value): DateTimeInterface
{
// Convert UTCDateTime instances to Carbon.
if ($value instanceof UTCDateTime) {
return Date::instance($value->toDateTime())
->setTimezone(new DateTimeZone(date_default_timezone_get()));
}
return parent::asDateTime($value);
}
/** @inheritdoc */
public function getDateFormat()
{
return $this->dateFormat ?: 'Y-m-d H:i:s';
}
/** @inheritdoc */
public function freshTimestamp()
{
return new UTCDateTime(Date::now());
}
/** @inheritdoc */
public function getAttribute($key)
{
if (! $key) {
return null;
}
$key = (string) $key;
// An unset attribute is null or throw an exception.
if (isset($this->unset[$key])) {
return $this->throwMissingAttributeExceptionIfApplicable($key);
}
// Dot notation support.
if (str_contains($key, '.') && Arr::has($this->attributes, $key)) {
return $this->getAttributeValue($key);
}
// This checks for embedded relation support.
// Ignore methods defined in the class Eloquent Model or in this trait.
if (
method_exists($this, $key)
&& ! method_exists(Model::class, $key)
&& ! method_exists(DocumentModel::class, $key)
&& ! $this->hasAttributeGetMutator($key)
) {
return $this->getRelationValue($key);
}
return parent::getAttribute($key);
}
/** @inheritdoc */
protected function transformModelValue($key, $value)
{
$value = parent::transformModelValue($key, $value);
// Casting attributes to any of date types, will convert that attribute
// to a Carbon or CarbonImmutable instance.
// @see Model::setAttribute()
if ($this->hasCast($key) && $value instanceof CarbonInterface) {
$value->settings(array_replace($value->getSettings(), ['toStringFormat' => $this->getDateFormat()]));
// "date" cast resets the time to 00:00:00.
$castType = $this->getCasts()[$key];
if (str_starts_with($castType, 'date:') || str_starts_with($castType, 'immutable_date:')) {
$value = $value->startOfDay();
}
}
return $value;
}
/** @inheritdoc */
protected function getCastType($key)
{
$castType = $this->getCasts()[$key];
if ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType)) {
$this->setDateFormat(Str::after($castType, ':'));
}
return parent::getCastType($key);
}
/** @inheritdoc */
protected function getAttributeFromArray($key)
{
$key = (string) $key;
// Support keys in dot notation.
if (str_contains($key, '.')) {
return Arr::get($this->attributes, $key);
}
return parent::getAttributeFromArray($key);
}
/** @inheritdoc */
public function setAttribute($key, $value)
{
$key = (string) $key;
$casts = $this->getCasts();
if (array_key_exists($key, $casts)) {
$castType = $this->getCastType($key);
$castOptions = Str::after($casts[$key], ':');
// Can add more native mongo type casts here.
$value = match ($castType) {
'decimal' => $this->fromDecimal($value, $castOptions),
default => $value,
};
}
// Convert _id to ObjectID.
if (($key === '_id' || $key === 'id') && is_string($value) && strlen($value) === 24) {
$value = $this->newBaseQueryBuilder()->convertKey($value);
}
// Support keys in dot notation.
if (str_contains($key, '.')) {
// Store to a temporary key, then move data to the actual key
parent::setAttribute('__LARAVEL_TEMPORARY_KEY__', $value);
Arr::set($this->attributes, $key, $this->attributes['__LARAVEL_TEMPORARY_KEY__'] ?? null);
unset($this->attributes['__LARAVEL_TEMPORARY_KEY__']);
return $this;
}
// Setting an attribute cancels the unset operation.
unset($this->unset[$key]);
return parent::setAttribute($key, $value);
}
/**
* @param mixed $value
*
* @inheritdoc
*/
protected function asDecimal($value, $decimals)
{
// Convert BSON to string.
if ($this->isBSON($value)) {
if ($value instanceof Binary) {
$value = $value->getData();
} elseif ($value instanceof Stringable) {
$value = (string) $value;
} else {
throw new MathException('BSON type ' . $value::class . ' cannot be converted to string');
}
}
return parent::asDecimal($value, $decimals);
}
/**
* Change to mongo native for decimal cast.
*
* @param mixed $value
* @param int $decimals
*
* @return Decimal128
*/
protected function fromDecimal($value, $decimals)
{
return new Decimal128($this->asDecimal($value, $decimals));
}
/** @inheritdoc */
public function attributesToArray()
{
$attributes = parent::attributesToArray();
// Because the original Eloquent never returns objects, we convert
// MongoDB related objects to a string representation. This kind
// of mimics the SQL behaviour so that dates are formatted
// nicely when your models are converted to JSON.
foreach ($attributes as $key => &$value) {
if ($value instanceof ObjectID) {
$value = (string) $value;
} elseif ($value instanceof Binary) {
$value = (string) $value->getData();
}
}
return $attributes;
}
/** @inheritdoc */
public function getCasts()
{
return $this->casts;
}
/** @inheritdoc */
public function getDirty()
{
$dirty = parent::getDirty();
// The specified value in the $unset expression does not impact the operation.
if ($this->unset !== []) {
$dirty['$unset'] = $this->unset;
}
return $dirty;
}
/** @inheritdoc */
public function originalIsEquivalent($key)
{
if (! array_key_exists($key, $this->original)) {
return false;
}
// Calling unset on an attribute marks it as "not equivalent".
if (isset($this->unset[$key])) {
return false;
}
$attribute = Arr::get($this->attributes, $key);
$original = Arr::get($this->original, $key);
if ($attribute === $original) {
return true;
}
if ($attribute === null) {
return false;
}
if ($this->isDateAttribute($key)) {
$attribute = $attribute instanceof UTCDateTime ? $this->asDateTime($attribute) : $attribute;
$original = $original instanceof UTCDateTime ? $this->asDateTime($original) : $original;
// Comparison on DateTimeInterface values
// phpcs:disable SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedEqualOperator
return $attribute == $original;
}
if ($this->hasCast($key, static::$primitiveCastTypes)) {
return $this->castAttribute($key, $attribute) ===
$this->castAttribute($key, $original);
}
return is_numeric($attribute) && is_numeric($original)
&& strcmp((string) $attribute, (string) $original) === 0;
}
/** @inheritdoc */
public function offsetUnset($offset): void
{
$offset = (string) $offset;
if (str_contains($offset, '.')) {
// Update the field in the subdocument
Arr::forget($this->attributes, $offset);
} else {
parent::offsetUnset($offset);
// Force unsetting even if the attribute is not set.
// End user can optimize DB calls by checking if the attribute is set before unsetting it.
$this->unset[$offset] = true;
}
}
/** @inheritdoc */
public function offsetSet($offset, $value): void
{
parent::offsetSet($offset, $value);
// Setting an attribute cancels the unset operation.
unset($this->unset[$offset]);
}
/**
* Remove one or more fields.
*
* @deprecated Use unset() instead.
*
* @param string|string[] $columns
*
* @return void
*/
public function drop($columns)
{
$this->unset($columns);
}
/**
* Remove one or more fields.
*
* @param string|string[] $columns
*
* @return void
*/
public function unset($columns)
{
$columns = Arr::wrap($columns);
// Unset attributes
foreach ($columns as $column) {
$this->__unset($column);
}
}
/** @inheritdoc */
public function push()
{
$parameters = func_get_args();
if ($parameters) {
$unique = false;
if (count($parameters) === 3) {
[$column, $values, $unique] = $parameters;
} else {
[$column, $values] = $parameters;
}
// Do batch push by default.
$values = Arr::wrap($values);
$query = $this->setKeysForSaveQuery($this->newQuery());
$this->pushAttributeValues($column, $values, $unique);
return $query->push($column, $values, $unique);
}
return parent::push();
}
/**
* Remove one or more values from an array.
*
* @param string $column
* @param mixed $values
*
* @return mixed
*/
public function pull($column, $values)
{
// Do batch pull by default.
$values = Arr::wrap($values);
$query = $this->setKeysForSaveQuery($this->newQuery());
$this->pullAttributeValues($column, $values);
return $query->pull($column, $values);
}
/**
* Append one or more values to the underlying attribute value and sync with original.
*
* @param string $column
* @param bool $unique
*/
protected function pushAttributeValues($column, array $values, $unique = false)
{
$current = $this->getAttributeFromArray($column) ?: [];
foreach ($values as $value) {
// Don't add duplicate values when we only want unique values.
if ($unique && (! is_array($current) || in_array($value, $current))) {
continue;
}
$current[] = $value;
}
$this->attributes[$column] = $current;
$this->syncOriginalAttribute($column);
}
/**
* Remove one or more values to the underlying attribute value and sync with original.
*
* @param string $column
*/
protected function pullAttributeValues($column, array $values)
{
$current = $this->getAttributeFromArray($column) ?: [];
if (is_array($current)) {
foreach ($values as $value) {
$keys = array_keys($current, $value);
foreach ($keys as $key) {
unset($current[$key]);
}
}
}
$this->attributes[$column] = array_values($current);
$this->syncOriginalAttribute($column);
}
/** @inheritdoc */
public function getForeignKey()
{
return Str::snake(class_basename($this)) . '_' . ltrim($this->primaryKey, '_');
}
/**
* Set the parent relation.
*/
public function setParentRelation(Relation $relation)
{
$this->parentRelation = $relation;
}
/**
* Get the parent relation.
*/
public function getParentRelation(): ?Relation
{
return $this->parentRelation ?? null;
}
/** @inheritdoc */
public function newEloquentBuilder($query)
{
return new Builder($query);
}
/** @inheritdoc */
public function qualifyColumn($column)
{
return $column;
}
/** @inheritdoc */
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
return new QueryBuilder($connection, $connection->getQueryGrammar(), $connection->getPostProcessor());
}
/** @inheritdoc */
protected function removeTableFromKey($key)
{
return $key;
}
/**
* Get the queueable relationships for the entity.
*
* @return array
*/
public function getQueueableRelations()
{
$relations = [];
foreach ($this->getRelationsWithoutParent() as $key => $relation) {
if (method_exists($this, $key)) {
$relations[] = $key;
}
if ($relation instanceof QueueableCollection) {
foreach ($relation->getQueueableRelations() as $collectionValue) {
$relations[] = $key . '.' . $collectionValue;
}
}
if ($relation instanceof QueueableEntity) {
foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) {
$relations[] = $key . '.' . $entityValue;
}
}
}
return array_unique($relations);
}
/**
* Get loaded relations for the instance without parent.
*
* @return array
*/
protected function getRelationsWithoutParent()
{
$relations = $this->getRelations();
$parentRelation = $this->getParentRelation();
if ($parentRelation) {
unset($relations[$parentRelation->getQualifiedForeignKeyName()]);
}
return $relations;
}
/**
* Checks if column exists on a table. As this is a document model, just return true. This also
* prevents calls to non-existent function Grammar::compileColumnListing().
*
* @param string $key
*
* @return bool
*/
protected function isGuardableColumn($key)
{
return true;
}
/** @inheritdoc */
protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes)
{
foreach ($this->getCasts() as $key => $castType) {
if (! Arr::has($attributes, $key) || Arr::has($mutatedAttributes, $key)) {
continue;
}
$originalValue = Arr::get($attributes, $key);
// Here we will cast the attribute. Then, if the cast is a date or datetime cast
// then we will serialize the date for the array. This will convert the dates
// to strings based on the date format specified for these Eloquent models.
$castValue = $this->castAttribute(
$key,
$originalValue,
);
// If the attribute cast was a date or a datetime, we will serialize the date as
// a string. This allows the developers to customize how dates are serialized
// into an array without affecting how they are persisted into the storage.
if ($castValue !== null && in_array($castType, ['date', 'datetime', 'immutable_date', 'immutable_datetime'])) {
$castValue = $this->serializeDate($castValue);
}
if ($castValue !== null && ($this->isCustomDateTimeCast($castType) || $this->isImmutableCustomDateTimeCast($castType))) {
$castValue = $castValue->format(explode(':', $castType, 2)[1]);
}
if ($castValue instanceof DateTimeInterface && $this->isClassCastable($key)) {
$castValue = $this->serializeDate($castValue);
}
if ($castValue !== null && $this->isClassSerializable($key)) {
$castValue = $this->serializeClassCastableAttribute($key, $castValue);
}
if ($this->isEnumCastable($key) && (! $castValue instanceof Arrayable)) {
$castValue = $castValue !== null ? $this->getStorableEnumValueFromLaravel11($this->getCasts()[$key], $castValue) : null;
}
if ($castValue instanceof Arrayable) {
$castValue = $castValue->toArray();
}
Arr::set($attributes, $key, $castValue);
}
return $attributes;
}
/**
* Duplicate of {@see HasAttributes::getStorableEnumValue()} for Laravel 11 as the signature of the method has
* changed in a non-backward compatible way.
*
* @todo Remove this method when support for Laravel 10 is dropped.
*/
private function getStorableEnumValueFromLaravel11($expectedEnum, $value)
{
if (! $value instanceof $expectedEnum) {
throw new ValueError(sprintf('Value [%s] is not of the expected enum type [%s].', var_export($value, true), $expectedEnum));
}
return $value instanceof BackedEnum
? $value->value
: $value->name;
}
/**
* Is a value a BSON type?
*
* @param mixed $value
*
* @return bool
*/
protected function isBSON(mixed $value): bool
{
return $value instanceof Type;
}
/**
* {@inheritDoc}
*/
public function save(array $options = [])
{
// SQL databases would autoincrement the id field if set to null.
// Apply the same behavior to MongoDB with _id only, otherwise null would be stored.
if (array_key_exists('_id', $this->attributes) && $this->attributes['_id'] === null) {
unset($this->attributes['_id']);
}
if (array_key_exists('id', $this->attributes) && $this->attributes['id'] === null) {
unset($this->attributes['id']);
}
$saved = parent::save($options);
// Clear list of unset fields
$this->unset = [];
return $saved;
}
/**
* {@inheritDoc}
*/
public function refresh()
{
parent::refresh();
// Clear list of unset fields
$this->unset = [];
return $this;
}
}
================================================
FILE: src/Eloquent/EmbedsRelations.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Illuminate\Support\Str;
use MongoDB\Laravel\Relations\EmbedsMany;
use MongoDB\Laravel\Relations\EmbedsOne;
use function class_basename;
use function debug_backtrace;
use const DEBUG_BACKTRACE_IGNORE_ARGS;
/**
* Embeds relations for MongoDB models.
*/
trait EmbedsRelations
{
/**
* Define an embedded one-to-many relationship.
*
* @param class-string $related
* @param string|null $localKey
* @param string|null $foreignKey
* @param string|null $relation
*
* @return EmbedsMany
*/
protected function embedsMany($related, $localKey = null, $foreignKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if ($relation === null) {
$relation = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'];
}
if ($localKey === null) {
$localKey = $relation;
}
if ($foreignKey === null) {
$foreignKey = Str::snake(class_basename($this));
}
$query = $this->newQuery();
$instance = new $related();
return new EmbedsMany($query, $this, $instance, $localKey, $foreignKey, $relation);
}
/**
* Define an embedded one-to-many relationship.
*
* @param class-string $related
* @param string|null $localKey
* @param string|null $foreignKey
* @param string|null $relation
*
* @return EmbedsOne
*/
protected function embedsOne($related, $localKey = null, $foreignKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if ($relation === null) {
$relation = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'];
}
if ($localKey === null) {
$localKey = $relation;
}
if ($foreignKey === null) {
$foreignKey = Str::snake(class_basename($this));
}
$query = $this->newQuery();
$instance = new $related();
return new EmbedsOne($query, $this, $instance, $localKey, $foreignKey, $relation);
}
}
================================================
FILE: src/Eloquent/HasSchemaVersion.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Error;
use LogicException;
use function sprintf;
/**
* Use this trait to implement schema versioning in your models. The document
* is updated automatically when its schema version retrieved from the database
* is lower than the current schema version of the model.
*
* class MyVersionedModel extends Model
* {
* use HasSchemaVersion;
*
* public const int SCHEMA_VERSION = 1;
*
* public function migrateSchema(int $fromVersion): void
* {
* // Your logic to update the document to the current schema version
* }
* }
*
* @see https://www.mongodb.com/docs/manual/tutorial/model-data-for-schema-versioning/
*
* Requires PHP 8.2+
*/
trait HasSchemaVersion
{
/**
* This method should be implemented in the model to migrate a document from
* an older schema version to the current schema version.
*/
public function migrateSchema(int $fromVersion): void
{
}
public static function bootHasSchemaVersion(): void
{
static::saving(function ($model) {
if ($model->getAttribute($model::getSchemaVersionKey()) === null) {
$model->setAttribute($model::getSchemaVersionKey(), $model->getModelSchemaVersion());
}
});
static::retrieved(function (self $model) {
$version = $model->getSchemaVersion();
if ($version < $model->getModelSchemaVersion()) {
$model->migrateSchema($version);
$model->setAttribute($model::getSchemaVersionKey(), $model->getModelSchemaVersion());
}
});
}
/**
* Get Current document version, fallback to 0 if not set
*/
public function getSchemaVersion(): int
{
return $this->{static::getSchemaVersionKey()} ?? 0;
}
protected static function getSchemaVersionKey(): string
{
return 'schema_version';
}
protected function getModelSchemaVersion(): int
{
try {
return $this::SCHEMA_VERSION;
} catch (Error) {
throw new LogicException(sprintf('Constant %s::SCHEMA_VERSION is required when using HasSchemaVersion', $this::class));
}
}
}
================================================
FILE: src/Eloquent/HybridRelations.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Illuminate\Database\Eloquent\Concerns\HasRelationships;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Support\Str;
use MongoDB\Laravel\Helpers\EloquentBuilder;
use MongoDB\Laravel\Relations\BelongsTo;
use MongoDB\Laravel\Relations\BelongsToMany;
use MongoDB\Laravel\Relations\HasMany;
use MongoDB\Laravel\Relations\HasOne;
use MongoDB\Laravel\Relations\MorphMany;
use MongoDB\Laravel\Relations\MorphTo;
use MongoDB\Laravel\Relations\MorphToMany;
use function array_pop;
use function debug_backtrace;
use function implode;
use function preg_split;
use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const PREG_SPLIT_DELIM_CAPTURE;
/**
* Cross-database relationships between SQL and MongoDB.
* Use this trait in SQL models to define relationships with MongoDB models.
*/
trait HybridRelations
{
/**
* Define a one-to-one relationship.
*
* @see HasRelationships::hasOne()
*
* @param class-string $related
* @param string|null $foreignKey
* @param string|null $localKey
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function hasOne($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::hasOne($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related();
$localKey = $localKey ?: $this->getKeyName();
return new HasOne($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a polymorphic one-to-one relationship.
*
* @see HasRelationships::morphOne()
*
* @param class-string $related
* @param string $name
* @param string|null $type
* @param string|null $id
* @param string|null $localKey
*
* @return MorphOne
*/
public function morphOne($related, $name, $type = null, $id = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::morphOne($related, $name, $type, $id, $localKey);
}
$instance = new $related();
[$type, $id] = $this->getMorphs($name, $type, $id);
$localKey = $localKey ?: $this->getKeyName();
return new MorphOne($instance->newQuery(), $this, $type, $id, $localKey);
}
/**
* Define a one-to-many relationship.
*
* @see HasRelationships::hasMany()
*
* @param class-string $related
* @param string|null $foreignKey
* @param string|null $localKey
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::hasMany($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related();
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a polymorphic one-to-many relationship.
*
* @see HasRelationships::morphMany()
*
* @param class-string $related
* @param string $name
* @param string|null $type
* @param string|null $id
* @param string|null $localKey
*
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::morphMany($related, $name, $type, $id, $localKey);
}
$instance = new $related();
// Here we will gather up the morph type and ID for the relationship so that we
// can properly query the intermediate table of a relation. Finally, we will
// get the table and create the relationship instances for the developers.
[$type, $id] = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphMany($instance->newQuery(), $this, $type, $id, $localKey);
}
/**
* Define an inverse one-to-one or many relationship.
*
* @see HasRelationships::belongsTo()
*
* @param class-string $related
* @param string|null $foreignKey
* @param string|null $ownerKey
* @param string|null $relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if ($relation === null) {
$relation = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'];
}
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::belongsTo($related, $foreignKey, $ownerKey, $relation);
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if ($foreignKey === null) {
$foreignKey = Str::snake($relation) . '_id';
}
$instance = new $related();
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$ownerKey = $ownerKey ?: $instance->getKeyName();
return new BelongsTo($query, $this, $foreignKey, $ownerKey, $relation);
}
/**
* Define a polymorphic, inverse one-to-one or many relationship.
*
* @see HasRelationships::morphTo()
*
* @param string $name
* @param string|null $type
* @param string|null $id
* @param string|null $ownerKey
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function morphTo($name = null, $type = null, $id = null, $ownerKey = null)
{
// If no name is provided, we will use the backtrace to get the function name
// since that is most likely the name of the polymorphic interface. We can
// use that to get both the class and foreign key that will be utilized.
if ($name === null) {
$name = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'];
}
[$type, $id] = $this->getMorphs(Str::snake($name), $type, $id);
// If the type value is null it is probably safe to assume we're eager loading
// the relationship. When that is the case we will pass in a dummy query as
// there are multiple types in the morph and we can't use single queries.
$class = $this->$type;
if ($class === null) {
return new MorphTo(
$this->newQuery(),
$this,
$id,
$ownerKey,
$type,
$name,
);
}
// If we are not eager loading the relationship we will essentially treat this
// as a belongs-to style relationship since morph-to extends that class and
// we will pass in the appropriate values so that it behaves as expected.
$class = $this->getActualClassNameForMorph($class);
$instance = new $class();
$ownerKey ??= $instance->getKeyName();
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($instance)) {
return parent::morphTo($name, $type, $id, $ownerKey);
}
return new MorphTo(
$instance->newQuery(),
$this,
$id,
$ownerKey,
$type,
$name,
);
}
/**
* Define a many-to-many relationship.
*
* @see HasRelationships::belongsToMany()
*
* @param class-string $related
* @param string|null $collection
* @param string|null $foreignPivotKey
* @param string|null $relatedPivotKey
* @param string|null $parentKey
* @param string|null $relatedKey
* @param string|null $relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany(
$related,
$collection = null,
$foreignPivotKey = null,
$relatedPivotKey = null,
$parentKey = null,
$relatedKey = null,
$relation = null,
) {
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if ($relation === null) {
$relation = $this->guessBelongsToManyRelation();
}
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::belongsToMany(
$related,
$collection,
$foreignPivotKey,
$relatedPivotKey,
$parentKey,
$relatedKey,
$relation,
);
}
// First, we'll need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we'll make the query
// instances as well as the relationship instances we need for this.
$foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey() . 's';
$instance = new $related();
$relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey() . 's';
// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
// are transformed to snake case from their default CamelCase also.
if ($collection === null) {
$collection = $instance->getTable();
}
// Now we're ready to create a new query builder for the related model and
// the relationship instances for the relation. The relations will set
// appropriate query constraint and entirely manages the hydrations.
$query = $instance->newQuery();
return new BelongsToMany(
$query,
$this,
$collection,
$foreignPivotKey,
$relatedPivotKey,
$parentKey ?: $this->getKeyName(),
$relatedKey ?: $instance->getKeyName(),
$relation,
);
}
/**
* Define a morph-to-many relationship.
*
* @param class-string $related
* @param string $name
* @param string|null $table
* @param string|null $foreignPivotKey
* @param string|null $relatedPivotKey
* @param string|null $parentKey
* @param string|null $relatedKey
* @param string|null $relation
* @param bool $inverse
*
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphToMany(
$related,
$name,
$table = null,
$foreignPivotKey = null,
$relatedPivotKey = null,
$parentKey = null,
$relatedKey = null,
$relation = null,
$inverse = false,
) {
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if ($relation === null) {
$relation = $this->guessBelongsToManyRelation();
}
// Check if it is a relation with an original model.
if (! Model::isDocumentModel($related)) {
return parent::morphToMany(
$related,
$name,
$table,
$foreignPivotKey,
$relatedPivotKey,
$parentKey,
$relatedKey,
$relation,
$inverse,
);
}
$instance = new $related();
$foreignPivotKey = $foreignPivotKey ?: $name . '_id';
$relatedPivotKey = $relatedPivotKey ?: Str::plural($instance->getForeignKey());
// Now we're ready to create a new query builder for the related model and
// the relationship instances for this relation. This relation will set
// appropriate query constraints then entirely manage the hydration.
if (! $table) {
$words = preg_split('/(_)/u', $name, -1, PREG_SPLIT_DELIM_CAPTURE);
$lastWord = array_pop($words);
$table = implode('', $words) . Str::plural($lastWord);
}
return new MorphToMany(
$instance->newQuery(),
$this,
$name,
$table,
$foreignPivotKey,
$relatedPivotKey,
$parentKey ?: $this->getKeyName(),
$relatedKey ?: $instance->getKeyName(),
$relation,
$inverse,
);
}
/**
* Define a polymorphic, inverse many-to-many relationship.
*
* @param class-string $related
* @param string $name
* @param string|null $table
* @param string|null $foreignPivotKey
* @param string|null $relatedPivotKey
* @param string|null $parentKey
* @param string|null $relatedKey
* @param string|null $relation
*
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphedByMany(
$related,
$name,
$table = null,
$foreignPivotKey = null,
$relatedPivotKey = null,
$parentKey = null,
$relatedKey = null,
$relation = null,
) {
// If the related model is an instance of eloquent model class, leave pivot keys
// as default. It's necessary for supporting hybrid relationship
if (Model::isDocumentModel($related)) {
// For the inverse of the polymorphic many-to-many relations, we will change
// the way we determine the foreign and other keys, as it is the opposite
// of the morph-to-many method since we're figuring out these inverses.
$foreignPivotKey = $foreignPivotKey ?: Str::plural($this->getForeignKey());
$relatedPivotKey = $relatedPivotKey ?: $name . '_id';
}
return $this->morphToMany(
$related,
$name,
$table,
$foreignPivotKey,
$relatedPivotKey,
$parentKey,
$relatedKey,
$relatedKey,
true,
);
}
/** @inheritdoc */
public function newEloquentBuilder($query)
{
if (Model::isDocumentModel($this)) {
return new Builder($query);
}
return new EloquentBuilder($query);
}
}
================================================
FILE: src/Eloquent/MassPrunable.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Illuminate\Database\Eloquent\MassPrunable as EloquentMassPrunable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Events\ModelsPruned;
use function class_uses_recursive;
use function event;
use function in_array;
trait MassPrunable
{
use EloquentMassPrunable;
/**
* Prune all prunable models in the database.
*
* @see \Illuminate\Database\Eloquent\MassPrunable::pruneAll()
*/
public function pruneAll(): int
{
$query = $this->prunable();
$total = in_array(SoftDeletes::class, class_uses_recursive(static::class))
? $query->forceDelete()
: $query->delete();
event(new ModelsPruned(static::class, $total));
return $total;
}
}
================================================
FILE: src/Eloquent/Model.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use Illuminate\Database\Eloquent\Model as BaseModel;
use MongoDB\Laravel\Auth\User;
use function array_key_exists;
use function class_uses_recursive;
use function is_object;
use function is_subclass_of;
abstract class Model extends BaseModel
{
use DocumentModel;
/**
* The primary key type.
*
* @var string
*/
protected $keyType = 'string';
private static $documentModelClasses = [User::class => true];
/**
* Indicates if the given model class is a MongoDB document model.
* It must be a subclass of {@see BaseModel} and use the
* {@see DocumentModel} trait.
*
* @param class-string|object $class
*/
final public static function isDocumentModel(string|object $class): bool
{
if (is_object($class)) {
$class = $class::class;
}
if (array_key_exists($class, self::$documentModelClasses)) {
return self::$documentModelClasses[$class];
}
// We know all child classes of this class are document models.
if (is_subclass_of($class, self::class)) {
return self::$documentModelClasses[$class] = true;
}
// Document models must be subclasses of Laravel's base model class.
if (! is_subclass_of($class, BaseModel::class)) {
return self::$documentModelClasses[$class] = false;
}
// Document models must use the DocumentModel trait.
return self::$documentModelClasses[$class] = array_key_exists(DocumentModel::class, class_uses_recursive($class));
}
}
================================================
FILE: src/Eloquent/SoftDeletes.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Eloquent;
use function sprintf;
use function trigger_error;
use const E_USER_DEPRECATED;
trigger_error(sprintf('Since mongodb/laravel-mongodb:5.5, trait "%s" is deprecated, use "%s" instead.', SoftDeletes::class, \Illuminate\Database\Eloquent\SoftDeletes::class), E_USER_DEPRECATED);
/** @deprecated since mongodb/laravel-mongodb:5.5, use \Illuminate\Database\Eloquent\SoftDeletes instead */
trait SoftDeletes
{
use \Illuminate\Database\Eloquent\SoftDeletes;
/** @inheritdoc */
public function getQualifiedDeletedAtColumn()
{
return $this->getDeletedAtColumn();
}
}
================================================
FILE: src/Helpers/EloquentBuilder.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Helpers;
use Illuminate\Database\Eloquent\Builder;
class EloquentBuilder extends Builder
{
use QueriesRelationships;
}
================================================
FILE: src/Helpers/QueriesRelationships.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Helpers;
use Closure;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
use LogicException;
use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Relations\MorphToMany;
use function array_count_values;
use function array_filter;
use function array_keys;
use function array_map;
use function class_basename;
use function collect;
use function in_array;
use function is_array;
use function is_string;
use function method_exists;
use function str_contains;
trait QueriesRelationships
{
/**
* Add a relationship count / exists condition to the query.
*
* @param Relation|string $relation
* @param string $operator
* @param int $count
* @param string $boolean
*
* @return Builder|static
*
* @throws Exception
*/
public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null)
{
if (is_string($relation)) {
if (str_contains($relation, '.')) {
return $this->hasNested($relation, $operator, $count, $boolean, $callback);
}
$relation = $this->getRelationWithoutConstraints($relation);
}
// If this is a hybrid relation then we can not use a normal whereExists() query that relies on a subquery
// We need to use a `whereIn` query
if (Model::isDocumentModel($this->getModel()) || $this->isAcrossConnections($relation)) {
return $this->addHybridHas($relation, $operator, $count, $boolean, $callback);
}
// If we only need to check for the existence of the relation, then we can optimize
// the subquery to only run a "where exists" clause instead of this full "count"
// clause. This will make these queries run much faster compared with a count.
$method = $this->canUseExistsForExistenceCheck($operator, $count)
? 'getRelationExistenceQuery'
: 'getRelationExistenceCountQuery';
$hasQuery = $relation->{$method}(
$relation->getRelated()->newQuery(),
$this
);
// Next we will call any given callback as an "anonymous" scope so they can get the
// proper logical grouping of the where clauses if needed by this Eloquent query
// builder. Then, we will be ready to finalize and return this query instance.
if ($callback) {
$hasQuery->callScope($callback);
}
return $this->addHasWhere(
$hasQuery,
$relation,
$operator,
$count,
$boolean,
);
}
/** @return bool */
protected function isAcrossConnections(Relation $relation)
{
return $relation->getParent()->getConnectionName() !== $relation->getRelated()->getConnectionName();
}
/**
* Compare across databases.
*
* @param string $operator
* @param int $count
* @param string $boolean
*
* @return mixed
*
* @throws Exception
*/
public function addHybridHas(Relation $relation, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null)
{
$this->assertHybridRelationSupported($relation);
$hasQuery = $relation->getQuery();
if ($callback) {
$hasQuery->callScope($callback);
}
// If the operator is <, <= or !=, we will use whereNotIn.
$not = in_array($operator, ['<', '<=', '!=']);
// If we are comparing to 0, we need an additional $not flip.
if ($count === 0) {
$not = ! $not;
}
$relations = match (true) {
$relation instanceof MorphToMany => $relation->getInverse() ?
$this->handleMorphedByMany($hasQuery, $relation) :
$this->handleMorphToMany($hasQuery, $relation),
default => $hasQuery->pluck($this->getHasCompareKey($relation))
};
$relatedIds = $this->getConstrainedRelatedIds($relations, $operator, $count);
return $this->whereIn($this->getRelatedConstraintKey($relation), $relatedIds, $boolean, $not);
}
/**
* @param Relation $relation
*
* @return void
*
* @throws Exception
*/
private function assertHybridRelationSupported(Relation $relation): void
{
if (
$relation instanceof HasOneOrMany
|| $relation instanceof BelongsTo
|| ($relation instanceof BelongsToMany && ! $this->isAcrossConnections($relation))
) {
return;
}
throw new LogicException(class_basename($relation) . ' is not supported for hybrid query constraints.');
}
/**
* @param Builder $hasQuery
* @param Relation $relation
*
* @return Collection
*/
private function handleMorphToMany($hasQuery, $relation)
{
// First we select the parent models that have a relation to our related model,
// Then extracts related model's ids from the pivot column
$hasQuery->where($relation->getTable() . '.' . $relation->getMorphType(), $relation->getParent()::class);
$relations = $hasQuery->pluck($relation->getTable());
$relations = $relation->extractIds($relations->flatten(1)->toArray(), $relation->getForeignPivotKeyName());
return collect($relations);
}
/**
* @param Builder $hasQuery
* @param Relation $relation
*
* @return Collection
*/
private function handleMorphedByMany($hasQuery, $relation)
{
$hasQuery->whereNotNull($relation->getForeignPivotKeyName());
return $hasQuery->pluck($relation->getForeignPivotKeyName())->flatten(1);
}
/** @return string */
protected function getHasCompareKey(Relation $relation)
{
if (method_exists($relation, 'getHasCompareKey')) {
return $relation->getHasCompareKey();
}
return $relation instanceof HasOneOrMany ? $relation->getForeignKeyName() : $relation->getOwnerKeyName();
}
/**
* @param Collection $relations
* @param string $operator
* @param int $count
*
* @return array
*/
protected function getConstrainedRelatedIds($relations, $operator, $count)
{
$relationCount = array_count_values(array_map(function ($id) {
return (string) $id; // Convert Back ObjectIds to Strings
}, is_array($relations) ? $relations : $relations->flatten()->toArray()));
// Remove unwanted related objects based on the operator and count.
$relationCount = array_filter($relationCount, function ($counted) use ($count, $operator) {
// If we are comparing to 0, we always need all results.
if ($count === 0) {
return true;
}
switch ($operator) {
case '>=':
case '<':
return $counted >= $count;
case '>':
case '<=':
return $counted > $count;
case '=':
case '!=':
return $counted === $count;
}
});
// All related ids.
return array_keys($relationCount);
}
/**
* Returns key we are constraining this parent model's query with.
*
* @return string
*
* @throws Exception
*/
protected function getRelatedConstraintKey(Relation $relation)
{
$this->assertHybridRelationSupported($relation);
if ($relation instanceof HasOneOrMany) {
return $relation->getLocalKeyName();
}
if ($relation instanceof BelongsTo) {
return $relation->getForeignKeyName();
}
if ($relation instanceof BelongsToMany) {
return $this->model->getKeyName();
}
throw new Exception(class_basename($relation) . ' is not supported for hybrid query constraints.');
}
}
================================================
FILE: src/MongoDBBusServiceProvider.php
================================================
<?php
namespace MongoDB\Laravel;
use Illuminate\Bus\BatchFactory;
use Illuminate\Bus\BatchRepository;
use Illuminate\Bus\BusServiceProvider;
use Illuminate\Container\Container;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;
use MongoDB\Laravel\Bus\MongoBatchRepository;
use Override;
use function sprintf;
class MongoDBBusServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register the service provider.
*/
#[Override]
public function register()
{
$this->app->singleton(MongoBatchRepository::class, function (Container $app) {
$connection = $app->make('db')->connection($app->config->get('queue.batching.database'));
if (! $connection instanceof Connection) {
throw new InvalidArgumentException(sprintf('The "mongodb" batch driver requires a MongoDB connection. The "%s" connection uses the "%s" driver.', $connection->getName(), $connection->getDriverName()));
}
return new MongoBatchRepository(
$app->make(BatchFactory::class),
$connection,
$app->config->get('queue.batching.collection', 'job_batches'),
);
});
/** The {@see BatchRepository} service is registered in {@see BusServiceProvider} */
$this->app->register(BusServiceProvider::class);
$this->app->extend(BatchRepository::class, function (BatchRepository $repository, Container $app) {
$driver = $app->config->get('queue.batching.driver');
return match ($driver) {
'mongodb' => $app->make(MongoBatchRepository::class),
default => $repository,
};
});
}
/** @inheritdoc */
#[Override]
public function provides()
{
return [
BatchRepository::class,
MongoBatchRepository::class,
];
}
}
================================================
FILE: src/MongoDBServiceProvider.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel;
use Closure;
use Illuminate\Cache\CacheManager;
use Illuminate\Cache\Repository;
use Illuminate\Container\Container;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Foundation\Application;
use Illuminate\Session\SessionManager;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;
use Laravel\Scout\EngineManager;
use League\Flysystem\Filesystem;
use League\Flysystem\GridFS\GridFSAdapter;
use League\Flysystem\ReadOnly\ReadOnlyFilesystemAdapter;
use MongoDB\GridFS\Bucket;
use MongoDB\Laravel\Cache\MongoStore;
use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Queue\MongoConnector;
use MongoDB\Laravel\Scout\ScoutEngine;
use MongoDB\Laravel\Session\MongoDbSessionHandler;
use Override;
use RuntimeException;
use function assert;
use function class_exists;
use function get_debug_type;
use function is_string;
use function sprintf;
class MongoDBServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*/
public function boot()
{
Model::setConnectionResolver($this->app['db']);
Model::setEventDispatcher($this->app['events']);
}
/**
* Register the service provider.
*/
#[Override]
public function register()
{
// Add database driver.
$this->app->resolving('db', function ($db) {
$db->extend('mongodb', function ($config, $name) {
$config['name'] = $name;
return new Connection($config);
});
});
// Session handler for MongoDB
$this->app->resolving(SessionManager::class, function (SessionManager $sessionManager) {
$sessionManager->extend('mongodb', function (Application $app) {
$connectionName = $app->config->get('session.connection') ?: 'mongodb';
$connection = $app->make('db')->connection($connectionName);
assert($connection instanceof Connection, new InvalidArgumentException(sprintf('The database connection "%s" used for the session does not use the "mongodb" driver.', $connectionName)));
return new MongoDbSessionHandler(
$connection,
$app->config->get('session.table', 'sessions'),
$app->config->get('session.lifetime'),
$app,
);
});
});
// Add cache and lock drivers.
$this->app->resolving('cache', function (CacheManager $cache) {
$cache->extend('mongodb', function (Application $app, array $config): Repository {
// The closure is bound to the CacheManager
assert($this instanceof CacheManager);
$store = new MongoStore(
$app['db']->connection($config['connection'] ?? null),
$config['collection'] ?? 'cache',
$this->getPrefix($config),
$app['db']->connection($config['lock_connection'] ?? $config['connection'] ?? null),
$config['lock_collection'] ?? ($config['collection'] ?? 'cache') . '_locks',
$config['lock_lottery'] ?? [2, 100],
$config['lock_timeout'] ?? 86400,
);
return $this->repository($store, $config);
});
});
// Add connector for queue support.
$this->app->resolving('queue', function ($queue) {
$queue->addConnector('mongodb', function () {
return new MongoConnector($this->app['db']);
});
});
$this->registerFlysystemAdapter();
$this->registerScoutEngine();
}
private function registerFlysystemAdapter(): void
{
// GridFS adapter for filesystem
$this->app->resolving('filesystem', static function (FilesystemManager $filesystemManager) {
$filesystemManager->extend('gridfs', function (Application $app, array $config) {
if (! class_exists(GridFSAdapter::class)) {
throw new RuntimeException('GridFS adapter for Flysystem is missing. Try running "composer require league/flysystem-gridfs"');
}
$bucket = $config['bucket'] ?? null;
if ($bucket instanceof Closure) {
// Get the bucket from a factory function
$bucket = $bucket($app, $config);
} elseif (is_string($bucket) && $app->has($bucket)) {
// Get the bucket from a service
$bucket = $app->get($bucket);
} elseif (is_string($bucket) || $bucket === null) {
// Get the bucket from the database connection
$connection = $app['db']->connection($config['connection']);
if (! $connection instanceof Connection) {
throw new InvalidArgumentException(sprintf('The database connection "%s" does not use the "mongodb" driver.', $config['connection'] ?? $app['config']['database.default']));
}
$bucket = $connection->getClient()
->getDatabase($config['database'] ?? $connection->getDatabaseName())
->selectGridFSBucket(['bucketName' => $config['bucket'] ?? 'fs', 'disableMD5' => true]);
}
if (! $bucket instanceof Bucket) {
throw new InvalidArgumentException(sprintf('Unexpected value for GridFS "bucket" configuration. Expecting "%s". Got "%s"', Bucket::class, get_debug_type($bucket)));
}
$adapter = new GridFSAdapter($bucket, $config['prefix'] ?? '');
/** @see FilesystemManager::createFlysystem() */
if ($config['read-only'] ?? false) {
if (! class_exists(ReadOnlyFilesystemAdapter::class)) {
throw new RuntimeException('Read-only Adapter for Flysystem is missing. Try running "composer require league/flysystem-read-only"');
}
$adapter = new ReadOnlyFilesystemAdapter($adapter);
}
/** Prevent using backslash on Windows in {@see FilesystemAdapter::__construct()} */
$config['directory_separator'] = '/';
return new FilesystemAdapter(new Filesystem($adapter, $config), $adapter, $config);
});
});
}
private function registerScoutEngine(): void
{
$this->app->resolving(EngineManager::class, function (EngineManager $engineManager) {
$engineManager->extend('mongodb', function (Container $app) {
$connectionName = $app->get('config')->get('scout.mongodb.connection', 'mongodb');
$connection = $app->get('db')->connection($connectionName);
$softDelete = (bool) $app->get('config')->get('scout.soft_delete', false);
$indexDefinitions = $app->get('config')->get('scout.mongodb.index-definitions', []);
assert($connection instanceof Connection, new InvalidArgumentException(sprintf('The connection "%s" is not a MongoDB connection.', $connectionName)));
return new ScoutEngine($connection->getDatabase(), $softDelete, $indexDefinitions);
});
return $engineManager;
});
}
}
================================================
FILE: src/Query/AggregationBuilder.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Query;
use Illuminate\Support\Collection as LaravelCollection;
use Illuminate\Support\LazyCollection;
use InvalidArgumentException;
use Iterator;
use MongoDB\Builder\BuilderEncoder;
use MongoDB\Builder\Stage\FluentFactoryTrait;
use MongoDB\Collection;
use MongoDB\Driver\CursorInterface;
use function array_replace;
use function collect;
use function sprintf;
use function str_starts_with;
class AggregationBuilder
{
use FluentFactoryTrait;
public function __construct(
private Collection $collection,
private readonly array $options = [],
) {
}
/**
* Add a stage without using the builder. Necessary if the stage is built
* outside the builder, or it is not yet supported by the library.
*/
public function addRawStage(string $operator, mixed $value): static
{
if (! str_starts_with($operator, '$')) {
throw new InvalidArgumentException(sprintf('The stage name "%s" is invalid. It must start with a "$" sign.', $operator));
}
$this->pipeline[] = [$operator => $value];
return $this;
}
/**
* Execute the aggregation pipeline and return the results.
*/
public function get(array $options = []): LaravelCollection|LazyCollection
{
$cursor = $this->execute($options);
return collect($cursor->toArray());
}
/**
* Execute the aggregation pipeline and return the results in a lazy collection.
*/
public function cursor($options = []): LazyCollection
{
$cursor = $this->execute($options);
return LazyCollection::make(function () use ($cursor) {
foreach ($cursor as $item) {
yield $item;
}
});
}
/**
* Execute the aggregation pipeline and return the first result.
*/
public function first(array $options = []): mixed
{
return (clone $this)
->limit(1)
->get($options)
->first();
}
/**
* Execute the aggregation pipeline and return MongoDB cursor.
*/
private function execute(array $options): CursorInterface&Iterator
{
$encoder = new BuilderEncoder();
$pipeline = $encoder->encode($this->getPipeline());
$options = array_replace(
['typeMap' => ['root' => 'array', 'document' => 'array']],
$this->options,
$options,
);
return $this->collection->aggregate($pipeline, $options);
}
}
================================================
FILE: src/Query/Builder.php
================================================
<?php
declare(strict_types=1);
namespace MongoDB\Laravel\Query;
use ArgumentCountError;
use BadMethodCallException;
use Carbon\CarbonPeriod;
use Closure;
use DateTimeInterface;
use DateTimeZone;
use Illuminate\Database\Query\Builder as BaseBuilder;
use Illuminate\Database\Query\Expression;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\LazyCollection;
use InvalidArgumentException;
use LogicException;
use MongoDB\BSON\Binary;
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\Regex;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Builder\Search;
use MongoDB\Builder\Stage\FluentFactoryTrait;
use MongoDB\Builder\Type\QueryInterface;
use MongoDB\Builder\Type\SearchOperatorInterface;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\ReadPreference;
use MongoDB\Laravel\Connection;
use Override;
use RuntimeException;
use stdClass;
use TypeError;
use function array_fill_keys;
use function array_filter;
use function array_is_list;
use function array_key_exists;
use function array_keys;
use function array_map;
use function array_merge;
use function array_replace;
use function array_values;
use function assert;
use function blank;
use function call_user_func;
use function call_user_func_array;
use function count;
use function ctype_xdigit;
use function date_default_timezone_get;
use function dd;
use function dump;
use function end;
use function explode;
use function func_get_args;
use function func_num_args;
use function get_debug_type;
use function get_object_vars;
use function implode;
use function in_array;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_object;
use function is_string;
use function md5;
use function preg_match;
use function preg_quote;
use function preg_replace;
use function property_exists;
use function serialize;
use function sprintf;
use function str_contains;
use function str_ends_with;
use function str_replace;
use function str_starts_with;
use function strlen;
use function strtolower;
use function substr;
use function trait_exists;
use function var_export;
/** @property Connection $connection */
class Builder extends BaseBuilder
{
use BuilderTimeout;
private const REGEX_DELIMITERS = ['/', '#', '~'];
/**
* The database collection.
*
* @var \MongoDB\Collection
*/
protected $collection;
/**
* The column projections.
*
* @var array
*/
public $projections = [];
/**
* The cursor hint value.
*
* @var int
*/
public $hint;
private ReadPreference $readPreference;
/**
* Custom options to add to the query.
*
* @var array
*/
public $options = [];
/**
* All of the available clause operators.
*
* @var array
*/
public $operators = [
'=',
'<',
'>',
'<=',
'>=',
'<>',
'!=',
'like',
'not like',
'between',
'ilike',
'&',
'|',
'^',
'<<',
'>>',
'rlike',
'regexp',
'not regexp',
'exists',
'type',
'mod',
'where',
'all',
'size',
'regex',
'not regex',
'text',
'slice',
'elemmatch',
'geowithin',
'geointersects',
'near',
'nearsphere',
'geometry',
'maxdistance',
'center',
'centersphere',
'box',
'polygon',
'uniquedocs',
];
/**
* Operator conversion.
*
* @var array
*/
protected $conversion = [
'=' => 'eq',
'!=' => 'ne',
'<>' => 'ne',
'<' => 'lt',
'<=' => 'lte',
'>' => 'gt',
'>=' => 'gte',
'regexp' => 'regex',
'not regexp' => 'not regex',
'ilike' => 'like',
'elemmatch' => 'elemMatch',
'geointersects' => 'geoIntersects',
'geowithin' => 'geoWithin',
'nearsphere' => 'nearSphere',
'maxdistance' => 'maxDistance',
'centersphere' => 'centerSphere',
'uniquedocs' => 'uniqueDocs',
];
/**
* Set the projections.
*
* @param array $columns
*
* @return $this
*/
public function project($columns)
{
$this->projections = is_array($columns) ? $columns : func_get_args();
return $this;
}
/**
* Set the cursor hint.
*
* @param mixed $index
*
* @return $this
*/
public function hint($index)
{
$this->hint = $index;
return $this;
}
/** @inheritdoc */
#[Override]
public function find($id, $columns = [])
{
return $this->where('_id', '=', $this->convertKey($id))->first($columns);
}
/** @inheritdoc */
#[Override]
public function value($column)
{
$result = (array) $this->first([$column]);
return Arr::get($result, $column);
}
/** @inheritdoc */
#[Override]
public function get($columns = [])
{
return $this->getFresh($columns);
}
/** @inheritdoc */
#[Override]
public function cursor($columns = [])
{
$result = $this->getFresh($columns, true);
if ($result instanceof LazyCollection) {
return $result;
}
throw new RuntimeException('Query not compatible with cursor');
}
/**
* Die and dump the current MongoDB query
*
* @return never-return
*/
#[Override]
public function dd()
{
dd($this->toMql());
}
/**
* Dump the current MongoDB query
*
* @param mixed ...$args
*
* @return $this
*/
#[Override]
public function dump(mixed ...$args)
{
dump($this->toMql(), ...$args);
return $this;
}
/**
* Return the MongoDB query to be run in the form of an element array like ['method' => [arguments]].
*
* Example: ['find' => [['name' => 'John Doe'], ['projection' => ['birthday' => 1]]]]
*
* @return array<string, mixed[]>
*/
public function toMql(): array
{
$columns = $this->columns ?? [];
// Drop all columns if * is present, MongoDB does not work this way.
if (in_array('*', $columns)) {
$columns = [];
}
$wheres = $this->compileWheres();
$wheres = $this->aliasIdForQuery($wheres);
// Use MongoDB's aggregation framework when using grouping or aggregation functions.
if ($this->groups || $this->aggregate) {
$group = [];
$unwinds = [];
$set = [];
// Add grouping columns to the $group part of the aggregation pipeline.
if ($this->groups) {
foreach ($this->groups as $column) {
$group['_id'][$column] = '$' . $column;
// When grouping, also add the $last operator to each grouped field,
// this mimics SQL's behaviour a bit.
$group[$column] = ['$last' => '$' . $column];
}
}
// Add the last value of each column when there is no aggregate function.
if ($this->groups && ! $this->aggregate) {
foreach ($columns as $column) {
$key = str_replace('.', '_', $column);
$group[$key] = ['$last' => '$' . $column];
}
}
// Add aggregation functions to the $group part of the aggregation pipeline,
// these may override previous aggregations.
if ($this->aggregate) {
$function = $this->aggregate['function'];
foreach ($this->aggregate['columns'] as $column) {
// Add unwind if a subdocument array should be aggregated
// column: subarray.price => {$unwind: '$subarray'}
$splitColumns = explode('.*.', $column);
if (count($splitColumns) === 2) {
$unwinds[] = $splitColumns[0];
$column = implode('.', $splitColumns);
}
$aggregations = blank($this->aggregate['columns']) ? [] : $this->aggregate['columns'];
if ($column === '*' && $function === 'count' && ! $this->groups) {
$options = $this->inheritConnectionOptions($this->options);
return ['countDocuments' => [$wheres, $options]];
}
// "aggregate" is the name of the field that will hold the aggregated value.
if ($function === 'count') {
if ($column === '*' || $aggregations === []) {
// Translate count into sum.
$group['aggregate'] = ['$sum' => 1];
} else {
// Count the number of distinct values.
$group['aggregate'] = ['$addToSet' => '$' . $column];
$set['aggregate'] = ['$size' => '$aggregate'];
}
} else {
$group['aggregate'] = ['$' . $function => '$' . $column];
}
}
}
// The _id field is mandatory when using grouping.
if ($group && empty($group['_id'])) {
$group['_id'] = null;
}
// Build the aggregation pipeline.
$pipeline = [];
if ($wheres) {
$pipeline[] = ['$match' => $wheres];
}
// apply unwinds for subdocument array aggregation
foreach ($unwinds as $unwind) {
$pipeline[] = ['$unwind' => '$' . $unwind];
}
if ($group) {
$pipeline[] = ['$group' => $group];
}
if ($set) {
$pipeline[] = ['$set' => $set];
}
// Apply order and limit
if ($this->orders) {
$pipeline[] = ['$sort' => $this->aliasIdForQuery($this->orders)];
}
if ($this->offset) {
$pipeline[] = ['$skip' => $this->offset];
}
if ($this->limit) {
$pipeline[] = ['$limit' => $this->limit];
}
if ($this->projections) {
$pipeline[] = ['$project' => $this->projections];
}
$options = [
'typeMap' => ['root' => 'object', 'document' => 'array'],
];
// Add custom query options
if (count($this->options)) {
$options = array_replace($options, $this->options);
}
$options = $this->inheritConnectionOptions($options);
return ['aggregate' => [$pipeline, $options]];
}
// Distinct query
if ($this->distinct) {
// Return distinct results directly
$column = $columns[0] ?? '_id';
$options = $this->inheritConnectionOptions();
return ['distinct' => [$column, $wheres, $options]];
}
// Normal query
// Convert select columns to simple projections.
$projection = $this->aliasIdForQuery(array_fill_keys($columns, true));
// Add custom projections.
if ($this->projections) {
$projection = array_replace($projection, $this->projections);
}
$options = [];
// Apply order, offset, limit and projection
if ($this->timeout) {
$options['maxTimeMS'] = (int) ($this->timeout * 1000);
}
if ($this->orders) {
$options['sort'] = $this->aliasIdForQuery($this->orders);
}
if ($this->offset) {
$options['skip'] = $this->offset;
}
if ($this->limit) {
$options['limit'] = $this->limit;
}
if ($this->hint) {
$options['hint'] = $this->hint;
}
if ($projection) {
$options['projection'] = $projection;
}
$options['typeMap'] = ['root' => 'object', 'document' => 'array'];
// Add custom query options
if (count($this->options)) {
$options = array_replace($options, $this->options);
}
$options = $this->inheritConnectionOptions($options);
return ['find' => [$wheres, $options]];
}
/**
* Execute the query as a fresh "select" statement.
*
* @param array $columns
* @param bool $returnLazy
*
* @return array|static[]|Collection|LazyCollection
*/
public function getFresh($columns = [], $returnLazy = false)
{
// If no columns have been specified for the select statement, we will set them
// here to either the passed columns, or the standard default of retrieving
// all of the columns on the table using the "wildcard" column character.
if ($this->columns === null) {
$this->columns = $columns;
}
// Drop all columns if * is present, MongoDB does not work this way.
if (in_array('*', $this->columns)) {
$this->columns = [];
}
$command = $this->toMql();
assert(count($command) >= 1, 'At least one method call is required to execute a query');
$result = $this->collection;
foreach ($command as $method => $arguments) {
$result = call_user_func_array([$result, $method], $arguments);
}
// countDocuments method returns int, wrap it to the format expected by the framework
if (is_int($result)) {
$result = [
[
'_id' => null,
'aggregate' => $result,
],
];
}
if ($returnLazy) {
return LazyCollection::make(function () use ($result) {
foreach ($result as $item) {
yield $this->aliasIdForResult($item);
}
});
}
if ($result instanceof Cursor) {
$result = $result->toArray();
}
foreach ($result as &$document) {
if (is_array($document) || is_object($document)) {
$document = $this->aliasIdForResult($document);
}
}
return new Collection($result);
}
/**
* Generate the unique cache key for the current query.
*
* @return string
*/
public function generateCacheKey()
{
$key = [
'connection' => $this->collection->getDatabaseName(),
'collection' => $this->collection->getCollectionName(),
'wheres' => $this->wheres,
'columns' => $this->columns,
'groups' => $this->groups,
'orders' => $this->orders,
'offset' => $this->offset,
'limit' => $this->limit,
'aggregate' => $this->aggregate,
];
return md5(serialize(array_values($key)));
}
/** @return ($function is null ? AggregationBuilder : mixed) */
#[Override]
public function aggregate($function = null, $columns = ['*'])
{
assert(is_array($columns), new TypeError(sprintf('Argument #2 ($columns) must be of type array, %s given', get_debug_type($columns))));
if ($function === null) {
if (! trait_exists(FluentFactoryTrait::class)) {
// This error will be unreachable when the mongodb/builder package will be merged into mongodb/mongodb
throw new BadMethodCallException('Aggregation builder requires package mongodb/builder 0.2+');
}
if ($columns !== ['*']) {
throw new InvalidArgumentException('Columns cannot be specified to create an aggregation builder. Add a $project stage instead.');
}
if ($this->wheres) {
throw new BadMethodCallException('Aggregation builder does not support previous query-builder instructions. Use a $match stage instead.');
}
return new AggregationBuilder($this->collection, $this->options);
}
$this->aggregate = [
'function' => $function,
'columns' => $columns,
];
$previousColumns = $this->columns;
// We will also back up the select bindings since the select clause will be
// removed when performing the aggregate function. Once the query is run
// we will add the bindings back onto this query so they can get used.
$previousSelectBindings = $this->bindings['select'];
$this->bindings['select'] = [];
$results = $this->get($columns);
// Once we have executed the query, we will reset the aggregate property so
// that more select queries can be executed against the database without
// the aggregate value getting in the way when the grammar builds it.
$this->aggregate = null;
$this->columns = $previousColumns;
$this->bindings['select'] = $previousSelectBindings;
// When the aggregation is per group, we return the results as is.
if ($this->groups) {
return $results->map(function (object $result) {
unset($result->id);
return $result;
});
}
if (isset($results[0])) {
$result = (array) $results[0];
return $result['aggregate'];
}
}
/**
* @param string $function
* @param array $columns
*
* @return mixed
*/
public function aggregateByGroup(string $function, array $columns = ['*'])
{
if (count($columns) > 1) {
throw new InvalidArgumentException('Aggregating by group requires zero or one columns.');
}
return $this->aggregate($function, $columns);
}
/** @inheritdoc */
#[Override]
public function exists()
{
return $this->first(['id']) !== null;
}
/** @inheritdoc */
public function distinct($column = false)
{
$this->distinct = true;
if ($column) {
$this->columns = [$column];
}
return $this;
}
/**
* @param int|string|array $direction
*
* @inheritdoc
*/
#[Override]
public function orderBy($column, $direction = 'asc')
{
if (is_string($direction)) {
$direction = match ($direction) {
'asc', 'ASC' => 1,
'desc', 'DESC' => -1,
default => throw new InvalidArgumentException('Order direction must be "asc" or "desc".'),
};
}
$column = (string) $column;
if ($column === 'natural') {
$this->orders['$natural'] = $direction;
} else {
$this->orders[$column] = $direction;
}
return $this;
}
/**
* Override Illuminate's removeExistingOrdersFor to support associative order storage used by MongoDB.
*
* @inheritdoc
*/
#[Override]
protected function removeExistingOrdersFor($column): array
{
$orders = $this->orders ?? [];
$toUnset = array_filter(
array_keys($orders),
function ($orderColumn) use ($column) {
return $orderColumn === $column
|| ($orderColumn === 'id' && $column === '_id')
|| ($orderColumn === '_id' && $column === 'id'
);
},
);
foreach ($toUnset as $column) {
unset($orders[$column]);
}
return $orders;
}
/** @inheritdoc */
#[Override]
public function whereBetween($column, iterable $values, $boolean = 'and', $not = false)
{
$type = 'between';
if ($values instanceof Collection) {
$values = $values->all();
}
if (is_array($values) && (! array_is_list($values) || count($values) !== 2)) {
throw new InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]');
}
$this->wheres[] = [
'column' => $column,
'type' => $type,
'boolean' => $boolean,
'values' => $values,
'not' => $not,
];
return $this;
}
/** @inheritdoc */
#[Override]
public function insert(array $values)
{
// Allow empty insert batch for consistency with Eloquent SQL
if ($values === []) {
return true;
}
// Since every insert gets treated like a batch insert, we will have to detect
// if the user is inserting a single document or an array of documents.
$batch = true;
foreach ($values as $value) {
// As soon as we find a value that is not an array we assume the user is
// inserting a single document.
if (! is_array($value)) {
$batc
gitextract_2jedx5y6/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── BUG_REPORT.md
│ │ ├── FEATURE-REQUEST.md
│ │ └── config.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependabot.yml
│ ├── labeler.yml
│ ├── release.yml
│ └── workflows/
│ ├── build-ci-atlas.yml
│ ├── build-ci.yml
│ ├── coding-standards.yml
│ ├── labeler.yml
│ ├── merge-up.yml
│ ├── release.yml
│ └── static-analysis.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── RELEASING.md
├── composer.json
├── docker-compose.yml
├── phpcs.xml.dist
├── phpstan-baseline.neon
├── phpstan.neon.dist
├── phpunit.xml.dist
├── rector.php
├── sbom.json
├── src/
│ ├── Auth/
│ │ └── User.php
│ ├── Bus/
│ │ └── MongoBatchRepository.php
│ ├── Cache/
│ │ ├── MongoLock.php
│ │ └── MongoStore.php
│ ├── CommandSubscriber.php
│ ├── Concerns/
│ │ └── ManagesTransactions.php
│ ├── Connection.php
│ ├── Eloquent/
│ │ ├── Builder.php
│ │ ├── Casts/
│ │ │ ├── BinaryUuid.php
│ │ │ └── ObjectId.php
│ │ ├── DocumentModel.php
│ │ ├── EmbedsRelations.php
│ │ ├── HasSchemaVersion.php
│ │ ├── HybridRelations.php
│ │ ├── MassPrunable.php
│ │ ├── Model.php
│ │ └── SoftDeletes.php
│ ├── Helpers/
│ │ ├── EloquentBuilder.php
│ │ └── QueriesRelationships.php
│ ├── MongoDBBusServiceProvider.php
│ ├── MongoDBServiceProvider.php
│ ├── Query/
│ │ ├── AggregationBuilder.php
│ │ ├── Builder.php
│ │ ├── BuilderTimeout.php
│ │ ├── Grammar.php
│ │ └── Processor.php
│ ├── Queue/
│ │ ├── MongoConnector.php
│ │ ├── MongoJob.php
│ │ └── MongoQueue.php
│ ├── Relations/
│ │ ├── BelongsTo.php
│ │ ├── BelongsToMany.php
│ │ ├── EmbedsMany.php
│ │ ├── EmbedsOne.php
│ │ ├── EmbedsOneOrMany.php
│ │ ├── HasMany.php
│ │ ├── HasOne.php
│ │ ├── MorphMany.php
│ │ ├── MorphTo.php
│ │ └── MorphToMany.php
│ ├── Schema/
│ │ ├── Blueprint.php
│ │ ├── BlueprintLaravelCompatibility.php
│ │ ├── Builder.php
│ │ └── Grammar.php
│ ├── Scout/
│ │ └── ScoutEngine.php
│ ├── Session/
│ │ └── MongoDbSessionHandler.php
│ └── Validation/
│ ├── DatabasePresenceVerifier.php
│ └── ValidationServiceProvider.php
└── tests/
├── AtlasSearchIndexManagement.php
├── AtlasSearchTest.php
├── AuthTest.php
├── Bus/
│ ├── Fixtures/
│ │ ├── ChainHeadJob.php
│ │ ├── SecondTestJob.php
│ │ └── ThirdTestJob.php
│ └── MongoBatchRepositoryTest.php
├── Cache/
│ ├── MongoCacheStoreTest.php
│ └── MongoLockTest.php
├── Casts/
│ ├── BinaryUuidTest.php
│ ├── BooleanTest.php
│ ├── CollectionTest.php
│ ├── DateTest.php
│ ├── DatetimeTest.php
│ ├── DecimalTest.php
│ ├── EncryptionTest.php
│ ├── FloatTest.php
│ ├── IntegerTest.php
│ ├── JsonTest.php
│ ├── ObjectIdTest.php
│ ├── ObjectTest.php
│ └── StringTest.php
├── ConnectionTest.php
├── DateTimeImmutableTest.php
├── Eloquent/
│ ├── CallBuilderTest.php
│ ├── MassPrunableTest.php
│ └── ModelTest.php
├── EmbeddedRelationsTest.php
├── ExternalPackageTest.php
├── FilesystemsTest.php
├── GeospatialTest.php
├── HybridRelationsTest.php
├── ModelTest.php
├── Models/
│ ├── Address.php
│ ├── Anniversary.php
│ ├── Birthday.php
│ ├── Book.php
│ ├── CastObjectId.php
│ ├── Casting.php
│ ├── Client.php
│ ├── Experience.php
│ ├── Group.php
│ ├── Guarded.php
│ ├── HiddenAnimal.php
│ ├── IdIsBinaryUuid.php
│ ├── IdIsInt.php
│ ├── IdIsString.php
│ ├── Item.php
│ ├── Label.php
│ ├── Location.php
│ ├── MemberStatus.php
│ ├── NonIncrementing.php
│ ├── Photo.php
│ ├── Role.php
│ ├── SchemaVersion.php
│ ├── Scoped.php
│ ├── Skill.php
│ ├── Soft.php
│ ├── SqlBook.php
│ ├── SqlRole.php
│ ├── SqlUser.php
│ └── User.php
├── PHPStan/
│ └── SarifErrorFormatter.php
├── PropertyTest.php
├── Query/
│ ├── AggregationBuilderTest.php
│ └── BuilderTest.php
├── QueryBuilderTest.php
├── QueryTest.php
├── Queue/
│ └── Failed/
│ └── DatabaseFailedJobProviderTest.php
├── QueueTest.php
├── RelationsTest.php
├── SchemaTest.php
├── SchemaVersionTest.php
├── Scout/
│ ├── Models/
│ │ ├── ScoutUser.php
│ │ ├── SearchableInSameNamespace.php
│ │ └── SearchableModel.php
│ ├── ScoutEngineTest.php
│ └── ScoutIntegrationTest.php
├── Seeder/
│ ├── DatabaseSeeder.php
│ └── UserTableSeeder.php
├── SeederTest.php
├── SessionTest.php
├── TestCase.php
├── Ticket/
│ ├── GH2489Test.php
│ ├── GH2783Test.php
│ ├── GH3326Test.php
│ ├── GH3328Test.php
│ └── GH3335Test.php
├── TransactionTest.php
├── ValidationTest.php
└── config/
├── database.php
└── queue.php
SYMBOL INDEX (1270 symbols across 136 files)
FILE: src/Auth/User.php
class User (line 10) | class User extends BaseUser
FILE: src/Bus/MongoBatchRepository.php
class MongoBatchRepository (line 29) | class MongoBatchRepository extends DatabaseBatchRepository implements Pr...
method __construct (line 33) | public function __construct(
method get (line 43) | #[Override]
method find (line 60) | #[Override]
method store (line 79) | #[Override]
method incrementTotalJobs (line 99) | #[Override]
method decrementPendingJobs (line 115) | #[Override]
method incrementFailedJobs (line 137) | #[Override]
method markAsFinished (line 159) | #[Override]
method cancel (line 169) | #[Override]
method delete (line 184) | #[Override]
method transaction (line 192) | #[Override]
method rollBack (line 199) | #[Override]
method prune (line 206) | #[Override]
method pruneUnfinished (line 217) | #[Override]
method pruneCancelled (line 231) | #[Override]
method toBatch (line 245) | #[Override]
method getUTCDateTime (line 263) | private function getUTCDateTime(): UTCDateTime
method toCarbon (line 270) | private function toCarbon(?UTCDateTime $date): ?CarbonImmutable
FILE: src/Cache/MongoLock.php
class MongoLock (line 16) | final class MongoLock extends Lock
method __construct (line 27) | public function __construct(
method acquire (line 44) | #[Override]
method release (line 96) | #[Override]
method forceRelease (line 111) | #[Override]
method createTTLIndex (line 120) | public function createTTLIndex(): void
method getCurrentOwner (line 133) | #[Override]
method getUTCDateTime (line 145) | private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
FILE: src/Cache/MongoStore.php
class MongoStore (line 22) | final class MongoStore implements LockProvider, Store
method __construct (line 40) | public function __construct(
method lock (line 59) | #[Override]
method restoreLock (line 74) | #[Override]
method put (line 87) | #[Override]
method add (line 113) | public function add($key, $value, $seconds): bool
method get (line 152) | #[Override]
method increment (line 179) | #[Override]
method decrement (line 213) | #[Override]
method forever (line 225) | #[Override]
method forget (line 236) | #[Override]
method forgetIfExpired (line 251) | public function forgetIfExpired($key): bool
method touch (line 267) | public function touch($key, $seconds): bool
method flush (line 282) | public function flush(): bool
method getPrefix (line 289) | public function getPrefix(): string
method createTTLIndex (line 295) | public function createTTLIndex(): void
method serialize (line 305) | private function serialize($value): string|int|float
method unserialize (line 315) | private function unserialize($value): mixed
method getUTCDateTime (line 324) | private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
FILE: src/CommandSubscriber.php
class CommandSubscriber (line 16) | final class CommandSubscriber implements CommandSubscriberInterface
method __construct (line 21) | public function __construct(private Connection $connection)
method commandStarted (line 25) | #[Override]
method commandFailed (line 31) | #[Override]
method commandSucceeded (line 37) | #[Override]
method logQuery (line 43) | private function logQuery(CommandSucceededEvent|CommandFailedEvent $ev...
FILE: src/Concerns/ManagesTransactions.php
type ManagesTransactions (line 23) | trait ManagesTransactions
method getClient (line 29) | abstract public function getClient(): ?Client;
method getSession (line 31) | public function getSession(): ?Session
method getSessionOrCreate (line 36) | private function getSessionOrCreate(): Session
method getSessionOrThrow (line 45) | private function getSessionOrThrow(): Session
method beginTransaction (line 59) | public function beginTransaction(array $options = []): void
method handleInitialTransactionState (line 68) | private function handleInitialTransactionState(): void
method commit (line 83) | public function commit(): void
method handleCommitState (line 91) | private function handleCommitState(): void
method rollBack (line 110) | public function rollBack($toLevel = null): void
method handleRollbackState (line 120) | private function handleRollbackState(): void
method runCallbacksBeforeTransaction (line 132) | private function runCallbacksBeforeTransaction(): void
method transaction (line 149) | public function transaction(Closure $callback, $attempts = 1, array $o...
FILE: src/Connection.php
class Connection (line 35) | class Connection extends BaseConnection
method __construct (line 63) | public function __construct(array $config)
method table (line 99) | #[Override]
method getCollection (line 114) | public function getCollection($name): Collection
method getSchemaBuilder (line 120) | #[Override]
method getMongoDB (line 133) | public function getMongoDB()
method getDatabase (line 147) | public function getDatabase(?string $name = null): Database
method getMongoClient (line 163) | public function getMongoClient()
method getClient (line 173) | public function getClient(): ?Client
method enableQueryLog (line 179) | #[Override]
method disableQueryLog (line 190) | #[Override]
method withFreshQueryLog (line 201) | #[Override]
method getDefaultDatabaseName (line 221) | protected function getDefaultDatabaseName(string $dsn, array $config):...
method createConnection (line 237) | protected function createConnection(string $dsn, array $config, array ...
method ping (line 274) | public function ping(): void
method disconnect (line 280) | public function disconnect()
method hasDsnString (line 291) | protected function hasDsnString(array $config): bool
method getDsnString (line 299) | protected function getDsnString(array $config): string
method getHostDsn (line 307) | protected function getHostDsn(array $config): string
method getDsn (line 336) | protected function getDsn(array $config): string
method getDriverName (line 350) | #[Override]
method getDriverTitle (line 357) | public function getDriverTitle()
method getDefaultPostProcessor (line 363) | #[Override]
method getDefaultQueryGrammar (line 370) | #[Override]
method getDefaultSchemaGrammar (line 378) | #[Override]
method setDatabase (line 388) | public function setDatabase(Database $db)
method threadCount (line 394) | public function threadCount()
method __call (line 409) | public function __call($method, $parameters)
method setRenameEmbeddedIdField (line 415) | public function setRenameEmbeddedIdField(bool $rename): void
method getRenameEmbeddedIdField (line 421) | public function getRenameEmbeddedIdField(): bool
method getServerVersion (line 432) | public function getServerVersion(): string
method getVersion (line 437) | private static function getVersion(): string
method lookupVersion (line 442) | private static function lookupVersion(): string
FILE: src/Eloquent/Builder.php
class Builder (line 37) | class Builder extends EloquentBuilder
method aggregate (line 78) | public function aggregate($function = null, $columns = ['*'])
method search (line 92) | public function search(
method vectorSearch (line 118) | public function vectorSearch(
method update (line 137) | #[Override]
method insert (line 153) | public function insert(array $values)
method insertGetId (line 168) | public function insertGetId(array $values, $sequence = null)
method delete (line 183) | public function delete()
method increment (line 198) | public function increment($column, $amount = 1, array $extra = [])
method decrement (line 220) | public function decrement($column, $amount = 1, array $extra = [])
method raw (line 248) | public function raw($value = null)
method firstOrCreate (line 280) | #[Override]
method createOrFirst (line 296) | #[Override]
method addUpdatedAtColumn (line 321) | #[Override]
method getConnection (line 341) | public function getConnection(): Connection
method ensureOrderForCursorPagination (line 347) | #[Override]
FILE: src/Eloquent/Casts/BinaryUuid.php
class BinaryUuid (line 19) | class BinaryUuid implements CastsAttributes
method get (line 29) | public function get($model, string $key, $value, array $attributes)
method set (line 55) | public function set($model, string $key, $value, array $attributes)
FILE: src/Eloquent/Casts/ObjectId.php
class ObjectId (line 11) | class ObjectId implements CastsAttributes
method get (line 21) | public function get($model, string $key, $value, array $attributes)
method set (line 38) | public function set($model, string $key, $value, array $attributes)
FILE: src/Eloquent/DocumentModel.php
type DocumentModel (line 54) | trait DocumentModel
method getIdAttribute (line 78) | public function getIdAttribute($value = null)
method getQualifiedKeyName (line 97) | public function getQualifiedKeyName()
method fromDateTime (line 109) | public function fromDateTime($value): UTCDateTime
method asDateTime (line 131) | protected function asDateTime($value): DateTimeInterface
method getDateFormat (line 143) | public function getDateFormat()
method freshTimestamp (line 149) | public function freshTimestamp()
method getAttribute (line 155) | public function getAttribute($key)
method transformModelValue (line 188) | protected function transformModelValue($key, $value)
method getCastType (line 208) | protected function getCastType($key)
method getAttributeFromArray (line 219) | protected function getAttributeFromArray($key)
method setAttribute (line 232) | public function setAttribute($key, $value)
method asDecimal (line 275) | protected function asDecimal($value, $decimals)
method fromDecimal (line 299) | protected function fromDecimal($value, $decimals)
method attributesToArray (line 305) | public function attributesToArray()
method getCasts (line 325) | public function getCasts()
method getDirty (line 331) | public function getDirty()
method originalIsEquivalent (line 344) | public function originalIsEquivalent($key)
method offsetUnset (line 385) | public function offsetUnset($offset): void
method offsetSet (line 402) | public function offsetSet($offset, $value): void
method drop (line 419) | public function drop($columns)
method unset (line 431) | public function unset($columns)
method push (line 442) | public function push()
method pull (line 475) | public function pull($column, $values)
method pushAttributeValues (line 493) | protected function pushAttributeValues($column, array $values, $unique...
method pullAttributeValues (line 516) | protected function pullAttributeValues($column, array $values)
method getForeignKey (line 536) | public function getForeignKey()
method setParentRelation (line 544) | public function setParentRelation(Relation $relation)
method getParentRelation (line 552) | public function getParentRelation(): ?Relation
method newEloquentBuilder (line 558) | public function newEloquentBuilder($query)
method qualifyColumn (line 564) | public function qualifyColumn($column)
method newBaseQueryBuilder (line 570) | protected function newBaseQueryBuilder()
method removeTableFromKey (line 578) | protected function removeTableFromKey($key)
method getQueueableRelations (line 588) | public function getQueueableRelations()
method getRelationsWithoutParent (line 618) | protected function getRelationsWithoutParent()
method isGuardableColumn (line 638) | protected function isGuardableColumn($key)
method addCastAttributesToArray (line 644) | protected function addCastAttributesToArray(array $attributes, array $...
method getStorableEnumValueFromLaravel11 (line 700) | private function getStorableEnumValueFromLaravel11($expectedEnum, $value)
method isBSON (line 718) | protected function isBSON(mixed $value): bool
method save (line 726) | public function save(array $options = [])
method refresh (line 749) | public function refresh()
FILE: src/Eloquent/EmbedsRelations.php
type EmbedsRelations (line 19) | trait EmbedsRelations
method embedsMany (line 31) | protected function embedsMany($related, $localKey = null, $foreignKey ...
method embedsOne (line 65) | protected function embedsOne($related, $localKey = null, $foreignKey =...
FILE: src/Eloquent/HasSchemaVersion.php
type HasSchemaVersion (line 33) | trait HasSchemaVersion
method migrateSchema (line 39) | public function migrateSchema(int $fromVersion): void
method bootHasSchemaVersion (line 43) | public static function bootHasSchemaVersion(): void
method getSchemaVersion (line 64) | public function getSchemaVersion(): int
method getSchemaVersionKey (line 69) | protected static function getSchemaVersionKey(): string
method getModelSchemaVersion (line 74) | protected function getModelSchemaVersion(): int
FILE: src/Eloquent/HybridRelations.php
type HybridRelations (line 31) | trait HybridRelations
method hasOne (line 44) | public function hasOne($related, $foreignKey = null, $localKey = null)
method morphOne (line 73) | public function morphOne($related, $name, $type = null, $id = null, $l...
method hasMany (line 100) | public function hasMany($related, $foreignKey = null, $localKey = null)
method morphMany (line 129) | public function morphMany($related, $name, $type = null, $id = null, $...
method belongsTo (line 162) | public function belongsTo($related, $foreignKey = null, $ownerKey = nu...
method morphTo (line 207) | public function morphTo($name = null, $type = null, $id = null, $owner...
method belongsToMany (line 272) | public function belongsToMany(
method morphToMany (line 349) | public function morphToMany(
method morphedByMany (line 424) | public function morphedByMany(
method newEloquentBuilder (line 459) | public function newEloquentBuilder($query)
FILE: src/Eloquent/MassPrunable.php
type MassPrunable (line 15) | trait MassPrunable
method pruneAll (line 24) | public function pruneAll(): int
FILE: src/Eloquent/Model.php
class Model (line 15) | abstract class Model extends BaseModel
method isDocumentModel (line 35) | final public static function isDocumentModel(string|object $class): bool
FILE: src/Eloquent/SoftDeletes.php
type SoftDeletes (line 15) | trait SoftDeletes
method getQualifiedDeletedAtColumn (line 20) | public function getQualifiedDeletedAtColumn()
FILE: src/Helpers/EloquentBuilder.php
class EloquentBuilder (line 9) | class EloquentBuilder extends Builder
FILE: src/Helpers/QueriesRelationships.php
type QueriesRelationships (line 31) | trait QueriesRelationships
method has (line 45) | public function has($relation, $operator = '>=', $count = 1, $boolean ...
method isAcrossConnections (line 90) | protected function isAcrossConnections(Relation $relation)
method addHybridHas (line 106) | public function addHybridHas(Relation $relation, $operator = '>=', $co...
method assertHybridRelationSupported (line 141) | private function assertHybridRelationSupported(Relation $relation): void
method handleMorphToMany (line 160) | private function handleMorphToMany($hasQuery, $relation)
method handleMorphedByMany (line 177) | private function handleMorphedByMany($hasQuery, $relation)
method getHasCompareKey (line 185) | protected function getHasCompareKey(Relation $relation)
method getConstrainedRelatedIds (line 201) | protected function getConstrainedRelatedIds($relations, $operator, $co...
method getRelatedConstraintKey (line 237) | protected function getRelatedConstraintKey(Relation $relation)
FILE: src/MongoDBBusServiceProvider.php
class MongoDBBusServiceProvider (line 17) | class MongoDBBusServiceProvider extends ServiceProvider implements Defer...
method register (line 22) | #[Override]
method provides (line 52) | #[Override]
FILE: src/MongoDBServiceProvider.php
class MongoDBServiceProvider (line 36) | class MongoDBServiceProvider extends ServiceProvider
method boot (line 41) | public function boot()
method register (line 51) | #[Override]
method registerFlysystemAdapter (line 111) | private function registerFlysystemAdapter(): void
method registerScoutEngine (line 163) | private function registerScoutEngine(): void
FILE: src/Query/AggregationBuilder.php
class AggregationBuilder (line 21) | class AggregationBuilder
method __construct (line 25) | public function __construct(
method addRawStage (line 35) | public function addRawStage(string $operator, mixed $value): static
method get (line 49) | public function get(array $options = []): LaravelCollection|LazyCollec...
method cursor (line 59) | public function cursor($options = []): LazyCollection
method first (line 73) | public function first(array $options = []): mixed
method execute (line 84) | private function execute(array $options): CursorInterface&Iterator
FILE: src/Query/Builder.php
class Builder (line 89) | class Builder extends BaseBuilder
method project (line 206) | public function project($columns)
method hint (line 220) | public function hint($index)
method find (line 228) | #[Override]
method value (line 235) | #[Override]
method get (line 244) | #[Override]
method cursor (line 251) | #[Override]
method dd (line 267) | #[Override]
method dump (line 280) | #[Override]
method toMql (line 295) | public function toMql(): array
method getFresh (line 492) | public function getFresh($columns = [], $returnLazy = false)
method generateCacheKey (line 550) | public function generateCacheKey()
method aggregate (line 568) | #[Override]
method aggregateByGroup (line 635) | public function aggregateByGroup(string $function, array $columns = ['...
method exists (line 645) | #[Override]
method distinct (line 652) | public function distinct($column = false)
method orderBy (line 668) | #[Override]
method removeExistingOrdersFor (line 694) | #[Override]
method whereBetween (line 717) | #[Override]
method insert (line 742) | #[Override]
method insertGetId (line 780) | #[Override]
method update (line 800) | #[Override]
method upsert (line 817) | #[Override]
method increment (line 864) | #[Override]
method incrementEach (line 890) | #[Override]
method decrement (line 908) | #[Override]
method decrementEach (line 915) | #[Override]
method multiply (line 935) | public function multiply($column, $amount, array $extra = [], array $o...
method divide (line 963) | public function divide($column, $amount, array $extra = [], array $opt...
method pluck (line 969) | #[Override]
method delete (line 980) | #[Override]
method from (line 1012) | #[Override]
method truncate (line 1022) | public function truncate(): bool
method lists (line 1040) | public function lists($column, $key = null)
method raw (line 1052) | #[Override]
method push (line 1078) | public function push($column, $value = null, $unique = false)
method pull (line 1109) | public function pull($column, $value = null)
method drop (line 1133) | public function drop($columns)
method newQuery (line 1155) | #[Override]
method runPaginationCountQuery (line 1161) | #[Override]
method performUpdate (line 1189) | protected function performUpdate(array $update, array $options = [])
method convertKey (line 1217) | public function convertKey($id)
method where (line 1244) | #[Override]
method compileWheres (line 1274) | protected function compileWheres(): array
method compileWhereBasic (line 1368) | protected function compileWhereBasic(array $where): array
method compileWhereNested (line 1436) | protected function compileWhereNested(array $where): mixed
method compileWhereIn (line 1441) | protected function compileWhereIn(array $where): array
method compileWhereNotIn (line 1446) | protected function compileWhereNotIn(array $where): array
method compileWhereLike (line 1451) | protected function compileWhereLike(array $where): array
method compileWhereNull (line 1458) | protected function compileWhereNull(array $where): array
method compileWhereNotNull (line 1466) | protected function compileWhereNotNull(array $where): array
method compileWhereBetween (line 1474) | protected function compileWhereBetween(array $where): array
method compileWhereDate (line 1505) | protected function compileWhereDate(array $where): array
method compileWhereMonth (line 1534) | protected function compileWhereMonth(array $where): array
method compileWhereDay (line 1548) | protected function compileWhereDay(array $where): array
method compileWhereYear (line 1562) | protected function compileWhereYear(array $where): array
method compileWhereTime (line 1576) | protected function compileWhereTime(array $where): array
method compileWhereRaw (line 1600) | protected function compileWhereRaw(array $where): mixed
method compileWhereSub (line 1605) | protected function compileWhereSub(array $where): mixed
method options (line 1617) | public function options(array $options)
method readPreference (line 1635) | public function readPreference(string $mode, ?array $tagSets = null, ?...
method search (line 1650) | public function search(
method vectorSearch (line 1689) | public function vectorSearch(
method autocomplete (line 1724) | public function autocomplete(string $path, string $query, bool|array $...
method inheritConnectionOptions (line 1741) | private function inheritConnectionOptions(array $options = []): array
method __call (line 1758) | #[Override]
method toSql (line 1769) | #[Override]
method toRawSql (line 1776) | #[Override]
method whereColumn (line 1783) | #[Override]
method whereFullText (line 1790) | #[Override]
method groupByRaw (line 1797) | #[Override]
method orderByRaw (line 1804) | #[Override]
method unionAll (line 1811) | #[Override]
method union (line 1818) | #[Override]
method having (line 1825) | #[Override]
method havingRaw (line 1832) | #[Override]
method havingBetween (line 1839) | #[Override]
method whereIntegerInRaw (line 1846) | #[Override]
method orWhereIntegerInRaw (line 1853) | #[Override]
method whereIntegerNotInRaw (line 1860) | #[Override]
method orWhereIntegerNotInRaw (line 1867) | #[Override]
method aliasIdForQuery (line 1873) | private function aliasIdForQuery(array $values, bool $root = true): array
method aliasIdForResult (line 1933) | public function aliasIdForResult(array|object $values, bool $root = tr...
FILE: src/Query/BuilderTimeout.php
type BuilderTimeout (line 19) | trait BuilderTimeout
method timeout (line 40) | public function timeout($seconds)
type BuilderTimeout (line 24) | trait BuilderTimeout
method timeout (line 40) | public function timeout($seconds)
FILE: src/Query/Grammar.php
class Grammar (line 9) | class Grammar extends BaseGrammar
FILE: src/Query/Processor.php
class Processor (line 9) | class Processor extends BaseProcessor
FILE: src/Queue/MongoConnector.php
class MongoConnector (line 15) | class MongoConnector implements ConnectorInterface
method __construct (line 27) | public function __construct(ConnectionResolverInterface $connections)
method connect (line 37) | public function connect(array $config)
FILE: src/Queue/MongoJob.php
class MongoJob (line 10) | class MongoJob extends DatabaseJob
method isReserved (line 17) | public function isReserved()
method reservedAt (line 23) | public function reservedAt()
FILE: src/Queue/MongoQueue.php
class MongoQueue (line 14) | class MongoQueue extends DatabaseQueue
method __construct (line 31) | public function __construct(Connection $database, $table, $default = '...
method pop (line 43) | #[Override]
method getNextAvailableJobAndReserve (line 79) | protected function getNextAvailableJobAndReserve($queue)
method releaseJobsThatHaveBeenReservedTooLong (line 114) | protected function releaseJobsThatHaveBeenReservedTooLong($queue)
method releaseJob (line 137) | protected function releaseJob($id, $attempts)
method deleteReserved (line 147) | #[Override]
method deleteAndRelease (line 154) | #[Override]
FILE: src/Relations/BelongsTo.php
class BelongsTo (line 17) | class BelongsTo extends EloquentBelongsTo
method getHasCompareKey (line 24) | public function getHasCompareKey()
method addConstraints (line 30) | #[Override]
method addEagerConstraints (line 42) | #[Override]
method getRelationExistenceQuery (line 52) | #[Override]
method whereInMethod (line 65) | #[Override]
method getQualifiedForeignKeyName (line 71) | #[Override]
FILE: src/Relations/BelongsToMany.php
class BelongsToMany (line 30) | class BelongsToMany extends EloquentBelongsToMany
method getHasCompareKey (line 37) | public function getHasCompareKey()
method getRelationExistenceQuery (line 43) | #[Override]
method hydratePivotRelation (line 50) | #[Override]
method getSelectColumns (line 61) | protected function getSelectColumns(array $columns = ['*'])
method shouldSelect (line 67) | #[Override]
method addConstraints (line 74) | #[Override]
method setWhere (line 87) | protected function setWhere()
method save (line 97) | #[Override]
method create (line 108) | #[Override]
method sync (line 124) | #[Override]
method updateExistingPivot (line 188) | #[Override]
method attach (line 196) | #[Override]
method detach (line 237) | #[Override]
method buildDictionary (line 278) | #[Override]
method newPivotQuery (line 298) | #[Override]
method newRelatedQuery (line 309) | public function newRelatedQuery()
method getForeignKey (line 319) | public function getForeignKey()
method getQualifiedForeignPivotKeyName (line 325) | #[Override]
method getQualifiedRelatedPivotKeyName (line 332) | #[Override]
method whereInMethod (line 343) | #[Override]
FILE: src/Relations/EmbedsMany.php
class EmbedsMany (line 30) | class EmbedsMany extends EmbedsOneOrMany
method initRelation (line 33) | public function initRelation(array $models, $relation)
method getResults (line 43) | public function getResults()
method performInsert (line 53) | public function performInsert(Model $model)
method performUpdate (line 83) | public function performUpdate(Model $model)
method performDelete (line 114) | public function performDelete(Model $model)
method associate (line 140) | public function associate(Model $model)
method dissociate (line 156) | public function dissociate($ids = [])
method destroy (line 186) | public function destroy($ids = [])
method delete (line 212) | public function delete($id = null): int
method detach (line 233) | public function detach($ids = [])
method attach (line 243) | public function attach(Model $model)
method associateNew (line 255) | protected function associateNew($model)
method associateExisting (line 277) | protected function associateExisting($model)
method paginate (line 307) | public function paginate($perPage = null, $columns = ['*'], $pageName ...
method getEmbedded (line 334) | protected function getEmbedded()
method setEmbedded (line 340) | protected function setEmbedded($records)
method __call (line 350) | public function __call($method, $parameters)
method whereInMethod (line 366) | protected function whereInMethod(Model $model, $key)
FILE: src/Relations/EmbedsOne.php
class EmbedsOne (line 20) | class EmbedsOne extends EmbedsOneOrMany
method initRelation (line 22) | public function initRelation(array $models, $relation)
method getResults (line 31) | public function getResults()
method getEager (line 36) | public function getEager()
method performInsert (line 49) | public function performInsert(Model $model)
method performUpdate (line 78) | public function performUpdate(Model $model)
method performDelete (line 103) | public function performDelete()
method associate (line 128) | public function associate(Model $model)
method dissociate (line 138) | public function dissociate()
method delete (line 152) | public function delete($id = null): int
method whereInMethod (line 166) | protected function whereInMethod(Model $model, $key)
FILE: src/Relations/EmbedsOneOrMany.php
class EmbedsOneOrMany (line 31) | abstract class EmbedsOneOrMany extends Relation
method __construct (line 57) | public function __construct(Builder $query, Model $parent, Model $rela...
method addConstraints (line 82) | #[Override]
method addEagerConstraints (line 91) | #[Override]
method match (line 98) | #[Override]
method get (line 112) | #[Override]
method count (line 127) | public function count($columns = '*'): int
method save (line 139) | public function save(Model $model)
method saveMany (line 153) | public function saveMany($models)
method create (line 167) | public function create(array $attributes = [])
method createMany (line 186) | public function createMany(array $records)
method getIdsArrayFrom (line 204) | protected function getIdsArrayFrom($ids)
method getEmbedded (line 224) | protected function getEmbedded()
method setEmbedded (line 234) | protected function setEmbedded($records)
method getForeignKeyValue (line 254) | protected function getForeignKeyValue($id)
method toCollection (line 269) | protected function toCollection(array $records = [])
method toModel (line 291) | protected function toModel(mixed $attributes = []): Model|null
method getParentRelation (line 319) | protected function getParentRelation()
method getQuery (line 325) | #[Override]
method toBase (line 334) | #[Override]
method isNested (line 347) | protected function isNested()
method getPathHierarchy (line 359) | protected function getPathHierarchy($glue = '.')
method getQualifiedParentKeyName (line 370) | #[Override]
method getParentKey (line 386) | protected function getParentKey()
method getUpdateValues (line 399) | public static function getUpdateValues($array, $prepend = '')
method getQualifiedForeignKeyName (line 420) | public function getQualifiedForeignKeyName()
method whereInMethod (line 432) | #[Override]
FILE: src/Relations/HasMany.php
class HasMany (line 17) | class HasMany extends EloquentHasMany
method getForeignKeyName (line 24) | #[Override]
method getHasCompareKey (line 35) | public function getHasCompareKey()
method getRelationExistenceQuery (line 41) | #[Override]
method whereInMethod (line 54) | #[Override]
FILE: src/Relations/HasOne.php
class HasOne (line 17) | class HasOne extends EloquentHasOne
method getForeignKeyName (line 24) | #[Override]
method getHasCompareKey (line 35) | public function getHasCompareKey()
method getRelationExistenceQuery (line 41) | #[Override]
method whereInMethod (line 50) | #[Override]
FILE: src/Relations/MorphMany.php
class MorphMany (line 16) | class MorphMany extends EloquentMorphMany
method whereInMethod (line 18) | #[Override]
FILE: src/Relations/MorphTo.php
class MorphTo (line 16) | class MorphTo extends EloquentMorphTo
method addConstraints (line 19) | #[Override]
method getResultsByType (line 35) | #[Override]
method whereInMethod (line 48) | #[Override]
FILE: src/Relations/MorphToMany.php
class MorphToMany (line 33) | class MorphToMany extends EloquentMorphToMany
method getRelationExistenceQuery (line 35) | #[Override]
method hydratePivotRelation (line 41) | #[Override]
method shouldSelect (line 47) | #[Override]
method addConstraints (line 53) | #[Override]
method addEagerConstraints (line 61) | #[Override]
method setWhere (line 83) | protected function setWhere()
method save (line 106) | #[Override]
method create (line 117) | #[Override]
method sync (line 133) | #[Override]
method updateExistingPivot (line 210) | #[Override]
method attach (line 217) | #[Override]
method detach (line 311) | #[Override]
method buildDictionary (line 386) | #[Override]
method newPivotQuery (line 414) | #[Override]
method newRelatedQuery (line 425) | public function newRelatedQuery()
method getQualifiedRelatedPivotKeyName (line 430) | #[Override]
method whereInMethod (line 436) | #[Override]
method extractIds (line 450) | public function extractIds(array $data, ?string $relatedPivotKey = null)
method addIdToParentRelationData (line 470) | private function addIdToParentRelationData($id)
FILE: src/Schema/Blueprint.php
class Blueprint (line 22) | class Blueprint extends BaseBlueprint
method index (line 42) | #[Override]
method primary (line 69) | #[Override]
method dropIndex (line 76) | #[Override]
method dropIndexIfExists (line 93) | public function dropIndexIfExists($indexOrColumns = null)
method hasIndex (line 109) | public function hasIndex($indexOrColumns = null)
method jsonSchema (line 125) | public function jsonSchema(
method transformColumns (line 146) | protected function transformColumns($indexOrColumns)
method unique (line 175) | #[Override]
method sparse (line 195) | public function sparse($columns = null, $options = [])
method geospatial (line 215) | public function geospatial($columns = null, $index = '2d', $options = [])
method expire (line 241) | public function expire($columns, $seconds)
method create (line 257) | #[Override]
method drop (line 269) | #[Override]
method renameColumn (line 278) | #[Override]
method addColumn (line 287) | #[Override]
method sparse_and_unique (line 305) | public function sparse_and_unique($columns = null, $options = [])
method searchIndex (line 332) | public function searchIndex(array $definition, string $name = 'default...
method vectorSearchIndex (line 346) | public function vectorSearchIndex(array $definition, string $name = 'd...
method dropSearchIndex (line 356) | public function dropSearchIndex(string $name): static
method fluent (line 370) | protected function fluent($columns = null)
method __call (line 391) | public function __call($method, $parameters)
FILE: src/Schema/BlueprintLaravelCompatibility.php
type BlueprintLaravelCompatibility (line 22) | trait BlueprintLaravelCompatibility
method __construct (line 31) | public function __construct(Connection $connection, string $collection...
method __construct (line 43) | public function __construct(Connection $connection, string $collection...
type BlueprintLaravelCompatibility (line 41) | trait BlueprintLaravelCompatibility
method __construct (line 31) | public function __construct(Connection $connection, string $collection...
method __construct (line 43) | public function __construct(Connection $connection, string $collection...
FILE: src/Schema/Builder.php
class Builder (line 44) | class Builder extends \Illuminate\Database\Schema\Builder
method hasColumn (line 52) | public function hasColumn($table, $column): bool
method hasColumns (line 63) | public function hasColumns($table, array $columns): bool
method hasCollection (line 90) | public function hasCollection($name)
method hasTable (line 102) | #[Override]
method table (line 109) | #[Override]
method create (line 120) | #[Override]
method dropIfExists (line 133) | #[Override]
method drop (line 142) | #[Override]
method dropAllTables (line 159) | #[Override]
method getTables (line 170) | #[Override]
method getViews (line 181) | #[Override]
method getTableListing (line 193) | #[Override]
method getColumns (line 217) | #[Override]
method getIndexes (line 276) | #[Override]
method getForeignKeys (line 331) | #[Override]
method createBlueprint (line 342) | #[Override]
method getCollection (line 355) | public function getCollection($name)
method getAllCollections (line 373) | protected function getAllCollections()
method isAtlasSearchNotSupportedException (line 386) | public static function isAtlasSearchNotSupportedException(ServerExcept...
method getCollectionRows (line 398) | private function getCollectionRows(string $collectionType, $schema = n...
method collationToString (line 435) | private function collationToString(array $collation): string
FILE: src/Schema/Grammar.php
class Grammar (line 9) | class Grammar extends BaseGrammar
FILE: src/Scout/ScoutEngine.php
class ScoutEngine (line 53) | final class ScoutEngine extends Engine
method __construct (line 69) | public function __construct(
method update (line 85) | #[Override]
method delete (line 147) | #[Override]
method search (line 168) | #[Override]
method paginate (line 184) | #[Override]
method performSearch (line 199) | private function performSearch(Builder $builder, ?int $offset = null):...
method mapIds (line 305) | #[Override]
method map (line 324) | #[Override]
method lazyMap (line 341) | #[Override]
method performMap (line 348) | private function performMap(Builder $builder, array $results, Model $m...
method getTotalCount (line 390) | #[Override]
method flush (line 409) | #[Override]
method createIndex (line 430) | #[Override]
method deleteIndex (line 463) | #[Override]
method getSearchableCollection (line 472) | private function getSearchableCollection(Model|EloquentCollection $mod...
method getIndexableCollection (line 484) | private function getIndexableCollection(Model|EloquentCollection $mode...
method serialize (line 504) | private static function serialize(mixed $value): mixed
method usesSoftDelete (line 523) | private function usesSoftDelete(Model|EloquentCollection $model): bool
method wait (line 536) | private function wait(Closure $callback): void
FILE: src/Session/MongoDbSessionHandler.php
class MongoDbSessionHandler (line 18) | final class MongoDbSessionHandler extends DatabaseSessionHandler
method close (line 22) | public function close(): bool
method gc (line 27) | #[Override]
method destroy (line 35) | #[Override]
method read (line 43) | #[Override]
method write (line 61) | #[Override]
method createTTLIndex (line 76) | public function createTTLIndex(): void
method getDefaultPayload (line 86) | #[Override]
method getCollection (line 105) | private function getCollection(): Collection
method getUTCDateTime (line 110) | private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
FILE: src/Validation/DatabasePresenceVerifier.php
class DatabasePresenceVerifier (line 14) | class DatabasePresenceVerifier extends \Illuminate\Validation\DatabasePr...
method getCount (line 17) | #[Override]
method getMultiCount (line 34) | #[Override]
FILE: src/Validation/ValidationServiceProvider.php
class ValidationServiceProvider (line 10) | class ValidationServiceProvider extends BaseProvider
method registerPresenceVerifier (line 12) | #[Override]
FILE: tests/AtlasSearchIndexManagement.php
type AtlasSearchIndexManagement (line 14) | trait AtlasSearchIndexManagement
method waitForSearchIndexesDropped (line 19) | public function waitForSearchIndexesDropped(Collection $collection)
method waitForSearchIndexesReady (line 35) | public function waitForSearchIndexesReady(Collection $collection)
FILE: tests/AtlasSearchTest.php
class AtlasSearchTest (line 24) | #[Group('atlas-search')]
method setUp (line 31) | public function setUp(): void
method tearDown (line 99) | public function tearDown(): void
method testGetIndexes (line 106) | public function testGetIndexes()
method testEloquentBuilderSearch (line 150) | public function testEloquentBuilderSearch()
method testDatabaseBuilderSearch (line 167) | public function testDatabaseBuilderSearch()
method testEloquentBuilderAutocomplete (line 182) | public function testEloquentBuilderAutocomplete()
method testDatabaseBuilderAutocomplete (line 195) | public function testDatabaseBuilderAutocomplete()
method testDatabaseBuilderVectorSearch (line 209) | public function testDatabaseBuilderVectorSearch()
method testEloquentBuilderVectorSearch (line 226) | public function testEloquentBuilderVectorSearch()
method addVector (line 252) | private function addVector(array $items): array
FILE: tests/AuthTest.php
class AuthTest (line 16) | class AuthTest extends TestCase
method tearDown (line 18) | public function tearDown(): void
method testAuthAttempt (line 26) | public function testAuthAttempt()
method testRemindOld (line 38) | public function testRemindOld()
FILE: tests/Bus/Fixtures/ChainHeadJob.php
class ChainHeadJob (line 10) | class ChainHeadJob implements ShouldQueue
FILE: tests/Bus/Fixtures/SecondTestJob.php
class SecondTestJob (line 10) | class SecondTestJob implements ShouldQueue
FILE: tests/Bus/Fixtures/ThirdTestJob.php
class ThirdTestJob (line 10) | class ThirdTestJob implements ShouldQueue
FILE: tests/Bus/MongoBatchRepositoryTest.php
class MongoBatchRepositoryTest (line 31) | final class MongoBatchRepositoryTest extends TestCase
method setUp (line 33) | protected function setUp(): void
method tearDown (line 43) | protected function tearDown(): void
method testJobsCanBeAddedToTheBatch (line 63) | public function testJobsCanBeAddedToTheBatch(): void
method testSuccessfulJobsCanBeRecorded (line 102) | public function testSuccessfulJobsCanBeRecorded()
method testFailedJobsCanBeRecordedWhileNotAllowingFailures (line 143) | public function testFailedJobsCanBeRecordedWhileNotAllowingFailures()
method testFailedJobsCanBeRecordedWhileAllowingFailures (line 186) | public function testFailedJobsCanBeRecordedWhileAllowingFailures()
method testBatchCanBeCancelled (line 228) | public function testBatchCanBeCancelled()
method testBatchCanBeDeleted (line 242) | public function testBatchCanBeDeleted()
method testBatchStateCanBeInspected (line 256) | public function testBatchStateCanBeInspected()
method testChainCanBeAddedToBatch (line 297) | public function testChainCanBeAddedToBatch()
method createTestBatch (line 333) | private function createTestBatch(Factory $queue, $allowFailures = false)
FILE: tests/Cache/MongoCacheStoreTest.php
class MongoCacheStoreTest (line 16) | class MongoCacheStoreTest extends TestCase
method tearDown (line 18) | public function tearDown(): void
method testGetNullWhenItemDoesNotExist (line 27) | public function testGetNullWhenItemDoesNotExist()
method testValueCanStoreNewCache (line 33) | public function testValueCanStoreNewCache()
method testPutOperationShouldNotStoreExpired (line 42) | public function testPutOperationShouldNotStoreExpired()
method testValueCanUpdateExistCache (line 51) | public function testValueCanUpdateExistCache()
method testValueCanUpdateExistCacheInTransaction (line 61) | public function testValueCanUpdateExistCacheInTransaction()
method testAddOperationShouldNotStoreExpired (line 75) | public function testAddOperationShouldNotStoreExpired()
method testAddOperationCanStoreNewCache (line 85) | public function testAddOperationCanStoreNewCache()
method testAddOperationShouldNotUpdateExistCache (line 95) | public function testAddOperationShouldNotUpdateExistCache()
method testAddOperationShouldNotUpdateExistCacheInTransaction (line 106) | public function testAddOperationShouldNotUpdateExistCacheInTransaction()
method testAddOperationCanUpdateIfCacheExpired (line 120) | public function testAddOperationCanUpdateIfCacheExpired()
method testAddOperationCanUpdateIfCacheExpiredInTransaction (line 131) | public function testAddOperationCanUpdateIfCacheExpiredInTransaction()
method testGetOperationReturnNullIfExpired (line 145) | public function testGetOperationReturnNullIfExpired()
method testGetOperationCanDeleteExpired (line 156) | public function testGetOperationCanDeleteExpired()
method testForgetIfExpiredOperationCanDeleteExpired (line 167) | public function testForgetIfExpiredOperationCanDeleteExpired()
method testForgetIfExpiredOperationShouldNotDeleteUnExpired (line 178) | public function testForgetIfExpiredOperationShouldNotDeleteUnExpired()
method testIncrementDecrement (line 189) | public function testIncrementDecrement()
method testTouchReturnsFalseWhenKeyDoesNotExist (line 204) | public function testTouchReturnsFalseWhenKeyDoesNotExist()
method testTouchExtendsExpirationAndPreservesValue (line 211) | public function testTouchExtendsExpirationAndPreservesValue()
method testTouchReturnsFalseOnExpiredItem (line 231) | public function testTouchReturnsFalseOnExpiredItem()
method testTTLIndex (line 241) | public function testTTLIndex()
method getStore (line 251) | private function getStore(): Repository
method getCacheCollectionName (line 259) | private function getCacheCollectionName(): string
method withCachePrefix (line 264) | private function withCachePrefix(string $key): string
method insertToCacheTable (line 269) | private function insertToCacheTable(string $key, $value, $ttl = 60)
FILE: tests/Cache/MongoLockTest.php
class MongoLockTest (line 16) | class MongoLockTest extends TestCase
method tearDown (line 18) | public function tearDown(): void
method testInvalidLottery (line 25) | #[TestWith([[5, 2]])]
method testLockCanBeAcquired (line 42) | public function testLockCanBeAcquired()
method testLockCanBeForceReleased (line 60) | public function testLockCanBeForceReleased()
method testExpiredLockCanBeRetrieved (line 72) | public function testExpiredLockCanBeRetrieved()
method testOwnedByCurrentProcess (line 84) | public function testOwnedByCurrentProcess()
method testRestoreLock (line 96) | public function testRestoreLock()
method testTTLIndex (line 111) | public function testTTLIndex()
method getCache (line 120) | private function getCache(): Repository
FILE: tests/Casts/BinaryUuidTest.php
class BinaryUuidTest (line 15) | class BinaryUuidTest extends TestCase
method setUp (line 17) | protected function setUp(): void
method testBinaryUuidCastModel (line 24) | #[DataProvider('provideBinaryUuidCast')]
method provideBinaryUuidCast (line 34) | public static function provideBinaryUuidCast(): Generator
method testQueryByStringDoesNotCast (line 43) | public function testQueryByStringDoesNotCast(): void
FILE: tests/Casts/BooleanTest.php
class BooleanTest (line 10) | class BooleanTest extends TestCase
method setUp (line 12) | protected function setUp(): void
method testBool (line 19) | public function testBool(): void
method testBoolAsString (line 42) | public function testBoolAsString(): void
method testBoolAsNumber (line 70) | public function testBoolAsNumber(): void
FILE: tests/Casts/CollectionTest.php
class CollectionTest (line 13) | class CollectionTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method testCollection (line 22) | public function testCollection(): void
FILE: tests/Casts/DateTest.php
class DateTest (line 16) | class DateTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method testDate (line 25) | public function testDate(): void
method testDateAsString (line 63) | public function testDateAsString(): void
method testDateWithCustomFormat (line 82) | public function testDateWithCustomFormat(): void
method testImmutableDate (line 101) | public function testImmutableDate(): void
method testImmutableDateWithCustomFormat (line 128) | public function testImmutableDateWithCustomFormat(): void
FILE: tests/Casts/DatetimeTest.php
class DatetimeTest (line 16) | class DatetimeTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method testDatetime (line 26) | public function testDatetime(): void
method testDatetimeAsString (line 47) | public function testDatetimeAsString(): void
method testDatetimeWithCustomFormat (line 68) | public function testDatetimeWithCustomFormat(): void
method testImmutableDatetime (line 87) | public function testImmutableDatetime(): void
method testImmutableDatetimeWithCustomFormat (line 115) | public function testImmutableDatetimeWithCustomFormat(): void
FILE: tests/Casts/DecimalTest.php
class DecimalTest (line 19) | class DecimalTest extends TestCase
method setUp (line 21) | protected function setUp(): void
method testDecimal (line 28) | public function testDecimal(): void
method testDecimalAsString (line 49) | public function testDecimalAsString(): void
method testDecimalAsDecimal128 (line 70) | public function testDecimalAsDecimal128(): void
method testOtherBSONTypes (line 85) | public function testOtherBSONTypes(): void
method setBSONType (line 117) | private function setBSONType($value, $id = null)
FILE: tests/Casts/EncryptionTest.php
class EncryptionTest (line 16) | class EncryptionTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method decryptRaw (line 25) | protected function decryptRaw(Casting $model, $key)
method testEncryptedString (line 33) | public function testEncryptedString(): void
method testEncryptedArray (line 49) | public function testEncryptedArray(): void
method testEncryptedObject (line 67) | public function testEncryptedObject(): void
method testEncryptedCollection (line 85) | public function testEncryptedCollection(): void
FILE: tests/Casts/FloatTest.php
class FloatTest (line 10) | class FloatTest extends TestCase
method setUp (line 12) | protected function setUp(): void
method testFloat (line 19) | public function testFloat(): void
method testFloatAsString (line 32) | public function testFloatAsString(): void
FILE: tests/Casts/IntegerTest.php
class IntegerTest (line 10) | class IntegerTest extends TestCase
method setUp (line 12) | protected function setUp(): void
method testInt (line 19) | public function testInt(): void
method testIntAsString (line 37) | public function testIntAsString(): void
method testIntAsFloat (line 55) | public function testIntAsFloat(): void
FILE: tests/Casts/JsonTest.php
class JsonTest (line 12) | class JsonTest extends TestCase
method setUp (line 14) | protected function setUp(): void
method testJson (line 21) | public function testJson(): void
FILE: tests/Casts/ObjectIdTest.php
class ObjectIdTest (line 13) | class ObjectIdTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method testStoreObjectId (line 22) | #[DataProvider('provideObjectIdCast')]
method provideObjectIdCast (line 34) | public static function provideObjectIdCast(): Generator
method testQueryByStringDoesNotCast (line 43) | public function testQueryByStringDoesNotCast(): void
FILE: tests/Casts/ObjectTest.php
class ObjectTest (line 10) | class ObjectTest extends TestCase
method setUp (line 12) | protected function setUp(): void
method testObject (line 19) | public function testObject(): void
FILE: tests/Casts/StringTest.php
class StringTest (line 12) | class StringTest extends TestCase
method setUp (line 14) | protected function setUp(): void
method testString (line 21) | public function testString(): void
FILE: tests/ConnectionTest.php
class ConnectionTest (line 24) | class ConnectionTest extends TestCase
method testConnection (line 26) | public function testConnection()
method testReconnect (line 35) | public function testReconnect()
method testDisconnectAndCreateNewConnection (line 47) | public function testDisconnectAndCreateNewConnection()
method testDb (line 63) | public function testDb()
method dataConnectionConfig (line 70) | public static function dataConnectionConfig(): Generator
method testConnectionConfig (line 201) | #[DataProvider('dataConnectionConfig')]
method testLegacyGetMongoClient (line 213) | public function testLegacyGetMongoClient(): void
method testLegacyGetMongoDB (line 221) | public function testLegacyGetMongoDB(): void
method testGetDatabase (line 229) | public function testGetDatabase(): void
method testGetOtherDatabase (line 240) | public function testGetOtherDatabase(): void
method testConnectionWithoutConfiguredDatabase (line 250) | public function testConnectionWithoutConfiguredDatabase(): void
method testConnectionWithoutConfiguredDsnOrHost (line 258) | public function testConnectionWithoutConfiguredDsnOrHost(): void
method testCollection (line 266) | public function testCollection()
method testPrefix (line 275) | public function testPrefix()
method testQueryLog (line 289) | public function testQueryLog()
method testQueryLogWithMultipleClients (line 325) | public function testQueryLogWithMultipleClients()
method testDisableQueryLog (line 353) | public function testDisableQueryLog()
method testSchemaBuilder (line 378) | public function testSchemaBuilder()
method testDriverName (line 384) | public function testDriverName()
method testPingMethod (line 390) | public function testPingMethod()
method testServerVersion (line 415) | public function testServerVersion()
method testThreadsCount (line 421) | public function testThreadsCount()
FILE: tests/DateTimeImmutableTest.php
class DateTimeImmutableTest (line 13) | final class DateTimeImmutableTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method tearDown (line 22) | protected function tearDown(): void
method testCanReturnCarbonImmutableObject (line 29) | public function testCanReturnCarbonImmutableObject(): void
FILE: tests/Eloquent/CallBuilderTest.php
class CallBuilderTest (line 19) | final class CallBuilderTest extends TestCase
method tearDown (line 21) | protected function tearDown(): void
method testCallingABuilderMethodDoesNotReturnTheBuilderInstance (line 28) | #[Dataprovider('provideFunctionNames')]
method provideFunctionNames (line 37) | public static function provideFunctionNames(): Generator
method callingUnsupportedMethodThrowsAnException (line 59) | #[Test]
method provideUnsupportedMethods (line 72) | public static function provideUnsupportedMethods(): Generator
FILE: tests/Eloquent/MassPrunableTest.php
class MassPrunableTest (line 17) | class MassPrunableTest extends TestCase
method tearDown (line 19) | public function tearDown(): void
method testPruneWithQuery (line 27) | public function testPruneWithQuery(): void
method testPruneSoftDelete (line 43) | public function testPruneSoftDelete(): void
method isPrunable (line 60) | protected function isPrunable($model)
FILE: tests/Eloquent/ModelTest.php
class ModelTest (line 16) | class ModelTest extends TestCase
method testIsDocumentModel (line 18) | #[DataProvider('provideDocumentModelClasses')]
method provideDocumentModelClasses (line 24) | public static function provideDocumentModelClasses(): Generator
FILE: tests/EmbeddedRelationsTest.php
class EmbeddedRelationsTest (line 17) | class EmbeddedRelationsTest extends TestCase
method tearDown (line 19) | public function tearDown(): void
method testEmbedsManySave (line 27) | public function testEmbedsManySave()
method testEmbedsToArray (line 110) | public function testEmbedsToArray()
method testEmbedsManyAssociate (line 120) | public function testEmbedsManyAssociate()
method testEmbedsManySaveMany (line 140) | public function testEmbedsManySaveMany()
method testEmbedsManyDuplicate (line 150) | public function testEmbedsManyDuplicate()
method testEmbedsManyCreate (line 172) | public function testEmbedsManyCreate()
method testEmbedsManyCreateMany (line 194) | public function testEmbedsManyCreateMany()
method testEmbedsManyDestroy (line 206) | public function testEmbedsManyDestroy()
method testEmbedsManyDelete (line 258) | public function testEmbedsManyDelete()
method testEmbedsManyDissociate (line 294) | public function testEmbedsManyDissociate()
method testEmbedsManyAliases (line 321) | public function testEmbedsManyAliases()
method testEmbedsManyCreatingEventReturnsFalse (line 333) | public function testEmbedsManyCreatingEventReturnsFalse()
method testEmbedsManySavingEventReturnsFalse (line 353) | public function testEmbedsManySavingEventReturnsFalse()
method testEmbedsManyUpdatingEventReturnsFalse (line 370) | public function testEmbedsManyUpdatingEventReturnsFalse()
method testEmbedsManyDeletingEventReturnsFalse (line 393) | public function testEmbedsManyDeletingEventReturnsFalse()
method testEmbedsManyFindOrContains (line 413) | public function testEmbedsManyFindOrContains()
method testEmbedsManyEagerLoading (line 429) | public function testEmbedsManyEagerLoading()
method testEmbedsManyDeleteAll (line 453) | public function testEmbedsManyDeleteAll()
method testEmbedsManyCollectionMethods (line 477) | public function testEmbedsManyCollectionMethods()
method testEmbedsOne (line 532) | public function testEmbedsOne()
method testEmbedsOneAssociate (line 605) | public function testEmbedsOneAssociate()
method testEmbedsOneNullAssociation (line 621) | public function testEmbedsOneNullAssociation()
method testEmbedsOneDelete (line 627) | public function testEmbedsOneDelete()
method testEmbedsOneRefresh (line 636) | public function testEmbedsOneRefresh()
method testEmbedsOneEmptyRefresh (line 650) | public function testEmbedsOneEmptyRefresh()
method testEmbedsManyToArray (line 666) | public function testEmbedsManyToArray()
method testEmbedsManyRefresh (line 679) | public function testEmbedsManyRefresh()
method testEmbeddedSave (line 695) | public function testEmbeddedSave()
method testNestedEmbedsOne (line 733) | public function testNestedEmbedsOne()
method testNestedEmbedsMany (line 761) | public function testNestedEmbedsMany()
method testNestedMixedEmbeds (line 783) | public function testNestedMixedEmbeds()
method testNestedEmbedsOneDelete (line 806) | public function testNestedEmbedsOneDelete()
method testNestedEmbedsManyDelete (line 821) | public function testNestedEmbedsManyDelete()
method testNestedMixedEmbedsDelete (line 839) | public function testNestedMixedEmbedsDelete()
method testDoubleAssociate (line 856) | public function testDoubleAssociate()
method testSaveEmptyModel (line 876) | public function testSaveEmptyModel()
method testIncrementEmbedded (line 884) | public function testIncrementEmbedded()
method testPaginateEmbedsMany (line 907) | public function testPaginateEmbedsMany()
method testGetQueueableRelationsEmbedsMany (line 925) | public function testGetQueueableRelationsEmbedsMany()
method testGetQueueableRelationsEmbedsOne (line 935) | public function testGetQueueableRelationsEmbedsOne()
method testUnsetPropertyOnEmbed (line 944) | public function testUnsetPropertyOnEmbed()
FILE: tests/ExternalPackageTest.php
class ExternalPackageTest (line 16) | class ExternalPackageTest extends TestCase
method tearDown (line 18) | protected function tearDown(): void
method testSpacieQueryBuilder (line 28) | public function testSpacieQueryBuilder(): void
FILE: tests/FilesystemsTest.php
class FilesystemsTest (line 19) | class FilesystemsTest extends TestCase
method tearDown (line 21) | public function tearDown(): void
method provideValidOptions (line 28) | public static function provideValidOptions(): Generator
method testValidOptions (line 65) | #[DataProvider('provideValidOptions')]
method provideInvalidOptions (line 81) | public static function provideInvalidOptions(): Generator
method testInvalidOptions (line 99) | #[DataProvider('provideInvalidOptions')]
method testReadOnlyAndThrowOptions (line 113) | public function testReadOnlyAndThrowOptions()
method testPrefix (line 132) | public function testPrefix()
method getBucket (line 146) | private function getBucket(): Bucket
FILE: tests/GeospatialTest.php
class GeospatialTest (line 10) | class GeospatialTest extends TestCase
method setUp (line 12) | public function setUp(): void
method tearDown (line 53) | public function tearDown(): void
method testGeoWithin (line 60) | public function testGeoWithin()
method testGeoIntersects (line 99) | public function testGeoIntersects()
method testNear (line 128) | public function testNear()
FILE: tests/HybridRelationsTest.php
class HybridRelationsTest (line 20) | class HybridRelationsTest extends TestCase
method setUp (line 22) | public function setUp(): void
method tearDown (line 37) | public function tearDown(): void
method testSqlRelations (line 49) | public function testSqlRelations()
method testHybridWhereHas (line 106) | public function testHybridWhereHas()
method testHybridWith (line 160) | public function testHybridWith()
method testHybridBelongsToMany (line 222) | public function testHybridBelongsToMany()
method testQueryingHybridBelongsToManyRelationFails (line 271) | public function testQueryingHybridBelongsToManyRelationFails()
method testHybridMorphToManySqlModelToMongoModel (line 288) | public function testHybridMorphToManySqlModelToMongoModel()
method testHybridMorphToManyMongoModelToSqlModel (line 339) | public function testHybridMorphToManyMongoModelToSqlModel()
FILE: tests/ModelTest.php
class ModelTest (line 50) | class ModelTest extends TestCase
method setUp (line 52) | protected function setUp(): void
method tearDown (line 59) | protected function tearDown(): void
method testNewModel (line 72) | public function testNewModel(): void
method testQualifyColumn (line 82) | public function testQualifyColumn(): void
method makeUser (line 93) | private function makeUser(): User
method testInsert (line 105) | public function testInsert(): void
method testInsertNonIncrementable (line 125) | public function testInsertNonIncrementable(): void
method testUpdate (line 145) | public function testUpdate(): void
method testUpdateTroughSetUpdatedAt (line 182) | public function testUpdateTroughSetUpdatedAt(): void
method testUpsert (line 197) | public function testUpsert()
method testManualStringId (line 230) | public function testManualStringId(): void
method testManualIntId (line 259) | public function testManualIntId(): void
method testDelete (line 275) | public function testDelete(): void
method testAll (line 287) | public function testAll(): void
method testFind (line 304) | public function testFind(): void
method testInsertEmpty (line 318) | public function testInsertEmpty(): void
method testGet (line 324) | public function testGet(): void
method testFirst (line 337) | public function testFirst(): void
method testNoDocument (line 350) | public function testNoDocument(): void
method testFindOrFail (line 363) | public function testFindOrFail(): void
method testCreate (line 369) | public function testCreate(): void
method testDestroy (line 383) | public function testDestroy(): void
method testTouch (line 392) | public function testTouch(): void
method testSoftDelete (line 406) | public function testSoftDelete(): void
method testPrimaryKey (line 439) | #[DataProvider('provideId')]
method provideId (line 468) | public static function provideId(): iterable
method testCustomPrimaryKey (line 532) | public function testCustomPrimaryKey(): void
method testScope (line 550) | public function testScope(): void
method testToArray (line 561) | public function testToArray(): void
method testUnset (line 574) | public function testUnset(): void
method testUnsetRefresh (line 614) | public function testUnsetRefresh(): void
method testUnsetAndSet (line 627) | public function testUnsetAndSet(): void
method testUnsetDotAttributes (line 671) | public function testUnsetDotAttributes(): void
method testUnsetDotAttributesAndSet (line 712) | public function testUnsetDotAttributesAndSet(): void
method testDateUseLocalTimeZone (line 744) | public function testDateUseLocalTimeZone(): void
method testDates (line 771) | public function testDates(): void
method provideDate (line 808) | public static function provideDate(): Generator
method testDateInputs (line 824) | #[DataProvider('provideDate')]
method testDateNull (line 855) | public function testDateNull(): void
method testCarbonDateMockingWorks (line 883) | public function testCarbonDateMockingWorks()
method testIdAttribute (line 893) | public function testIdAttribute(): void
method testPushPull (line 903) | public function testPushPull(): void
method testRaw (line 930) | public function testRaw(): void
method testRawHyradeModel (line 953) | #[DataProvider('provideTypeMap')]
method provideTypeMap (line 997) | public static function provideTypeMap(): Generator
method testDotNotation (line 1006) | public function testDotNotation(): void
method testAttributeMutator (line 1026) | public function testAttributeMutator(): void
method testMultipleLevelDotNotation (line 1043) | public function testMultipleLevelDotNotation(): void
method testGetDirtyDates (line 1058) | public function testGetDirtyDates(): void
method testChunkById (line 1068) | public function testChunkById(): void
method testTruncateModel (line 1082) | public function testTruncateModel(): void
method testGuardedModel (line 1091) | public function testGuardedModel(): void
method testFirstOrCreate (line 1114) | public function testFirstOrCreate(): void
method testFirstOrCreateWithValues (line 1132) | public function testFirstOrCreateWithValues(): void
method testEnumCast (line 1151) | public function testEnumCast(): void
method testNumericFieldName (line 1166) | public function testNumericFieldName(): void
method testCreateOrFirst (line 1182) | #[TestWith([true])]
method testUpdateOrCreate (line 1262) | #[TestWith([['_id' => new ObjectID()]])]
method testCreateWithNullId (line 1316) | #[TestWith(['_id'])]
method registerModelEvents (line 1327) | private static function registerModelEvents(string $modelClass, array ...
FILE: tests/Models/Address.php
class Address (line 11) | class Address extends Model
method addresses (line 19) | public function addresses(): EmbedsMany
FILE: tests/Models/Anniversary.php
class Anniversary (line 14) | class Anniversary extends Model
FILE: tests/Models/Birthday.php
class Birthday (line 15) | class Birthday extends Model
FILE: tests/Models/Book.php
class Book (line 16) | class Book extends Model
method author (line 26) | public function author(): BelongsTo
method sqlAuthor (line 31) | public function sqlAuthor(): BelongsTo
FILE: tests/Models/CastObjectId.php
class CastObjectId (line 10) | class CastObjectId extends Model
FILE: tests/Models/Casting.php
class Casting (line 10) | class Casting extends Model
FILE: tests/Models/Client.php
class Client (line 13) | class Client extends Model
method users (line 22) | public function users(): BelongsToMany
method skillsWithCustomKeys (line 27) | public function skillsWithCustomKeys()
method photo (line 38) | public function photo(): MorphOne
method addresses (line 43) | public function addresses(): HasMany
method labels (line 48) | public function labels()
method labelsWithCustomKeys (line 53) | public function labelsWithCustomKeys()
FILE: tests/Models/Experience.php
class Experience (line 11) | class Experience extends Model
method sqlUsers (line 22) | public function sqlUsers(): MorphToMany
FILE: tests/Models/Group.php
class Group (line 11) | class Group extends Model
method users (line 20) | public function users(): BelongsToMany
FILE: tests/Models/Guarded.php
class Guarded (line 10) | class Guarded extends Model
FILE: tests/Models/HiddenAnimal.php
class HiddenAnimal (line 15) | final class HiddenAnimal extends Model
FILE: tests/Models/IdIsBinaryUuid.php
class IdIsBinaryUuid (line 11) | class IdIsBinaryUuid extends Model
FILE: tests/Models/IdIsInt.php
class IdIsInt (line 10) | class IdIsInt extends Model
FILE: tests/Models/IdIsString.php
class IdIsString (line 10) | class IdIsString extends Model
FILE: tests/Models/Item.php
class Item (line 14) | class Item extends Model
method user (line 23) | public function user(): BelongsTo
method scopeSharp (line 28) | public function scopeSharp(Builder $query)
FILE: tests/Models/Label.php
class Label (line 16) | class Label extends Model
method users (line 31) | public function users()
method sqlUsers (line 36) | public function sqlUsers(): MorphToMany
method clients (line 41) | public function clients()
method clientsWithCustomKeys (line 46) | public function clientsWithCustomKeys()
FILE: tests/Models/Location.php
class Location (line 10) | class Location extends Model
FILE: tests/Models/NonIncrementing.php
class NonIncrementing (line 14) | class NonIncrementing extends Model
FILE: tests/Models/Photo.php
class Photo (line 11) | class Photo extends Model
method hasImage (line 20) | public function hasImage(): MorphTo
method hasImageWithCustomOwnerKey (line 25) | public function hasImageWithCustomOwnerKey(): MorphTo
FILE: tests/Models/Role.php
class Role (line 11) | class Role extends Model
method user (line 20) | public function user(): BelongsTo
method sqlUser (line 25) | public function sqlUser(): BelongsTo
FILE: tests/Models/SchemaVersion.php
class SchemaVersion (line 10) | class SchemaVersion extends Model
method migrateSchema (line 20) | public function migrateSchema(int $fromVersion): void
FILE: tests/Models/Scoped.php
class Scoped (line 11) | class Scoped extends Model
method boot (line 20) | protected static function boot()
FILE: tests/Models/Skill.php
class Skill (line 11) | class Skill extends Model
method sqlUsers (line 20) | public function sqlUsers(): BelongsToMany
FILE: tests/Models/Soft.php
class Soft (line 15) | class Soft extends Model
method prunable (line 27) | public function prunable(): Builder
method user (line 32) | public function user()
FILE: tests/Models/SqlBook.php
class SqlBook (line 16) | class SqlBook extends EloquentModel
method author (line 25) | public function author(): BelongsTo
method executeSchema (line 33) | public static function executeSchema(): void
FILE: tests/Models/SqlRole.php
class SqlRole (line 16) | class SqlRole extends EloquentModel
method user (line 24) | public function user(): BelongsTo
method sqlUser (line 29) | public function sqlUser(): BelongsTo
method executeSchema (line 37) | public static function executeSchema()
FILE: tests/Models/SqlUser.php
class SqlUser (line 19) | class SqlUser extends EloquentModel
method books (line 27) | public function books(): HasMany
method role (line 32) | public function role(): HasOne
method skills (line 37) | public function skills(): BelongsToMany
method sqlBooks (line 42) | public function sqlBooks(): HasMany
method labels (line 47) | public function labels(): MorphToMany
method experiences (line 52) | public function experiences(): MorphToMany
method executeSchema (line 60) | public static function executeSchema(): void
FILE: tests/Models/User.php
class User (line 33) | class User extends Model implements AuthenticatableContract, CanResetPas...
method books (line 60) | public function books()
method softs (line 65) | public function softs()
method softsWithTrashed (line 70) | public function softsWithTrashed()
method sqlBooks (line 75) | public function sqlBooks()
method items (line 80) | public function items()
method role (line 85) | public function role()
method sqlRole (line 90) | public function sqlRole()
method clients (line 95) | public function clients()
method groups (line 100) | public function groups()
method photos (line 105) | public function photos()
method labels (line 110) | public function labels()
method addresses (line 115) | public function addresses()
method father (line 120) | public function father()
method serializeDate (line 125) | protected function serializeDate(DateTimeInterface $date)
method username (line 130) | protected function username(): Attribute
method prunable (line 138) | public function prunable(): Builder
FILE: tests/PHPStan/SarifErrorFormatter.php
class SarifErrorFormatter (line 24) | class SarifErrorFormatter implements ErrorFormatter
method __construct (line 28) | public function __construct(
method formatErrors (line 35) | public function formatErrors(AnalysisResult $analysisResult, Output $o...
FILE: tests/PropertyTest.php
class PropertyTest (line 11) | final class PropertyTest extends TestCase
method setUp (line 13) | protected function setUp(): void
method testCanHideCertainProperties (line 20) | public function testCanHideCertainProperties(): void
FILE: tests/Query/AggregationBuilderTest.php
class AggregationBuilderTest (line 23) | class AggregationBuilderTest extends TestCase
method tearDown (line 25) | public function tearDown(): void
method testCreateAggregationBuilder (line 32) | public function testCreateAggregationBuilder(): void
method testAddRawStage (line 91) | public function testAddRawStage(): void
method testAddRawStageInvalid (line 110) | public function testAddRawStageInvalid(): void
method testColumnsCannotBeSpecifiedToCreateAnAggregationBuilder (line 121) | public function testColumnsCannotBeSpecifiedToCreateAnAggregationBuild...
method testAggrecationBuilderDoesNotSupportPreviousQueryBuilderInstructions (line 128) | public function testAggrecationBuilderDoesNotSupportPreviousQueryBuild...
method assertSamePipeline (line 135) | private static function assertSamePipeline(array $expected, Pipeline $...
FILE: tests/Query/BuilderTest.php
class BuilderTest (line 32) | class BuilderTest extends TestCase
method testMql (line 34) | #[DataProvider('provideQueryBuilderToMql')]
method provideQueryBuilderToMql (line 58) | public static function provideQueryBuilderToMql(): iterable
method testException (line 1476) | #[DataProvider('provideExceptions')]
method provideExceptions (line 1486) | public static function provideExceptions(): iterable
method testEloquentMethodsNotSupported (line 1574) | #[DataProvider('getEloquentMethodsNotSupported')]
method getEloquentMethodsNotSupported (line 1585) | public static function getEloquentMethodsNotSupported()
method testDisableRenameEmbeddedIdField (line 1632) | #[DataProvider('provideDisableRenameEmbeddedIdField')]
method provideDisableRenameEmbeddedIdField (line 1643) | public static function provideDisableRenameEmbeddedIdField()
method getBuilder (line 1714) | private function getBuilder(bool $renameEmbeddedIdField = true): Builder
FILE: tests/QueryBuilderTest.php
class QueryBuilderTest (line 42) | class QueryBuilderTest extends TestCase
method tearDown (line 44) | public function tearDown(): void
method testDeleteWithId (line 52) | public function testDeleteWithId()
method testCollection (line 86) | public function testCollection()
method testGet (line 91) | public function testGet()
method testNoDocument (line 102) | public function testNoDocument()
method testInsert (line 114) | public function testInsert()
method testInsertWithCustomId (line 129) | #[TestWith([true])]
method testInsertGetId (line 145) | public function testInsertGetId()
method testBatchInsert (line 151) | public function testBatchInsert()
method testFind (line 169) | public function testFind()
method testFindWithTimeout (line 177) | public function testFindWithTimeout()
method testFindNull (line 209) | public function testFindNull()
method testCount (line 215) | public function testCount()
method testUpdate (line 225) | public function testUpdate()
method testUpdateOperators (line 240) | public function testUpdateOperators()
method testDelete (line 272) | public function testDelete()
method testTruncate (line 286) | public function testTruncate()
method testSubKey (line 296) | public function testSubKey()
method testInArray (line 314) | public function testInArray()
method testRaw (line 332) | public function testRaw()
method testRawResultRenameId (line 357) | public function testRawResultRenameId()
method testPush (line 444) | public function testPush()
method testPushRefuses2ndArgumentWhen1stIsAnArray (line 500) | public function testPushRefuses2ndArgumentWhen1stIsAnArray()
method testPull (line 508) | public function testPull()
method testDistinct (line 539) | public function testDistinct()
method testCustomId (line 559) | public function testCustomId()
method testTake (line 598) | public function testTake()
method testSkip (line 612) | public function testSkip()
method testPluck (line 626) | public function testPluck()
method testPluckObjectId (line 637) | public function testPluckObjectId()
method testList (line 648) | public function testList()
method testAggregate (line 671) | public function testAggregate()
method testSubdocumentAggregate (line 690) | public function testSubdocumentAggregate()
method testSubdocumentArrayAggregate (line 706) | public function testSubdocumentArrayAggregate()
method testAggregateGroupBy (line 729) | public function testAggregateGroupBy()
method testAggregateByGroupException (line 774) | public function testAggregateByGroupException(): void
method testUpdateWithUpsert (line 782) | public function testUpdateWithUpsert()
method testUpsert (line 801) | public function testUpsert()
method testUnset (line 833) | public function testUnset()
method testUpdateSubdocument (line 855) | public function testUpdateSubdocument()
method testDates (line 865) | public function testDates()
method testImmutableDates (line 899) | public function testImmutableDates()
method testOperators (line 926) | public function testOperators()
method testIncrement (line 1022) | public function testIncrement()
method testMultiplyAndDivide (line 1071) | public function testMultiplyAndDivide()
method testProjections (line 1120) | public function testProjections()
method testValue (line 1135) | public function testValue()
method testHintOptions (line 1148) | public function testHintOptions()
method testCursor (line 1169) | public function testCursor()
method testStringableColumn (line 1186) | public function testStringableColumn()
method testIncrementEach (line 1245) | public function testIncrementEach()
method testIdAlias (line 1295) | #[TestWith(['id', 'id'])]
FILE: tests/QueryTest.php
class QueryTest (line 17) | class QueryTest extends TestCase
method setUp (line 21) | public function setUp(): void
method tearDown (line 43) | public function tearDown(): void
method testWhere (line 52) | public function testWhere(): void
method testAndWhere (line 73) | public function testAndWhere(): void
method testRegexp (line 82) | public function testRegexp(): void
method testLike (line 97) | public function testLike(): void
method testNotLike (line 118) | public function testNotLike(): void
method testSelect (line 133) | public function testSelect(): void
method testWhereNot (line 159) | public function testWhereNot(): void
method testOrWhere (line 201) | public function testOrWhere(): void
method testBetween (line 210) | public function testBetween(): void
method testIn (line 223) | public function testIn(): void
method testWhereNull (line 239) | public function testWhereNull(): void
method testWhereNotNull (line 245) | public function testWhereNotNull(): void
method testWhereDate (line 251) | public function testWhereDate(): void
method testWhereDay (line 275) | public function testWhereDay(): void
method testWhereMonth (line 284) | public function testWhereMonth(): void
method testWhereYear (line 302) | public function testWhereYear(): void
method testWhereTime (line 317) | public function testWhereTime(): void
method testOrder (line 338) | public function testOrder(): void
method testStringableOrder (line 359) | public function testStringableOrder(): void
method testGroupBy (line 370) | public function testGroupBy(): void
method testCount (line 400) | public function testCount(): void
method testExists (line 410) | public function testExists(): void
method testSubQuery (line 418) | public function testSubQuery(): void
method testWhereRaw (line 467) | public function testWhereRaw(): void
method testMultipleOr (line 481) | public function testMultipleOr(): void
method testPaginate (line 502) | public function testPaginate(): void
method testCursorPaginate (line 516) | public function testCursorPaginate(): void
method testPaginateGroup (line 539) | public function testPaginateGroup(): void
method testPaginateDistinct (line 569) | public function testPaginateDistinct(): void
method testUpdate (line 577) | public function testUpdate(): void
method testUnsorted (line 594) | public function testUnsorted(): void
method testSort (line 605) | public function testSort(): void
method testSortOrder (line 612) | public function testSortOrder(): void
method testMultipleSort (line 619) | public function testMultipleSort(): void
method testMultipleSortOrder (line 630) | public function testMultipleSortOrder(): void
method testDelete (line 641) | public function testDelete(): void
method testLimitCount (line 666) | public function testLimitCount(): void
FILE: tests/Queue/Failed/DatabaseFailedJobProviderTest.php
class DatabaseFailedJobProviderTest (line 20) | class DatabaseFailedJobProviderTest extends TestCase
method setUp (line 22) | public function setUp(): void
method tearDown (line 37) | public function tearDown(): void
method testLog (line 47) | public function testLog(): void
method testCount (line 66) | public function testCount(): void
method testAll (line 75) | public function testAll(): void
method testFindAndForget (line 85) | public function testFindAndForget(): void
method testIds (line 111) | public function testIds(): void
method testIdsFilteredByQuery (line 119) | public function testIdsFilteredByQuery(): void
method testFlush (line 127) | public function testFlush(): void
method testPrune (line 138) | public function testPrune(): void
method getProvider (line 150) | private function getProvider(): DatabaseFailedJobProvider
FILE: tests/QueueTest.php
class QueueTest (line 20) | class QueueTest extends TestCase
method setUp (line 22) | public function setUp(): void
method testQueueJobLifeCycle (line 33) | public function testQueueJobLifeCycle(): void
method testQueueJobExpired (line 63) | public function testQueueJobExpired(): void
method testFailQueueJob (line 84) | public function testFailQueueJob(): void
method testFindFailJobNull (line 91) | public function testFindFailJobNull(): void
method testIncrementAttempts (line 99) | public function testIncrementAttempts(): void
method testJobRelease (line 118) | public function testJobRelease(): void
method testQueueDeleteReserved (line 135) | public function testQueueDeleteReserved(): void
method testQueueRelease (line 148) | public function testQueueRelease(): void
method testQueueDeleteAndRelease (line 173) | public function testQueueDeleteAndRelease(): void
method testFailedJobLogging (line 187) | public function testFailedJobLogging()
FILE: tests/RelationsTest.php
class RelationsTest (line 22) | class RelationsTest extends TestCase
method tearDown (line 24) | public function tearDown(): void
method testHasMany (line 43) | public function testHasMany(): void
method testHasManyWithTrashed (line 62) | public function testHasManyWithTrashed(): void
method testBelongsTo (line 80) | public function testBelongsTo(): void
method testHasOne (line 99) | public function testHasOne(): void
method testWithBelongsTo (line 122) | public function testWithBelongsTo(): void
method testWithHashMany (line 139) | public function testWithHashMany(): void
method testWithHasOne (line 154) | public function testWithHasOne(): void
method testEasyRelation (line 167) | public function testEasyRelation(): void
method testBelongsToMany (line 192) | public function testBelongsToMany(): void
method testBelongsToManyAttachesExistingModels (line 266) | public function testBelongsToManyAttachesExistingModels(): void
method testBelongsToManySync (line 305) | public function testBelongsToManySync(): void
method testBelongsToManyAttachArray (line 331) | public function testBelongsToManyAttachArray(): void
method testBelongsToManyAttachEloquentCollection (line 341) | public function testBelongsToManyAttachEloquentCollection(): void
method testBelongsToManySyncWithCustomKeys (line 353) | public function testBelongsToManySyncWithCustomKeys(): void
method testBelongsToManySyncModelWithCustomKeys (line 382) | public function testBelongsToManySyncModelWithCustomKeys(): void
method testBelongsToManySyncEloquentCollectionWithCustomKeys (line 401) | public function testBelongsToManySyncEloquentCollectionWithCustomKeys(...
method testBelongsToManyAttachWithCustomKeys (line 431) | public function testBelongsToManyAttachWithCustomKeys(): void
method testBelongsToManyAttachModelWithCustomKeys (line 460) | public function testBelongsToManyAttachModelWithCustomKeys(): void
method testBelongsToManyAttachEloquentCollectionWithCustomKeys (line 479) | public function testBelongsToManyAttachEloquentCollectionWithCustomKey...
method testBelongsToManyDetachWithCustomKeys (line 509) | public function testBelongsToManyDetachWithCustomKeys(): void
method testBelongsToManyDetachModelWithCustomKeys (line 542) | public function testBelongsToManyDetachModelWithCustomKeys(): void
method testBelongsToManySyncAlreadyPresent (line 575) | public function testBelongsToManySyncAlreadyPresent(): void
method testBelongsToManyCustom (line 592) | public function testBelongsToManyCustom(): void
method testMorph (line 612) | public function testMorph(): void
method testMorphToMany (line 683) | public function testMorphToMany(): void
method testMorphToManyAttachEloquentCollection (line 700) | public function testMorphToManyAttachEloquentCollection(): void
method testMorphToManyAttachMultipleIds (line 714) | public function testMorphToManyAttachMultipleIds(): void
method testMorphToManyDetaching (line 728) | public function testMorphToManyDetaching(): void
method testMorphToManyDetachingMultipleIds (line 746) | public function testMorphToManyDetachingMultipleIds(): void
method testMorphToManySyncing (line 765) | public function testMorphToManySyncing(): void
method testMorphToManySyncingEloquentCollection (line 786) | public function testMorphToManySyncingEloquentCollection(): void
method testMorphToManySyncingMultipleIds (line 800) | public function testMorphToManySyncingMultipleIds(): void
method testMorphToManySyncingWithCustomKeys (line 814) | public function testMorphToManySyncingWithCustomKeys(): void
method testMorphToManyLoadAndRefreshing (line 835) | public function testMorphToManyLoadAndRefreshing(): void
method testMorphToManyHasQuery (line 866) | public function testMorphToManyHasQuery(): void
method testMorphedByMany (line 894) | public function testMorphedByMany(): void
method testMorphedByManyAttachEloquentCollection (line 912) | public function testMorphedByManyAttachEloquentCollection(): void
method testMorphedByManyAttachMultipleIds (line 930) | public function testMorphedByManyAttachMultipleIds(): void
method testMorphedByManyDetaching (line 948) | public function testMorphedByManyDetaching(): void
method testMorphedByManyDetachingMultipleIds (line 967) | public function testMorphedByManyDetachingMultipleIds(): void
method testMorphedByManySyncing (line 986) | public function testMorphedByManySyncing(): void
method testMorphedByManySyncingEloquentCollection (line 1004) | public function testMorphedByManySyncingEloquentCollection(): void
method testMorphedByManySyncingMultipleIds (line 1021) | public function testMorphedByManySyncingMultipleIds(): void
method testMorphedByManySyncingWithCustomKeys (line 1038) | public function testMorphedByManySyncingWithCustomKeys(): void
method testMorphedByManyLoadAndRefreshing (line 1064) | public function testMorphedByManyLoadAndRefreshing(): void
method testMorphedByManyHasQuery (line 1096) | public function testMorphedByManyHasQuery(): void
method testHasManyHas (line 1127) | public function testHasManyHas(): void
method testHasOneHas (line 1177) | public function testHasOneHas(): void
method testNestedKeys (line 1199) | public function testNestedKeys(): void
method testDoubleSaveOneToMany (line 1225) | public function testDoubleSaveOneToMany(): void
method testDoubleSaveManyToMany (line 1248) | public function testDoubleSaveManyToMany(): void
method testWhereBelongsTo (line 1275) | public function testWhereBelongsTo()
FILE: tests/SchemaTest.php
class SchemaTest (line 21) | class SchemaTest extends TestCase
method tearDown (line 27) | public function tearDown(): void
method testCreate (line 39) | public function testCreate(): void
method testCreateWithCallback (line 46) | public function testCreateWithCallback(): void
method testCreateWithOptions (line 55) | public function testCreateWithOptions(): void
method testCreateWithSchemaValidator (line 66) | public function testCreateWithSchemaValidator(): void
method testDrop (line 99) | public function testDrop(): void
method testBluePrint (line 106) | public function testBluePrint(): void
method testIndex (line 117) | public function testIndex(): void
method testPrimary (line 141) | public function testPrimary(): void
method testUnique (line 151) | public function testUnique(): void
method testDropIndex (line 161) | public function testDropIndex(): void
method testDropIndexIfExists (line 216) | public function testDropIndexIfExists(): void
method testHasIndex (line 257) | public function testHasIndex(): void
method testSparse (line 278) | public function testSparse(): void
method testExpire (line 288) | public function testExpire(): void
method testSoftDeletes (line 298) | public function testSoftDeletes(): void
method testFluent (line 312) | public function testFluent(): void
method testGeospatial (line 327) | public function testGeospatial(): void
method testDummies (line 345) | public function testDummies(): void
method testSparseUnique (line 354) | public function testSparseUnique(): void
method testRenameColumn (line 365) | public function testRenameColumn(): void
method testHasColumn (line 405) | public function testHasColumn(): void
method testHasColumns (line 418) | public function testHasColumns(): void
method testGetTables (line 433) | public function testGetTables()
method testGetViews (line 477) | public function testGetViews()
method testGetTableListing (line 511) | public function testGetTableListing()
method testGetTableListingBySchema (line 524) | public function testGetTableListingBySchema()
method testGetColumns (line 545) | public function testGetColumns()
method testGetIndexes (line 588) | public function testGetIndexes()
method testSearchIndex (line 637) | public function testSearchIndex(): void
method testVectorSearchIndex (line 668) | public function testVectorSearchIndex()
method assertIndexExists (line 696) | protected function assertIndexExists(string $collection, string $name)...
method assertIndexNotExists (line 705) | protected function assertIndexNotExists(string $collection, string $na...
method getIndex (line 712) | protected function getIndex(string $collection, string $name): ?IndexInfo
method getSearchIndex (line 726) | protected function getSearchIndex(string $collection, string $name): ?...
FILE: tests/SchemaVersionTest.php
class SchemaVersionTest (line 13) | class SchemaVersionTest extends TestCase
method tearDown (line 15) | public function tearDown(): void
method testWithBasicDocument (line 22) | public function testWithBasicDocument()
method testIncompleteImplementation (line 50) | public function testIncompleteImplementation(): void
FILE: tests/Scout/Models/ScoutUser.php
class ScoutUser (line 16) | class ScoutUser extends Model
method executeSchema (line 28) | public static function executeSchema(): void
FILE: tests/Scout/Models/SearchableInSameNamespace.php
class SearchableInSameNamespace (line 11) | class SearchableInSameNamespace extends Model
method indexableAs (line 26) | public function indexableAs(): string
FILE: tests/Scout/Models/SearchableModel.php
class SearchableModel (line 9) | class SearchableModel extends Model
method searchableAs (line 18) | public function searchableAs(): string
method indexableAs (line 24) | public function indexableAs(): string
method getScoutKey (line 35) | public function getScoutKey(): string
method getScoutKeyName (line 46) | public function getScoutKeyName(): string
FILE: tests/Scout/ScoutEngineTest.php
class ScoutEngineTest (line 32) | class ScoutEngineTest extends TestCase
method testCreateIndexInvalidDefinition (line 36) | public function testCreateIndexInvalidDefinition(): void
method testCreateIndex (line 46) | public function testCreateIndex(): void
method testCreateIndexCustomDefinition (line 74) | public function testCreateIndexCustomDefinition(): void
method testSearch (line 113) | #[DataProvider('provideSearchPipelines')]
method provideSearchPipelines (line 145) | public static function provideSearchPipelines(): iterable
method testPaginate (line 409) | public function testPaginate()
method testMapMethodRespectsOrder (line 472) | public function testMapMethodRespectsOrder()
method testLazyMapMethodRespectsOrder (line 512) | public function testLazyMapMethodRespectsOrder()
method testUpdate (line 552) | public function testUpdate(): void
method testUpdateWithSoftDelete (line 590) | public function testUpdateWithSoftDelete(): void
method testDelete (line 618) | public function testDelete(): void
method testDeleteWithRemoveableScoutCollection (line 637) | public function testDeleteWithRemoveableScoutCollection(): void
method testDeleteRejectsNonEloquentCollection (line 659) | public function testDeleteRejectsNonEloquentCollection(): void
FILE: tests/Scout/ScoutIntegrationTest.php
class ScoutIntegrationTest (line 28) | #[Group('atlas-search')]
method getPackageProviders (line 33) | #[Override]
method getEnvironmentSetUp (line 39) | #[Override]
method setUp (line 51) | public function setUp(): void
method testItCanCreateTheCollection (line 101) | public function testItCanCreateTheCollection()
method testItCanUseBasicSearch (line 144) | #[Depends('testItCanCreateTheCollection')]
method testItCanUseBasicSearchCursor (line 164) | #[Depends('testItCanCreateTheCollection')]
method testItCanUseBasicSearchWithQueryCallback (line 184) | #[Depends('testItCanCreateTheCollection')]
method testItCanUseBasicSearchToFetchKeys (line 202) | #[Depends('testItCanCreateTheCollection')]
method testItCanUseBasicSearchWithQueryCallbackToFetchKeys (line 210) | #[Depends('testItCanCreateTheCollection')]
method testItCanUsePaginatedSearch (line 220) | #[Depends('testItCanCreateTheCollection')]
method testItCanUsePaginatedSearchWithQueryCallback (line 243) | #[Depends('testItCanCreateTheCollection')]
method testItCannotIndexInTheSameNamespace (line 267) | public function testItCannotIndexInTheSameNamespace()
FILE: tests/Seeder/DatabaseSeeder.php
class DatabaseSeeder (line 9) | class DatabaseSeeder extends Seeder
method run (line 11) | public function run(): void
FILE: tests/Seeder/UserTableSeeder.php
class UserTableSeeder (line 10) | class UserTableSeeder extends Seeder
method run (line 12) | public function run()
FILE: tests/SeederTest.php
class SeederTest (line 12) | class SeederTest extends TestCase
method tearDown (line 14) | public function tearDown(): void
method testSeed (line 21) | public function testSeed(): void
method testArtisan (line 30) | public function testArtisan(): void
FILE: tests/SessionTest.php
class SessionTest (line 12) | class SessionTest extends TestCase
method tearDown (line 14) | protected function tearDown(): void
method testSessionHandlerFunctionality (line 22) | #[TestWith([DatabaseSessionHandler::class])]
method testDatabaseSessionHandlerRegistration (line 48) | public function testDatabaseSessionHandlerRegistration()
method testMongoDBSessionHandlerRegistration (line 60) | public function testMongoDBSessionHandlerRegistration()
method assertSessionCanStoreInMongoDB (line 72) | private function assertSessionCanStoreInMongoDB(SessionManager $sessio...
FILE: tests/TestCase.php
class TestCase (line 15) | class TestCase extends OrchestraTestCase
method getPackageProviders (line 22) | protected function getPackageProviders($app): array
method getEnvironmentSetUp (line 35) | protected function getEnvironmentSetUp($app): void
method skipIfSearchIndexManagementIsNotSupported (line 70) | public function skipIfSearchIndexManagementIsNotSupported(): void
FILE: tests/Ticket/GH2489Test.php
class GH2489Test (line 11) | class GH2489Test extends TestCase
method tearDown (line 13) | public function tearDown(): void
method testQuerySubdocumentsUsingWhereInId (line 20) | public function testQuerySubdocumentsUsingWhereInId()
FILE: tests/Ticket/GH2783Test.php
class GH2783Test (line 16) | class GH2783Test extends TestCase
method testMorphToInfersCustomOwnerKey (line 18) | public function testMorphToInfersCustomOwnerKey()
class GH2783Image (line 43) | class GH2783Image extends Model
method imageable (line 48) | public function imageable(): MorphTo
class GH2783Post (line 54) | class GH2783Post extends Model
method image (line 59) | public function image(): MorphOne
class GH2783User (line 65) | class GH2783User extends Model
method image (line 71) | public function image(): MorphOne
FILE: tests/Ticket/GH3326Test.php
class GH3326Test (line 14) | class GH3326Test extends TestCase
method testCreatedEventCanSafelyCallSave (line 16) | public function testCreatedEventCanSafelyCallSave(): void
class GH3326Model (line 29) | class GH3326Model extends Model
method booted (line 35) | protected static function booted(): void
FILE: tests/Ticket/GH3328Test.php
class GH3328Test (line 30) | class GH3328Test extends TestCase
method testAfterCommitOnSuccessfulTransaction (line 32) | public function testAfterCommitOnSuccessfulTransaction(): void
method testAfterCommitOnFailedTransaction (line 55) | public function testAfterCommitOnFailedTransaction(): void
method testAfterCommitOnSuccessfulManualTransaction (line 101) | public function testAfterCommitOnSuccessfulManualTransaction(): void
method testAfterCommitOnFailedManualTransaction (line 125) | public function testAfterCommitOnFailedManualTransaction(): void
method assertTransactionCallbackResult (line 151) | private function assertTransactionCallbackResult(Closure $callback, Cl...
method assertCallbackResultForConnection (line 171) | private function assertCallbackResultForConnection(Connection $connect...
method assertTransactionResult (line 190) | private function assertTransactionResult(Closure $callback, Closure $a...
method assertManualResultForConnection (line 208) | private function assertManualResultForConnection(Connection $connectio...
method beforeStartingTransactionIsSupported (line 231) | private function beforeStartingTransactionIsSupported(): bool
class AfterCommitEvent (line 237) | class AfterCommitEvent implements ShouldDispatchAfterCommit
class BeforeTransactionEvent (line 242) | class BeforeTransactionEvent
class RegularEvent (line 246) | class RegularEvent
class Fake (line 250) | class Fake extends RuntimeException
method __construct (line 252) | public function __construct()
class FakeConcurrencyErrorDetector (line 259) | class FakeConcurrencyErrorDetector implements ConcurrencyErrorDetector
method causedByConcurrencyError (line 261) | public function causedByConcurrencyError(Throwable $e): bool
FILE: tests/Ticket/GH3335Test.php
class GH3335Test (line 11) | class GH3335Test extends TestCase
method tearDown (line 13) | public function tearDown(): void
method testNumericalFieldName (line 20) | public function testNumericalFieldName()
FILE: tests/TransactionTest.php
class TransactionTest (line 16) | class TransactionTest extends TestCase
method setUp (line 18) | public function setUp(): void
method tearDown (line 29) | public function tearDown(): void
method testCreateWithCommit (line 36) | public function testCreateWithCommit(): void
method testCreateRollBack (line 52) | public function testCreateRollBack(): void
method testInsertWithCommit (line 66) | public function testInsertWithCommit(): void
method testInsertWithRollBack (line 75) | public function testInsertWithRollBack(): void
method testEloquentCreateWithCommit (line 84) | public function testEloquentCreateWithCommit(): void
method testEloquentCreateWithRollBack (line 101) | public function testEloquentCreateWithRollBack(): void
method testInsertGetIdWithCommit (line 116) | public function testInsertGetIdWithCommit(): void
method testInsertGetIdWithRollBack (line 128) | public function testInsertGetIdWithRollBack(): void
method testUpdateWithCommit (line 138) | public function testUpdateWithCommit(): void
method testUpdateWithRollback (line 150) | public function testUpdateWithRollback(): void
method testEloquentUpdateWithCommit (line 162) | public function testEloquentUpdateWithCommit(): void
method testEloquentUpdateWithRollBack (line 183) | public function testEloquentUpdateWithRollBack(): void
method testDeleteWithCommit (line 204) | public function testDeleteWithCommit(): void
method testDeleteWithRollBack (line 216) | public function testDeleteWithRollBack(): void
method testEloquentDeleteWithCommit (line 228) | public function testEloquentDeleteWithCommit(): void
method testEloquentDeleteWithRollBack (line 240) | public function testEloquentDeleteWithRollBack(): void
method testIncrementWithCommit (line 252) | public function testIncrementWithCommit(): void
method testIncrementWithRollBack (line 263) | public function testIncrementWithRollBack(): void
method testDecrementWithCommit (line 274) | public function testDecrementWithCommit(): void
method testDecrementWithRollBack (line 285) | public function testDecrementWithRollBack(): void
method testQuery (line 296) | public function testQuery()
method testTransaction (line 323) | public function testTransaction(): void
method testTransactionRepeatsOnTransientFailure (line 341) | public function testTransactionRepeatsOnTransientFailure(): void
method testTransactionRespectsRepetitionLimit (line 366) | public function testTransactionRespectsRepetitionLimit(): void
method testTransactionReturnsCallbackResult (line 400) | public function testTransactionReturnsCallbackResult(): void
method testNestedTransactionsCauseException (line 411) | public function testNestedTransactionsCauseException(): void
method testNestingTransactionInManualTransaction (line 422) | public function testNestingTransactionInManualTransaction()
method testCommitWithoutSession (line 433) | public function testCommitWithoutSession(): void
method testRollBackWithoutSession (line 441) | public function testRollBackWithoutSession(): void
method getPrimaryServerType (line 449) | private function getPrimaryServerType(): int
FILE: tests/ValidationTest.php
class ValidationTest (line 10) | class ValidationTest extends TestCase
method tearDown (line 12) | public function tearDown(): void
method testUnique (line 19) | public function testUnique(): void
method testExists (line 80) | public function testExists(): void
Condensed preview — 171 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (935K chars).
[
{
"path": ".editorconfig",
"chars": 172,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_"
},
{
"path": ".gitattributes",
"chars": 429,
"preview": "/.github export-ignore\n/.phpunit.cache export-ignore\n/tests export-ignore\n*.m"
},
{
"path": ".github/CODEOWNERS",
"chars": 19,
"preview": "* @mongodb/dbx-php\n"
},
{
"path": ".github/ISSUE_TEMPLATE/BUG_REPORT.md",
"chars": 399,
"preview": "---\nname: \"Bug report\"\nabout: 'Report errors or unexpected behavior.'\n---\n\n- Laravel-mongodb Version: #.#.#\n- PHP Versio"
},
{
"path": ".github/ISSUE_TEMPLATE/FEATURE-REQUEST.md",
"chars": 518,
"preview": "---\nname: Feature request\nabout: Suggest an idea.\ntitle: \"[Feature Request] \"\n\n---\n\n### Is your feature request related "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 915,
"preview": "blank_issues_enabled: false\n\ncontact_links:\n - name: Discussions\n url: https://github.com/mongodb/laravel-mongodb/di"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 198,
"preview": "<!--\nReplace this notice by a description of your feature/bugfix.\nThis will help reviewers and should be a good start fo"
},
{
"path": ".github/dependabot.yml",
"chars": 112,
"preview": "version: 2\nupdates:\n - package-ecosystem: github-actions\n directory: /\n schedule:\n interval: weekly\n"
},
{
"path": ".github/labeler.yml",
"chars": 105,
"preview": "# https://github.com/actions/labeler\ngithub:\n - changed-files:\n - any-glob-to-any-file: '.github/**'\n"
},
{
"path": ".github/release.yml",
"chars": 396,
"preview": "changelog:\n exclude:\n labels:\n - ignore-for-release\n - minor\n authors:\n - mongodb-php-bot\n catego"
},
{
"path": ".github/workflows/build-ci-atlas.yml",
"chars": 3015,
"preview": "name: Atlas CI\n\non:\n push:\n branches:\n - '[0-9]+.[0-9x]+'\n pull_request:\n branches:\n - '[0-9]+.[0-9x]+"
},
{
"path": ".github/workflows/build-ci.yml",
"chars": 4159,
"preview": "name: CI\n\non:\n push:\n branches:\n - '[0-9]+.[0-9x]+'\n pull_request:\n branches:\n - '[0-9]+.[0-9x]+'\n "
},
{
"path": ".github/workflows/coding-standards.yml",
"chars": 1732,
"preview": "name: Coding Standards\n\non:\n push:\n branches:\n - '[0-9]+.[0-9x]+'\n pull_request:\n branches:\n - '[0-9]+"
},
{
"path": ".github/workflows/labeler.yml",
"chars": 209,
"preview": "name: Pull Request Labeler\non:\n - pull_request_target\n\njobs:\n labeler:\n permissions:\n contents: read\n pul"
},
{
"path": ".github/workflows/merge-up.yml",
"chars": 764,
"preview": "name: Merge up\n\non:\n push:\n branches:\n - '[0-9]+.[0-9x]+'\n\nenv:\n GH_TOKEN: ${{ secrets.MERGE_UP_TOKEN }}\n\njobs"
},
{
"path": ".github/workflows/release.yml",
"chars": 6340,
"preview": "name: \"Release New Version\"\nrun-name: \"Release ${{ inputs.version }}\"\n\non:\n workflow_dispatch:\n inputs:\n versio"
},
{
"path": ".github/workflows/static-analysis.yml",
"chars": 3067,
"preview": "name: Static Analysis\n\non:\n push:\n branches:\n - '[0-9]+.[0-9x]+'\n pull_request:\n branches:\n - '[0-9]+."
},
{
"path": ".gitignore",
"chars": 135,
"preview": "*.project\n*.sublime-project\n*.sublime-workspace\n.DS_Store\n.idea/\n/vendor\ncomposer.lock\ncomposer.phar\nphpunit.xml\nphpstan"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 376,
"preview": "# MongoDB Code of Conduct\r\n\r\nThe Code of Conduct outlines the expectations for our behavior as members of the MongoDB co"
},
{
"path": "CONTRIBUTING.md",
"chars": 3547,
"preview": "# Contributing\r\n\r\nContributions are **welcome** and will be fully **credited**.\r\n\r\nPlease read and understand the contri"
},
{
"path": "Dockerfile",
"chars": 520,
"preview": "ARG PHP_VERSION=8.2\n\nFROM php:${PHP_VERSION}-cli\n\n# Install extensions\nRUN apt-get update && \\\n apt-get install -y au"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2023 MongoDB, Inc\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "README.md",
"chars": 2740,
"preview": "Laravel MongoDB\n===============\n\n[;\n\nnamespace MongoDB\\Laravel\\Auth;\n\nuse Illuminate\\Foundation\\Auth\\User as BaseUser;\nuse M"
},
{
"path": "src/Bus/MongoBatchRepository.php",
"chars": 8357,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Bus;\n\nuse Carbon\\CarbonImmutable;\nuse Closure;\nuse DateTimeInterface;\nuse Illuminate\\Bu"
},
{
"path": "src/Cache/MongoLock.php",
"chars": 4849,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Cache;\n\nuse Illuminate\\Cache\\Lock;\nuse Illuminate\\Support\\Carbon;\nuse InvalidArgumentEx"
},
{
"path": "src/Cache/MongoStore.php",
"chars": 9219,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Cache;\n\nuse Illuminate\\Cache\\RetrievesMultipleKeys;\nuse Illuminate\\Contracts\\Cache\\Lock"
},
{
"path": "src/CommandSubscriber.php",
"chars": 1644,
"preview": "<?php\n\nnamespace MongoDB\\Laravel;\n\nuse MongoDB\\BSON\\Document;\nuse MongoDB\\Driver\\Monitoring\\CommandFailedEvent;\nuse Mong"
},
{
"path": "src/Concerns/ManagesTransactions.php",
"chars": 4933,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Concerns;\n\nuse Closure;\nuse MongoDB\\Client;\nuse MongoDB\\Drive"
},
{
"path": "src/Connection.php",
"chars": 12437,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel;\n\nuse Composer\\InstalledVersions;\nuse Illuminate\\Database\\Con"
},
{
"path": "src/Eloquent/Builder.php",
"chars": 11404,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Buil"
},
{
"path": "src/Eloquent/Casts/BinaryUuid.php",
"chars": 1590,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\C"
},
{
"path": "src/Eloquent/Casts/ObjectId.php",
"chars": 961,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\C"
},
{
"path": "src/Eloquent/DocumentModel.php",
"chars": 21594,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse BackedEnum;\nuse Carbon\\CarbonInterface;\nuse Da"
},
{
"path": "src/Eloquent/EmbedsRelations.php",
"chars": 2566,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Illuminate\\Support\\Str;\nuse MongoDB\\Laravel\\Re"
},
{
"path": "src/Eloquent/HasSchemaVersion.php",
"chars": 2297,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Error;\nuse LogicException;\n\nuse function sprin"
},
{
"path": "src/Eloquent/HybridRelations.php",
"chars": 15753,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Illuminate\\Database\\Eloquent\\Concerns\\HasRelat"
},
{
"path": "src/Eloquent/MassPrunable.php",
"chars": 838,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Illuminate\\Database\\Eloquent\\MassPrunable as E"
},
{
"path": "src/Eloquent/Model.php",
"chars": 1643,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse Illuminate\\Database\\Eloquent\\Model as BaseMode"
},
{
"path": "src/Eloquent/SoftDeletes.php",
"chars": 658,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Eloquent;\n\nuse function sprintf;\nuse function trigger_error;\n"
},
{
"path": "src/Helpers/EloquentBuilder.php",
"chars": 184,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Helpers;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\n\nclass El"
},
{
"path": "src/Helpers/QueriesRelationships.php",
"chars": 8291,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Helpers;\n\nuse Closure;\nuse Exception;\nuse Illuminate\\Database"
},
{
"path": "src/MongoDBBusServiceProvider.php",
"chars": 1984,
"preview": "<?php\n\nnamespace MongoDB\\Laravel;\n\nuse Illuminate\\Bus\\BatchFactory;\nuse Illuminate\\Bus\\BatchRepository;\nuse Illuminate\\B"
},
{
"path": "src/MongoDBServiceProvider.php",
"chars": 7499,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel;\n\nuse Closure;\nuse Illuminate\\Cache\\CacheManager;\nuse Illumin"
},
{
"path": "src/Query/AggregationBuilder.php",
"chars": 2556,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Query;\n\nuse Illuminate\\Support\\Collection as LaravelCollectio"
},
{
"path": "src/Query/Builder.php",
"chars": 60259,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Query;\n\nuse ArgumentCountError;\nuse BadMethodCallException;\nu"
},
{
"path": "src/Query/BuilderTimeout.php",
"chars": 1129,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Query;\n\nuse Illuminate\\Database\\Query\\Builder;\n\nuse function "
},
{
"path": "src/Query/Grammar.php",
"chars": 169,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Query;\n\nuse Illuminate\\Database\\Query\\Grammars\\Grammar as Bas"
},
{
"path": "src/Query/Processor.php",
"chars": 179,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Query;\n\nuse Illuminate\\Database\\Query\\Processors\\Processor as"
},
{
"path": "src/Queue/MongoConnector.php",
"chars": 1635,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Queue;\n\nuse Illuminate\\Contracts\\Queue\\Queue;\nuse Illuminate\\"
},
{
"path": "src/Queue/MongoJob.php",
"chars": 446,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Queue;\n\nuse DateTime;\nuse Illuminate\\Queue\\Jobs\\DatabaseJob;\n"
},
{
"path": "src/Queue/MongoQueue.php",
"chars": 4190,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Queue;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Queue\\DatabaseQueue"
},
{
"path": "src/Relations/BelongsTo.php",
"chars": 2124,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Relations/BelongsToMany.php",
"chars": 9963,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Relations/EmbedsMany.php",
"chars": 9636,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Col"
},
{
"path": "src/Relations/EmbedsOne.php",
"chars": 3992,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mongo"
},
{
"path": "src/Relations/EmbedsOneOrMany.php",
"chars": 10763,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Relations/HasMany.php",
"chars": 1318,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Relations/HasOne.php",
"chars": 1314,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Relations/MorphMany.php",
"chars": 502,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illum"
},
{
"path": "src/Relations/MorphTo.php",
"chars": 1502,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illum"
},
{
"path": "src/Relations/MorphToMany.php",
"chars": 16287,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Ill"
},
{
"path": "src/Schema/Blueprint.php",
"chars": 10022,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Schema;\n\nuse Illuminate\\Database\\Schema\\Blueprint as BaseBlue"
},
{
"path": "src/Schema/BlueprintLaravelCompatibility.php",
"chars": 1696,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Schema;\n\nuse Closure;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Schem"
},
{
"path": "src/Schema/Builder.php",
"chars": 14006,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Schema;\n\nuse Closure;\nuse MongoDB\\Collection;\nuse MongoDB\\Dri"
},
{
"path": "src/Schema/Grammar.php",
"chars": 171,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Schema;\n\nuse Illuminate\\Database\\Schema\\Grammars\\Grammar as B"
},
{
"path": "src/Scout/ScoutEngine.php",
"chars": 18347,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Scout;\n\nuse Closure;\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Collection"
},
{
"path": "src/Session/MongoDbSessionHandler.php",
"chars": 2919,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Session;\n\nuse Illuminate\\Session\\DatabaseSessionHandler;\nuse MongoDB\\BSON\\Binary;\nuse M"
},
{
"path": "src/Validation/DatabasePresenceVerifier.php",
"chars": 1650,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Validation;\n\nuse MongoDB\\BSON\\Regex;\nuse Override;\n\nuse funct"
},
{
"path": "src/Validation/ValidationServiceProvider.php",
"chars": 435,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Validation;\n\nuse Illuminate\\Validation\\ValidationServiceProvi"
},
{
"path": "tests/AtlasSearchIndexManagement.php",
"chars": 1369,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse MongoDB\\Collection;\nuse RuntimeException;\n\nuse function hrtime;\nuse functio"
},
{
"path": "tests/AtlasSearchTest.php",
"chars": 9220,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;\nuse Illumina"
},
{
"path": "tests/AuthTest.php",
"chars": 2448,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Auth\\Passwords\\Pass"
},
{
"path": "tests/Bus/Fixtures/ChainHeadJob.php",
"chars": 309,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Bus\\Fixtures;\n\nuse Illuminate\\Bus\\Batchable;\nuse Illuminate\\Bus\\Queueable;\nuse Il"
},
{
"path": "tests/Bus/Fixtures/SecondTestJob.php",
"chars": 310,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Bus\\Fixtures;\n\nuse Illuminate\\Bus\\Batchable;\nuse Illuminate\\Bus\\Queueable;\nuse Il"
},
{
"path": "tests/Bus/Fixtures/ThirdTestJob.php",
"chars": 309,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Bus\\Fixtures;\n\nuse Illuminate\\Bus\\Batchable;\nuse Illuminate\\Bus\\Queueable;\nuse Il"
},
{
"path": "tests/Bus/MongoBatchRepositoryTest.php",
"chars": 12015,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Bus;\n\nuse Carbon\\CarbonImmutable;\nuse Illuminate\\Bus\\Batch;\nuse Illuminate\\Bus\\Ba"
},
{
"path": "tests/Cache/MongoCacheStoreTest.php",
"chars": 7665,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Cache;\n\nuse Illuminate\\Cache\\Repository;\nuse Illuminate\\Support\\Carbon;\nuse Illum"
},
{
"path": "tests/Cache/MongoLockTest.php",
"chars": 3654,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Cache;\n\nuse Illuminate\\Cache\\Repository;\nuse Illuminate\\Support\\Carbon;\nuse Illum"
},
{
"path": "tests/Casts/BinaryUuidTest.php",
"chars": 1433,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Generator;\nuse MongoDB\\BSON\\Binary;\nuse Mon"
},
{
"path": "tests/Casts/BooleanTest.php",
"chars": 2542,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/Casts/CollectionTest.php",
"chars": 1500,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Illuminate\\Support\\Collection;\nuse MongoDB\\"
},
{
"path": "tests/Casts/DateTest.php",
"chars": 6173,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Carbon\\CarbonImmutable;\nuse DateTime;\nuse I"
},
{
"path": "tests/Casts/DatetimeTest.php",
"chars": 5723,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Carbon\\CarbonImmutable;\nuse DateTime;\nuse I"
},
{
"path": "tests/Casts/DecimalTest.php",
"chars": 4854,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Illuminate\\Support\\Exceptions\\MathException"
},
{
"path": "tests/Casts/EncryptionTest.php",
"chars": 4223,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Illuminate\\Database\\Eloquent\\Casts\\Json;\nus"
},
{
"path": "tests/Casts/FloatTest.php",
"chars": 1067,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/Casts/IntegerTest.php",
"chars": 1805,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/Casts/JsonTest.php",
"chars": 1198,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/Casts/ObjectIdTest.php",
"chars": 1446,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse Generator;\nuse MongoDB\\BSON\\ObjectId;\nuse M"
},
{
"path": "tests/Casts/ObjectTest.php",
"chars": 978,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/Casts/StringTest.php",
"chars": 1153,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Casts;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Casting;\nuse M"
},
{
"path": "tests/ConnectionTest.php",
"chars": 14669,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Generator;\nuse Illuminate\\Support\\Facades\\DB;\nuse"
},
{
"path": "tests/DateTimeImmutableTest.php",
"chars": 920,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Carbon\\CarbonImmutable;\nuse Illuminate\\Support\\Fa"
},
{
"path": "tests/Eloquent/CallBuilderTest.php",
"chars": 3458,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Eloquent;\n\nuse BadMethodCallException;\nuse Generator;\nu"
},
{
"path": "tests/Eloquent/MassPrunableTest.php",
"chars": 1694,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Eloquent;\n\nuse Illuminate\\Database\\Console\\PruneCommand"
},
{
"path": "tests/Eloquent/ModelTest.php",
"chars": 1600,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Eloquent;\n\nuse Generator;\nuse Illuminate\\Database\\Eloquent\\Model as BaseModel;\nus"
},
{
"path": "tests/EmbeddedRelationsTest.php",
"chars": 38975,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse DateTime;\nuse Illuminate\\Database\\Eloquent\\Collec"
},
{
"path": "tests/ExternalPackageTest.php",
"chars": 1435,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Http\\Request;\nuse MongoDB\\Laravel\\Test"
},
{
"path": "tests/FilesystemsTest.php",
"chars": 4728,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Generator;\nuse Illuminate\\Foundation\\Application;\nuse Illuminate\\Support\\Fa"
},
{
"path": "tests/GeospatialTest.php",
"chars": 3869,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse MongoDB\\La"
},
{
"path": "tests/HybridRelationsTest.php",
"chars": 13912,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Database\\SQLiteConnection;\nuse Illumin"
},
{
"path": "tests/ModelTest.php",
"chars": 46911,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Carbon\\Carbon;\nuse DateTime;\nuse Generator;\nuse I"
},
{
"path": "tests/Models/Address.php",
"chars": 475,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Anniversary.php",
"chars": 516,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Birthday.php",
"chars": 517,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Book.php",
"chars": 771,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/CastObjectId.php",
"chars": 349,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse MongoDB\\Laravel\\Eloquent\\Casts\\ObjectId;\nu"
},
{
"path": "tests/Models/Casting.php",
"chars": 1919,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse MongoDB\\Laravel\\Eloquent\\Casts\\BinaryUuid;"
},
{
"path": "tests/Models/Client.php",
"chars": 1557,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Experience.php",
"chars": 593,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Group.php",
"chars": 573,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Guarded.php",
"chars": 378,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/HiddenAnimal.php",
"chars": 488,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/IdIsBinaryUuid.php",
"chars": 450,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/IdIsInt.php",
"chars": 366,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/IdIsString.php",
"chars": 375,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Item.php",
"chars": 709,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Database\\Elo"
},
{
"path": "tests/Models/Label.php",
"chars": 1218,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Location.php",
"chars": 366,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/MemberStatus.php",
"chars": 132,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nenum MemberStatus: string\n{\n case Member = "
},
{
"path": "tests/Models/NonIncrementing.php",
"chars": 466,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Photo.php",
"chars": 624,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Role.php",
"chars": 612,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/SchemaVersion.php",
"chars": 541,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse MongoDB\\Laravel\\Eloquent\\HasSchemaVersion;"
},
{
"path": "tests/Models/Scoped.php",
"chars": 614,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Mo"
},
{
"path": "tests/Models/Skill.php",
"chars": 530,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Il"
},
{
"path": "tests/Models/Soft.php",
"chars": 808,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Database\\Elo"
},
{
"path": "tests/Models/SqlBook.php",
"chars": 1233,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model as Eloq"
},
{
"path": "tests/Models/SqlRole.php",
"chars": 1195,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model as Eloq"
},
{
"path": "tests/Models/SqlUser.php",
"chars": 2986,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model as Eloq"
},
{
"path": "tests/Models/User.php",
"chars": 3272,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Models;\n\nuse Carbon\\Carbon;\nuse DateTimeInterface;\nuse "
},
{
"path": "tests/PHPStan/SarifErrorFormatter.php",
"chars": 4136,
"preview": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file was copied from https://github.com/jbelien/phpstan-sarif-formatter/blo"
},
{
"path": "tests/PropertyTest.php",
"chars": 981,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse MongoDB\\Laravel\\Tests\\Models\\HiddenAnimal;\n\nuse f"
},
{
"path": "tests/Query/AggregationBuilderTest.php",
"chars": 5121,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Query;\n\nuse BadMethodCallException;\nuse DateTimeImmutab"
},
{
"path": "tests/Query/BuilderTest.php",
"chars": 61979,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Query;\n\nuse ArgumentCountError;\nuse BadMethodCallExcept"
},
{
"path": "tests/QueryBuilderTest.php",
"chars": 50493,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Carbon\\Carbon;\nuse DateTime;\nuse DateTimeImmutabl"
},
{
"path": "tests/QueryTest.php",
"chars": 23340,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse BadMethodCallException;\nuse DateTimeImmutable;\nus"
},
{
"path": "tests/Queue/Failed/DatabaseFailedJobProviderTest.php",
"chars": 4597,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Queue\\Failed;\n\nuse Illuminate\\Queue\\Failed\\DatabaseFailedJobProvider;\nuse Illumin"
},
{
"path": "tests/QueueTest.php",
"chars": 6931,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Illuminate\\Queu"
},
{
"path": "tests/RelationsTest.php",
"chars": 54586,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Mock"
},
{
"path": "tests/SchemaTest.php",
"chars": 26657,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Sup"
},
{
"path": "tests/SchemaVersionTest.php",
"chars": 1677,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\DB;\nuse LogicException"
},
{
"path": "tests/Scout/Models/ScoutUser.php",
"chars": 1153,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Scout\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n"
},
{
"path": "tests/Scout/Models/SearchableInSameNamespace.php",
"chars": 672,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Scout\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n"
},
{
"path": "tests/Scout/Models/SearchableModel.php",
"chars": 1246,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Scout\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\El"
},
{
"path": "tests/Scout/ScoutEngineTest.php",
"chars": 24774,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Scout;\n\nuse ArrayIterator;\nuse Closure;\nuse DateTimeImmutable;\nuse Illuminate\\Dat"
},
{
"path": "tests/Scout/ScoutIntegrationTest.php",
"chars": 10050,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Scout;\n\nuse DateTimeImmutable;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\"
},
{
"path": "tests/Seeder/DatabaseSeeder.php",
"chars": 236,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Seeder;\n\nuse Illuminate\\Database\\Seeder;\n\nclass Databas"
},
{
"path": "tests/Seeder/UserTableSeeder.php",
"chars": 336,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Seeder;\n\nuse Illuminate\\Database\\Seeder;\nuse Illuminate"
},
{
"path": "tests/SeederTest.php",
"chars": 824,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\Artisan;\nuse MongoDB\\L"
},
{
"path": "tests/SessionTest.php",
"chars": 2946,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Session\\DatabaseSessionHandler;\nuse Illuminate\\Session\\SessionMa"
},
{
"path": "tests/TestCase.php",
"chars": 2669,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Foundation\\Application;\nuse MongoDB\\Dr"
},
{
"path": "tests/Ticket/GH2489Test.php",
"chars": 1325,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Ticket;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Location;\nuse"
},
{
"path": "tests/Ticket/GH2783Test.php",
"chars": 2274,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Ticket;\n\nuse Illuminate\\Database\\Eloquent\\Relations\\Mor"
},
{
"path": "tests/Ticket/GH3326Test.php",
"chars": 968,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Ticket;\n\nuse MongoDB\\Laravel\\Eloquent\\Model;\nuse MongoD"
},
{
"path": "tests/Ticket/GH3328Test.php",
"chars": 8216,
"preview": "<?php\n\nnamespace MongoDB\\Laravel\\Tests\\Ticket;\n\nuse Closure;\nuse Exception;\nuse Illuminate\\Contracts\\Database\\Concurrenc"
},
{
"path": "tests/Ticket/GH3335Test.php",
"chars": 702,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests\\Ticket;\n\nuse MongoDB\\Laravel\\Tests\\Models\\Location;\nuse"
},
{
"path": "tests/TransactionTest.php",
"chars": 15119,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\DB;\nuse MongoDB\\BSON\\O"
},
{
"path": "tests/ValidationTest.php",
"chars": 3927,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace MongoDB\\Laravel\\Tests;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse MongoDB"
},
{
"path": "tests/config/database.php",
"chars": 688,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n 'connections' => [\n 'mongodb' => [\n 'name' => 'mongodb',"
},
{
"path": "tests/config/queue.php",
"chars": 423,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n\n 'default' => env('QUEUE_CONNECTION'),\n\n 'connections' => [\n\n 'd"
}
]
About this extraction
This page contains the full source code of the mongodb/laravel-mongodb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 171 files (872.5 KB), approximately 219.5k tokens, and a symbol index with 1270 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.