Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOCSP-35964 eloquent models standardization #2726

Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
518 changes: 12 additions & 506 deletions docs/eloquent-models.txt

Large diffs are not rendered by default.

286 changes: 286 additions & 0 deletions docs/eloquent-models/model-class.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
.. _laravel-eloquent-model-class:

====================
Eloquent Model Class
====================

GromNaN marked this conversation as resolved.
Show resolved Hide resolved
.. facet::
:name: genre
:values: reference

.. meta::
:keywords: php framework, odm, code example, authentication, laravel

Overview
--------

This guide shows you how to use the {+odm-long+} to define and
customize Laravel Eloquent models. You can use these models to work with
MongoDB data by using the Laravel Eloquent object-relational mapper (ORM).

The following sections explain how to add Laravel Eloquent ORM behaviors
to {+odm-short+} models:

- :ref:`laravel-model-define` demonstrates how to create a model class.
- :ref:`laravel-authenticatable-model` shows how to set MongoDB as the
authentication user provider.
- :ref:`laravel-model-customize` explains several model class customizations
- :ref:`laravel-model-pruning` shows how to remove models that you no longer
need periodically.
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

.. _laravel-model-define:

Define an Eloquent Model Class
------------------------------

Eloquent models are classes that represent your data. They include methods
that perform database operations such as inserts, updates, and deletes.

To declare a {+odm-short+} model class, create a file in your Laravel
application ``app/Models`` directory. Add the import for the
``MongoDB\Laravel\Eloquent\Model`` package and extend the ``Model`` class as
shown in the following code example:
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

.. literalinclude:: /includes/eloquent-models/Planet.php
:language: php
:dedent:

Alternatively, use the ``artisan`` console to generate the model class and
change the ``Illuminate\Database\Eloquent\Model`` import to ``MongoDB\Laravel\Eloquent\Model``.
To learn more about the ``artisan`` console, see `Artisan Console <https://laravel.com/docs/{+laravel-docs-version+}/artisan>`__
in the Laravel docs.

.. _laravel-authenticatable-model:

Extend the Authenticatable Model
--------------------------------

To configure MongoDB as the Laravel user provider, you can extend the
{+odm-short+} ``MongoDB\Laravel\Auth\User`` class. The following code example
shows how to extend this class:

.. literalinclude:: /includes/eloquent-models/AuthenticatableUser.php
:language: php
:dedent:

To learn more about customizing a Laravel authentication user provider,
see `Adding Custom User Providers <https://laravel.com/docs/{+laravel-docs-version+}/authentication#adding-custom-user-providers>`__
in the Laravel docs.

.. _laravel-model-customize:

Customize an Eloquent Model Class
---------------------------------

This section shows how to perform the following Eloquent model behavior
customizations:

- :ref:`laravel-model-customize-collection-name`
- :ref:`laravel-model-customize-primary-key`
- :ref:`laravel-model-soft-delete`
- :ref:`laravel-model-cast-data-types`
- :ref:`laravel-model-mass-assignment`

.. _laravel-model-customize-collection-name:

Change the Model Collection Name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To customize the name of the collection the model uses to retrieve and save
data in MongoDB, override the ``$collection`` property of the model
class.

By default, the model uses the MongoDB database name set in your Laravel
application's ``config/database.php`` setting and the snake case plural form of
your model class name for the collection.
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

The following example specifies the custom MongoDB collection name,
``celestial_body``, for the ``Planet`` class:
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

.. literalinclude:: /includes/eloquent-models/PlanetCollection.php
:language: php
:emphasize-lines: 9
:dedent:

.. _laravel-model-customize-primary-key:

Change the Primary Key Field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To customize the model's primary key field that uniquely identify a MongoDB
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
document, override the ``$primaryKey`` property of the model class.

By default, the model uses the PHP MongoDB driver to generate unique IDs for
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
each document your Laravel application inserts.

The following example specifies the ``name`` field as the primary key for
the ``Planet`` class:

.. literalinclude:: /includes/eloquent-models/PlanetPrimaryKey.php
:language: php
:emphasize-lines: 9
:dedent:

To learn more about primary key behavior and customization options, see
`Eloquent Primary Keys <https://laravel.com/docs/{+laravel-docs-version+}/eloquent#primary-keys>`__
in the Laravel docs.

To learn more about the ``_id`` field and the MongoDB document structure, see
:manual:`Documents </core/document>` in the MongoDB server docs.

.. _laravel-model-soft-delete:

Enable Soft Deletes
~~~~~~~~~~~~~~~~~~~

Eloquent includes a soft delete feature that changes the behavior of the
``delete()`` method on a model. When soft delete is enabled on a model, the
``delete()`` method marks a document as deleted instead of removing it from the
database. It sets a timestamp on the ``deleted_at`` field to exclude it from
retrieve operations automatically.

To enable soft deletes on a class, import the ``MongoDB\Laravel\Eloquent\SoftDeletes``
package and add the trait to the class definition as shown in the following
code example:
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

.. literalinclude:: /includes/eloquent-models/PlanetSoftDelete.php
:language: php
:emphasize-lines: 6,10
:dedent:

To learn about methods you can perform on models with soft deletes enabled, see
`Eloquent Soft Deleting <https://laravel.com/docs/{+laravel-docs-version+}/eloquent#soft-deleting>`__
in the Laravel docs.

.. _laravel-model-cast-data-types:

Cast Data Types
---------------

Eloquent lets you convert model attribute data types before storing or
retrieving data by using a casting helper. This helper is a convenient
alternative to defining equivalent accessor and mutator methods on your model.

In the following example, the casting helper converts the ``discovery_dt``
model attribute, stored in MongoDB as a `MongoDB\\BSON\\UTCDateTime <https://www.php.net/manual/en/class.mongodb-bson-utcdatetime.php>`__
type, to the Laravel ``datetime`` type.

.. literalinclude:: /includes/eloquent-models/PlanetDate.php
:language: php
:emphasize-lines: 9-11
:dedent:

This conversion lets you use the PHP `DateTime <https://www.php.net/manual/en/class.datetime.php>`__
or the `Carbon class <https://carbon.nesbot.com/docs/>`__ to work with dates
in this field. The following example shows a Laravel query that uses the
casting helper on the model to query for planets with a ``discovery_dt`` of
less than three years ago:

.. code-block:: php

Planet::where(
'discovery_dt', '>',
new DateTime('-3 years')
)->get();
GromNaN marked this conversation as resolved.
Show resolved Hide resolved


To learn more about MongoDB's data types, see :manual:`BSON Types </reference/bson-types/>`
in the MongoDB server docs.

To learn more about the Laravel casting helper and supported types, see `Attribute Casting <https://laravel.com/docs/{+laravel-docs-version+}/eloquent-mutators#attribute-casting>`__
in the Laravel docs.

.. _laravel-model-mass-assignment:

Customize Mass Assignment
~~~~~~~~~~~~~~~~~~~~~~~~~

Eloquent lets you create several models and their attribute data by passing
an array of data to the ``create()`` model method. This process of inserting
multiple models is called mass assignment.

Mass assignment can be an efficient way to create multiple models. However, it
can be expose an exploitable security vulnerability. The data in the fields
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
could contain updates that could lead to unauthorized permissions or access.

Eloquent provides the following traits to protect your data from mass
assignment vulnerabilities:

- ``$fillable`` contains the fields that are writeable in a mass assignment
- ``$guarded`` contains the fields that are ignored in a mass assignment

.. important::

We recommend using ``$fillable`` instead of ``$guarded`` to protect against
vulnerabilities. To learn more about this recommendation, see the
`Security Release: Laravel 6.18.35, 7.24.0 <https://blog.laravel.com/security-release-laravel-61835-7240>`__
article on the Laravel site.

In the following example, the model allows mass assignment of the fields
by using the ``$fillable`` attribute:

.. literalinclude:: /includes/eloquent-models/PlanetMassAssignment.php
:language: php
:emphasize-lines: 9
:dedent:

The following code example shows mass assignment of the ``Planet`` model:

.. code-block:: php

$planets = [
[ 'name' => 'Earth', gravity => 9.8, day_length => '24 hours' ],
[ 'name' => 'Mars', gravity => 3.7, day_length => '25 hours' ],
];

Planet::create($planets);

The models saved to the database contain only the ``name`` and ``gravity``
fields since ``day_length`` is omitted from the ``$fillable`` attribute.

To learn how to change the behavior when attempting to fill a field omitted
from the ``$fillable`` array, see `Mass Assignment Exceptions <https://laravel.com/docs/{+laravel-docs-version+}/eloquent#mass-assignment-exceptions>`__
in the Laravel docs.

.. _laravel-model-pruning:

Specify Pruning Behavior
------------------------

Eloquent lets you specify criteria to delete model data that you no longer
need automatically. When you schedule or run the ``model:prune`` command,
Laravel calls the ``prunable()`` method on all models that import the
``Prunable`` and ``MassPrunable`` traits to match the models for deletion.

To use this feature with models that use MongoDB as a database, add the
appropriate import to your model:

- ``MongoDB\Laravel\Eloquent\Prunable`` optionally performs a cleanup
step before deleting a model that matches the criteria
- ``MongoDB\Laravel\Eloquent\MassPrunable`` deletes models that match the
criteria without fetching the model data

To learn more about the pruning feature, see `Pruning Models <https://laravel.com/docs/{+laravel-docs-version+}/eloquent#pruning-models>`__
in the Laravel docs.

Prunable Example
~~~~~~~~~~~~~~~~

The following example model shows how to perform a prune that calls the
``pruning()`` method before deleting a model that matches the query in the
``prunable()`` method:

.. literalinclude:: /includes/eloquent-models/PlanetPrune.php
:language: php
:dedent:

Mass Prunable Example
~~~~~~~~~~~~~~~~~~~~~

The following example model shows how to perform a "mass prune" which deletes
all models that match the query in the ``prunable()`` method:
GromNaN marked this conversation as resolved.
Show resolved Hide resolved

.. literalinclude:: /includes/eloquent-models/PlanetMassPrune.php
:language: php
:dedent:

7 changes: 7 additions & 0 deletions docs/includes/eloquent-models/AuthenticatableUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace App\Models;

class User extends Authenticatable
{
}
9 changes: 9 additions & 0 deletions docs/includes/eloquent-models/Planet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
{
}
10 changes: 10 additions & 0 deletions docs/includes/eloquent-models/PlanetCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
{
protected $collection = 'celestial_body';
}
12 changes: 12 additions & 0 deletions docs/includes/eloquent-models/PlanetDate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
{
protected $casts = [
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
'discovery_dt' => 'datetime',
];
}
20 changes: 20 additions & 0 deletions docs/includes/eloquent-models/PlanetMassAssignment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'gravitational_force',
'diameter',
'moons',
];
}
17 changes: 17 additions & 0 deletions docs/includes/eloquent-models/PlanetMassPrune.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\MassPrunable;
use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
{
use MassPrunable;

public function prunable()
{
// matches models in which the solar_system field contains a null value
GromNaN marked this conversation as resolved.
Show resolved Hide resolved
return static::where('gravitational_force', '>', 0.5);
}
}
10 changes: 10 additions & 0 deletions docs/includes/eloquent-models/PlanetPrimaryKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Models;

use MongoDB\Laravel\Eloquent\Model;

class Planet extends Model
{
protected $primaryKey = 'name';
}
Loading