Technical Documentation: microsoft/sql-server-samples
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
Azure Data SQL Samples Repository
This GitHub repository contains code samples that demonstrate how to use Microsoft's Azure Data products including SQL Server, Azure SQL Database, Azure Synapse, and Azure SQL Edge. Each sample includes a README file that explains how to run and use the sample.
Note that certain features like In-Memory OLTP are edition specific for SQL Server and would be possible to implement if the edition which supports that feature is being used to run the sample.
Releases in this repository
Releases allow you to conveniently download sample databases or applications without the need to build them from source code. This SQL Server samples repository has the following notable releases:
- Wide World Importers sample database v1.0 is the main sample for SQL Server 2016 and Azure SQL Database. It contains both an OLTP and an OLAP database.
- In-Memory OLTP Performance Demo v1.0 illustrates the performance benefits of the In-Memory OLTP technology built into SQL Server and Azure SQL Database.
- IoT Smart Grid sample v1.0 illustrates how SQL Server can be leveraged to ingest data from IoT devices and sensors, and how you can run analytics on that data.
To see the complete list of resources in this repository, navigate to Releases
Working in GitHub
To work in GitHub, go to https://github.com/microsoft/sql-server-samples and fork the repository. Work in your own fork and when you are ready to submit to make a change or publish your sample for the first time, submit a pull request into the master branch of sql-server-samples. One of the approvers will review your request and accept or reject the pull request.
Each sample should be in its own folder with a README.md file that follows the template. Generated files (e.g., .exe or .bacpac) and user configuration settings (e.g., .user) should not be committed to GitHub.
Cloning only a subset of the repo (with sparse checkout)
You can follow the steps below to clone individual files from the sql-server-samples git repo. Note: The following script clones only the files under the features and demos folders.
git clone -n https://github.com/Microsoft/sql-server-samples
cd sql-server-samples
git config core.sparsecheckout true
echo samples/features/*| out-file -append -encoding ascii .git/info/sparse-checkout
echo samples/demos/*| out-file -append -encoding ascii .git/info/sparse-checkout
git checkoutFor more information about sparse checkout please visit this stackoverflow thread.
Code of Conduct
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
License
These samples and templates are all licensed under the MIT license. See the license.txt file in the root.
Questions
Email questions to: [email protected].
Samples Manage Sql Assessment Api Docs README (`samples/manage/sql-assessment-api/docs/README.md`)
SQL Assessment API User Guide
The SQL Assessment API User Guide helps you better understand the SQL Assessment API functionality, how to use built-in features, and how to customize workflows to make your assessment even more precise.
NOTE: Some features described in these documents are available only in the SqlServer PowerShell module version 22.0.30-preview or later.
In This Section
Samples Manage Sql Assessment Api Docs Customization README (`samples/manage/sql-assessment-api/docs/Customization/README.md`)
Customization
The SQL Assessment API is a comprehensive solution that allows you not only to use the functionality that comes out of the box, but also customize the assessment workflows, depending on your needs.
In This Section
Samples Manage Sql Assessment Api Docs How To QuickStart (`samples/manage/sql-assessment-api/docs/How-To/QuickStart.md`)
SQL Assessment API Quick Start Guide
Assess your SQL Server configuration in 2 simple steps.
1. Setup
Install the PowerShell SqlServer module using the following command.
Install-Module -Name SqlServer -AllowClobber2. Invoke assessment
To invoke an assessment against a local SQL Server instance, run the following command.
Get-SqlInstance -ServerInstance 'localhost' | Invoke-SqlAssessmentSample result:
PS:> Get-SqlInstance -ServerInstance localhost | Invoke-SqlAssessment
TargetPath: Server[@Name='LOCAL']
Sev. Message Check ID Origin
---- ------- -------- ------
Info Enable trace flag 834 to use large-page allocations to improve TF834 Microsoft Ruleset 0.1.202
analytical and data warehousing workloads.
Low Detected deprecated or discontinued feature uses: String literals DeprecatedFeatures Microsoft Ruleset 0.1.202
as column aliases, syscolumns, sysusers, SET FMTONLY ON, XP_API,
Table hint without WITH, More than two-part column name. We
recommend to replace them with features actual for SQL Server
version 14.0.1000.
Medi Amount of single use plans in cache is high (100%). Consider PlansUseRatio Microsoft Ruleset 0.1.202
enabling the Optimize for ad hoc workloads setting on heavy OLTP
ad-hoc workloads to conserve resources.
...In the results, you will see that each rule has some properties (not the full list):
- Severity (info, low, medium, high)
- Message property explains the recommendation but if you need more info, there is a HelpLink property that points at documentation on the subject.
- Origin shows which ruleset and version the recommendation is coming from
See ruleset.json for a full list of rules and properties.
If you want to get recommendations for all databases on the local instance, run this command.
Get-SqlDatabase -ServerInstance 'localhost' | Invoke-SqlAssessmentLearn more about SQL Assessment API
To learn more about the SQL Assessment API such as customizing and extending rulesets, saving results to a table, etc., visit:
- Docs online page for SQL Assessment API PowerShell cmdlets: https://docs.microsoft.com/sql/sql-assessment-api/sql-assessment-api-overview
- SQL Assessment User Guide
- SQL Assessment API Tutorial notebook: SQLAssessmentAPITutorialNotebook.ipynb
- Azure Data Studio extension: https://techcommunity.microsoft.com/t5/sql-server/released-sql-server-assessment-extension-for-azure-data-studio/ba-p/1470603
Samples Manage Sql Assessment Api Docs How To README (`samples/manage/sql-assessment-api/docs/How-To/README.md`)
How-To
This section explains how to install and invoke assessment, use probes that are specific to VMs running in Azure environments, and how to enable probes that use non-SQL based queries to get data for assessment.
In This Section
- SQL Assessment API Quick Start Guide
- Assessment of SQL Server on Azure Virtual Machines
- Retrieving Data from Operating System
Samples Manage Sql Assessment Api Docs Reference README (`samples/manage/sql-assessment-api/docs/Reference/README.md`)
Reference
This reference is intended to guide you through some of the most commonly used scenarios in the SQL Assessment API.
In This Section
Samples Manage Sql Assessment Api Docs Tutorials README (`samples/manage/sql-assessment-api/docs/Tutorials/README.md`)
Tutorial
This section is intended to guide you through some of the most frequently used customization workflows in the SQL Assessment API. You can easily create your own rules, disable built-in rules if do not want to use them, or you can override default thresholds with your own values to assess your configuration in a particular manner.
In This Section
Samples Manage Sql Assessment Api Docs Customization AutomaticVariables README (`samples/manage/sql-assessment-api/docs/Customization/AutomaticVariables/README.md`)
Automatic variables
Data for assessment is delivered by probes. Some data is available before the first probe is invoked, e.g. target SQL Server version or requirements for probes. This data might be accessed via automatic variables.
Automatic variables are grouped in namespaces.
Samples Manage Sql Assessment Api Docs Customization ProbeRequirements README (`samples/manage/sql-assessment-api/docs/Customization/ProbeRequirements/README.md`)
Probe requirements
Probe requirements help to deal with situations when a probe cannot get data due to insufficient permissions or configuration issues. SQL Assessment API can skip probes when their requirements were stated explicitly.
By default any error in probe terminates assessment process immediately with an error message. This leads to incomplete results because not all checks have been run. For example, the following probe will generate an error and terminate assessment if current user does not have sysadmin role.
"DBMetaInfo": [
{
"type": "SQL",
"target": { "type": "Database" },
"implementation": {
"query": "DBCC DBINFO(@TargetName) WITH TABLERESULTS,NO_INFOMSGS",
}
}
]This requirement can be specified explicitly in the probe's requires property. With this property SQL Assessment API will check if current user has sysadmin role before running the query. If not, the query will not be run and all checks, that depend on this probe, will be skipped. The user will get a warning about this.
"DBMetaInfo": [
{
"type": "SQL",
"target": { "type": "Database" },
"implementation": {
"query": "DBCC DBINFO(@TargetName) WITH TABLERESULTS,NO_INFOMSGS",
},
"requires": {
"role": [ "sysadmin" ]
}
}
]In some scenarios there is no need for the warning. Let's take a probe which detects database mirroring endpoints with the following T-SQL query.
SELECT
[name] AS endpoint_name,
is_encryption_enabled,
encryption_algorithm,
encryption_algorithm_desc
FROM
sys.database_mirroring_endpointsThis probe makes little sense when High Availability abd Disaster Recovery (HADR) is disabled. We can add a requirement for this probe to skip it in these cases.
"AGEndpoints": [
{
"type": "SQL",
"target": { "type": "Server" },
"implementation": { "query": " … " },
"requires": {
"feature": [ "HADR" ]
}
}
]With this implementation, the user will get a warning for each SQL Server instance not involved in HADR operations, which would be confusing. There is another probe propery named runFor which specifies requirements in the same format as requires. The difference is the absence of the warning message. The probe does not run the query but return an empty set immediately.
"AGEndpoints": [
{
"type": "SQL",
"target": { "type": "Server" },
"implementation": { "query": " … " },
"runFor": {
"feature": [ "HADR" ]
}
}
]Each requirement is represented by a JSON property. The property name is the requirement name. The property value is a JSON array of strings representing required values. For example, the following probe requires ALTER TABLE and ADMINISTER BULK OPERATIONS server permissions.
"requires": {
"server permission": [
"ALTER TABLE",
"ADMINISTER BULK OPERATIONS"
]
}Requirement types
SQL Assessment API supports a variety of requirement types. The are documented below.
Each requirement type has specific name format. Fixed literal characters in the name format are bold. Variable parts of the name are italic. Optional parts are [ enclosed in square brackets ].
Supported requirement types:
Samples Manage Sql Assessment Api Docs Reference DataTransformation README (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/README.md`)
Data transformation
In This Section
Samples Manage Sql Assessment Api Docs Reference Probes README (`samples/manage/sql-assessment-api/docs/Reference/Probes/README.md`)
Probes
The SQL Assessment API provides different types of probes to get data for assessment. Data can be taken from the SQL Server dynamic management views and from the operating system, for example, from the Windows registry.
In This Section
Samples Development Frameworks Laravel Vendor Mockery Mockery Docs README (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/README.md`)
mockery-docs
Document for the PHP Mockery framework on readthedocs.org
Samples Manage Sql Assessment Api Docs Customization DataTransformation (`samples/manage/sql-assessment-api/docs/Customization/DataTransformation.md`)
Data Transformation
Sometimes data needs to go through series of transformations.
When dta comes in an unconvenient format, a transformation can be applied in the probe implementation. For example, the following T-SQL query returns host_release as a string like '10.0.19044.2006'.
SELECT host_platform, host_release
FROM sys.dm_os_host_infoWhile it is possible to parse the string in T-SQL, a transformation make the code more readable and easier to create and maintain:
"implementation": {
"query": "SELECT host_platform, host_release FROM sys.dm_os_host_info",
"transform": {
"type": "parse",
"map": {
"host_release": "/^(?<major>\\d+)\\.(?<minor>\\d+)"
}
}
}Transformations can be applied in probe references to increase probe reuse. When one check needs an average value for some metric while another best practice involves maximum for the same metric. Both checks can have references to the same probe but each applies its own specific transformation. In this case not only the probe code is reused, but the data is reused as well, because the probe will be called only once.
See Data transformation reference for more details.
Samples Manage Sql Assessment Api Docs Customization LocalVariables (`samples/manage/sql-assessment-api/docs/Customization/LocalVariables.md`)
Local Variables
A check can define local variables available for conditions and message templates. Local variables are any expressions involving literals, probe data, and transformation results.
{
"probes": ["SysDmOsSysInfo"],
"locals": {
"workers": {"sub": [ "@max_workers_count", 1 ] }
},
"message": "Workers = @{workers}.",
"condition": {
"lt": [ 0, "@workers" ],
"lt": [ "@workers", 4 ]
}
}Samples Manage Sql Assessment Api Docs Customization MessageTemplate (`samples/manage/sql-assessment-api/docs/Customization/MessageTemplate.md`)
Message template
Overview
A check produces a recommendation message specified in the mesasge property. The message can contain data returned from a probe or calculated by the check.
Message template resembles C# string interpolation. Data variables can be inserted in curly braces preceded by the 'at' sign '@'.
In the following example a probe returns @indexName, @Schema, and @Object string variables. The API will substitute the references in curly braces with actual values.
"message": "Drop hypothetical @{IndexName} index for @{Schema}.@{Object}"Message template supports format specifiers as well. The specifier must follow the variable name separated by a colon ':'. For more information on formatting values see How to format numbers, dates, enums, and other types in .NET
In the following example the number @fragmentation will be multiplied by 100, rounded to 2 digits after decimal point, and decorated with percent sign '%'.
"message": "Current fragmentation level is @{fragmentation:P2}"Output:
Current fragmentation level is 37.20%Formatting for string values is extended. The format string will inserted into the resulting message if the value is not null and not an empty string. The pound sign '#' is replaced by the string value itself. This could be useful for adding sentence parts when additional information is present.
Take the following example:
"message": "Create index on @{Table} with key columns @{KeyCols}@{IncludedCols: and included columns: #}"When @IncludedCols is empty the message would be
Create index on MyTable with key columns Id, NameWhen @IncludedCols is contains names of included columns "SpaceAvailable, CPULoad", tha message will be:
Create index on MyTable with key columns Id, name and included columns: SpaceAvailable, CPULoadSamples Manage Sql Assessment Api Docs Customization Probe (`samples/manage/sql-assessment-api/docs/Customization/Probe.md`)
Probe
A Probe is a JSON property. The property name is the probe ID used in checks. The property value is an array of probe implementations. The SQL Assessment API engine selects the first implementation with matching target pattern. This means that the order of the implementations in the array is important. A probe can be comprised by a mix of CLR and SQL implementations.
Another ruleset may add probe implementations on top of the list.
A probe should be designed as a function with no side effects. The order of calling probes is not determined. The engine may reorder probe calls to optimize the target SQL Server load. When no check needs data from a probe, that probe will not be called.
Probes from the default rule set read metadata only, e.g. update logs or server properties. They do not read user data from tables or write anything to databases or instances. Probes do not set any flags or properties.
Probe implementation
Probe implementation is represented by a JSON object. Its properties define procedures for getting data and selecting appropriate implementation.
Probe properties
implementation
The implementation property contains probe parameters and data transformations affecting the probe output. For example, for a T-SQL probe the main parameter is the query for selecting data.
Probe parameters are specific for probe type.
requires
Explicit functional requirements for this probe. SQL Assessment API checks if all the requirements are met. If not, the probe is not executed, all dependent checks are skipped, and a warning is returned.
runFor
Explicit logical requirements for this probe. SQL Assessment API checks if all the requirements are met. If not, the probe implementation is not executed and an empty result set is returned immediately.
target
Target object pattern.
type
Probe type determines the mechanism used to get data. it may be a T-SQL or a WMI. Available probe types are listed in the following table.
| Type | Description |
|---|---|
| AzGraph | Kusto query to Azure resource graph |
| AzMetadata | JSONPath for the object returned by Azure Instance Metadata Service |
| CMD | Command shell script run on the target machine |
| External | Arbitrary .NET code |
| PowerShell | PowerShell script |
| Registry | Data from registry |
| SQL | T-SQl query |
| WMI | WMI query |
Samples Manage Sql Assessment Api Docs Customization ProbeReference (`samples/manage/sql-assessment-api/docs/Customization/ProbeReference.md`)
Probe reference
Data for checks comes from probes. Probe reference is a JSON object that describes a probe needed by the check. When a probe is referenced with no additional options or parameters, a probe reference may be abbreviated to a string containing probe ID.
Properties
alias
An alternative name used for this probe.
Alias is an alternative name for the probe which can be used in expressions in this check. It is useful in two scenarios: calling a probe multiple times and passing data from one probe to another one.
id
Referenced probe ID.
params
Parameters passed to the probe called for this check. They are represented as properties of a JSON object. Property name is the parameter name while property value can be any expression. Expression can include constants, global and local variables, and data returned by other probes (see alias).
transform
Data transformation applied to the data before calculation the condition value, see Data transformation.
Calling probe multiple times
For some checks you may need to call a probe multiple times with different parameters. In this case add multiple probe references with the same id. To distinguish results returned for different parameters prepend the output variable name with probe alias and double colon '::'.
The following check compares f4ree space on disks C: and D:.
"probes": [
{
"type": "DiskInfo",
"alias": "FirstDisk",
"params": {
"DiskName": "C:"
}
},
{
"type": "DiskInfo",
"alias": "SecondDisk",
"params": {
"DiskName": "D:"
}
}
],
"condition": {
"greater": [
"@FirstDisk::FreeSpace",
"@SecondDisk::FreeSpace"
]
}Using data from another probe
Data returned by one probe can be passed to another one as a parameter. The expression for the parameter should contain the output variable name prefixed with the previous probe id or alias.
In the following example DatabaseMasterFiles probe finds volume IDs for all disks used by the target database. The AzStorage probe is called for each volume ID and adds Azure related storage properties along with volume ID.
"probes": [
{
"id": "DatabaseMasterFiles",
"alias": "db_files",
"params": {
"dbId": null,
"type": null
},
"transform": [
{
"type": "aggregate",
"group": [
"volume_mount_point",
"volume_id"
]
},
{
"type": "aggregate",
"group": "volume_id",
"map": {
"volume_mount_point": "join"
}
}
]
},
{
"id": "AzStorage",
"params": {
"path": "@db_files::volume_id"
}
}
]Samples Manage Sql Assessment Api Docs Customization Rule (`samples/manage/sql-assessment-api/docs/Customization/Rule.md`)
SQL Assessment API Rule
A rule is represented by a JSON object. A rule applies its properties to a new or existing check.
Rule properties
itemType
Allowed values: definition, override
This property specifies whether this rule defines a new check or modifies an existing one. A check can be modified by more than one rule.
tags
An array of short strings used to categorize checks. For example, checks marked with the "Memory" tag are coming from memory-related best practices. Single-word tags work best.
id
An ID of the check to be defined or modified by this rule. A check can be modified by more than one rule.
An array of IDs or tags of checks to be modified by this rule. A rule can modify multiple checks at once. Checks are selected either by ID or by tag. If multiple tags are specified, every check having any listed tag will be affected by this rule.
target
Target pattern is a JSON object used to select applicable rules. A rule will be applied if the assessed object matches the target pattern. For more information, see Target pattern.
targetFilter
Target pattern with the same syntax as the target property, but used exclusively in overrides. For more information on the usage and object format, see Overrides and Target pattern, respectively.
displayName
Short display names are shown in checklists. You may think of a display name as of a file name if a rule was stored in a separate file. Usually, the display name tells what the check is looking for.
message
A string which is used as a template for generating messages to the user. Such a message appears when the check detects configurations that are not in compliance with the best practice recommendation. For more information, see Message template.
description
Long description that explains why the check looks for this particular issue. It briefly discusses the impact of the detected issue.
helpLink
Hyperlink to an article that explains the best practice recommendations and remediation suggestions.
level
Allowed values: Information, Low, Medium, High
The severity level of the issue detected by this check.
probes
The probes array contains references to probes to be used to get data required by this check. For more information, see Probe References.
condition
Condition is an expression in form of JSON object tree. It uses check parameters and data from probes This expression should return true when the best practice found implemented. If condition evaluates to false, the message is displayed to the user.
parameters
Arbitrary properties passed to conditions, message templates, probe parameters, and transforms along with the data from probes.
Samples Manage Sql Assessment Api Docs Customization RulesandProbes (`samples/manage/sql-assessment-api/docs/Customization/RulesandProbes.md`)
Understanding rules and probes
The SQL Assessment API uses sets of best practice recommendations to check if a SQL Server environment or configuration could be improved. Best practices are not universal. Guidelines depend on SQL Server version, edition, and configuration, hosting platform, and even usage pattern. For example, some best practices are applicable only to cloud environments, whereas others work for SQL Server instances installed on a physical machine. Databases may also be of different types. For example, a set of best practices for the msdb database might be different from that used for user databases.
SQL Assessment API makes recommendations more specific by implementing a two-step process:
Build a checklist for the given target
Such a checklist contains a complete set of checks, depending on the specified target.
Go through the checklist and report every best practice violation
At this step, the SQL Assessment API goes through the checklist to validate whether the given target satisfies the given best practice.
The checklist construction process is based on rules. Each rule either defines a new check or modifies one or more of the existing ones. Rules are stored in rulesets. Each ruleset has its own name and version. Users can add multiple rulesets to the SQL Assessment API engine one by one. While building the checklist, the engine will apply rules in the order they were added.
A single check can be affected by multiple rules. The first rule must define the check and assign a unique string ID. Checks may have tags that allow managing them in groups. The following rules override checks referred by IDs or tags, which gives the override the ability to modify multiple checks at once.
For example, the following rule makes a check with the MaxMemory ID appear in the checklist for all SQL Server 2012 instances and higher. Note that the rule sets the limit parameter to 2147483647.
{
"id": "MaxMemory",
"itemType": "definition",
"target":
{
"type": "Server",
"version": "[11.0,)"
},
"limit": 2147483647
}The rule below modifies the limit parameter for the MaxMemory check defined above.
{
"id": "MaxMemory",
"itemType": "override",
"limit": 2000000000
}Note that the rule override can modify checks for selected targets if needed. The following rules modify the limit of the MaxMemory check for specific SQL Server editions.
{
"id": "MaxMemory",
"itemType": "override",
"targetFilter":
{
"engineEdition": "Standard"
},
"limit": 131072
},
{
"id": "MaxMemory",
"itemType": "override",
"targetFilter":
{
"engineEdition": "Express"
},
"limit": 1410
}Having a check in the checklist does not mean this check will be run by the assessment engine. Each check has the enabled property which is set to true by default. If the property becomes false after all rules are applied, the engine will skip the check.
The following rule disables the MaxMemory check and all performance-related checks for all instances running on Linux.
{
"id": [ "MaxMemory", "Performance" ],
"itemType": "override",
"targetFilter": {
"platform": "Linux"
},
"enabled": false
}Each check needs data to analyze. Checks do not retrieve any data from the target server or database but refer to probes instead. Most of the probes use T-SQL queries, but the SQL Assessment API also supports probes for WMI, Windows registry, Azure Instance Metadata Service, as well as custom probes implemented as .NET classes.
Each probe returns zero or more data rows containing named items. If a check gets data from multiple probes, the resulting data set is constructed as all combinations of rows. This behavior is similar to CROSS JOIN in T-SQL.
A check has a condition expression which formally describes best practice as an arithmetic expression referring to data from a data row. Condition is calculated and checked if it holds for each row separately. For example, when a database uses 3 disks for storing its files, then a free space best practice may apply to each disk independently. If a check uses data from two probes, and one probe produces 2 rows while another one produces 3, the check condition will be evaluated 2×3=6 times. If condition gives false 2 times out of 6, the check will produce 2 messages.
At the same time, probe implementation may depend on the SQL Server version. For example, dynamic management views may vary between SQL Server releases. This is why a probe may have multiple implementations. Each implementation has a target specification, the same way the rules do. The assessment engine uses the most appropriate implementation for each target.
Related topics
Samples Manage Sql Assessment Api Docs Customization RulesetFileStructure (`samples/manage/sql-assessment-api/docs/Customization/RulesetFileStructure.md`)
Ruleset file structure
Rule set is stored in a text file that contains a JSON object. The rule set object has three simple mandatory properties: name, version, and schemaVersion. The latter specifies the file format version. As of the time of writing this document, the file format version is 1.0. The name and version properties comprise the identity of the set.
An essential part of a ruleset is the optional rules property that stores an array of SQL Assessment API rules. Rules are used to build a checklist. For more information, see Understanding Rules and Probes.
The optional probes property contains definitions for probes. Probes are used to get actual data from target SQL Server instances, hosting machines, and other sources. Each probe definition is a JSON array of one or more implementations. For more information, see Probes.
The rules and probes properties are optional because rules from one ruleset can use probes from another one.
{
"name": "Ruleset name",
"version": "Ruleset version",
"schemaVersion": "Schema version",
"rules":[
{
… rule A …
},
{
… rule B …
},
…
],
"probes":{
"probe1": [
{
… implementation 1 …
},
{
… implementation 2 …
},
…
],
"probe2": [
…
],
…
}
}Ruleset examples:
Samples Manage Sql Assessment Api Docs Customization TargetPattern (`samples/manage/sql-assessment-api/docs/Customization/TargetPattern.md`)
Target pattern
Target pattern specifies criteria for filtering rules and probe implementations. A rule will be applied to those SQL Server instances and databases, which match the rule's target pattern.
this mechanism allows rules specific to certain SQL Server versions or editions, or even specific to a certain database. When used in custom rulesets, SQL Server instances can be distinguished by name to apply different rules. For example, servers servers used for application development might not need frequent backups.
Target pattern structure
Target pattern is represented by a JSON object of the following structure. All properties are optional. Every value is a match when a property is omitted.
engineEdition
Allowed values: PersonalOrDesktopEngine, Standard, Enterprise, Express, AzureDatabase, DataWarehouse, StretchDatabase, ManagedInstance;
Azure = AzureDatabase, DataWarehouse, StretchDatabase, ManagedInstance;
SqlServer = PersonalOrDesktopEngine, Standard, Enterprise, Express.
Any combination of comma-separated values above is allowed. Lists SQL Server engine editions matching this target pattern. Azure and SqlServer are short names for frequently used lists.
In the following example engineEdition is any on-premises edition or Azure Managed Instance.
"engineEdtion": "SqlServer, ManagedInstance"name
A string pattern for the target SQL
Server object name. It's a database name or an instance name.
In the following example name matches anything except master, tempdb, and model.
"name": { "not": [ "master", "tempdb", "model"]}machineType
A string pattern for the type of machine hosting target SQL Server instance.
Supported machine type values are: Physical, AzureVm, Hypervisor, Other.
In the following example any physical or Azure virtual machine mathes the pattern.
"machineType": ["AzureVm", "Physical"]platform
A string pattern for the platform of machine hosting target SQL Server instance.
Supported machine type values are: Windows, Linux.
In the following example Windows and Linux installations match.
"platform": ["Windows", "Linux"]serverName
A string pattern for the SQL Server instance name. If target is a SQL SErver instance, then serverName equals name, otherwise it's the name of SQL Server instance hosting the target object.
In the following example all instances match except those with names ending with Test.
"serverName": {"not": "/*.Test$/"}type
Allowed values: Server, Database.
Any comma-separated list of allowed values defines which type of SQL Server object matches this pattern.
Check's target is always either Sever or Database. For a probe it's often both.
In the following example only databases match the pattern.
"type": "Database"version
A version pattern specifying ranges of matching SQL Server versions.
In the following example the pattern matches SQL Server 2016 SP2+, 2014 SP3+, and 2019+.
"version": ["[13.0.5026.0, 14.0)", "[12.0.6024.0, 13.0)", "[15.0)"]String pattern
String pattern defines matching strings. It can be a string, a JSON object, or a JSON array of string patterns. With arrays, string patterns have a recursive structure. An array matches a string when any of its elements is a match.
A string pattern can be an arbitrary string. In this case SQL Assessment API looks for an exact match.
When the string starts and ends with slash '/' ti represents a regular expression.
When string pattern is represented by a JSON object, it may have only one property named not. The property value must be any string pattern. This means that the pattern matches anything which is not a match for the __not__property value.
For example, the following matches anything that does not end with Test.
{ "not": "/*.Test$/c" }Regular expression
Regular expressions are enclosed in slashes: "/Win*./". Regular expression options can be specified after the closing slash. For example, this is the case sensitive search: "/win.*/c". If the string does not start with a slash, it is treated as an exact string match. The string "Linux" is equivalent to the regular expression "/^Linux$/".
SQL Assessment API supports .NET Regular Expressions..
Regular expression options are listed in the Regular expression options article.
NOTE: Regular expressions are case-insensitive by default. For case-sensitive matching use 'c' option.
Version pattern
The version range list is a single version range or an array of version ranges. A single version range is equivalent to an array containing the only element. The version range list matches any version matching any of its ranges.
"version": [
"[10.0.4326,10.0.4371]",
"[10.0.5794,10.50)",
"[10.50.2806,11.0)",
"[11.0.2316,)"
]Version range
A range of versions is encoded by a string. The string contains one or two versions delimited by the comma and enclosed into optional parenthesis or brackets. If there are two versions, the former version must be less than or equal to the latter. They represent the range boundaries. The version must be specified at least by two numbers separated by the period: major and minor version numbers.
Th version range format follows Nuget version range format.
| Version Range | Matches |
|---|---|
| "10.0" | Version 10.0 exactly. |
| "[10.0, 13.0]" | Anything between 10.0 and 13.0, inclusive: 10.0, 10.50, 11.0.345, 13.0. |
| "(10.0, 13.0)" | Anything between 10.0 and 13.0, exclusive: 10.50, 11.0.345. Does not match 10.0 or 13.0. |
| "[10.0, 13.1)" | Anything between 10.0 and 13.1, excluding the right boundary: 10.0, 10.50, 11.0.345, 13.0, 13.0.234. Does not match 13.1. |
| "(10.0, 13.1]" | Anything between 10.0 and 13.1, excluding 10.0. |
| "[10.0,)" | 10.0 and abo |
| "(10.0,)" | Above 10.0, but not itself |
| "(,10.0]" | 10.0 or below |
| "(,10.0)" | Below 10.0, but not 10.0. |
Samples Manage Sql Assessment Api Docs How To UsingAzureRules (`samples/manage/sql-assessment-api/docs/How-To/UsingAzureRules.md`)
Assessment of SQL Server on Azure Virtual Machines
With SQL Assessment cmdlets, you can assess an instance of SQL Server on an Azure VM not only as on-premises SQL Server, but also with rules that are specific to Azure environments.
To use such rules, do the following:
Make sure that both the Azure PowerShell module and the Az.ResourceGraph module are installed.
Sign in with Azure PowerShell before invoking SQL Assessment against SQL Server on an Azure VM.
NOTE: It is possible to use Azure account connection persisted between PowerShell sessions, i.e. invoke Connect-AzAccount in one session and omit this command later. However, in such a scenario, SQL Assessment cmdlets need the Az.ResourceGraph module to be imported explicitly by running Import-Module Az.ResourceGraph.
Performing Assessment
The following example shows how to invoke assessment for SQL Server on an Azure VM instance. Active Azure subscription connection enables rules that are specific to SQL Server on Azure VMs—AzSqlVmSize in this example:
Invoke the Connect-AzAccount cmdlet that establishes connection with the Azure account to get data from Azure Resource Graph.
powershellConnect-AzAccount[Optional step] After invoking Connect-AzAccount, you can run the Set-AzContext cmdlet.
powershellSet-AzContext My-Pay-As-You-Go[Optional step] Invoke the Get-Credential cmdlet that creates a credential object for the specified user name and password.
powershell$cred = Get-CredentialSelect SQL Server objects to assess. For example, the following command gets a SQL Server instance.
powershell$target = Get-SqlInstance -ServerInstance "Computer002\InstanceName" -Credential $cred-Credentialis an optional parameter and can be omitted.Run the Invoke-SqlAssessment cmdlet that builds a check list for each input object, runs through the list, and returns best practice recommendations.
powershellInvoke-SqlAssessment $target
As a result, you would get an output similar to the following one.
TargetPath : Server[@Name='ContosoAzureSQL']
Sev. Message Check ID Origin
---- ------- -------- ------
Medi Amount of single use plans in cache is high (100%). Consider PlansUseRatio Microsoft Ruleset 0.1.202
enabling the Optimize for ad hoc workloads setting on heavy OLTP
ad-hoc workloads to conserve resources
Low Use memory optimized virtual machine sizes for the best AzSqlVmSize Microsoft Ruleset 0.1.202
performance of SQL Server workloadsHere, Server[@Name='ContosoAzureSQL'] shows the server name that hosts the assessed SQL Server instance, the Sev. column shows the severity level, which can be Information, Medium, Low, or High, in the Message column, the actual best practice recommendations are shown, the Check ID column shows the rule name, and the Origin column displays the ruleset name and version.
In this example, the AzSqlVmSize rule is applicable solely to the SQL Server deployed on an Azure VM; it checks whether the size of the VM is memory-optimized or not.
Samples Manage Sql Assessment Api Docs How To UsingNonSQLProbes (`samples/manage/sql-assessment-api/docs/How-To/UsingNonSQLProbes.md`)
Retrieving Data from Operating System
In the SQL Assessment API, most of the probes use T-SQL to get data for assessment. However, there are probes that obtain data from the operating system not presented in SQL Server dynamic management views. In order for these probes to get data, the xp_cmdshell stored procedure and PowerShell access should be enabled on the target SQL Server. While these facilities are disabled, some checks may be skipped.
Keep in mind that the xp_cmdshell stored procedure should be enabled temporarily as it is not recommended by the best practices; once you complete the assessment, make sure to disable it.
The following steps are required to enable xp_cmdshell and PowerShell:
Enable the xp_cmdshell stored procedure to work with T-SQL queries, as described in xp_cmdshell configuration option.
Enable SQL Server PowerShell on the target SQL server, as described in SQL Server PowerShell.
Make sure that the SQL Server user has access to the xp_cmdshell stored procedure. For more information, see xp_cmdshell (Transact-SQL).
Disable the xp_cmdshell stored procedure by executing the following T-SQL query on the target SQL Server.
sqlEXECUTE sp_configure 'xp_cmdshell', 0; RECONFIGURE
Samples Manage Sql Assessment Api Docs Reference JSONConfiguration (`samples/manage/sql-assessment-api/docs/Reference/JSONConfiguration.md`)
JSON configuration file format
This section explains the structure of the JSON file with rules and probes.
Engine configuration
| Property | Property Type | Description |
|---|---|---|
| version | string | Configuration file version. The current version is "0.3". |
| checks | array | Each item is a Check object. |
| probes | object | Each property represents a Probe Family. |
Check
| Property | Property Type | Description |
|---|---|---|
| name | string | Short single name. Must be unique. |
| tags | array of strings | A set of tags for the check. Tags represent check groups and categories. A tag can be used instead of the check name in API calls. |
| displayName | string | Long name that is shown to the user. |
| description | string | Long description that explains the purpose of the check. |
| enabled? | bool | Indicates if the check is enabled. Disabled checks are not run for any object. True by default. |
| messge | string | Recommendation text displayed to the user when the check fails. Recommendation text may contain variable references in the @{variableName} form. Such references are replaced by string representation of the variable value. The optional format string can be specified for the variable in the @{variableName:formatString} form. |
| target? | SQL Object Pattern | Check can be applied to objects that satisfy the pattern. By default matches any object. |
| probes | array of strings | IDs of the Probe Families required by the check. |
| condition? | Condition Expression | A condition expression that must be satisfied by the target object. If the condition expression returns false, the recommendation is generated. True by default. |
| level | string | Severity level: Information, Warning, or Critical. |
| any | Expression | Other properties are treated as check parameters and accessible from check expressions as variables by the name prefixed with the at-sign @. Parameters may refer to variables or other parameters. |
Probe
A Probe is a JSON property. The property name is the probe family ID used in Checks. The property value is an array of probe implementations. Probe implementations are checked in the order if their target patterns match the target object. The first matching probe will be used to get data. This means that the order of the probes is important. A probe can be comprised by a mix of CLR and SQL implementations.
Probe implementation
A JSON object. Security is the user responsibility. Probes only read metadata like update logs or server properties; they do not read user data from tables or write anything to databases or instances. Probes do not set any flags or properties.
| Property | Property Type | Description |
|---|---|---|
| type | string | Probe type. Supported values: SQL, WMI, External, PowerShell, CmdShell, AzGraph, AzMetadata, Registry. |
| target? | SQL Object Pattern | Probe may be applied to objects satisfying the pattern. |
| implementation | object | Any parameters required by the probe. Probes with type="SQL" need a query property containing the SQL command executed to get the probe data. Probes with type="CLR" need a class property specifying the class name and assembly property specifying assembly. Other properties are used to populate a new class instance. |
SQL probe implementation
| Property | Property Type | Description |
|---|---|---|
| query | string | T-SQL query. The query can refer to parameters by the name. |
External probe implementation
External probe implementation refers to an arbitrary .NET class in the given assembly. The class must implement IProbeImplementation interface.
| Property | Property Type | Description |
|---|---|---|
| assembly | string | String specifying assembly to load. |
| class | string | Full class name. |
SQL Object Pattern
Regular expression
Regular expressions are enclosed in slashes: "/Win*./". Regular expression options can be specified after the closing slash. For example, this is the case insensitive search: "/win.*/i". If the string does not start with a slash, it is treated as an exact string match. The string "Linux" is equivalent to "/^Linux$/".
Version range list
The version range list is a single version range or an array of version ranges. A single version range is equivalent to an array containing the only element. The version range list matches any version matching any of its ranges.
"version": [
"[10.0.4326,10.0.4371]",
"[10.0.5794,10.50)",
"[10.50.2806,11.0)",
"[11.0.2316,)"
]Version range
A range of versions is encoded by a string. The string contains one or two versions delimited by the comma and enclosed into optional parenthesis or brackets. If there are two versions, the former version must be less than or equal to the latter. They represent the range boundaries. The version must be specified at least by two numbers separated by the period: major and minor version numbers.
| Version Range | Matches |
|---|---|
| "10.0" | Version 10.0 exactly. |
| "[10.0, 13.0]" | Anything between 10.0 and 13.0, inclusive: 10.0, 10.50, 11.0.345, 13.0. |
| "(10.0, 13.0)" | Anything between 10.0 and 13.0, exclusive: 10.50, 11.0.345. Does not match 10.0 or 13.0. |
| "[10.0, 13.1)" | Anything between 10.0 and 13.1, excluding the right boundary: 10.0, 10.50, 11.0.345, 13.0, 13.0.234. Does not match 13.1. |
| "(10.0, 13.1]" | Anything between 10.0 and 13.1, excluding 10.0. |
| "[10.0,)" | 10.0 and abo |
| "(10.0,)" | Above 10.0, but not itself |
| "(,10.0]" | 10.0 or below |
| "(,10.0)" | Below 10.0, but not 10.0. |
Expression
Expressions define calculations made to decide if a recommendation should be given to the user.
Boolean literals
JSON values true and false are treated as Boolean constants.
Numeric literals
JSON numbers are treated as decimal constants.
String literals
String literals represent strings except those starting with the "@" character denoting a reference to a variable.
Variables
Variables are represented by strings containing their names preceded by the "@" character. Variable values are set by probes and consumed by expressions or recommendation texts.
Expression JSON object
JSON object with a single property is an expression represented by the property. See Property Expressions. JSON object with more than one property is a short version for the AND operation. Its arguments are the object properties. The results are converted into the Boolean type if possible. So these two expressions are equivalent:
expression1: {
"@version": "10.50.0",
"@memroySize": 4096
}
expression2: {
"and": [
{"@version": "10.50.0"},
{"@memroySize": 4096}
]
}Property Expressions
Any expression can be represented in a form of a JSON property. The property name is the operation name while the property value is an array of operation arguments. Arguments are any expressions except condition expressions.
When the property name starts with the "@" character, it is not the operation name. The expression is a short variant of the equal operation with the variable as the first argument and the only property value as the second. The following expressions are equivalent:
expression1: {"@memorySize": 4096}
expression2: {
"equal": [
"@memorySize",
4096
]
}Condition Expression
Condition expressions can be any expressions or an array of expressions. An array of expressions is a short version for OR operations. An array of items holds arguments for the operation. The following expressions are equivalent:
"condition": [
{"@version": "10.50.0"},
{"@memroySize": 4096}
]
"condition": {
"or": [
{"@version": "10.50.0"},
{"@memroySize": 4096}
]
}Note: The short version for "OR" works only as condition expressions while the short version for "AND" works everywhere. The following expressions are equivalent:
"condition": {
"@version": "10.50.0",
"@memroySize": 4096
}
"condition": {
"and": [
{"@version": "10.50.0"},
{"@memroySize": 4096}
]
}Samples Manage Sql Assessment Api Docs Reference LocalVariables (`samples/manage/sql-assessment-api/docs/Reference/LocalVariables.md`)
Local Variables
A rule can define local variables available for conditions and message templates. Local variables are any expressions involving literals, probe data, and transformation results.
{
"probes": ["SysDmOsSysInfo"],
"locals": {
"workers": {"sub": [ "@max_workers_count", 1 ] }
},
"message": "Workers = @{workers}.",
"condition": {
"lt": [ 0, "@workers" ],
"lt": [ "@workers", 4 ]
}
}Samples Manage Sql Assessment Api Docs Reference Operators (`samples/manage/sql-assessment-api/docs/Reference/Operators.md`)
Operators
With the SQL Assessment API, you can use different kinds of operators to make your assessment even more precise.
In This Section
Logical
| Operator | Arguments | Description |
|---|---|---|
| not | (x) | Logical not. |
| and | (a..*) | Logical AND. Returns false without arguments. |
| or | (a..*) | Logical OR. Returns true without arguments. |
String
| Operator | Arguments | Description |
|---|---|---|
| indexof | (str_a, str_b) | Finds a zero-based index of the first str_b occurrence in the string str_a. Case-sensitive. |
| iindexof | (str_a, str_b) | Finds a zero-based index of the first str_b occurrence in the string str_a. Case-insensitive. |
| startswith | (str_a, str_b) | Returns true if the string str_a starts with the string str_b. Case-sensitive. |
| istartswith | (str_a, str_b) | Returns true if the string str_a starts with the string str_b. Case-insensitive. |
| endswith | (str_a, str_b) | Returns true if the string str_a ends with the string str_b. Case-sensitive. |
| iendswith | (str_a, str_b) | Returns true if the string str_a ends with the string str_b. Case-insensitive. |
Math
| Operator | Arguments | Description |
|---|---|---|
| ceiling | x | Rounds x to the nearest greater or equal value. |
| floor | x | Rounds x to the nearest lower or equal value. |
| max | (a, b) | Returns maximum of a and b. |
| min | (a, b) | Returns minimum of a and b. |
| mul | (a..*) | Arithmetic multiplication. |
| div | (a, b) | Arithmetic division of a by b. |
| mod | (a, b) | Arithmetic remainder of a divided by b. |
| add | (a..*) | Arithmetic sum. |
| sub | (a, b) | Arithmetic difference of a and b. |
| bitand | (a..*) | Bitwise AND. |
| bitor | (a..*) | Bitwise OR. |
| bitxor | (a..*) | Bitwise XOR. |
Set
| Operator | Arguments | Description |
|---|---|---|
| intersect | (a, b) | Sets intersection of a and b arguments. Case-sensitive. |
| in | (a, b) | Checks if the argument a was found in b. The b argument represents a collection. Case-sensitive. |
| iin | (a, b) | Checks if the argument a was found in b. The b argument represents a collection. Case-insensitive. |
Comparison
| Operator | Synonyms | Arguments | Description |
|---|---|---|---|
| lt | less | (a, b) | Checks if the argument a is less than the argument b. |
| gt | greater | (a, b) | Checks if the argument a is greater than the argument b. |
| eq | equal | (a, b) | Checks if both arguments are equal. Case-sensitive. |
| ieq | (a, b) | Checks if both arguments are equal. Case-insensitive. | |
| ge | greaterequal | (a, b) | Checks if the argument a is greater than or equals to the argument b. |
| le | lessequal | (a, b) | Checks if the argument a is less than or equals to the argument b. |
| ne | notequal | (a, b) | Checks if the argument a is not equal to the argument b. Case-sensitive. |
| ine | (a, b) | Checks if the argument a is not equal to the argument b. Case-insensitive. | |
| match | (a, b) | Regular expression match. The second argument is treated as a regular expression. Case-sensitive. | |
| imatch | (a, b) | Regular expression match. The second argument is treated as a regular expression. Case-insensitive. | |
| interval | (a,v1,t1,...,vn,tn,d) | Finds the first ti that is greater than or equal to a and returns the corresponding vi. Returns d if all t are less than a. |
Samples Manage Sql Assessment Api Docs Tutorials CreatingCustomRules (`samples/manage/sql-assessment-api/docs/Tutorials/CreatingCustomRules.md`)
Creating Custom Rules
Sometimes rulesets that come right out of the box after installing the SQL Assessment API might not be enough to validate your environment as required. In such cases, you can simply write your own rulesets.
A typical ruleset — a JSON file — consists of two blocks: rules and probes.
Rules
The Rules block defines the rule structure. It says which objects in your environment should be assessed, which versions of these objects should be considered during the assessment, the platform that hosts the objects being assessed, and so on.
Usually, rules are best practices or company internal policies that should be applied to SQL Server configurations. If any of these configurations violates conditions specified in the rule, the rule throws alerts, pointing at certain areas within your environment that should be changed in order to comply with the best practices. These alerts are represented as messages that give a short and straightforward advice on how to mitigate the issue. Alerts also contain help links to the Microsoft pages when you can get comprehensive instructions on how to configure certain things to avoid potential security and performance issues.
The following is an example of a rule:
/* Detailed source-code truncated for AI context efficiency. */Probes
The Probes block defines the way how to get the required data to check compliance with the rule. Probes are invoked during the assessment. They use queries to obtain data from your environment. This data is then evaluated and based on this evaluation, the rule can tell whether your environment is in compliance with the best practices or not. If not, the rule fires, telling you exactly what should be changed in order to avoid both performance degradation and security risks.
The following is an example of a probe:
/* Detailed source-code truncated for AI context efficiency. */The complete example is available in the MakingCustomChecks_sample file.
You can also build more complex rules by applying certain conditions and using different kinds of operators, as described in Customization
Samples Manage Sql Assessment Api Docs Tutorials DisablingBuiltInRules (`samples/manage/sql-assessment-api/docs/Tutorials/DisablingBuiltInRules.md`)
Disabling Built-in Rules
You can silence specific rules when they aren't applied to your environment or until the scheduled work is done to rectify the issue.
The following is an example consisting of three rules. The first rule shows how to disable the check by specifying its ID, the second example disables all checks that have the TraceFlag tag, and the third example disables all checks from the default ruleset using the DefaultRuleset tag for databases DBName1 and DBName2.
{
"schemaVersion": "1.0",
"version": "0.2",
"name": "Custom Overrides",
"rules":
[
{
"id": "LatestCU",
"itemType": "override",
"enabled": false
},
{
"id": ["TraceFlag"],
"itemType": "override",
"enabled": false
},
{
"id": ["DefaultRuleset"],
"itemType": "override",
"targetFilter":
{
"type": "Database",
"name": [ "DBName1", "DBName2" ]
},
"enabled": false
}
]
}Samples Manage Sql Assessment Api Docs Tutorials OverridingDefaultThresholds (`samples/manage/sql-assessment-api/docs/Tutorials/OverridingDefaultThresholds.md`)
Overriding Default Thresholds
Some of the default thresholds provided by the SQL Assessment API might not fit your current infrastructure at the moment of the assessment. In such scenarios, you can easily override them with your own values.
Let's consider an example of using the FullBackup rule that validates whether the date your backup was created goes beyond the threshold specified in the rule.
To invoke the assessment, you can run the following command:
Invoke-SqlAssessment -Check FullBackup | Select TagerObject, MessageDepending on the number of objects, the output will be similar to the following one:
TargetObject Message
------------- --------
[DevTest] Create full backup. Last full backup is over 7 days old
[Prototype] Create full backup. Last full backup is over 7 days oldAs you can see, the output tells us that there are two databases that have their backups created more than 7 days ago, which is the default threshold.
Let's say you need to change this rule to validate backups that were created more than 3 days ago instead of 7. You can do this by creating a new json file. Such a file would then be acting as an additional configuration that overrides the default thresholds. As per this example, we will create a file called BackupPolicy.json and add the following contents to this file:
{
//Sets the schema version
"schemaVersion": "1.0",
//Sets the version
"version": "1.0",
//Sets the rule name
"name": "Backup Policy",
//Sets the override for the specified rule
"rules":
[
{
//Sets the type, which is 'override'
"itemType": "override",
//Sets the name of the rule that should be overridden
"id": "FullBackup",
//Sets the new threshold
"threshold": 3
}
]
}Then you can save this file to whatever place you need and invoke the assessment, as the following example demonstrates.
Invoke-SqlAssessment -Check FullBackup -Configuration .\BackupPolicy.json | Select TargetObject, MessageHere, you are basically using the same command, as shown in the example above, but extended with -Configuration .\BackupPolicy.json. This command instructs the assessment to use a custom configuration file that keeps your overrides.
The output in this case would be similar to the following one:
TargetObject Message
------------- --------
[DevProd] Create full backup. Last full backup is over 3 days old
[TestDB] Create full backup. Last full backup is over 3 days old
[DevTest] Create full backup. Last full backup is over 3 days old
[Prototype] Create full backup. Last full backup is over 3 days oldAs you can see, the output is now different from the first one; now it shows all the databases, the backup date of which is over 3 days.
Samples Manage Sql Assessment Api Docs Customization AutomaticVariables AttrService (`samples/manage/sql-assessment-api/docs/Customization/AutomaticVariables/AttrService.md`)
attr::service:: variables
Automatic variables in the *attr::service:: namespace are provided with Service requirements.
The following variables are available for each service. Service key is a value from Service requirement supported values.
| Variable name | Type | Description |
|---|---|---|
| attr::service::key | bool | Inidicates if the service is present |
| attr::service::key.name | string | Actual service name |
| attr::service::key.account | string | User account name for this service |
Examples
In the following example the message will report actual user account name when the SQL Server Agent service is present and running under local service account. See Message template.
{
…
"message": "Account '@{attr::service::SQLAgent.account}' is not supported for 'SQL Server Agent' service.",
"localServiceAccount": "NT AUTHORITY\\LOCALSERVICE",
"condition": [
{ "not": "@attr::service::SQLAgent" },
{ "ine": [
"@attr::service::SQLAgent.account",
"@localServiceAccount"
]}
],
"probes": [ "IsClusteredServer" ]
}The next example extends the previous check with support for clustered servers. When the server is clustered, three more accounts are not supported.
{
…
"message": "Account '@{attr::service::SQLAgent.account}' is not supported for 'SQL Server Agent' service.",
"localServiceAccount": "NT AUTHORITY\\LOCALSERVICE",
"unsupportedAccounts": [
"NT AUTHORITY\\SYSTEM",
"LOCALSYSTEM",
"NT AUTHORITY\\NETWORKSERVICE"
],
"condition": [
{ "not": "@attr::service::SQLAgent" },
{
"ine": [
"@attr::service::SQLAgent.account",
"@localServiceAccount"
],
"or": [
{ "not": "@is_clustered_server" },
{ "not": {
"iin": [
"@attr::service::SQLAgent.account",
"@unsupportedAccounts"
]
}}
]
}
],
"probes": [ "IsClusteredServer" ]
}Samples Manage Sql Assessment Api Docs Customization AutomaticVariables AttrTarget (`samples/manage/sql-assessment-api/docs/Customization/AutomaticVariables/AttrTarget.md`)
attr::target:: variables
Automatic variables in attr::target:: namespace include the data which matched the target pattern.
| Variable name | Type | Description |
|---|---|---|
| attr::target::version | version | Target SQL Server version |
| attr::target::platform | string | Target SQL Server host platform (e.g. Windows, Linux) |
| attr:target::engine_edition | string | Target engine edition |
| attr::target::server_name | string | Target server name |
| attr::target::machine_type | string | Target machine type |
| attr::target::urn | string | Target object URN |
Samples Manage Sql Assessment Api Docs Customization ProbeRequirements FeatureRequirement (`samples/manage/sql-assessment-api/docs/Customization/ProbeRequirements/FeatureRequirement.md`)
Feature requirement
Feature requirement lists SQL Server features.
Name format
feature
Supported values
HADR - High Availability and Disaster Recovery (Always On Availability Groups).
Examples
"runFor": {
"feature": [ "HADR" ]
}See also
Samples Manage Sql Assessment Api Docs Customization ProbeRequirements PermissionRequirement (`samples/manage/sql-assessment-api/docs/Customization/ProbeRequirements/PermissionRequirement.md`)
Permission requirement
Permission requirements specify special permissions required by the probe. for more information see sys.fn_my_permissions
Name format
securable_class permission [ on securable_name ]
securable_class is the name of the class of securable for which permissions are listed. securable_class is a sysname. Examples of securable_class are: DATABASE, OBJECT, REMOTE SERVICE BINDING, SERVER.
securable_name is the name of the securable. If the securable is the server or a database, this part should be omitted. securable_name is a sysname. securable_name can be a multipart name.
Supported values
Allowed values depend on securable class. See SQL Server Permissions and SQL Server Permissions Hierarchy.
Examples
"requires": {
"server permission": [
"ALTER TRACE"
]
},"requires": {
"object permission on [msdb].[dbo].[sysalerts]": [
"SELECT"
]
},"requires": {
"object permission on [msdb].[dbo].[sysjobs]": [
"SELECT"
],
"object permission on [msdb].[dbo].[sysjobsteps]": [
"SELECT"
]
},See also
Samples Manage Sql Assessment Api Docs Customization ProbeRequirements RoleRequirement (`samples/manage/sql-assessment-api/docs/Customization/ProbeRequirements/RoleRequirement.md`)
Role requirement
Specifies current user roles required for running this probe.
Name format
role
Supported values
SQL Server role names.
Examples
"requires": {
"role": [
"bulkadmin",
"diskadmin"
]
}See also
Samples Manage Sql Assessment Api Docs Customization ProbeRequirements ServiceRequirement (`samples/manage/sql-assessment-api/docs/Customization/ProbeRequirements/ServiceRequirement.md`)
Service requirement
Lists SQL Server services required for the probe.
Name format
service
Supported values
MSSQL – SQL Server service
SQLAgent – SQL Server Agent service
MSOLAP – SQL Server Analysis Services
ReportServer – SQL Server Reporting Services
MsDtsServer – Integration Services
MSSQLFDLauncher – Full-Text Filter daemon host launcher service
SQLBrowser – SQL Server Browser service
Examples
"runFor": {
"service": [ "ReportServer" ]
}See also
Samples Manage Sql Assessment Api Docs Reference DataTransformation Aggregate (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/aggregate.md`)
Data transformation: **aggregate**
Takes all data rows returned from probes or previous transformations and calculates aggregate values for specified columns. If grouping was specified, returns an aggregate row for every group. Returns one row otherwise.
Paramters
| Parameter | Required | Type | Description |
|---|---|---|---|
| map | Required | Map | Maps column names to aggregate functions |
| group | Optional | String or Array of strings | Names of columns used for grouping |
Grouping
By default aggregate functions are applied to all data records returned by probes or previous transformations. Optionally, aggregates may be applied to groups of rows having the same value(s) in selected column(s). it works much like GROUP BY T-SQL clause.
Example 1
In this example blocked_spid becomes the number of unique non-null blocked_spids, block_time_min becomes the minimum of all block_time_mins. Other columns are removed.
"transform": {
"type": "aggregate",
"map": {
"blocked_spid": "count",
"block_time_min": "min"
}
}Example 2
In this example the transformation count non-unique non-null RecoveryUnitIds.
"transform": {
"type": "aggregate",
"map": {
"RecoveryUnitId": {
"type": "count",
"distinct": false
},
"blocked_spid": "count",
"block_time_min": "min"
}
}Example 3
In the following example the transform constructs a string containing a comma-separated list of all publications for each publisher_db.
"transform": {
"type": "aggregate",
"group": "publisher_db",
"map": {
"publication": "join"
}
}Aggregate Functions
and/or
Calculates 'and'/'or' aggregate value for boolean values. Null, DBNull, empty string, empty array, and string 'false' are converted to false. Non-empty string, non-empty array, and string 'true' are converted to true.
array
Collects all values into an array.
count
Count all values.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| distinct | Optional | Bool | true | If true count only distinct values |
| notNull | Optional | Bool | true | if true count only non-null values |
join
Converts values to string and joins them into string separated by comma by default.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| trim | Optional | Bool | true | If true, trim white space from the beginning and the end of each value |
| separator | Optional | String | ', ' | A string used to separate values |
| limit | Optional | Int | 0 | When limit > 0, join returns a string containing not more than first limit items with ellipsis replacing the rest. E.g. when limit=3, for [1,2,3,4,5] join returns "1, 2, 3, ..." |
| distinct | Optional | Bool | true | Skips repeating values. E.g. for [cat,lion,cat,cat,tiger,lion] join returns "cat, lion, tiger" |
| comparison | Optional | Comparison | CurrentCulture | Specifies the culture, case, and sort rules to be used for selecting distinct values. See StringComparison Enum for allowed values and more details. |
max/min
Calculates max/min value. For numeric values only.
sum
Calculates sum of all the values. For numeric values only.
Samples Manage Sql Assessment Api Docs Reference DataTransformation DefaultValue (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/defaultValue.md`)
Data transformation: **defaultValue**
Seta default values for data columns. The default value is used when the column does not contain any data.
Paramters
| Parameter | Required | Type | Description |
|---|---|---|---|
| map | Required | Map | Maps names to default values |
map
Default value map is a JSON objects setting a default value for each data column. In the following example column automatic_soft_NUMA_disabled has default value 0.
Example 1
"transform": {
"type": "defaultValue",
"map": {
"automatic_soft_NUMA_disabled": 0
}
}Samples Manage Sql Assessment Api Docs Reference DataTransformation NameValuePairs (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/nameValuePairs.md`)
Data transformation: **nameValuePairs**
From all data rows returned from probes or previous transformations takes two columns and transposes this two-column table.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| keyColumn | Required | String | Key column name used for transformation |
| valueColumn | Required | String | Value column name used for transformation |
| map | Required | Map | Maps keyColumn values to column names |
Remarks
This transform takes a name from the keyColumn and uses it to create a new column with the corresponding value from the valueColumn. If map is present, then the value from the keyColumn is used as a key to find the new column name in the map.
In the following example the source table is transformed to result table. The Description column is omitted. CPU Utilization and Disk Free Space columns are renamed according to the map.
Example 1
Source table:
| Metric | MeasuredValue | Description |
|---|---|---|
| CPU Utilization | 0.65 | Average CPU utilization |
| NOPM | 120 | Number of new orders per minute |
| Disk Free Space | 15 | Disk free space |
| TPM | 11236 | Number of transactions per minute |
"transform": {
"type": "nameValuePairs",
"keyColumn": "Metric",
"valueColumn": "MeasuredValue",
"map": {
"CPU Utilization": "cpu_utilization",
"Disk Free Space": "disk_space"
}
}Result table:
| cpu_utilization | NOPM | disk_space | TPM |
|---|---|---|---|
| 0.65 | 120 | 15 | 11236 |
Samples Manage Sql Assessment Api Docs Reference DataTransformation NoData (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/noData.md`)
Data transformation: **noData**
Defines a record returned when the probe(s) or previous transformations produced no data.
When no data comes from probes, the check passes without calculating the value for condition. this transformation allows processing empty data sets. You can use optional presenceFlag parameter to apply special logics in the condition.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| define | Required | Map | Defines default columns and their values |
| presenceFlag | Optional | String | Indicates if data was present |
define
The record definition is a JSON objects setting a default value for each data column. In the following example, in case of missing data InUse = 2, Name = 'master'.
Example 1
"transform": {
"define": {
"InUse": 0,
"Name": "master"
}presenceFlag
Presence flag is a boolean variable indicating if data was present. Use presenceFlag to specify variable name, which will be set to true when data was present and false otherwise. In the following example, in case when some data was produced by probes or previous transformations dataFound is true, otherwise it's false.
Example 2
"transform": {
"presenceFlag": "dataFound",
"define": {
"InUse": 0,
"Name": "master"
}Samples Manage Sql Assessment Api Docs Reference DataTransformation Parse (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/parse.md`)
Data transformation: **parse**
The regular expression parser extracts data from substrings of variable values that correspond to the named groups specified in regular expressions.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| map | Required | Map | Sets regular expressions for variables. |
| flatten | Optional | bool | Enables combining fields from subsequent rows. |
| join | Optional | string | Enables joining of strings from all rows and sets the separator. |
Map
Map is a JSON object setting regular expression. Each map property defines a regular expression for a variable of the same name. Named groups in regular expressions define substrings to be returned as new variables. A new variable name consists of original.group where original is the name of the parsed variable and group is the regular expression group name.
When a regular expression has more than one match, a new row is generated for every match. To pack partial matches into a single row, use flattening or joining.
NOTE: The Explicit captures option improves the morph memory footprint and performance. Use 'x' after the closing slash to enable this option: /(?\d+)/x.
The following examples demonstrate transformation results:
Example 1
Input:
| @a | @b |
|---|---|
| "There are 12 chairs" | "The chairs are blue" |
| "Found 5 files" | "Red status" |
| "Number of Napoleons: 6" | "Black pearl" |
Morph:
{
"type": "parse",
"map" : {
"a": "/(?<amount>\\d+)(\\s*(?<kind>\\w+?)s?\\b)?/x",
"b": "/(?<color>red|green|blue|yellow)/ix"
}
}Output:
| @a | @a.amount | @a.kind | @b | @b.color |
|---|---|---|---|---|
| "There are 12 chairs" | "12" | "chair" | "The chairs are blue" | "blue" |
| "Found 5 files" | "5" | "file" | "Red status" | "Red" |
| "Number of Napoleons: 6" | "15" | - | "Black pearl" | – |
Example 2
Input:
| @a | @b |
|---|---|
| "12 chairs and 1 priest" | "The chairs are blue" |
| "40 pages in 5 files" | "Red status" |
| "Number of Napoleons: 6" | "Black pearl" |
Morph:
{
"type": "parse",
"map" : {
"a": "/(?<amount>\\d+)(\\s*(?<kind>\\w+?)s?\b)?/x",
"b": "/(?<color>red|green|blue|yellow)/ix"
}
}Output:
| @a | @a.amount | @a.kind | @b | @b.color |
|---|---|---|---|---|
| "12 chairs and 1 priest" | "12" | "chair" | "The chairs are blue" | "blue" |
| "12 chairs and 1 priest" | "1" | "priest" | "The chairs are blue" | "blue" |
| "40 pages in 5 files" | "40" | "page" | "Red status" | "Red" |
| "40 pages in 5 files" | "5" | "file" | "Red status" | "Red" |
| "Number of Napoleons: 6" | "6" | – | "Black pearl" | - |
Flattening
Flattening enables combining fields from sequential rows into one in cases when a data row occupies more than one line.
Flattening works only for fields generated by the parsing process; other data is removed.
Example 3
Raw output data:
| @a.f1 | @a.f2 | @a.f3 | @other |
|---|---|---|---|
| 11 | - | - | "extra" |
| - | - | 13 | - |
| - | 12 | - | - |
| 21 | 22 | 23 | "data" |
| - | 32 | 33 | "will" |
| 31 | - | - | - |
| 41 | - | - | "be" |
| - | 42 | - | - |
| 51 | - | - | "ignored" |
After flattening:
| @a.f1 | @a.f2 | @a.f3 | @other |
|---|---|---|---|
| 11 | 12 | 13 | - |
| 21 | 22 | 23 | - |
| 31 | 32 | 33 | - |
| 41 | 42 | - | - |
| 51 | - | - | - |
Joining strings
This option joins all rows into one. Such a new row contains string equivalents of field values joined with the specified delimiter.
Joining works only for variables mentioned in Map; other data is removed.
In the following example, join = ", ".
Input:
| @a | @b | @c | @notMentioned |
|---|---|---|---|
| 42 | "Lorem" | - | "extra" |
| 13 | "ipsum" | true | "data" |
| 0 | "dolor" | false | "ignored" |
Joined:
| @a | @b | @c | @notMentioned |
|---|---|---|---|
| "42, 13, 0" | "Lorem, ipsum, dolor" | "true, false" | - |
Samples Manage Sql Assessment Api Docs Reference DataTransformation Performance (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/performance.md`)
Data transformation: **performance**
Performance probe returns a table containing multiple samples for all requested counters. A check needs some derived value. E.g. average, maximum, more complex functions.
Use the Performance transform in probe references to get derived values. Performance transform calculates specified derived value for each counter used by the check.
Derived value functions
The following table lists available performance value functions.
- n – number of samples for this counter
- c₁, c₂ – sample values for this counter
- t₁, t₂ – time stamps for samples
- b₁, b₂ – sample values for base_counter
| Type | Parameter | Formula |
|---|---|---|
| average | – | $\frac{1}{n}\sum_{i=1}^n c_i$ |
| delta_ratio | base_counter | $\frac{c_2 - c_1}{b_2 - b_1}$ |
| min/max | – | Minimum/maximum of all samples |
| rate | – | $\frac{c_2 - c_1}{t_2 - t_1}$ |
| ratio | base_counter | $\left(\frac{c_2}{b_2} + \frac{c_1}{b_1}\right)/2$ |
Example ruleset
The following JSON object represents a complete rule set using performance counters.
/* Detailed source-code truncated for AI context efficiency. */How to use multiple performance counters in a single check
While using multiple performance counters for different instances results might not look as expected. Take a look at the following example.
"probes": [
{
"id": "PerformanceProbe",
"alias": "b",
"transform": {
"type": "performance",
"counters": {
"batch_request_sec": "rate",
"lock_requests_sec": {
"type": "rate",
"instance": "_Total"
}
}
}
}
]The code worked as expected. The data transform returned two rows of data from the Performance probe:
| batch_request_sec | lock_requests_sec | instance_name |
|---|---|---|
| 123s | null | ‘’ (no instance selected) |
| Null | 456s | ‘_Total’ |
The condition is checked once per row and triggers a message for the first one and an error for another.
The following JSON illustrates a solution. The Performance probe is referenced twice. The first reference gets batch_request_sec rate. The second one gets lock_requests_sec rate for the _Total instance. Note aliases associated with each probe reference.
"probes": [
{
"id": "PerformanceProbe",
"alias": "b",
"transform": {
"type": "performance",
"counters": {
"batch_request_sec": "rate"
}
}
},
{
"id": "PerformanceProbe",
"alias": "l",
"transform": {
"type": "performance",
"counters": {
"lock_requests_sec": {
"type": "rate",
"instance": "_Total"
}
}
}
}
]Alias is any alternative name for the probe. Any data variable may be prefixed with an alias or a probe id. E.g. the following names refer to the same value in an unambiguous case:
@PerformanceProbe::batch_request_sec
@b::batch_request_sec
@batch_request_secThose two probe references result in the following data passed to the check:
| b::batch_request_sec | b::instance_name | l::lock_requests_sec | l::instance_name |
|---|---|---|---|
| 123s | ‘’ no instance | 456s | ‘_Total’ |
Samples Manage Sql Assessment Api Docs Reference DataTransformation Rename (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/rename.md`)
Data transformation: **rename**
Renames any data column.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| map | Required | Map | Maps new names to old ones |
Map
Rename map is a JSON objects setting correspondence between new names and old ones. Each property name is the new column name. The value sets the name of the old column to be renamed. In the following example column Log File Size (Byte) will be renamed to size.
Example 1
"transform": {
"type": "rename",
"map": {
"id": "Archive #",
"size": "Log File Size (Byte)",
"date": "Date"
}
}Samples Manage Sql Assessment Api Docs Reference DataTransformation ToString (`samples/manage/sql-assessment-api/docs/Reference/DataTransformation/toString.md`)
Data transformation: **defaultValue**
Replaces values with strings.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| map | Required | MapOfMaps | Maps columns to value maps |
map
String map is a JSON objects defining a string-to-value mapping for one or more columns. In the following example value 2 in column a will be replaced with the word 'two'. The same word two will be assigned to column b if it's value is 'w'.
Example 1
"transform": {
"type": "defaultValue",
"map": {
"a":{
"one" : 1,
"two" : 2,
"three": 3
},
"b":{
"one" : "o",
"two" : "w",
"three": "r"
}
}
}Samples Manage Sql Assessment Api Docs Reference Probes AzGraphProbe (`samples/manage/sql-assessment-api/docs/Reference/Probes/AzGraphProbe.md`)
AzGraph probe
Type code: AzGraph
This probe runs a Kusto query on Azure resource graph.
Implementation properties
Implementation part of the probe definition contains the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| query | Required | String | Kusto query |
Use at-sign '@' to ember parameters into the query string.
Example
The following qprobe return @name for a resource with resource id equal to parameter @resId.
...
"implementation": {
"query": "Resources | where id =~ @resId | project name"
}
...Samples Manage Sql Assessment Api Docs Reference Probes AzMetadataProbe (`samples/manage/sql-assessment-api/docs/Reference/Probes/AzMetadataProbe.md`)
AzMetadata probe
Type code: AzMetadata
Azure metadata probe returns data which can be retrieved by Azure Instance Metadata Service. IMDS returns data as a JSON object. AzMetadata probe retrieves data by JSONPath.
When assessment is running remotely and Azure Graph is available, IMDS is emulated with a Kusto query.
Implementation properties
Implementation part of the probe definition contains the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| query | Required | String | JSONPath to the data to retrieve |
Samples Manage Sql Assessment Api Docs Reference Probes CMDShellProbes (`samples/manage/sql-assessment-api/docs/Reference/Probes/CMDShellProbes.md`)
CMD shell probe
Type code: CMD
CmdShell probes execute CMD.EXE shell commands and return text lines in the @stdout variable.
How to use
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| command | Required | string | Shell command to execute |
Each line returned by the command it returned as separate data row with a single @stdout column. Use the Regex parser transformation to extract data from the @stdout variable.
Example
The following probe lists file system entries in the current directory:
{
"type": "CmdShell",
"target": …,
"implementation": {
"command": "dir"
}
}Output:
| Row | @stdout |
|---|---|
| 0 | "03/18/2017 06:52 AM <DIR> UV" |
| 1 | "03/18/2017 06:52 AM <DIR> UV-FOGRA" |
| 2 | "03/16/2017 03:21 PM 6,419 x3dom.css" |
| 3 | "03/16/2017 03:21 PM 926,910 x3dom.js" |
Samples Manage Sql Assessment Api Docs Reference Probes ExternalProbe (`samples/manage/sql-assessment-api/docs/Reference/Probes/ExternalProbe.md`)
External probe
Type code: External
External probe type allows running external code as probe. This probe can call any external .NET class implementing Microsoft.SqlServer.Management.Assessment.IProbeImplementation interface.
Implementation properties
Implementation part of the probe definition contains the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| class | Required | string | The name of the class implementing IProbeImplementation |
|
| assembly | Optional | string | SQL Assessment API engine assembly | Path to an assembly file containing class. If not specified the engine will look for an internal class with the specified name. |
IProbeImplmenetation interface
The IProbeImplementation interface has the following properties. The engine sets their values so the probe implementation could have optional parameters and information about the assessed SQL Server instance or database.
| Property | Type | Description |
|---|---|---|
| ServerName | string | The name of the target server |
| TargetName | string | The name of the assessed instance or the database |
| Urn | string | A string identifier of the target object |
| Parameters | dictionary | A dictionary containing named parameters passed to the probe from the calling check |
After setting all the IProbeImplementation properties the engine calls GetDataAsync method to retrieve all the data.
Samples Manage Sql Assessment Api Docs Reference Probes Performance (`samples/manage/sql-assessment-api/docs/Reference/Probes/Performance.md`)
Performance probe
Type code: Performance
Performance probe returns values for performance counters. This probe is meant to be used with performance transform.
Implementation properties
Implementation part of the probe definition contains the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| numberOfSamples | Optional | number | 2 | Number of samples taken |
| interval | Optional | number | 1 | Time interval between samples in seconds |
| counters | Required | object | The list of performance counters |
Performance counters list
The list of performance counters is represented by a JSON object. Each property is for performance objects, e.g. 'Latches', 'Databases', 'Buffer Manager'. Each performance object has a JSON object, where each property represents a performance counter.
Counter names often contain spaces and other non-alphanumeric characters. That is why each counter must have an alias. Counter alias is the name which will be used in check conditions and messages.
Optionally, counter may have a list of specific instances of interest.
In the following example the probe retrieves 'Page Allocated/sec' metric for 'Access Methods' and returns samples as page_allocated values.
{
"type": "Performance",
"implementation": {
"Counters": {
"Access Methods": {
"Pages Allocated/sec": "pages_allocated"
}
}
}
}In the next example the probe takes only one sample for 'Free Node memory (KB)'.
{
"type": "Performance",
"implementation": {
"NumberOfSamples": 1,
"Counters": {
"Memory Node": {
"Free Node Memory (KB)": "free_node_memory"
}
}
}
}In the third example the probe returns data for two performance objects 'Memory Node' and 'Access Methods'. For the 'Free Node Memory (KB)' counter it returns data for '000' instance only.
{
"type": "Performance",
"implementation": {
"NumberOfSamples": 1,
"Counters": {
"Memory Node": {
"Free Node Memory (KB)": {
"alias": "free_node_memory",
"instances": ["000"]
},
"Target Node Memory (KB)": "target_node_memory"
},
"Access Methods": {
"Pages Allocated/sec": "pages_allocated"
}
}
}
}Example ruleset
The following JSON object represents a complete rule set using performance counters.
/* Detailed source-code truncated for AI context efficiency. */How to use multiple performance counters in a single check
While using multiple performance counters for different instances an issue the results might not look as expected. Take a look at the following example.
"probes": [
{
"id": "PerformanceProbe",
"alias": "b",
"transform": {
"type": "performance",
"counters": {
"batch_request_sec": "rate",
"lock_requests_sec": {
"type": "rate",
"instance": "_Total"
}
}
}
}
]The code worked as expected. The data transform returned two rows of data from the Performance probe:
| batch_request_sec | lock_requests_sec | instance_name |
|---|---|---|
| 123s | null | ‘’ no instance selected |
| Null | 456s | ‘_Total’ |
The condition is checked once per row and triggers a message for the first one and an error for another.
The following JSON illustrates a solution. The Performance probe is referenced twice. The first reference gets batch_request_sec rate. The second one gets lock_requests_sec rate for the _Total instance. Note aliases associated with each probe reference.
"probes": [
{
"id": "PerformanceProbe",
"alias": "b",
"transform": {
"type": "performance",
"counters": {
"batch_request_sec": "rate"
}
}
},
{
"id": "PerformanceProbe",
"alias": "l",
"transform": {
"type": "performance",
"counters": {
"lock_requests_sec": {
"type": "rate",
"instance": "_Total"
}
}
}
}
]Alias is any alternative name for the probe. Any data variable may be prefixed with an alias or a probe id. E.g. the following names refer to the same value in an unambiguous case:
@PerformanceProbe::batch_request_sec
@b::batch_request_sec
@batch_request_secThose two probe references result in the following data passed to the check:
| b::batch_request_sec | b::instance_name | l::lock_requests_sec | l::instance_name |
|---|---|---|---|
| 123s | ‘’ no instance | 456s | ‘_Total’ |
Samples Manage Sql Assessment Api Docs Reference Probes PowerShellProbes (`samples/manage/sql-assessment-api/docs/Reference/Probes/PowerShellProbes.md`)
PowerShell probe
Type code: PowerShell
PowerShell probes execute commands in PowerShell (fx) on the target machine and return the pipeline output in the @Output variable.
Implementation parameters
PowerShell probe implementation has the following parameters:
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| command | Required | string | PowerShell command to execute |
Use the $ (dollar) sign in the command text to access probe parameters passed by checks.
Use the . (dot) notation to access the object properties. For example, if the returned object is a string, then @Output.Length returns its length.
NOTE: Pipeline output is not shown on the screen. For example, the Write-Host output is ignored.
Example
The following probe enumerates file system items in the current dirrectory:
{
"type": "PowerShell",
"target": …,
"implementation": {
"command": 'Get-ChildItem'
}
}Output:
| @Output | @Output.FullName | @Output.Parent.Name |
|---|---|---|
| "UV" | "C:\Windows\system32\UV" | "system32" |
| "UV-FOGRA" | "C:\Windows\system32\UV-FOGRA" | "system32" |
| "x3dom.css" | "C:\Windows\system32\x3dom.css" | "system32" |
| "x3dom.js" | "C:\Windows\system32\x3dom.js" | "system32" |
Samples Manage Sql Assessment Api Docs Reference Probes RegistryProbes (`samples/manage/sql-assessment-api/docs/Reference/Probes/RegistryProbes.md`)
Registry probe
Type code: Registry
Registry probes obtain data from the target machine registry.
Implementation parameters
Registry probe implementation has the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| query | Required | object | Tree-like structure specifying Registry keys and values to collect see Registry query | |
| instance | Optional | bool | false | Indicates whether the probe should return data specific to this SQL Server instance see Instance specific data |
Registry query
Registry query is a complex JSON object.
Top-level properties represent registry hives including HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER.
Each top-level property value is another JSON object. Its properties represent registry keys. The property name is the full path from the hive to the key.
Use the * (asterisk) symbol at any level to enumerate all keys. The key name replacing * will be returned in @RegistryKeyName variable.
The value for each key property is an array of registry value names to read. Multi-string values are read as multiple string values with the same name.
Instance specific data
When instance property is true, the probe replaces MSSQLSERVER in paths with registry path specific for this SQL Server instance. E.g. the following registry path:
Software\Microsoft\MSSQLSERVER\SQLServerAgentwill be replace with the following instance-specific one:
Software\Microsoft\Microsoft SQL Server\MSSQL12.SQL2014\SQLServerAgentwhere MSSQL12.SQL2014 is the SQL Server instance name.
Example 1
The following registry query returns 2 values for for system hardware. Please, note how multi-string value is handled as multiple strings. Use join aggregate function to merge them when needed.
"probes": {
"MuRegistryProbe": [
{
"type": "Registry",
"target": { "type": "Server" },
"implementation": {
"query": {
"HKEY_LOCAL_MACHINE":{
"HARDWARE\\DESCRIPTION\\System": [
"Identifier",
"SystemBiosVersion"
]
}
}
}
}
]
}Output:
| @Identifier | @SystemBiosVersion |
|---|---|
| "AT/AT COMPATIBLE" | "ALASKA - 1072009" |
| "AT/AT COMPATIBLE" | "3802" |
| "AT/AT COMPATIBLE" | "American Megatrends - 5000C" |
Example 2
Use asterisk '*' to enumerate all subkeys of the given key. The following registry query returns processor id and an identifier of its vendor:
{
"type": "Registry",
"target": { "type": "Server" },
"implementation": {
"query": {
"HKEY_LOCAL_MACHINE":{
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\*": [
"VendorIdentifier"
]
}
}
}
}Output:
| @RegistryKeyName | @VendorIdentifier |
|---|---|
| 0 | "Genuine Intel" |
| 1 | "Genuine Intel" |
| 2 | "Genuine Intel" |
| 3 | "Genuine Intel" |
Example 3
The following registry query gets an identifier for each hardware item.
{
"HKEY_LOCAL_MACHINE": {
"HARDWARE\\DESCRIPTION\\*": [
"Identifier"
]
}
}Example 4
Use at-sign '@' to insert probe parameters int the registry query. The following check gets two registry keys HKEY_LOCAL_MACHINE\SOFTWARE\Policies\test and HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\some\test, and compares each to the 'result' string.
"rules": [
{
"id": "MyKeys",
"itemType": "definition",
"target": {
"type": "Server",
"platform": "Windows"
},
"displayName": "My custom keys",
"message": "The current key is @{test}",
"testParam": "test",
"resultParam": "result",
"hiveParam": "Policies",
"condition": {
"@test": "@resultParam"
},
"probes": [
{
"id": "myprobe",
"params": {
"hiveParam": "@hiveParam",
"testParam": "@testParam"
}
}
]
}
],
"probes": {
"myprobe": [
{
"type": "Registry",
"target": {
"type": "Server",
"platform": "Windows",
"instance": true
},
"implementation": {
"query": {
"HKEY_LOCAL_MACHINE": {
"SOFTWARE\\@{hiveParam}": [ "@{testParam}" ],
"SOFTWARE\\@{hiveParam}\\Microsoft\\some": [ "@{testParam}" ]
}
}
}
}
]
}Samples Manage Sql Assessment Api Docs Reference Probes TSQLProbes (`samples/manage/sql-assessment-api/docs/Reference/Probes/TSQLProbes.md`)
SQL probe
Type code: SQL
T-SQL probes are based on T-SQL queries used to retrieve data from the specified databases for further assessment of your environment.
Implementation properties
Implementation part of the probe definition contains the following parameters.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| query | Required | String | T-SQL query | |
| UseDatabase | Optional | Bool | false | Indicates whether USE DATABASE statement should be issued before running the query. use for probes targeted to databases |
| timeout | Optional | Number | 30 | Sets command execution timeout in seconds |
Example
{
"type": "SQL",
"target": {
"type": "Server",
"engineEdition": "OnPremises",
"platform": "Linux",
"version": "[11.0,)"
},
"implementation": {
"query": "SELECT [host_platform] AS [host_platform] ,[host_release] AS [host_release] ,64 AS [host_architecture] FROM sys.dm_os_host_info(NOLOCK)",
"transform": {
"type": "parse",
"map": {
"host_release": "/^(?<major>\\d+)\\.(?<minor>\\d+)(?:\\.(?<build>\\d+))?(?:\\.(?<revision>\\d+))?$/x"
}
}
}
}Samples Manage Sql Assessment Api Docs Reference Probes WMIProbes (`samples/manage/sql-assessment-api/docs/Reference/Probes/WMIProbes.md`)
WMI probe
Type code: WMI
WMI probes run WMI queries.
A WMI query returns a number of WMI objects. Each object is processed as a separate row. @Output variable represents the object. Use dot notation to access object's properties: @Output.BlockSize.
Implementation properties
Implementation part has the following properties.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| query | Required | String | WMI query returning probe data | |
| methods | Optional | Map | List of WMI methods to be called on selected WMI objects |
WMI methods
To call a WMI method mention its name as a property value of the methods JSON object. The property's name is one for the variable where the result will be stored. In Example 3 the @da variable stores the value returned from the DefragAnalysis method.
Examples
Example 1
Simple WMI probe returns name and block size for volumes.
{
"type": "WMI",
"target": …,
"implementation": {
"query": "SELECT Name, BlockSize FROM Win32_Volume WHERE Capacity <> NULL"
}
}Output:
| @Output.Name | @Output.BlockSize |
|---|---|
| E:\ | 4096 |
| C:\ | 4096 |
| \?\Volume{b9878a89-2e73-4790-8576-9c8217b2fba7}\ | 4096 |
| M:\ | 4096 |
| G:\ | 4096 |
| R:\ | 4096 |
| \?\Volume{41c4c545-aad7-4a8c-86e5-11a52611a81d}\ | 1024 |
Example 2
Use the $ (dollar) sign to access probe parameters passed by checks.
{
"type": "WMI",
"target": {
"type": "Server",
"platform": "Windows",
"engineEdition": "OnPremises",
"version": "[11.0,)"
},
"implementation": {
"query": "SELECT Name, StartingOffset FROM Win32_DiskPartition WHERE StartingOffset < $threshold"
}
}Example 3
Call a WMI method opn each WMI object returned by a WMI query.
{
"type": "WMI",
"target": {
"type": "Server",
"platform": "Windows",
"engineEdition": "OnPremises",
"version": "[11.0,)"
},
"implementation": {
"query": "SELECT DeviceID, Name FROM Win32_Volume WHERE DriveType=3 AND Name LIKE '_:\\\\'",
"methods": {
"da": "DefragAnalysis"
}
}
}Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Index (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/index.rst`)
Mockery
Mockery is a simple yet flexible PHP mock object framework for use in unit
testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is
to offer a test double framework with a succinct API capable of clearly
defining all possible object operations and interactions using a human
readable Domain Specific Language (DSL). Designed as a drop in alternative to
PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with
PHPUnit and can operate alongside phpunit-mock-objects without the World
ending.
Mock Objects
In unit tests, mock objects simulate the behaviour of real objects. They are
commonly utilised to offer test isolation, to stand in for objects which do
not yet exist, or to allow for the exploratory design of class APIs without
requiring actual implementation up front.
The benefits of a mock object framework are to allow for the flexible
generation of such mock objects (and stubs). They allow the setting of
expected method calls and return values using a flexible API which is capable
of capturing every possible real object behaviour in way that is stated as
close as possible to a natural language description.
Getting Started
Ready to dive into the Mockery framework? Then you can get started by reading
the "Getting Started" section!
.. toctree::
:hidden:
getting_started/index.. include:: getting_started/map.rst.inc
Reference
The reference contains a complete overview of all features of the Mockery
framework.
.. toctree::
:hidden:
reference/index.. include:: reference/map.rst.inc
Cookbook
Want to learn some easy tips and tricks? Take a look at the cookbook articles!
.. toctree::
:hidden:
cookbook/index.. include:: cookbook/map.rst.inc
Samples Development Frameworks Laravel Vendor Monolog Monolog Doc 01 Usage (`samples/development-frameworks/laravel/vendor/monolog/monolog/doc/01-usage.md`)
Using Monolog
- Installation
- Core Concepts
- Log Levels
- Configuring a logger
- Adding extra data in the records
- Leveraging channels
- Customizing the log format
Installation
Monolog is available on Packagist (monolog/monolog)
and as such installable via Composer.
composer require monolog/monologIf you do not use Composer, you can grab the code from GitHub, and use any
PSR-0 compatible autoloader (e.g. the Symfony2 ClassLoader component)
to load Monolog classes.
Core Concepts
Every Logger instance has a channel (name) and a stack of handlers. Whenever
you add a record to the logger, it traverses the handler stack. Each handler
decides whether it fully handled the record, and if so, the propagation of the
record ends there.
This allows for flexible logging setups, for example having a StreamHandler at
the bottom of the stack that will log anything to disk, and on top of that add
a MailHandler that will send emails only when an error message is logged.
Handlers also have a $bubble property which defines whether they block the
record or not if they handled it. In this example, setting the MailHandler's$bubble argument to false means that records handled by the MailHandler will
not propagate to the StreamHandler anymore.
You can create many Loggers, each defining a channel (e.g.: db, request,
router, ..) and each of them combining various handlers, which can be shared
or not. The channel is reflected in the logs and allows you to easily see or
filter records.
Each Handler also has a Formatter, a default one with settings that make sense
will be created if you don't set one. The formatters normalize and format
incoming records so that they can be used by the handlers to output useful
information.
Custom severity levels are not available. Only the eight
RFC 5424 levels (debug, info, notice,
warning, error, critical, alert, emergency) are present for basic filtering
purposes, but for sorting and other use cases that would require
flexibility, you should add Processors to the Logger that can add extra
information (tags, user ip, ..) to the records before they are handled.
Log Levels
Monolog supports the logging levels described by RFC 5424.
DEBUG (100): Detailed debug information.
INFO (200): Interesting events. Examples: User logs in, SQL logs.
NOTICE (250): Normal but significant events.
WARNING (300): Exceptional occurrences that are not errors. Examples:
Use of deprecated APIs, poor use of an API, undesirable things that are not
necessarily wrong.ERROR (400): Runtime errors that do not require immediate action but
should typically be logged and monitored.CRITICAL (500): Critical conditions. Example: Application component
unavailable, unexpected exception.ALERT (550): Action must be taken immediately. Example: Entire website
down, database unavailable, etc. This should trigger the SMS alerts and wake
you up.EMERGENCY (600): Emergency: system is unusable.
Configuring a logger
Here is a basic setup to log to a file and to firephp on the DEBUG level:
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
// Create the logger
$logger = new Logger('my_logger');
// Now add some handlers
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
// You can now use your logger
$logger->addInfo('My logger is now ready');Let's explain it. The first step is to create the logger instance which will
be used in your code. The argument is a channel name, which is useful when
you use several loggers (see below for more details about it).
The logger itself does not know how to handle a record. It delegates it to
some handlers. The code above registers two handlers in the stack to allow
handling records in two different ways.
Note that the FirePHPHandler is called first as it is added on top of the
stack. This allows you to temporarily add a logger with bubbling disabled if
you want to override other configured loggers.
If you use Monolog standalone and are looking for an easy way to
configure many handlers, the theorchard/monolog-cascade
can help you build complex logging configs via PHP arrays, yaml or json configs.
Adding extra data in the records
Monolog provides two different ways to add extra informations along the simple
textual message.
Using the logging context
The first way is the context, allowing to pass an array of data along the
record:
<?php
$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));Simple handlers (like the StreamHandler for instance) will simply format
the array to a string but richer handlers can take advantage of the context
(FirePHP is able to display arrays in pretty way for instance).
Using processors
The second way is to add extra data for all records by using a processor.
Processors can be any callable. They will get the record as parameter and
must return it after having eventually changed the extra part of it. Let's
write a processor adding some dummy data in the record:
<?php
$logger->pushProcessor(function ($record) {
$record['extra']['dummy'] = 'Hello world!';
return $record;
});Monolog provides some built-in processors that can be used in your project.
Look at the dedicated chapter for the list.
Tip: processors can also be registered on a specific handler instead of
the logger to apply only for this handler.
Leveraging channels
Channels are a great way to identify to which part of the application a record
is related. This is useful in big applications (and is leveraged by
MonologBundle in Symfony2).
Picture two loggers sharing a handler that writes to a single log file.
Channels would allow you to identify the logger that issued every record.
You can easily grep through the log files filtering this or that channel.
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
// Create some handlers
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();
// Create the main logger of the app
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);
// Create a logger for the security-related stuff with a different channel
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);Customizing the log format
In Monolog it's easy to customize the format of the logs written into files,
sockets, mails, databases and other handlers. Most of the handlers use the
$record['formatted']value to be automatically put into the log device. This value depends on the
formatter settings. You can choose between predefined formatter classes or
write your own (e.g. a multiline text file for human-readable output).
To configure a predefined formatter class, just set it as the handler's field:
// the default date format is "Y-m-d H:i:s"
$dateFormat = "Y n j, g:i a";
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
// finally, create a formatter
$formatter = new LineFormatter($output, $dateFormat);
// Create a handler
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$stream->setFormatter($formatter);
// bind it to a logger object
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);You may also reuse the same formatter between multiple handlers and share those
handlers between multiple loggers.
Handlers, Formatters and Processors →
Samples Development Frameworks Laravel Vendor Monolog Monolog Doc 02 Handlers Formatters Processors (`samples/development-frameworks/laravel/vendor/monolog/monolog/doc/02-handlers-formatters-processors.md`)
Handlers, Formatters and Processors
Handlers
Log to files and syslog
- StreamHandler: Logs records into any PHP stream, use this for log files.
- RotatingFileHandler: Logs records to a file and creates one logfile per day.
It will also delete files older than$maxFiles. You should use
logrotate for high profile
setups though, this is just meant as a quick and dirty solution. - SyslogHandler: Logs records to the syslog.
- ErrorLogHandler: Logs records to PHP's
error_log()function.
Send alerts and emails
- NativeMailerHandler: Sends emails using PHP's
mail()function. - SwiftMailerHandler: Sends emails using a
Swift_Mailerinstance. - PushoverHandler: Sends mobile notifications via the Pushover API.
- HipChatHandler: Logs records to a HipChat chat room using its API.
- FlowdockHandler: Logs records to a Flowdock account.
- SlackHandler: Logs records to a Slack account.
- MandrillHandler: Sends emails via the Mandrill API using a
Swift_Messageinstance. - FleepHookHandler: Logs records to a Fleep conversation using Webhooks.
- IFTTTHandler: Notifies an IFTTT trigger with the log channel, level name and message.
Log specific servers and networked logging
- SocketHandler: Logs records to sockets, use this
for UNIX and TCP sockets. See an example. - AmqpHandler: Logs records to an amqp compatible
server. Requires the php-amqp extension (1.0+). - GelfHandler: Logs records to a Graylog2 server.
- CubeHandler: Logs records to a Cube server.
- RavenHandler: Logs records to a Sentry server using
raven. - ZendMonitorHandler: Logs records to the Zend Monitor present in Zend Server.
- NewRelicHandler: Logs records to a NewRelic application.
- LogglyHandler: Logs records to a Loggly account.
- RollbarHandler: Logs records to a Rollbar account.
- SyslogUdpHandler: Logs records to a remote Syslogd server.
- LogEntriesHandler: Logs records to a LogEntries account.
Logging in development
- FirePHPHandler: Handler for FirePHP, providing
inlineconsolemessages within FireBug. - ChromePHPHandler: Handler for ChromePHP, providing
inlineconsolemessages within Chrome. - BrowserConsoleHandler: Handler to send logs to browser's Javascript
consolewith
no browser extension required. Most browsers supportingconsoleAPI are supported. - PHPConsoleHandler: Handler for PHP Console, providing
inlineconsoleand notification popup messages within Chrome.
Log to databases
- RedisHandler: Logs records to a redis server.
- MongoDBHandler: Handler to write records in MongoDB via a
Mongo extension connection. - CouchDBHandler: Logs records to a CouchDB server.
- DoctrineCouchDBHandler: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
- ElasticSearchHandler: Logs records to an Elastic Search server.
- DynamoDbHandler: Logs records to a DynamoDB table with the AWS SDK.
Wrappers / Special Handlers
- FingersCrossedHandler: A very interesting wrapper. It takes a logger as
parameter and will accumulate log records of all levels until a record
exceeds the defined severity level. At which point it delivers all records,
including those of lower severity, to the handler it wraps. This means that
until an error actually happens you will not see anything in your logs, but
when it happens you will have the full information, including debug and info
records. This provides you with all the information you need, but only when
you need it. - WhatFailureGroupHandler: This handler extends the GroupHandler ignoring
exceptions raised by each child handler. This allows you to ignore issues
where a remote tcp connection may have died but you do not want your entire
application to crash and may wish to continue to log to other handlers. - BufferHandler: This handler will buffer all the log records it receives
untilclose()is called at which point it will callhandleBatch()on the
handler it wraps with all the log messages at once. This is very useful to
send an email with all records at once for example instead of having one mail
for every log record. - GroupHandler: This handler groups other handlers. Every record received is
sent to all the handlers it is configured with. - FilterHandler: This handler only lets records of the given levels through
to the wrapped handler. - SamplingHandler: Wraps around another handler and lets you sample records
if you only want to store some of them. - NullHandler: Any record it can handle will be thrown away. This can be used
to put on top of an existing handler stack to disable it temporarily. - PsrHandler: Can be used to forward log records to an existing PSR-3 logger
- TestHandler: Used for testing, it records everything that is sent to it and
has accessors to read out the information.
Formatters
- LineFormatter: Formats a log record into a one-line string.
- HtmlFormatter: Used to format log records into a human readable html table, mainly suitable for emails.
- NormalizerFormatter: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
- ScalarFormatter: Used to format log records into an associative array of scalar values.
- JsonFormatter: Encodes a log record into json.
- WildfireFormatter: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
- ChromePHPFormatter: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
- GelfMessageFormatter: Used to format log records into Gelf message instances, only useful for the GelfHandler.
- LogstashFormatter: Used to format log records into logstash event json, useful for any handler listed under inputs here.
- ElasticaFormatter: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
- LogglyFormatter: Used to format log records into Loggly messages, only useful for the LogglyHandler.
- FlowdockFormatter: Used to format log records into Flowdock messages, only useful for the FlowdockHandler.
- MongoDBFormatter: Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler.
Processors
- IntrospectionProcessor: Adds the line/file/class/method from which the log call originated.
- WebProcessor: Adds the current request URI, request method and client IP to a log record.
- MemoryUsageProcessor: Adds the current memory usage to a log record.
- MemoryPeakUsageProcessor: Adds the peak memory usage to a log record.
- ProcessIdProcessor: Adds the process id to a log record.
- UidProcessor: Adds a unique identifier to a log record.
- GitProcessor: Adds the current git branch and commit to a log record.
- TagProcessor: Adds an array of predefined tags to a log record.
Third Party Packages
Third party handlers, formatters and processors are
listed in the wiki. You
can also add your own there if you publish one.
← Usage | Utility classes →
Samples Development Frameworks Laravel Vendor Monolog Monolog Doc 03 Utilities (`samples/development-frameworks/laravel/vendor/monolog/monolog/doc/03-utilities.md`)
Utilities
- Registry: The
Monolog\Registryclass lets you configure global loggers that you
can then statically access from anywhere. It is not really a best practice but can
help in some older codebases or for ease of use. - ErrorHandler: The
Monolog\ErrorHandlerclass allows you to easily register
a Logger instance as an exception handler, error handler or fatal error handler. - ErrorLevelActivationStrategy: Activates a FingersCrossedHandler when a certain log
level is reached. - ChannelLevelActivationStrategy: Activates a FingersCrossedHandler when a certain
log level is reached, depending on which channel received the log record.
← Handlers, Formatters and Processors | Extending Monolog →
Samples Development Frameworks Laravel Vendor Monolog Monolog Doc 04 Extending (`samples/development-frameworks/laravel/vendor/monolog/monolog/doc/04-extending.md`)
Extending Monolog
Monolog is fully extensible, allowing you to adapt your logger to your needs.
Writing your own handler
Monolog provides many built-in handlers. But if the one you need does not
exist, you can write it and use it in your logger. The only requirement is
to implement Monolog\Handler\HandlerInterface.
Let's write a PDOHandler to log records to a database. We will extend the
abstract class provided by Monolog to keep things DRY.
<?php
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
class PDOHandler extends AbstractProcessingHandler
{
private $initialized = false;
private $pdo;
private $statement;
public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
{
$this->pdo = $pdo;
parent::__construct($level, $bubble);
}
protected function write(array $record)
{
if (!$this->initialized) {
$this->initialize();
}
$this->statement->execute(array(
'channel' => $record['channel'],
'level' => $record['level'],
'message' => $record['formatted'],
'time' => $record['datetime']->format('U'),
));
}
private function initialize()
{
$this->pdo->exec(
'CREATE TABLE IF NOT EXISTS monolog '
.'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
);
$this->statement = $this->pdo->prepare(
'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
);
$this->initialized = true;
}
}You can now use this handler in your logger:
<?php
$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')));
// You can now use your logger
$logger->addInfo('My logger is now ready');The Monolog\Handler\AbstractProcessingHandler class provides most of the
logic needed for the handler, including the use of processors and the formatting
of the record (which is why we use $record['formatted'] instead of $record['message']).
Samples Development Frameworks Laravel Vendor Monolog Monolog Doc Sockets (`samples/development-frameworks/laravel/vendor/monolog/monolog/doc/sockets.md`)
Sockets Handler
This handler allows you to write your logs to sockets using fsockopen
or pfsockopen.
Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening
the connections between requests.
You can use a unix:// prefix to access unix sockets and udp:// to open UDP sockets instead of the default TCP.
Basic Example
<?php
use Monolog\Logger;
use Monolog\Handler\SocketHandler;
// Create the logger
$logger = new Logger('my_logger');
// Create the handler
$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
$handler->setPersistent(true);
// Now add the handler
$logger->pushHandler($handler, Logger::DEBUG);
// You can now use your logger
$logger->addInfo('My logger is now ready');In this example, using syslog-ng, you should see the log on the log server:
cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Headers (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/headers.rst`)
Message Headers
Sometimes you'll want to add your own headers to a message or modify/remove
headers that are already present. You work with the message's HeaderSet to do
this.
Header Basics
All MIME entities in Swift Mailer -- including the message itself --
store their headers in a single object called a HeaderSet. This HeaderSet is
retrieved with the getHeaders() method.
As mentioned in the previous chapter, everything that forms a part of a message
in Swift Mailer is a MIME entity that is represented by an instance ofSwift_Mime_MimeEntity. This includes -- most notably -- the message object
itself, attachments, MIME parts and embedded images. Each of these MIME entities
consists of a body and a set of headers that describe the body.
For all of the "standard" headers in these MIME entities, such as theContent-Type, there are named methods for working with them, such assetContentType() and getContentType(). This is because headers are a
moderately complex area of the library. Each header has a slightly different
required structure that it must meet in order to comply with the standards that
govern email (and that are checked by spam blockers etc).
You fetch the HeaderSet from a MIME entity like so:
.. code-block:: php
$message = Swift_Message::newInstance();
// Fetch the HeaderSet from a Message object
$headers = $message->getHeaders();
$attachment = Swift_Attachment::fromPath('document.pdf');
// Fetch the HeaderSet from an attachment object
$headers = $attachment->getHeaders();The job of the HeaderSet is to contain and manage instances of Header objects.
Depending upon the MIME entity the HeaderSet came from, the contents of the
HeaderSet will be different, since an attachment for example has a different
set of headers to those in a message.
You can find out what the HeaderSet contains with a quick loop, dumping out
the names of the headers:
.. code-block:: php
foreach ($headers->getAll() as $header) {
printf("%s\n", $header->getFieldName());
}
/*
Content-Transfer-Encoding
Content-Type
MIME-Version
Date
Message-ID
From
Subject
To
*/You can also dump out the rendered HeaderSet by calling its toString()
method:
.. code-block:: php
echo $headers->toString();
/*
Message-ID: <[email protected]>
Date: Tue, 17 Feb 2009 22:26:31 +1100
Subject: Awesome subject!
From: [email protected]
To: [email protected]
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
*/Where the complexity comes in is when you want to modify an existing header.
This complexity comes from the fact that each header can be of a slightly
different type (such as a Date header, or a header that contains email
addresses, or a header that has key-value parameters on it!). Each header in the
HeaderSet is an instance of Swift_Mime_Header. They all have common
functionality, but knowing exactly what type of header you're working with will
allow you a little more control.
You can determine the type of header by comparing the return value of itsgetFieldType() method with the constants TYPE_TEXT,TYPE_PARAMETERIZED, TYPE_DATE, TYPE_MAILBOX, TYPE_ID andTYPE_PATH which are defined in Swift_Mime_Header.
.. code-block:: php
foreach ($headers->getAll() as $header) {
switch ($header->getFieldType()) {
case Swift_Mime_Header::TYPE_TEXT: $type = 'text';
break;
case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized';
break;
case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox';
break;
case Swift_Mime_Header::TYPE_DATE: $type = 'date';
break;
case Swift_Mime_Header::TYPE_ID: $type = 'ID';
break;
case Swift_Mime_Header::TYPE_PATH: $type = 'path';
break;
}
printf("%s: is a %s header\n", $header->getFieldName(), $type);
}
/*
Content-Transfer-Encoding: is a text header
Content-Type: is a parameterized header
MIME-Version: is a text header
Date: is a date header
Message-ID: is a ID header
From: is a mailbox header
Subject: is a text header
To: is a mailbox header
*/Headers can be removed from the set, modified within the set, or added to the
set.
The following sections show you how to work with the HeaderSet and explain the
details of each implementation of Swift_Mime_Header that may
exist within the HeaderSet.
Header Types
Because all headers are modeled on different data (dates, addresses, text!)
there are different types of Header in Swift Mailer. Swift Mailer attempts to
categorize all possible MIME headers into more general groups, defined by a
small number of classes.
Text Headers
Text headers are the simplest type of Header. They contain textual information
with no special information included within it -- for example the Subject
header in a message.
There's nothing particularly interesting about a text header, though it is
probably the one you'd opt to use if you need to add a custom header to a
message. It represents text just like you'd think it does. If the text
contains characters that are not permitted in a message header (such as new
lines, or non-ascii characters) then the header takes care of encoding the
text so that it can be used.
No header -- including text headers -- in Swift Mailer is vulnerable to
header-injection attacks. Swift Mailer breaks any attempt at header injection by
encoding the dangerous data into a non-dangerous form.
It's easy to add a new text header to a HeaderSet. You do this by calling the
HeaderSet's ``addTextHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addTextHeader('Your-Header-Name', 'the header value');
Changing the value of an existing text header is done by calling it's
``setValue()`` method.
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('new subject');
When output via ``toString()``, a text header produces something like the
following:
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('amazing subject line');
echo $subject->toString();
/*
Subject: amazing subject line
*/
If the header contains any characters that are outside of the US-ASCII range
however, they will be encoded. This is nothing to be concerned about since
mail clients will decode them back.
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('contains – dash');
echo $subject->toString();
/*
Subject: contains =?utf-8?Q?=E2=80=93?= dash
*/
Parameterized HeadersParameterized headers are text headers that contain key-value parameters
following the textual content. The Content-Type header of a message is a
parameterized header since it contains charset information after the content
type.
The parameterized header type is a special type of text header. It extends the
text header by allowing additional information to follow it. All of the methods
from text headers are available in addition to the methods described here.
Adding a parameterized header to a HeaderSet is done by using theaddParameterizedHeader() method which takes a text value likeaddTextHeader() but it also accepts an associative array of
key-value parameters.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addParameterizedHeader(
'Header-Name', 'header value',
array('foo' => 'bar')
);To change the text value of the header, call it's setValue() method just as
you do with text headers.
To change the parameters in the header, call the header's setParameters()
method or the setParameter() method (note the pluralization).
.. code-block:: php
$type = $message->getHeaders()->get('Content-Type');
// setParameters() takes an associative array
$type->setParameters(array(
'name' => 'file.txt',
'charset' => 'iso-8859-1'
));
// setParameter() takes two args for $key and $value
$type->setParameter('charset', 'iso-8859-1');When output via toString(), a parameterized header produces something like
the following:
.. code-block:: php
$type = $message->getHeaders()->get('Content-Type');
$type->setValue('text/html');
$type->setParameter('charset', 'utf-8');
echo $type->toString();
/*
Content-Type: text/html; charset=utf-8
*/If the header contains any characters that are outside of the US-ASCII range
however, they will be encoded, just like they are for text headers. This is
nothing to be concerned about since mail clients will decode them back.
Likewise, if the parameters contain any non-ascii characters they will be
encoded so that they can be transmitted safely.
.. code-block:: php
$attachment = Swift_Attachment::newInstance();
$disp = $attachment->getHeaders()->get('Content-Disposition');
$disp->setValue('attachment');
$disp->setParameter('filename', 'report–may.pdf');
echo $disp->toString();
/*
Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf
*/Date Headers
Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')``
returns). They are used anywhere a date or time is needed to be presented as a
message header.
The data on which a date header is modeled is simply a UNIX timestamp such as
that returned by ``time()`` or ``strtotime()``. The timestamp is used to create
a correctly structured RFC 2822 formatted date such as
``Tue, 17 Feb 2009 22:26:31 +1100``.
The obvious place this header type is used is in the ``Date:`` header of the
message itself.
It's easy to add a new date header to a HeaderSet. You do this by calling
the HeaderSet's ``addDateHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addDateHeader('Your-Header-Name', strtotime('3 days ago'));
Changing the value of an existing date header is done by calling it's
``setTimestamp()`` method.
.. code-block:: php
$date = $message->getHeaders()->get('Date');
$date->setTimestamp(time());
When output via ``toString()``, a date header produces something like the
following:
.. code-block:: php
$date = $message->getHeaders()->get('Date');
echo $date->toString();
/*
Date: Wed, 18 Feb 2009 13:35:02 +1100
*/
Mailbox (e-mail address) HeadersMailbox headers contain one or more email addresses, possibly with
personalized names attached to them. The data on which they are modeled is
represented by an associative array of email addresses and names.
Mailbox headers are probably the most complex header type to understand in
Swift Mailer because they accept their input as an array which can take various
forms, as described in the previous chapter.
All of the headers that contain e-mail addresses in a message -- with the
exception of Return-Path: which has a stricter syntax -- use this header
type. That is, To:, From: etc.
You add a new mailbox header to a HeaderSet by calling the HeaderSet'saddMailboxHeader() method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addMailboxHeader('Your-Header-Name', array(
'[email protected]' => 'Person Name One',
'[email protected]',
'[email protected]',
'[email protected]' => 'Another named person'
));Changing the value of an existing mailbox header is done by calling it'ssetNameAddresses() method.
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setNameAddresses(array(
'[email protected]' => 'Joe Bloggs',
'[email protected]' => 'John Doe',
'[email protected]'
));If you don't wish to concern yourself with the complicated accepted input
formats accepted by setNameAddresses() as described in the previous chapter
and you only want to set one or more addresses (not names) then you can just
use the setAddresses() method instead.
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setAddresses(array(
'[email protected]',
'[email protected]',
'[email protected]'
));.. note::
Both methods will accept the above input format in practice.If all you want to do is set a single address in the header, you can use a
string as the input parameter to setAddresses() and/orsetNameAddresses().
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setAddresses('[email protected]');When output via toString(), a mailbox header produces something like the
following:
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setNameAddresses(array(
'[email protected]' => 'Name of Person',
'[email protected]',
'[email protected]' => 'Another Person'
));
echo $to->toString();
/*
To: Name of Person <[email protected]>, [email protected], Another Person
<[email protected]>
*/ID Headers
ID headers contain identifiers for the entity (or the message). The most
notable ID header is the Message-ID header on the message itself.
An ID that exists inside an ID header looks more-or-less less like an email
address. For example, ``<[email protected]>``.
The part to the left of the @ sign is usually unique, based on the current time
and some random factor. The part on the right is usually a domain name.
Any ID passed to the header's ``setId()`` method absolutely MUST conform to
this structure, otherwise you'll get an Exception thrown at you by Swift Mailer
(a ``Swift_RfcComplianceException``). This is to ensure that the generated
email complies with relevant RFC documents and therefore is less likely to be
blocked as spam.
It's easy to add a new ID header to a HeaderSet. You do this by calling
the HeaderSet's ``addIdHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addIdHeader('Your-Header-Name', '[email protected]');
Changing the value of an existing date header is done by calling its
``setId()`` method.
.. code-block:: php
$msgId = $message->getHeaders()->get('Message-ID');
$msgId->setId(time() . '.' . uniqid('thing') . '@example.org');
When output via ``toString()``, an ID header produces something like the
following:
.. code-block:: php
$msgId = $message->getHeaders()->get('Message-ID');
echo $msgId->toString();
/*
Message-ID: <[email protected]>
*/
Path HeadersPath headers are like very-restricted mailbox headers. They contain a single
email address with no associated name. The Return-Path header of a message is
a path header.
You add a new path header to a HeaderSet by calling the HeaderSet'saddPathHeader() method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addPathHeader('Your-Header-Name', '[email protected]');Changing the value of an existing path header is done by calling itssetAddress() method.
.. code-block:: php
$return = $message->getHeaders()->get('Return-Path');
$return->setAddress('[email protected]');When output via toString(), a path header produces something like the
following:
.. code-block:: php
$return = $message->getHeaders()->get('Return-Path');
$return->setAddress('[email protected]');
echo $return->toString();
/*
Return-Path:
*/Header Operations
Working with the headers in a message involves knowing how to use the methods
on the HeaderSet and on the individual Headers within the HeaderSet.
Adding new Headers
New headers can be added to the HeaderSet by using one of the provided
``add..Header()`` methods.
To add a header to a MIME entity (such as the message):
Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Add the header to the HeaderSet by calling one of the ``add..Header()``
methods.
The added header will appear in the message when it is sent.
.. code-block:: php
// Adding a custom header to a message
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addTextHeader('X-Mine', 'something here');
// Adding a custom header to an attachment
$attachment = Swift_Attachment::fromPath('/path/to/doc.pdf');
$attachment->getHeaders()->addDateHeader('X-Created-Time', time());
Retrieving HeadersHeaders are retrieved through the HeaderSet's get() and getAll()
methods.
To get a header, or several headers from a MIME entity:
Get the HeaderSet from the entity by via its
getHeaders()method.Get the header(s) from the HeaderSet by calling either
get()orgetAll().
When using get() a single header is returned that matches the name (case
insensitive) that is passed to it. When using getAll() with a header name,
an array of headers with that name are returned. Calling getAll() with no
arguments returns an array of all headers present in the entity.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``getAll()`` exists to fetch all
headers with a specified name. In addition, ``get()`` accepts an optional
numerical index, starting from zero to specify which header you want more
specifically... note::
If you want to modify the contents of the header and you don't know for
sure what type of header it is then you may need to check the type by
calling its ``getFieldType()`` method.
.. code-block:: php
$headers = $message->getHeaders();
// Get the To: header
$toHeader = $headers->get('To');
// Get all headers named "X-Foo"
$fooHeaders = $headers->getAll('X-Foo');
// Get the second header named "X-Foo"
$foo = $headers->get('X-Foo', 1);
// Get all headers that are present
$all = $headers->getAll();Check if a Header Exists
You can check if a named header is present in a HeaderSet by calling its
``has()`` method.
To check if a header exists:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Call the HeaderSet's ``has()`` method specifying the header you're looking
for.
If the header exists, ``true`` will be returned or ``false`` if not.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``has()`` accepts an optional
numerical index, starting from zero to specify which header you want to
check more specifically.
.. code-block:: php
$headers = $message->getHeaders();
// Check if the To: header exists
if ($headers->has('To')) {
echo 'To: exists';
}
// Check if an X-Foo header exists twice (i.e. check for the 2nd one)
if ($headers->has('X-Foo', 1)) {
echo 'Second X-Foo header exists';
}
Removing Headers
~~~~~~~~~~~~~~~~
Removing a Header from the HeaderSet is done by calling the HeaderSet's
``remove()`` or ``removeAll()`` methods.
To remove an existing header:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Call the HeaderSet's ``remove()`` or ``removeAll()`` methods specifying the
header you want to remove.
When calling ``remove()`` a single header will be removed. When calling
``removeAll()`` all headers with the given name will be removed. If no headers
exist with the given name, no errors will occur.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``remove()`` accepts an optional
numerical index, starting from zero to specify which header you want to
check more specifically. For the same reason, ``removeAll()`` exists to
remove all headers that have the given name.
.. code-block:: php
$headers = $message->getHeaders();
// Remove the Subject: header
$headers->remove('Subject');
// Remove all X-Foo headers
$headers->removeAll('X-Foo');
// Remove only the second X-Foo header
$headers->remove('X-Foo', 1);
Modifying a Header's ContentTo change a Header's content you should know what type of header it is and then
call it's appropriate setter method. All headers also have asetFieldBodyModel() method that accepts a mixed parameter and delegates to
the correct setter.
To modify an existing header:
Get the HeaderSet from the entity by via its
getHeaders()method.Get the Header by using the HeaderSet's
get().Call the Header's appropriate setter method or call the header's
setFieldBodyModel()method.
The header will be updated inside the HeaderSet and the changes will be seen
when the message is sent.
.. code-block:: php
$headers = $message->getHeaders();
// Change the Subject: header
$subj = $headers->get('Subject');
$subj->setValue('new subject here');
// Change the To: header
$to = $headers->get('To');
$to->setNameAddresses(array(
'[email protected]' => 'Person',
'[email protected]'
));
// Using the setFieldBodyModel() just delegates to the correct method
// So here to calls setNameAddresses()
$to->setFieldBodyModel(array(
'[email protected]' => 'Person',
'[email protected]'
));Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Help Resources (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/help-resources.rst`)
Getting Help
There are a number of ways you can get help when using Swift Mailer, depending
upon the nature of your problem. For bug reports and feature requests create a
new ticket in GitHub. For general advice ask on the Google Group
(swiftmailer).
Submitting Bugs & Feature Requests
Bugs and feature requests should be posted on GitHub.
If you post a bug or request a feature in the forum, or on the Google Group
you will most likely be asked to create a ticket in GitHub_ since it is
simply not feasible to manage such requests from a number of a different
sources.
When you go to GitHub you will be asked to create a username and password
before you can create a ticket. This is free and takes very little time.
When you create your ticket, do not assign it to any milestones. A developer
will assess your ticket and re-assign it as needed.
If your ticket is reporting a bug present in the current version, which was
not present in the previous version please include the tag "regression" in
your ticket.
GitHub will update you when work is performed on your ticket.
Ask on the Google Group
You can seek advice at Google Groups, within the "swiftmailer" group_.
You can post messages to this group if you want help, or there's something you
wish to discuss with the developers and with other users.
This is probably the fastest way to get help since it is primarily email-based
for most users, though bug reports should not be posted here since they may
not be resolved.
.. _GitHub: https://github.com/swiftmailer/swiftmailer/issues
.. _group: http://groups.google.com/group/swiftmailer
Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Including The Files (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/including-the-files.rst`)
Including Swift Mailer (Autoloading)
If you are using Composer, Swift Mailer will be automatically autoloaded.
If not, you can use the built-in autoloader by requiring theswift_required.php file::
require_once '/path/to/swift-mailer/lib/swift_required.php';
/* rest of code goes here */If you want to override the default Swift Mailer configuration, call theinit() method on the Swift class and pass it a valid PHP callable (a
PHP function name, a PHP 5.3 anonymous function, ...)::
require_once '/path/to/swift-mailer/lib/swift_required.php';
function swiftmailer_configurator() {
// configure Swift Mailer
Swift_DependencyContainer::getInstance()->...
Swift_Preferences::getInstance()->...
}
Swift::init('swiftmailer_configurator');
/* rest of code goes here */The advantage of using the init() method is that your code will be
executed only if you use Swift Mailer in your script.
.. note::
While Swift Mailer's autoloader is designed to play nicely with other
autoloaders, sometimes you may have a need to avoid using Swift Mailer's
autoloader and use your own instead. Include the ``swift_init.php``
instead of the ``swift_required.php`` if you need to do this. The very
minimum include is the ``swift_init.php`` file since Swift Mailer will not
work without the dependency injection this file sets up:
.. code-block:: php
require_once '/path/to/swift-mailer/lib/swift_init.php';
/* rest of code goes here */Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Index (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/index.rst`)
Swiftmailer
.. toctree::
:maxdepth: 2
introduction
overview
installing
help-resources
including-the-files
messages
headers
sending
plugins
japaneseSamples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Installing (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/installing.rst`)
Installing the Library
Installing with Composer
The recommended way to install Swiftmailer is via Composer:
.. code-block:: bash
$ php composer.phar require swiftmailer/swiftmailer @stableInstalling from Git
It's possible to download and install Swift Mailer directly from github.com if
you want to keep up-to-date with ease.
Swift Mailer's source code is kept in a git repository at github.com so you
can get the source directly from the repository.
.. note::
You do not need to have git installed to use Swift Mailer from GitHub. If
you don't have git installed, go to `GitHub`_ and click the "Download"
button.Cloning the Repository
The repository can be cloned from git://github.com/swiftmailer/swiftmailer.git
using the ``git clone`` command.
You will need to have ``git`` installed before you can use the
``git clone`` command.
To clone the repository:
* Open your favorite terminal environment (command line).
* Move to the directory you want to clone to.
* Run the command ``git clone git://github.com/swiftmailer/swiftmailer.git
swiftmailer``.
The source code will be downloaded into a directory called "swiftmailer".
The example shows the process on a UNIX-like system such as Linux, BSD or Mac
OS X.
.. code-block:: bash
$ cd source_code/
$ git clone git://github.com/swiftmailer/swiftmailer.git swiftmailer
Initialized empty Git repository in /Users/chris/source_code/swiftmailer/.git/
remote: Counting objects: 6815, done.
remote: Compressing objects: 100% (2761/2761), done.
remote: Total 6815 (delta 3641), reused 6326 (delta 3286)
Receiving objects: 100% (6815/6815), 4.35 MiB | 162 KiB/s, done.
Resolving deltas: 100% (3641/3641), done.
Checking out files: 100% (1847/1847), done.
$ cd swiftmailer/
$ ls
CHANGES LICENSE ...
$
Troubleshooting
---------------
Swift Mailer does not work when used with function overloading as implemented
by ``mbstring`` (``mbstring.func_overload`` set to ``2``). A workaround is to
temporarily change the internal encoding to ``ASCII`` when sending an email:
.. code-block:: php
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
// Create your message and send it with Swift Mailer
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
.. _`GitHub`: http://github.com/swiftmailer/swiftmailer
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Introduction (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/introduction.rst`)
Introduction
============
Swift Mailer is a component-based library for sending e-mails from PHP
applications.
Organization of this Book
-------------------------
This book has been written so that those who need information quickly are able
to find what they need, and those who wish to learn more advanced topics can
read deeper into each chapter.
The book begins with an overview of Swift Mailer, discussing what's included
in the package and preparing you for the remainder of the book.
It is possible to read this user guide just like any other book (from
beginning to end). Each chapter begins with a discussion of the contents it
contains, followed by a short code sample designed to give you a head start.
As you get further into a chapter you will learn more about Swift Mailer's
capabilities, but often you will be able to head directly to the topic you
wish to learn about.
Throughout this book you will be presented with code samples, which most
people should find ample to implement Swift Mailer appropriately in their own
projects. We will also use diagrams where appropriate, and where we believe
readers may find it helpful we will discuss some related theory, including
reference to certain documents you are able to find online.
Code Samples
------------
Code samples presented in this book will be displayed on a different colored
background in a monospaced font. Samples are not to be taken as copy & paste
code snippets.
Code examples are used through the book to clarify what is written in text.
They will sometimes be usable as-is, but they should always be taken as
outline/pseudo code only.
A code sample will look like this::
class AClass
{
...
}
// A Comment
$obj = new AClass($arg1, $arg2, ... );
/* A note about another way of doing something
$obj = AClass::newInstance($arg1, $arg2, ... );
*/
The presence of 3 dots ``...`` in a code sample indicates that we have left
out a chunk of the code for brevity, they are not actually part of the code.
We will often place multi-line comments ``/* ... */`` in the code so that we
can show alternative ways of achieving the same result.
You should read the code examples given and try to understand them. They are
kept concise so that you are not overwhelmed with information.
History of Swift Mailer
-----------------------
Swift Mailer began back in 2005 as a one-class project for sending mail over
SMTP. It has since grown into the flexible component-based library that is in
development today.
Chris Corbyn first posted Swift Mailer on a web forum asking for comments from
other developers. It was never intended as a fully supported open source
project, but members of the forum began to adopt it and make use of it.
Very quickly feature requests were coming for the ability to add attachments
and use SMTP authentication, along with a number of other "obvious" missing
features. Considering the only alternative was PHPMailer it seemed like a good
time to bring some fresh tools to the table. Chris began working towards a
more component based, PHP5-like approach unlike the existing single-class,
legacy PHP4 approach taken by PHPMailer.
Members of the forum offered a lot of advice and critique on the code as he
worked through this project and released versions 2 and 3 of the library in
2005 and 2006, which by then had been broken down into smaller classes
offering more flexibility and supporting plugins. To this day the Swift Mailer
team still receive a lot of feature requests from users both on the forum and
in by email.
Until 2008 Chris was the sole developer of Swift Mailer, but entering 2009 he
gained the support of two experienced developers well-known to him: Paul
Annesley and Christopher Thompson. This has been an extremely welcome change.
As of September 2009, Chris handed over the maintenance of Swift Mailer to
Fabien Potencier.
Now 2009 and in its fourth major version Swift Mailer is more object-oriented
and flexible than ever, both from a usability standpoint and from a
development standpoint.
By no means is Swift Mailer ready to call "finished". There are still many
features that can be added to the library along with the constant refactoring
that happens behind the scenes.
It's a Library!
---------------
Swift Mailer is not an application - it's a library.
To most experienced developers this is probably an obvious point to make, but
it's certainly worth mentioning. Many people often contact us having gotten
the completely wrong end of the stick in terms of what Swift Mailer is
actually for.
It's not an application. It does not have a graphical user interface. It
cannot be opened in your web browser directly.
It's a library (or a framework if you like). It provides a whole lot of
classes that do some very complicated things, so that you don't have to. You
"use" Swift Mailer within an application so that your application can have the
ability to send emails.
The component-based structure of the library means that you are free to
implement it in a number of different ways and that you can pick and choose
what you want to use.
An application on the other hand (such as a blog or a forum) is already "put
together" in a particular way, (usually) provides a graphical user interface
and most likely doesn't offer a great deal of integration with your own
application.
Embrace the structure of the library and use the components it offers to your
advantage. Learning what the components do, rather than blindly copying and
pasting existing code will put you in a great position to build a powerful
application!
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Japanese (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/japanese.rst`)
Using Swift Mailer for Japanese Emails
======================================
To send emails in Japanese, you need to tweak the default configuration.
After requiring the Swift Mailer autoloader (by including the
``swift_required.php`` file), call the ``Swift::init()`` method with the
following code::
require_once '/path/to/swift-mailer/lib/swift_required.php';
Swift::init(function () {
Swift_DependencyContainer::getInstance()
->register('mime.qpheaderencoder')
->asAliasOf('mime.base64headerencoder');
Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
});
/* rest of code goes here */
That's all!
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Messages (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/messages.rst`)
Creating Messages
=================
Creating messages in Swift Mailer is done by making use of the various MIME
entities provided with the library. Complex messages can be quickly created
with very little effort.
Quick Reference for Creating a Message
---------------------------------------
You can think of creating a Message as being similar to the steps you perform
when you click the Compose button in your mail client. You give it a subject,
specify some recipients, add any attachments and write your message.
To create a Message:
* Call the ``newInstance()`` method of ``Swift_Message``.
* Set your sender address (``From:``) with ``setFrom()`` or ``setSender()``.
* Set a subject line with ``setSubject()``.
* Set recipients with ``setTo()``, ``setCc()`` and/or ``setBcc()``.
* Set a body with ``setBody()``.
* Add attachments with ``attach()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the message
$message = Swift_Message::newInstance()
// Give the message a subject
->setSubject('Your subject')
// Set the From address with an associative array
->setFrom(array('[email protected]' => 'John Doe'))
// Set the To addresses with an associative array
->setTo(array('[email protected]', '[email protected]' => 'A name'))
// Give it a body
->setBody('Here is the message itself')
// And optionally an alternative body
->addPart('<q>Here is the message itself</q>', 'text/html')
// Optionally add any attachments
->attach(Swift_Attachment::fromPath('my-document.pdf'))
;
Message Basics
--------------
A message is a container for anything you want to send to somebody else. There
are several basic aspects of a message that you should know.
An e-mail message is made up of several relatively simple entities that are
combined in different ways to achieve different results. All of these entities
have the same fundamental outline but serve a different purpose. The Message
itself can be defined as a MIME entity, an Attachment is a MIME entity, all
MIME parts are MIME entities -- and so on!
The basic units of each MIME entity -- be it the Message itself, or an
Attachment -- are its Headers and its body:
.. code-block:: text
Header-Name: A header value
Other-Header: Another value
The body content itself
The Headers of a MIME entity, and its body must conform to some strict
standards defined by various RFC documents. Swift Mailer ensures that these
specifications are followed by using various types of object, including
Encoders and different Header types to generate the entity.
The Structure of a MessageOf all of the MIME entities, a message -- Swift_Message
is the largest and most complex. It has many properties that can be updated
and it can contain other MIME entities -- attachments for example --
nested inside it.
A Message has a lot of different Headers which are there to present
information about the message to the recipients' mail client. Most of these
headers will be familiar to the majority of users, but we'll list the basic
ones. Although it's possible to work directly with the Headers of a Message
(or other MIME entity), the standard Headers have accessor methods provided to
abstract away the complex details for you. For example, although the Date on a
message is written with a strict format, you only need to pass a UNIX
timestamp to setDate().
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Header | Description | Accessors |
+===============================+====================================================================================================================================+=============================================+
| Message-ID | Identifies this message with a unique ID, usually containing the domain name and time generated | getId() / setId() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Return-Path | Specifies where bounces should go (Swift Mailer reads this for other uses) | getReturnPath() / setReturnPath() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| From | Specifies the address of the person who the message is from. This can be multiple addresses if multiple people wrote the message. | getFrom() / setFrom() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Sender | Specifies the address of the person who physically sent the message (higher precedence than From:) | getSender() / setSender() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| To | Specifies the addresses of the intended recipients | getTo() / setTo() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Cc | Specifies the addresses of recipients who will be copied in on the message | getCc() / setCc() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Bcc | Specifies the addresses of recipients who the message will be blind-copied to. Other recipients will not be aware of these copies. | getBcc() / setBcc() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Reply-To | Specifies the address where replies are sent to | getReplyTo() / setReplyTo() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Subject | Specifies the subject line that is displayed in the recipients' mail client | getSubject() / setSubject() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Date | Specifies the date at which the message was sent | getDate() / setDate() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Content-Type | Specifies the format of the message (usually text/plain or text/html) | getContentType() / setContentType() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Content-Transfer-Encoding | Specifies the encoding scheme in the message | getEncoder() / setEncoder() |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
Working with a Message Object
Although there are a lot of available methods on a message object, you only
need to make use of a small subset of them. Usually you'll use
``setSubject()``, ``setTo()`` and
``setFrom()`` before setting the body of your message with
``setBody()``.
Calling methods is simple. You just call them like functions, but using the
object operator "``->``" to do so. If you've created
a message object and called it ``$message`` then you'd set a
subject on it like so:
.. code-block:: php
require_once 'lib/swift_required.php';
$message = Swift_Message::newInstance();
$message->setSubject('My subject');
All MIME entities (including a message) have a ``toString()``
method that you can call if you want to take a look at what is going to be
sent. For example, if you ``echo
$message->toString();`` you would see something like this:
.. code-block:: bash
Message-ID: <[email protected]>
Date: Thu, 25 Dec 2008 13:54:38 +1100
Subject: Example subject
From: Chris Corbyn <[email protected]>
To: Receiver Name <[email protected]>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Here is the message
We'll take a closer look at the methods you use to create your message in the
following sections.
Adding Content to Your Message
------------------------------
Rich content can be added to messages in Swift Mailer with relative ease by
calling methods such as ``setSubject()``, ``setBody()``, ``addPart()`` and
``attach()``.
Setting the Subject Line
~~~~~~~~~~~~~~~~~~~~~~~~
The subject line, displayed in the recipients' mail client can be set with the
``setSubject()`` method, or as a parameter to ``Swift_Message::newInstance()``.
To set the subject of your Message:
* Call the ``setSubject()`` method of the Message, or specify it at the time
you create the message.
.. code-block:: php
// Pass it as a parameter when you create the message
$message = Swift_Message::newInstance('My amazing subject');
// Or set it after like this
$message->setSubject('My amazing subject');
Setting the Body Content
~~~~~~~~~~~~~~~~~~~~~~~~
The body of the message -- seen when the user opens the message --
is specified by calling the ``setBody()`` method. If an alternative body is to
be included ``addPart()`` can be used.
The body of a message is the main part that is read by the user. Often people
want to send a message in HTML format (``text/html``), other
times people want to send in plain text (``text/plain``), or
sometimes people want to send both versions and allow the recipient to choose
how they view the message.
As a rule of thumb, if you're going to send a HTML email, always include a
plain-text equivalent of the same content so that users who prefer to read
plain text can do so.
To set the body of your Message:
* Call the ``setBody()`` method of the Message, or specify it at the time you
create the message.
* Add any alternative bodies with ``addPart()``.
If the recipient's mail client offers preferences for displaying text vs. HTML
then the mail client will present that part to the user where available. In
other cases the mail client will display the "best" part it can - usually HTML
if you've included HTML.
.. code-block:: php
// Pass it as a parameter when you create the message
$message = Swift_Message::newInstance('Subject here', 'My amazing body');
// Or set it after like this
$message->setBody('My *amazing* body', 'text/html');
// Add alternative parts with addPart()
$message->addPart('My amazing body in plain text', 'text/plain');
Attaching Files
---------------
Attachments are downloadable parts of a message and can be added by calling
the ``attach()`` method on the message. You can add attachments that exist on
disk, or you can create attachments on-the-fly.
Attachments are actually an interesting area of Swift Mailer and something
that could put a lot of power at your fingertips if you grasp the concept
behind the way a message is held together.
Although we refer to files sent over e-mails as "attachments" -- because
they're attached to the message -- lots of other parts of the message are
actually "attached" even if we don't refer to these parts as attachments.
File attachments are created by the ``Swift_Attachment`` class
and then attached to the message via the ``attach()`` method on
it. For all of the "every day" MIME types such as all image formats, word
documents, PDFs and spreadsheets you don't need to explicitly set the
content-type of the attachment, though it would do no harm to do so. For less
common formats you should set the content-type -- which we'll cover in a
moment.
Attaching Existing Files
~~~~~~~~~~~~~~~~~~~~~~~~
Files that already exist, either on disk or at a URL can be attached to a
message with just one line of code, using ``Swift_Attachment::fromPath()``.
You can attach files that exist locally, or if your PHP installation has
``allow_url_fopen`` turned on you can attach files from other
websites.
To attach an existing file:
* Create an attachment with ``Swift_Attachment::fromPath()``.
* Add the attachment to the message with ``attach()``.
The attachment will be presented to the recipient as a downloadable file with
the same filename as the one you attached.
.. code-block:: php
// Create the attachment
// * Note that you can technically leave the content-type parameter out
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg');
// Attach it to the message
$message->attach($attachment);
// The two statements above could be written in one line instead
$message->attach(Swift_Attachment::fromPath('/path/to/image.jpg'));
// You can attach files from a URL if allow_url_fopen is on in php.ini
$message->attach(Swift_Attachment::fromPath('http://site.tld/logo.png'));
Setting the Filename
~~~~~~~~~~~~~~~~~~~~
Usually you don't need to explicitly set the filename of an attachment because
the name of the attached file will be used by default, but if you want to set
the filename you use the ``setFilename()`` method of the Attachment.
To change the filename of an attachment:
* Call its ``setFilename()`` method.
The attachment will be attached in the normal way, but meta-data sent inside
the email will rename the file to something else.
.. code-block:: php
// Create the attachment and call its setFilename() method
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
->setFilename('cool.jpg');
// Because there's a fluid interface, you can do this in one statement
$message->attach(
Swift_Attachment::fromPath('/path/to/image.jpg')->setFilename('cool.jpg')
);
Attaching Dynamic Content
~~~~~~~~~~~~~~~~~~~~~~~~~
Files that are generated at runtime, such as PDF documents or images created
via GD can be attached directly to a message without writing them out to disk.
Use the standard ``Swift_Attachment::newInstance()`` method.
To attach dynamically created content:
* Create your content as you normally would.
* Create an attachment with ``Swift_Attachment::newInstance()``, specifying
the source data of your content along with a name and the content-type.
* Add the attachment to the message with ``attach()``.
The attachment will be presented to the recipient as a downloadable file
with the filename and content-type you specify.
.. note::
If you would usually write the file to disk anyway you should just attach
it with ``Swift_Attachment::fromPath()`` since this will use less memory:
.. code-block:: php
// Create your file contents in the normal way, but don't write them to disk
$data = create_my_pdf_data();
// Create the attachment with your data
$attachment = Swift_Attachment::newInstance($data, 'my-file.pdf', 'application/pdf');
// Attach it to the message
$message->attach($attachment);
// You can alternatively use method chaining to build the attachment
$attachment = Swift_Attachment::newInstance()
->setFilename('my-file.pdf')
->setContentType('application/pdf')
->setBody($data)
;
Changing the Disposition
~~~~~~~~~~~~~~~~~~~~~~~~
Attachments just appear as files that can be saved to the Desktop if desired.
You can make attachment appear inline where possible by using the
``setDisposition()`` method of an attachment.
To make an attachment appear inline:
* Call its ``setDisposition()`` method.
The attachment will be displayed within the email viewing window if the mail
client knows how to display it.
.. note::
If you try to create an inline attachment for a non-displayable file type
such as a ZIP file, the mail client should just present the attachment as
normal:
.. code-block:: php
// Create the attachment and call its setDisposition() method
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
->setDisposition('inline');
// Because there's a fluid interface, you can do this in one statement
$message->attach(
Swift_Attachment::fromPath('/path/to/image.jpg')->setDisposition('inline')
);
Embedding Inline Media Files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Often people want to include an image or other content inline with a HTML
message. It's easy to do this with HTML linking to remote resources, but this
approach is usually blocked by mail clients. Swift Mailer allows you to embed
your media directly into the message.
Mail clients usually block downloads from remote resources because this
technique was often abused as a mean of tracking who opened an email. If
you're sending a HTML email and you want to include an image in the message
another approach you can take is to embed the image directly.
Swift Mailer makes embedding files into messages extremely streamlined. You
embed a file by calling the ``embed()`` method of the message,
which returns a value you can use in a ``src`` or
``href`` attribute in your HTML.
Just like with attachments, it's possible to embed dynamically generated
content without having an existing file available.
The embedded files are sent in the email as a special type of attachment that
has a unique ID used to reference them within your HTML attributes. On mail
clients that do not support embedded files they may appear as attachments.
Although this is commonly done for images, in theory it will work for any
displayable (or playable) media type. Support for other media types (such as
video) is dependent on the mail client however.
Embedding Existing Files
........................
Files that already exist, either on disk or at a URL can be embedded in a
message with just one line of code, using ``Swift_EmbeddedFile::fromPath()``.
You can embed files that exist locally, or if your PHP installation has
``allow_url_fopen`` turned on you can embed files from other websites.
To embed an existing file:
* Create a message object with ``Swift_Message::newInstance()``.
* Set the body as HTML, and embed a file at the correct point in the message with ``embed()``.
The file will be displayed with the message inline with the HTML wherever its ID
is used as a ``src`` attribute.
.. note::
``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
another. ``Swift_Image`` exists for semantic purposes.
.. note::
You can embed files in two stages if you prefer. Just capture the return
value of ``embed()`` in a variable and use that as the ``src`` attribute.
.. code-block:: php
// Create the message
$message = Swift_Message::newInstance('My subject');
// Set the body
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . // Embed the file
$message->embed(Swift_Image::fromPath('image.png')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
// You can embed files from a URL if allow_url_fopen is on in php.ini
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' .
$message->embed(Swift_Image::fromPath('http://site.tld/logo.png')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html'
);
// If placing the embed() code inline becomes cumbersome
// it's easy to do this in two steps
$cid = $message->embed(Swift_Image::fromPath('image.png'));
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . $cid . '" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
Embedding Dynamic Content
.........................
Images that are generated at runtime, such as images created via GD can be
embedded directly to a message without writing them out to disk. Use the
standard ``Swift_Image::newInstance()`` method.
To embed dynamically created content:
* Create a message object with ``Swift_Message::newInstance()``.
* Set the body as HTML, and embed a file at the correct point in the message
with ``embed()``. You will need to specify a filename and a content-type.
The file will be displayed with the message inline with the HTML wherever its ID
is used as a ``src`` attribute.
.. note::
``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
another. ``Swift_Image`` exists for semantic purposes.
.. note::
You can embed files in two stages if you prefer. Just capture the return
value of ``embed()`` in a variable and use that as the ``src`` attribute.
.. code-block:: php
// Create your file contents in the normal way, but don't write them to disk
$img_data = create_my_image_data();
// Create the message
$message = Swift_Message::newInstance('My subject');
// Set the body
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . // Embed the file
$message->embed(Swift_Image::newInstance($img_data, 'image.jpg', 'image/jpeg')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
// If placing the embed() code inline becomes cumbersome
// it's easy to do this in two steps
$cid = $message->embed(Swift_Image::newInstance($img_data, 'image.jpg', 'image/jpeg'));
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . $cid . '" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
Adding Recipients to Your Message
---------------------------------
Recipients are specified within the message itself via ``setTo()``, ``setCc()``
and ``setBcc()``. Swift Mailer reads these recipients from the message when it
gets sent so that it knows where to send the message to.
Message recipients are one of three types:
* ``To:`` recipients -- the primary recipients (required)
* ``Cc:`` recipients -- receive a copy of the message (optional)
* ``Bcc:`` recipients -- hidden from other recipients (optional)
Each type can contain one, or several addresses. It's possible to list only
the addresses of the recipients, or you can personalize the address by
providing the real name of the recipient.
Make sure to add only valid email addresses as recipients. If you try to add an
invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift
Mailer will throw a ``Swift_RfcComplianceException``.
If you add recipients automatically based on a data source that may contain
invalid email addresses, you can prevent possible exceptions by validating the
addresses using ``Swift_Validate::email($email)`` and only adding addresses
that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and
``setBcc()`` calls in a try-catch block and handle the
``Swift_RfcComplianceException`` in the catch block.
.. sidebar:: Syntax for Addresses
If you only wish to refer to a single email address (for example your
``From:`` address) then you can just use a string.
.. code-block:: php
$message->setFrom('[email protected]');
If you want to include a name then you must use an associative array.
.. code-block:: php
$message->setFrom(array('[email protected]' => 'The Name'));
If you want to include multiple addresses then you must use an array.
.. code-block:: php
$message->setTo(array('[email protected]', '[email protected]'));
You can mix personalized (addresses with a name) and non-personalized
addresses in the same list by mixing the use of associative and
non-associative array syntax.
.. code-block:: php
$message->setTo(array(
'[email protected]' => 'Recipient Name One',
'[email protected]', // Note that this is not a key-value pair
'[email protected]' => 'Recipient Name Two'
));
Setting ``To:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~
``To:`` recipients are required in a message and are set with the
``setTo()`` or ``addTo()`` methods of the message.
To set ``To:`` recipients, create the message object using either
``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``,
then call the ``setTo()`` method with a complete array of addresses, or use the
``addTo()`` method to iteratively add recipients.
The ``setTo()`` method accepts input in various formats as described earlier in
this chapter. The ``addTo()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
``To:`` recipients are visible in the message headers and will be
seen by the other recipients.
.. note::
Multiple calls to ``setTo()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add
recipients, use the ``addTo()`` method.
.. code-block:: php
// Using setTo() to set all recipients in one go
$message->setTo(array(
'[email protected]',
'[email protected]' => 'Person 2 Name',
'[email protected]',
'[email protected]',
'[email protected]' => 'Person 5 Name'
));
// Using addTo() to add recipients iteratively
$message->addTo('[email protected]');
$message->addTo('[email protected]', 'Person 2 Name');
Setting ``Cc:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~
``Cc:`` recipients are set with the ``setCc()`` or ``addCc()`` methods of the
message.
To set ``Cc:`` recipients, create the message object using either
``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call
the ``setCc()`` method with a complete array of addresses, or use the
``addCc()`` method to iteratively add recipients.
The ``setCc()`` method accepts input in various formats as described earlier in
this chapter. The ``addCc()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
``Cc:`` recipients are visible in the message headers and will be
seen by the other recipients.
.. note::
Multiple calls to ``setCc()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add Cc:
recipients, use the ``addCc()`` method.
.. code-block:: php
// Using setCc() to set all recipients in one go
$message->setCc(array(
'[email protected]',
'[email protected]' => 'Person 2 Name',
'[email protected]',
'[email protected]',
'[email protected]' => 'Person 5 Name'
));
// Using addCc() to add recipients iteratively
$message->addCc('[email protected]');
$message->addCc('[email protected]', 'Person 2 Name');
Setting ``Bcc:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~~
``Bcc:`` recipients receive a copy of the message without anybody else knowing
it, and are set with the ``setBcc()`` or ``addBcc()`` methods of the message.
To set ``Bcc:`` recipients, create the message object using either ``new
Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call the
``setBcc()`` method with a complete array of addresses, or use
the ``addBcc()`` method to iteratively add recipients.
The ``setBcc()`` method accepts input in various formats as described earlier in
this chapter. The ``addBcc()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
Only the individual ``Bcc:`` recipient will see their address in the message
headers. Other recipients (including other ``Bcc:`` recipients) will not see the
address.
.. note::
Multiple calls to ``setBcc()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add Bcc:
recipients, use the ``addBcc()`` method.
.. code-block:: php
// Using setBcc() to set all recipients in one go
$message->setBcc(array(
'[email protected]',
'[email protected]' => 'Person 2 Name',
'[email protected]',
'[email protected]',
'[email protected]' => 'Person 5 Name'
));
// Using addBcc() to add recipients iteratively
$message->addBcc('[email protected]');
$message->addBcc('[email protected]', 'Person 2 Name');
Specifying Sender Details
-------------------------
An email must include information about who sent it. Usually this is managed
by the ``From:`` address, however there are other options.
The sender information is contained in three possible places:
* ``From:`` -- the address(es) of who wrote the message (required)
* ``Sender:`` -- the address of the single person who sent the message
(optional)
* ``Return-Path:`` -- the address where bounces should go to (optional)
You must always include a ``From:`` address by using ``setFrom()`` on the
message. Swift Mailer will use this as the default ``Return-Path:`` unless
otherwise specified.
The ``Sender:`` address exists because the person who actually sent the email
may not be the person who wrote the email. It has a higher precedence than the
``From:`` address and will be used as the ``Return-Path:`` unless otherwise
specified.
Setting the ``From:`` AddressA From: address is required and is set with the setFrom() method of the
message. From: addresses specify who actually wrote the email, and usually who sent it.
What most people probably don't realise is that you can have more than oneFrom: address if more than one person wrote the email -- for example if an
email was put together by a committee.
To set the From: address(es):
- Call the
setFrom()method on the Message.
The From: address(es) are visible in the message headers and
will be seen by the recipients.
.. note::
If you set multiple ``From:`` addresses then you absolutely must set a
``Sender:`` address to indicate who physically sent the message.
.. code-block:: php
// Set a single From: address
$message->setFrom('[email protected]');
// Set a From: address including a name
$message->setFrom(array('[email protected]' => 'Your Name'));
// Set multiple From: addresses if multiple people wrote the email
$message->setFrom(array(
'[email protected]' => 'Sender One',
'[email protected]' => 'Sender Two'
));Setting the Sender: Address
A ``Sender:`` address specifies who sent the message and is set with the
``setSender()`` method of the message.
To set the ``Sender:`` address:
* Call the ``setSender()`` method on the Message.
The ``Sender:`` address is visible in the message headers and will be seen by
the recipients.
This address will be used as the ``Return-Path:`` unless otherwise specified.
.. note::
If you set multiple ``From:`` addresses then you absolutely must set a
``Sender:`` address to indicate who physically sent the message.
You must not set more than one sender address on a message because it's not
possible for more than one person to send a single message.
.. code-block:: php
$message->setSender('[email protected]');
Setting the ``Return-Path:`` (Bounce) AddressThe Return-Path: address specifies where bounce notifications should
be sent and is set with the setReturnPath() method of the message.
You can only have one Return-Path: and it must not include
a personal name.
To set the Return-Path: address:
- Call the
setReturnPath()method on the Message.
Bounce notifications will be sent to this address.
.. code-block:: php
$message->setReturnPath('[email protected]');Signed/Encrypted Message
To increase the integrity/security of a message it is possible to sign and/or
encrypt an message using one or multiple signers.
S/MIME
S/MIME can sign and/or encrypt a message using the OpenSSL extension.
When signing a message, the signer creates a signature of the entire content of the message (including attachments).
The certificate and private key must be PEM encoded, and can be either created using for example OpenSSL or
obtained at an official Certificate Authority (CA).
**The recipient must have the CA certificate in the list of trusted issuers in order to verify the signature.**
**Make sure the certificate supports emailProtection.**
When using OpenSSL this can done by the including the *-addtrust emailProtection* parameter when creating the certificate.
.. code-block:: php
$message = Swift_Message::newInstance();
$smimeSigner = Swift_Signers_SMimeSigner::newInstance();
$smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem');
$message->attachSigner($smimeSigner);
When the private key is secured using a passphrase use the following instead.
.. code-block:: php
$message = Swift_Message::newInstance();
$smimeSigner = Swift_Signers_SMimeSigner::newInstance();
$smimeSigner->setSignCertificate('/path/to/certificate.pem', array('/path/to/private-key.pem', 'passphrase'));
$message->attachSigner($smimeSigner);
By default the signature is added as attachment,
making the message still readable for mailing agents not supporting signed messages.
Storing the message as binary is also possible but not recommended.
.. code-block:: php
$smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem', PKCS7_BINARY);
When encrypting the message (also known as enveloping), the entire message (including attachments)
is encrypted using a certificate, and the recipient can then decrypt the message using corresponding private key.
Encrypting ensures nobody can read the contents of the message without the private key.
Normally the recipient provides a certificate for encrypting and keeping the decryption key private.
Using both signing and encrypting is also possible.
.. code-block:: php
$message = Swift_Message::newInstance();
$smimeSigner = Swift_Signers_SMimeSigner::newInstance();
$smimeSigner->setSignCertificate('/path/to/sign-certificate.pem', '/path/to/private-key.pem');
$smimeSigner->setEncryptCertificate('/path/to/encrypt-certificate.pem');
$message->attachSigner($smimeSigner);
The used encryption cipher can be set as the second parameter of setEncryptCertificate()
See http://php.net/manual/openssl.ciphers for a list of supported ciphers.
By default the message is first signed and then encrypted, this can be changed by adding.
.. code-block:: php
$smimeSigner->setSignThenEncrypt(false);
**Changing this is not recommended as most mail agents don't support this none-standard way.**
Only when having trouble with sign then encrypt method, this should be changed.
Requesting a Read Receipt
-------------------------
It is possible to request a read-receipt to be sent to an address when the
email is opened. To request a read receipt set the address with
``setReadReceiptTo()``.
To request a read receipt:
* Set the address you want the receipt to be sent to with the
``setReadReceiptTo()`` method on the Message.
When the email is opened, if the mail client supports it a notification will be sent to this address.
.. note::
Read receipts won't work for the majority of recipients since many mail
clients auto-disable them. Those clients that will send a read receipt
will make the user aware that one has been requested.
.. code-block:: php
$message->setReadReceiptTo('[email protected]');
Setting the Character Set
-------------------------
The character set of the message (and it's MIME parts) is set with the
``setCharset()`` method. You can also change the global default of UTF-8 by
working with the ``Swift_Preferences`` class.
Swift Mailer will default to the UTF-8 character set unless otherwise
overridden. UTF-8 will work in most instances since it includes all of the
standard US keyboard characters in addition to most international characters.
It is absolutely vital however that you know what character set your message
(or it's MIME parts) are written in otherwise your message may be received
completely garbled.
There are two places in Swift Mailer where you can change the character set:
* In the ``Swift_Preferences`` class
* On each individual message and/or MIME part
To set the character set of your Message:
* Change the global UTF-8 setting by calling
``Swift_Preferences::setCharset()``; or
* Call the ``setCharset()`` method on the message or the MIME part.
.. code-block:: php
// Approach 1: Change the global setting (suggested)
Swift_Preferences::getInstance()->setCharset('iso-8859-2');
// Approach 2: Call the setCharset() method of the message
$message = Swift_Message::newInstance()
->setCharset('iso-8859-2');
// Approach 3: Specify the charset when setting the body
$message->setBody('My body', 'text/html', 'iso-8859-2');
// Approach 4: Specify the charset for each part added
$message->addPart('My part', 'text/plain', 'iso-8859-2');
Setting the Line Length
-----------------------
The length of lines in a message can be changed by using the ``setMaxLineLength()`` method on the message. It should be kept to less than
1000 characters.
Swift Mailer defaults to using 78 characters per line in a message. This is
done for historical reasons and so that the message can be easily viewed in
plain-text terminals.
To change the maximum length of lines in your Message:
* Call the ``setMaxLineLength()`` method on the Message.
Lines that are longer than the line length specified will be wrapped between
words.
.. note::
You should never set a maximum length longer than 1000 characters
according to RFC 2822. Doing so could have unspecified side-effects such
as truncating parts of your message when it is transported between SMTP
servers.
.. code-block:: php
$message->setMaxLineLength(1000);
Setting the Message Priority
----------------------------
You can change the priority of the message with ``setPriority()``. Setting the
priority will not change the way your email is sent -- it is purely an
indicative setting for the recipient.
The priority of a message is an indication to the recipient what significance
it has. Swift Mailer allows you to set the priority by calling the ``setPriority`` method. This method takes an integer value between 1 and 5:
* Highest
* High
* Normal
* Low
* Lowest
To set the message priority:
* Set the priority as an integer between 1 and 5 with the ``setPriority()``
method on the Message.
.. code-block:: php
// Indicate "High" priority
$message->setPriority(2);
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Overview (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/overview.rst`)
Library Overview
================
Most features (and more) of your every day mail client software are provided
by Swift Mailer, using object-oriented PHP code as the interface.
In this chapter we will take a short tour of the various components, which put
together form the Swift Mailer library as a whole. You will learn key
terminology used throughout the rest of this book and you will gain a little
understanding of the classes you will work with as you integrate Swift Mailer
into your application.
This chapter is intended to prepare you for the information contained in the
subsequent chapters of this book. You may choose to skip this chapter if you
are fairly technically minded, though it is likely to save you some time in
the long run if you at least read between the lines here.
System Requirements
-------------------
The basic requirements to operate Swift Mailer are extremely minimal and
easily achieved. Historically, Swift Mailer has supported both PHP 4 and PHP 5
by following a parallel development workflow. Now in it's fourth major
version, and Swift Mailer operates on servers running PHP 5.2 or higher.
The library aims to work with as many PHP 5 projects as possible:
* PHP 5.2 or higher, with the SPL extension (standard)
* Limited network access to connect to remote SMTP servers
* 8 MB or more memory limit (Swift Mailer uses around 2 MB)
Component Breakdown
-------------------
Swift Mailer is made up of many classes. Each of these classes can be grouped
into a general "component" group which describes the task it is designed to
perform.
We'll take a brief look at the components which form Swift Mailer in this
section of the book.
The MailerThe mailer class, Swift_Mailer is the central class in the library where
all of the other components meet one another. Swift_Mailer acts as a sort
of message dispatcher, communicating with the underlying Transport to deliver
your Message to all intended recipients.
If you were to dig around in the source code for Swift Mailer you'd notice
that Swift_Mailer itself is pretty bare. It delegates to other objects for
most tasks and in theory, if you knew the internals of Swift Mailer well you
could by-pass this class entirely. We wouldn't advise doing such a thing
however -- there are reasons this class exists:
for consistency, regardless of the Transport used
to provide abstraction from the internals in the event internal API changes
are madeto provide convenience wrappers around aspects of the internal API
An instance of Swift_Mailer is created by the developer before sending any
Messages.
Transports
Transports are the classes in Swift Mailer that are responsible for
communicating with a service in order to deliver a Message. There are several
types of Transport in Swift Mailer, all of which implement the Swift_Transport
interface and offer underlying start(), stop() and send() methods.
Typically you will not need to know how a Transport works under-the-surface,
you will only need to know how to create an instance of one, and which one to
use for your environment.
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| Class | Features | Pros/cons |
+=================================+=============================================================================================+===============================================================================================================================================+
| ``Swift_SmtpTransport`` | Sends messages over SMTP; Supports Authentication; Supports Encryption | Very portable; Pleasingly predictable results; Provides good feedback |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_SendmailTransport`` | Communicates with a locally installed ``sendmail`` executable (Linux/UNIX) | Quick time-to-run; Provides less-accurate feedback than SMTP; Requires ``sendmail`` installation |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_MailTransport`` | Uses PHP's built-in ``mail()`` function | Very portable; Potentially unpredictable results; Provides extremely weak feedback |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_LoadBalancedTransport`` | Cycles through a collection of the other Transports to manage load-reduction | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down); Keeps the load on remote services down by spreading the work |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_FailoverTransport`` | Works in conjunction with a collection of the other Transports to provide high-availability | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down) |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
MIME EntitiesEverything that forms part of a Message is called a MIME Entity. All MIME
entities in Swift Mailer share a common set of features. There are various
types of MIME entity that serve different purposes such as Attachments and
MIME parts.
An e-mail message is made up of several relatively simple entities that are
combined in different ways to achieve different results. All of these entities
have the same fundamental outline but serve a different purpose. The Message
itself can be defined as a MIME entity, an Attachment is a MIME entity, all
MIME parts are MIME entities -- and so on!
The basic units of each MIME entity -- be it the Message itself, or an
Attachment -- are its Headers and its body:
.. code-block:: text
Other-Header: Another value
The body content itselfThe Headers of a MIME entity, and its body must conform to some strict
standards defined by various RFC documents. Swift Mailer ensures that these
specifications are followed by using various types of object, including
Encoders and different Header types to generate the entity.
Each MIME component implements the base Swift_Mime_MimeEntity interface,
which offers methods for retrieving Headers, adding new Headers, changing the
Encoder, updating the body and so on!
All MIME entities have one Header in common -- the Content-Type Header,
updated with the entity's setContentType() method.
Encoders
Encoders are used to transform the content of Messages generated in Swift
Mailer into a format that is safe to send across the internet and that
conforms to RFC specifications.
Generally speaking you will not need to interact with the Encoders in Swift
Mailer -- the correct settings will be handled by the library itself.
However they are probably worth a brief mention in the event that you do want
to play with them.
Both the Headers and the body of all MIME entities (including the Message
itself) use Encoders to ensure the data they contain can be sent over the
internet without becoming corrupted or misinterpreted.
There are two types of Encoder: Base64 and Quoted-Printable.
Plugins
~~~~~~~
Plugins exist to extend, or modify the behaviour of Swift Mailer. They respond
to Events that are fired within the Transports during sending.
There are a number of Plugins provided as part of the base Swift Mailer
package and they all follow a common interface to respond to Events fired
within the library. Interfaces are provided to "listen" to each type of Event
fired and to act as desired when a listened-to Event occurs.
Although several plugins are provided with Swift Mailer out-of-the-box, the
Events system has been specifically designed to make it easy for experienced
object-oriented developers to write their own plugins in order to achieve
goals that may not be possible with the base library.
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Plugins (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/plugins.rst`)
Plugins
=======
Plugins are provided with Swift Mailer and can be used to extend the behavior
of the library in situations where using simple class inheritance would be more complex.
AntiFlood Plugin
----------------
Many SMTP servers have limits on the number of messages that may be sent
during any single SMTP connection. The AntiFlood plugin provides a way to stay
within this limit while still managing a large number of emails.
A typical limit for a single connection is 100 emails. If the server you
connect to imposes such a limit, it expects you to disconnect after that
number of emails has been sent. You could manage this manually within a loop,
but the AntiFlood plugin provides the necessary wrapper code so that you don't
need to worry about this logic.
Regardless of limits imposed by the server, it's usually a good idea to be
conservative with the resources of the SMTP server. Sending will become
sluggish if the server is being over-used so using the AntiFlood plugin will
not be a bad idea even if no limits exist.
The AntiFlood plugin's logic is basically to disconnect and the immediately
re-connect with the SMTP server every X number of emails sent, where X is a
number you specify to the plugin.
You can also specify a time period in seconds that Swift Mailer should pause
for between the disconnect/re-connect process. It's a good idea to pause for a
short time (say 30 seconds every 100 emails) simply to give the SMTP server a
chance to process its queue and recover some resources.
Using the AntiFlood PluginThe AntiFlood Plugin -- like all plugins -- is added with the Mailer class'sregisterPlugin() method. It takes two constructor parameters: the number of
emails to pause after, and optionally the number of seconds to pause for.
To use the AntiFlood plugin:
Create an instance of the Mailer using any Transport you choose.
Create an instance of the
Swift_Plugins_AntiFloodPluginclass, passing
in one or two constructor parameters.Register the plugin using the Mailer's
registerPlugin()method.Continue using Swift Mailer to send messages as normal.
When Swift Mailer sends messages it will count the number of messages that
have been sent since the last re-connect. Once the number hits your specified
threshold it will disconnect and re-connect, optionally pausing for a
specified amount of time.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// Use AntiFlood to re-connect after 100 emails
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100));
// And specify a time in seconds to pause for (30 secs)
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}Throttler Plugin
If your SMTP server has restrictions in place to limit the rate at which you
send emails, then your code will need to be aware of this rate-limiting. The
Throttler plugin makes Swift Mailer run at a rate-limited speed.
Many shared hosts don't open their SMTP servers as a free-for-all. Usually
they have policies in place (probably to discourage spammers) that only allow
you to send a fixed number of emails per-hour/day.
The Throttler plugin supports two modes of rate-limiting and with each, you
will need to do that math to figure out the values you want. The plugin can
limit based on the number of emails per minute, or the number of
bytes-transferred per-minute.
Using the Throttler Plugin
The Throttler Plugin -- like all plugins -- is added with the Mailer class'
``registerPlugin()`` method. It has two required constructor parameters that
tell it how to do its rate-limiting.
To use the Throttler plugin:
* Create an instance of the Mailer using any Transport you choose.
* Create an instance of the ``Swift_Plugins_ThrottlerPlugin`` class, passing
the number of emails, or bytes you wish to limit by, along with the mode
you're using.
* Register the plugin using the Mailer's ``registerPlugin()`` method.
* Continue using Swift Mailer to send messages as normal.
When Swift Mailer sends messages it will keep track of the rate at which sending
messages is occurring. If it realises that sending is happening too fast, it
will cause your program to ``sleep()`` for enough time to average out the rate.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// Rate limit to 100 emails per-minute
$mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE
));
// Rate limit to 10MB per-minute
$mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE
));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
Logger Plugin
-------------
The Logger plugins helps with debugging during the process of sending. It can
help to identify why an SMTP server is rejecting addresses, or any other
hard-to-find problems that may arise.
The Logger plugin comes in two parts. There's the plugin itself, along with
one of a number of possible Loggers that you may choose to use. For example,
the logger may output messages directly in realtime, or it may capture
messages in an array.
One other notable feature is the way in which the Logger plugin changes
Exception messages. If Exceptions are being thrown but the error message does
not provide conclusive information as to the source of the problem (such as an
ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in
the error message so that debugging becomes a simpler task.
There are a few available Loggers included with Swift Mailer, but writing your
own implementation is incredibly simple and is achieved by creating a short
class that implements the ``Swift_Plugins_Logger`` interface.
* ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages
inside an array. The array content can be cleared or dumped out to the
screen.
* ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in
realtime. Handy for very rudimentary debug output.
Using the Logger Plugin
~~~~~~~~~~~~~~~~~~~~~~~
The Logger Plugin -- like all plugins -- is added with the Mailer class'
``registerPlugin()`` method. It accepts an instance of ``Swift_Plugins_Logger``
in its constructor.
To use the Logger plugin:
* Create an instance of the Mailer using any Transport you choose.
* Create an instance of the a Logger implementation of
``Swift_Plugins_Logger``.
* Create an instance of the ``Swift_Plugins_LoggerPlugin`` class, passing the
created Logger instance to its constructor.
* Register the plugin using the Mailer's ``registerPlugin()`` method.
* Continue using Swift Mailer to send messages as normal.
* Dump the contents of the log with the logger's ``dump()`` method.
When Swift Mailer sends messages it will keep a log of all the interactions
with the underlying Transport being used. Depending upon the Logger that has
been used the behaviour will differ, but all implementations offer a way to
get the contents of the log.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// To use the ArrayLogger
$logger = new Swift_Plugins_Loggers_ArrayLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Or to use the Echo Logger
$logger = new Swift_Plugins_Loggers_EchoLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
// Dump the log contents
// NOTE: The EchoLogger dumps in realtime so dump() does nothing for it
echo $logger->dump();
Decorator Plugin
----------------
Often there's a need to send the same message to multiple recipients, but with
tiny variations such as the recipient's name being used inside the message
body. The Decorator plugin aims to provide a solution for allowing these small
differences.
The decorator plugin works by intercepting the sending process of Swift
Mailer, reading the email address in the To: field and then looking up a set
of replacements for a template.
While the use of this plugin is simple, it is probably the most commonly
misunderstood plugin due to the way in which it works. The typical mistake
users make is to try registering the plugin multiple times (once for each
recipient) -- inside a loop for example. This is incorrect.
The Decorator plugin should be registered just once, but containing the list
of all recipients prior to sending. It will use this list of recipients to
find the required replacements during sending.
Using the Decorator PluginTo use the Decorator plugin, simply create an associative array of replacements
based on email addresses and then use the mailer's registerPlugin() method
to add the plugin.
First create an associative array of replacements based on the email addresses
you'll be sending the message to.
.. note::
The replacements array becomes a 2-dimensional array whose keys are the
email addresses and whose values are an associative array of replacements
for that email address. The curly braces used in this example can be any
type of syntax you choose, provided they match the placeholders in your
email template.
.. code-block:: php
$replacements = array();
foreach ($users as $user) {
$replacements[$user['email']] = array(
'{username}'=>$user['username'],
'{password}'=>$user['password']
);
}Now create an instance of the Decorator plugin using this array of replacements
and then register it with the Mailer. Do this only once!
.. code-block:: php
$decorator = new Swift_Plugins_DecoratorPlugin($replacements);
$mailer->registerPlugin($decorator);When you create your message, replace elements in the body (and/or the subject
line) with your placeholders.
.. code-block:: php
$message = Swift_Message::newInstance()
->setSubject('Important notice for {username}')
->setBody(
"Hello {username}, we have reset your password to {password}\n" .
"Please log in and change it at your earliest convenience."
)
;
foreach ($users as $user) {
$message->addTo($user['email']);
}When you send this message to each of your recipients listed in your$replacements array they will receive a message customized for just
themselves. For example, the message used above when received may appear like
this to one user:
.. code-block:: text
Subject: Important notice for smilingsunshine2009
Hello smilingsunshine2009, we have reset your password to rainyDays
Please log in and change it at your earliest convenience.While another use may receive the message as:
.. code-block:: text
Subject: Important notice for billy-bo-bob
Hello billy-bo-bob, we have reset your password to dancingOctopus
Please log in and change it at your earliest convenience.While the decorator plugin provides a means to solve this problem, there are
various ways you could tackle this problem without the need for a plugin.
We're trying to come up with a better way ourselves and while we have several
(obvious) ideas we don't quite have the perfect solution to go ahead and
implement it. Watch this space.
Providing Your Own Replacements Lookup for the Decorator
Filling an array with replacements may not be the best solution for providing
replacement information to the decorator. If you have a more elegant algorithm
that performs replacement lookups on-the-fly you may provide your own
implementation.
Providing your own replacements lookup implementation for the Decorator is
simply a matter of passing an instance of ``Swift_Plugins_Decorator_Replacements`` to the decorator plugin's constructor,
rather than passing in an array.
The Replacements interface is very simple to implement since it has just one
method: ``getReplacementsFor($address)``.
Imagine you want to look up replacements from a database on-the-fly, you might
provide an implementation that does this. You need to create a small class.
.. code-block:: php
class DbReplacements implements Swift_Plugins_Decorator_Replacements {
public function getReplacementsFor($address) {
$sql = sprintf(
"SELECT * FROM user WHERE email = '%s'",
mysql_real_escape_string($address)
);
$result = mysql_query($sql);
if ($row = mysql_fetch_assoc($result)) {
return array(
'{username}'=>$row['username'],
'{password}'=>$row['password']
);
}
}
}
Now all you need to do is pass an instance of your class into the Decorator
plugin's constructor instead of passing an array.
.. code-block:: php
$decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements());
$mailer->registerPlugin($decorator);
For each message sent, the plugin will call your class' ``getReplacementsFor()``
method to find the array of replacements it needs.
.. note::
If your lookup algorithm is case sensitive, you should transform the
``$address`` argument as appropriate -- for example by passing it
through ``strtolower()``.
---
### Samples Development Frameworks Laravel Vendor Swiftmailer Swiftmailer Doc Sending (`samples/development-frameworks/laravel/vendor/swiftmailer/swiftmailer/doc/sending.rst`)
Sending Messages
================
Quick Reference for Sending a Message
-------------------------------------
Sending a message is very straightforward. You create a Transport, use it to
create the Mailer, then you use the Mailer to send the message.
To send a Message:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``, ``Swift_MailTransport``
or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Send the message via the ``send()`` method on the Mailer object.
.. caution::
The ``Swift_SmtpTransport`` and ``Swift_SendmailTransport`` transports use
``proc_*`` PHP functions, which might not be available on your PHP
installation. You can easily check if that's the case by running the
following PHP script: ``<?php echo function_exists('proc_open') ? "Yep,
that will work" : "Sorry, that won't work";``
When using ``send()`` the message will be sent just like it would be sent if you
used your mail client. An integer is returned which includes the number of
successful recipients. If none of the recipients could be sent to then zero will
be returned, which equates to a boolean ``false``. If you set two ``To:``
recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
->setUsername('your username')
->setPassword('your password')
;
/*
You could alternatively use a different transport such as Sendmail or Mail:
// Sendmail
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
// Mail
$transport = Swift_MailTransport::newInstance();
*/
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('[email protected]' => 'John Doe'))
->setTo(array('[email protected]', '[email protected]' => 'A name'))
->setBody('Here is the message itself')
;
// Send the message
$result = $mailer->send($message);
Transport Types
~~~~~~~~~~~~~~~
A Transport is the component which actually does the sending. You need to
provide a Transport object to the Mailer class and there are several possible
options.
Typically you will not need to know how a Transport works under-the-surface,
you will only need to know how to create an instance of one, and which one to
use for your environment.
The SMTP Transport
..................
The SMTP Transport sends messages over the (standardized) Simple Message
Transfer Protocol. It can deal with encryption and authentication.
The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly
used Transport because it will work on 99% of web servers (I just made that
number up, but you get the idea). All the server needs is the ability to
connect to a remote (or even local) SMTP server on the correct port number
(usually 25).
SMTP servers often require users to authenticate with a username and password
before any mail can be sent to other domains. This is easily achieved using
Swift Mailer with the SMTP Transport.
SMTP is a protocol -- in other words it's a "way" of communicating a job
to be done (i.e. sending a message). The SMTP protocol is the fundamental
basis on which messages are delivered all over the internet 7 days a week, 365
days a year. For this reason it's the most "direct" method of sending messages
you can use and it's the one that will give you the most power and feedback
(such as delivery failures) when using Swift Mailer.
Because SMTP is generally run as a remote service (i.e. you connect to it over
the network/internet) it's extremely portable from server-to-server. You can
easily store the SMTP server address and port number in a configuration file
within your application and adjust the settings accordingly if the code is
moved or if the SMTP server is changed.
Some SMTP servers -- Google for example -- use encryption for security reasons.
Swift Mailer supports using both SSL and TLS encryption settings.
Using the SMTP Transport
^^^^^^^^^^^^^^^^^^^^^^^^
The SMTP Transport is easy to use. Most configuration options can be set with
the constructor.
To use the SMTP Transport you need to know which SMTP server your code needs
to connect to. Ask your web host if you're not sure. Lots of people ask me who
to connect to -- I really can't answer that since it's a setting that's
extremely specific to your hosting environment.
To use the SMTP Transport:
* Call ``Swift_SmtpTransport::newInstance()`` with the SMTP server name and
optionally with a port number (defaults to 25).
* Use the returned object to create the Mailer.
A connection to the SMTP server will be established upon the first call to
``send()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
/*
It's also possible to use multiple method calls
$transport = Swift_SmtpTransport::newInstance()
->setHost('smtp.example.org')
->setPort(25)
;
*/
Encrypted SMTP
^^^^^^^^^^^^^^
You can use SSL or TLS encryption with the SMTP Transport by specifying it as
a parameter or with a method call.
To use encryption with the SMTP Transport:
* Pass the encryption setting as a third parameter to
``Swift_SmtpTransport::newInstance()``; or
* Call the ``setEncryption()`` method on the Transport.
A connection to the SMTP server will be established upon the first call to
``send()``. The connection will be initiated with the correct encryption
settings.
.. note::
For SSL or TLS encryption to work your PHP installation must have
appropriate OpenSSL transports wrappers. You can check if "tls" and/or
"ssl" are present in your PHP installation by using the PHP function
``stream_get_transports()``
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 587, 'ssl');
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
/*
It's also possible to use multiple method calls
$transport = Swift_SmtpTransport::newInstance()
->setHost('smtp.example.org')
->setPort(587)
->setEncryption('ssl')
;
*/
SMTP with a Username and Password
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some servers require authentication. You can provide a username and password
with ``setUsername()`` and ``setPassword()`` methods.
To use a username and password with the SMTP Transport:
* Create the Transport with ``Swift_SmtpTransport::newInstance()``.
* Call the ``setUsername()`` and ``setPassword()`` methods on the Transport.
Your username and password will be used to authenticate upon first connect
when ``send()`` are first used on the Mailer.
If authentication fails, an Exception of type ``Swift_TransportException`` will
be thrown.
.. note::
If you need to know early whether or not authentication has failed and an
Exception is going to be thrown, call the ``start()`` method on the
created Transport.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport the call setUsername() and setPassword()
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
->setUsername('username')
->setPassword('password')
;
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
The Sendmail Transport
......................
The Sendmail Transport sends messages by communicating with a locally
installed MTA -- such as ``sendmail``.
The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect to
any remote services. It is designed for Linux servers that have ``sendmail``
installed. The Transport starts a local ``sendmail`` process and sends messages
to it. Usually the ``sendmail`` process will respond quickly as it spools your
messages to disk before sending them.
The Transport is named the Sendmail Transport for historical reasons
(``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It
will send messages using other transfer agents such as Exim or Postfix despite
its name, provided they have the relevant sendmail wrappers so that they can be
started with the correct command-line flags.
It's a common misconception that because the Sendmail Transport returns a
result very quickly it must therefore deliver messages to recipients quickly
-- this is not true. It's not slow by any means, but it's certainly not
faster than SMTP when it comes to getting messages to the intended recipients.
This is because sendmail itself sends the messages over SMTP once they have
been quickly spooled to disk.
The Sendmail Transport has the potential to be just as smart of the SMTP
Transport when it comes to notifying Swift Mailer about which recipients were
rejected, but in reality the majority of locally installed ``sendmail``
instances are not configured well enough to provide any useful feedback. As such
Swift Mailer may report successful deliveries where they did in fact fail before
they even left your server.
You can run the Sendmail Transport in two different modes specified by command
line flags:
* "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP
Transport
* "``-t``" runs in piped mode with no feedback, but theoretically faster,
though not advised
You can think of the Sendmail Transport as a sort of asynchronous SMTP Transport
-- though if you have problems with delivery failures you should try using the
SMTP Transport instead. Swift Mailer isn't doing the work here, it's simply
passing the work to somebody else (i.e. ``sendmail``).
Using the Sendmail Transport
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To use the Sendmail Transport you simply need to call
``Swift_SendmailTransport::newInstance()`` with the command as a parameter.
To use the Sendmail Transport you need to know where ``sendmail`` or another MTA
exists on the server. Swift Mailer uses a default value of
``/usr/sbin/sendmail``, which should work on most systems.
You specify the entire command as a parameter (i.e. including the command line
flags). Swift Mailer supports operational modes of "``-bs``" (default) and
"``-t``".
.. note::
If you run sendmail in "``-t``" mode you will get no feedback as to whether
or not sending has succeeded. Use "``-bs``" unless you have a reason not to.
To use the Sendmail Transport:
* Call ``Swift_SendmailTransport::newInstance()`` with the command, including
the correct command line flags. The default is to use ``/usr/sbin/sendmail
-bs`` if this is not specified.
* Use the returned object to create the Mailer.
A sendmail process will be started upon the first call to ``send()``. If the
process cannot be started successfully an Exception of type
``Swift_TransportException`` will be thrown.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/exim -bs');
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
The Mail Transport
..................
The Mail Transport sends messages by delegating to PHP's internal
``mail()`` function.
In my experience -- and others' -- the ``mail()`` function is not particularly
predictable, or helpful.
Quite notably, the ``mail()`` function behaves entirely differently between
Linux and Windows servers. On linux it uses ``sendmail``, but on Windows it uses
SMTP.
In order for the ``mail()`` function to even work at all ``php.ini`` needs to be
configured correctly, specifying the location of sendmail or of an SMTP server.
The problem with ``mail()`` is that it "tries" to simplify things to the point
that it actually makes things more complex due to poor interface design. The
developers of Swift Mailer have gone to a lot of effort to make the Mail
Transport work with a reasonable degree of consistency.
Serious drawbacks when using this Transport are:
* Unpredictable message headers
* Lack of feedback regarding delivery failures
* Lack of support for several plugins that require real-time delivery feedback
It's a last resort, and we say that with a passion!
Using the Mail Transport
^^^^^^^^^^^^^^^^^^^^^^^^
To use the Mail Transport you simply need to call
``Swift_MailTransport::newInstance()``. It's unlikely you'll need to configure
the Transport.
To use the Mail Transport:
* Call ``Swift_MailTransport::newInstance()``.
* Use the returned object to create the Mailer.
Messages will be sent using the ``mail()`` function.
.. note::
The ``mail()`` function can take a ``$additional_parameters`` parameter.
Swift Mailer sets this to "``-f%s``" by default, where the "``%s``" is
substituted with the address of the sender (via a ``sprintf()``) at send
time. You may override this default by passing an argument to
``newInstance()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_MailTransport::newInstance();
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
Available Methods for Sending Messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Mailer class offers two methods for sending Messages -- ``send()``.
Each behaves in a slightly different way.
When a message is sent in Swift Mailer, the Mailer class communicates with
whichever Transport class you have chosen to use.
Each recipient in the message should either be accepted or rejected by the
Transport. For example, if the domain name on the email address is not
reachable the SMTP Transport may reject the address because it cannot process
it. Whichever method you use -- ``send()`` -- Swift Mailer will return
an integer indicating the number of accepted recipients.
.. note::
It's possible to find out which recipients were rejected -- we'll cover that
later in this chapter.
Using the ``send()`` Method
...........................
The ``send()`` method of the ``Swift_Mailer`` class sends a message using
exactly the same logic as your Desktop mail client would use. Just pass it a
Message and get a result.
To send a Message with ``send()``:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
``Swift_MailTransport`` or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Send the message via the ``send()`` method on the Mailer object.
The message will be sent just like it would be sent if you used your mail
client. An integer is returned which includes the number of successful
recipients. If none of the recipients could be sent to then zero will be
returned, which equates to a boolean ``false``. If you set two
``To:`` recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('[email protected]' => 'John Doe'))
->setTo(array('[email protected]', '[email protected]' => 'A name'))
->setBody('Here is the message itself')
;
// Send the message
$numSent = $mailer->send($message);
printf("Sent %d messages\n", $numSent);
/* Note that often that only the boolean equivalent of the
return value is of concern (zero indicates FALSE)
if ($mailer->send($message))
{
echo "Sent\n";
}
else
{
echo "Failed\n";
}
*/
Sending Emails in Batch
.......................
If you want to send a separate message to each recipient so that only their
own address shows up in the ``To:`` field, follow the following recipe:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
``Swift_MailTransport`` or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Iterate over the recipients and send message via the ``send()`` method on
the Mailer object.
Each recipient of the messages receives a different copy with only their own
email address on the ``To:`` field.
Make sure to add only valid email addresses as recipients. If you try to add an
invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift
Mailer will throw a ``Swift_RfcComplianceException``.
If you add recipients automatically based on a data source that may contain
invalid email addresses, you can prevent possible exceptions by validating the
addresses using ``Swift_Validate::email($email)`` and only adding addresses
that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and
``setBcc()`` calls in a try-catch block and handle the
``Swift_RfcComplianceException`` in the catch block.
Handling invalid addresses properly is especially important when sending emails
in large batches since a single invalid address might cause an unhandled
exception and stop the execution or your script early.
.. note::
In the following example, two emails are sent. One to each of
``[email protected]`` and ``[email protected]``. These recipients will
not be aware of each other.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('[email protected]' => 'John Doe'))
->setBody('Here is the message itself')
;
// Send the message
$failedRecipients = array();
$numSent = 0;
$to = array('[email protected]', '[email protected]' => 'A name');
foreach ($to as $address => $name)
{
if (is_int($address)) {
$message->setTo($name);
} else {
$message->setTo(array($address => $name));
}
$numSent += $mailer->send($message, $failedRecipients);
}
printf("Sent %d messages\n", $numSent);
Finding out Rejected Addresses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's possible to get a list of addresses that were rejected by the Transport
by using a by-reference parameter to ``send()``.
As Swift Mailer attempts to send the message to each address given to it, if a
recipient is rejected it will be added to the array. You can pass an existing
array, otherwise one will be created by-reference.
Collecting the list of recipients that were rejected can be useful in
circumstances where you need to "prune" a mailing list for example when some
addresses cannot be delivered to.
Getting Failures By-reference
.............................
Collecting delivery failures by-reference with the ``send()`` method is as
simple as passing a variable name to the method call.
To get failed recipients by-reference:
* Pass a by-reference variable name to the ``send()`` method of the Mailer
class.
If the Transport rejects any of the recipients, the culprit addresses will be
added to the array provided by-reference.
.. note::
If the variable name does not yet exist, it will be initialized as an
empty array and then failures will be added to that array. If the variable
already exists it will be type-cast to an array and failures will be added
to it.
.. code-block:: php
$mailer = Swift_Mailer::newInstance( ... );
$message = Swift_Message::newInstance( ... )
->setFrom( ... )
->setTo(array(
'[email protected]' => 'Receiver Name',
'[email protected]' => 'A name',
'[email protected]' => 'Other Name'
))
->setBody( ... )
;
// Pass a variable name to the send() method
if (!$mailer->send($message, $failures))
{
echo "Failures:";
print_r($failures);
}
/*
Failures:
Array (
0 => [email protected],
1 => [email protected]
)
*/
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Cookbook Default Expectations (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/cookbook/default_expectations.rst`)
.. index::
single: Cookbook; Default Mock Expectations
Default Mock Expectations
=========================
Often in unit testing, we end up with sets of tests which use the same object
dependency over and over again. Rather than mocking this class/object within
every single unit test (requiring a mountain of duplicate code), we can
instead define reusable default mocks within the test case's ``setup()``
method. This even works where unit tests use varying expectations on the same
or similar mock object.
How this works, is that you can define mocks with default expectations. Then,
in a later unit test, you can add or fine-tune expectations for that specific
test. Any expectation can be set as a default using the ``byDefault()``
declaration.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Cookbook Detecting Mock Objects (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/cookbook/detecting_mock_objects.rst`)
.. index::
single: Cookbook; Detecting Mock Objects
Detecting Mock Objects
======================
Users may find it useful to check whether a given object is a real object or a
simulated Mock Object. All Mockery mocks implement the
``\Mockery\MockInterface`` interface which can be used in a type check.
.. code-block:: php
assert($mightBeMocked instanceof \Mockery\MockInterface);
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Cookbook Index (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/cookbook/index.rst`)
Cookbook
========
.. toctree::
:hidden:
default_expectations
detecting_mock_objects
mocking_hard_dependencies
.. include:: map.rst.inc
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Cookbook Mocking Hard Dependencies (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/cookbook/mocking_hard_dependencies.rst`)
.. index::
single: Cookbook; Mocking Hard Dependencies
Mocking Hard Dependencies (new Keyword)
=======================================
One prerequisite to mock hard dependencies is that the code we are trying to test uses autoloading.
Let's take the following code for an example:
.. code-block:: php
<?php
namespace App;
class Service
{
function callExternalService($param)
{
$externalService = new Service\External();
$externalService->sendSomething($param);
return $externalService->getSomething();
}
}
The way we can test this without doing any changes to the code itself is by creating :doc:`instance mocks </reference/instance_mocking>` by using the ``overload`` prefix.
.. code-block:: php
<?php
namespace AppTest;
use Mockery as m;
class ServiceTest extends \PHPUnit_Framework_TestCase
{
public function testCallingExternalService()
{
$param = 'Testing';
$externalMock = m::mock('overload:App\Service\External');
$externalMock->shouldReceive('sendSomething')
->once()
->with($param);
$externalMock->shouldReceive('getSomething')
->once()
->andReturn('Tested!');
$service = new \App\Service();
$result = $service->callExternalService($param);
$this->assertSame('Tested!', $result);
}
}
If we run this test now, it should pass. Mockery does its job and our ``App\Service`` will use the mocked external service instead of the real one.
The problem with this is when we want to, for example, test the ``App\Service\External`` itself, or if we use that class somewhere else in our tests.
When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a "class already exists" exception. This is where autoloading kicks in and makes our job a lot easier.
To make this possible, we'll tell PHPUnit to run the tests that have overloaded classes in separate processes and to not preserve global state. That way we'll avoid having the overloaded class included more than once. Of course this has its downsides as these tests will run slower.
Our test example from above now becomes:
.. code-block:: php
<?php
namespace AppTest;
use Mockery as m;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class ServiceTest extends \PHPUnit_Framework_TestCase
{
public function testCallingExternalService()
{
$param = 'Testing';
$externalMock = m::mock('overload:App\Service\External');
$externalMock->shouldReceive('sendSomething')
->once()
->with($param);
$externalMock->shouldReceive('getSomething')
->once()
->andReturn('Tested!');
$service = new \App\Service();
$result = $service->callExternalService($param);
$this->assertSame('Tested!', $result);
}
}
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Getting Started Index (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/getting_started/index.rst`)
Getting Started
===============
.. toctree::
:hidden:
installation
upgrading
simple_example
.. include:: map.rst.inc
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Getting Started Installation (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/getting_started/installation.rst`)
.. index::
single: Installation
Installation
============
Mockery can be installed using Composer, PEAR or by cloning it from its GitHub
repository. These three options are outlined below.
Composer
--------
You can read more about Composer on `getcomposer.org <https://getcomposer.org>`_.
To install Mockery using Composer, first install Composer for your project
using the instructions on the `Composer download page <https://getcomposer.org/download/>`_.
You can then define your development dependency on Mockery using the suggested
parameters below. While every effort is made to keep the master branch stable,
you may prefer to use the current stable version tag instead (use the
``@stable`` tag).
.. code-block:: json
{
"require-dev": {
"mockery/mockery": "dev-master"
}
}
To install, you then may call:
.. code-block:: bash
php composer.phar update
This will install Mockery as a development dependency, meaning it won't be
installed when using ``php composer.phar update --no-dev`` in production.
PEAR
----
Mockery is hosted on the `survivethedeepend.com <http://pear.survivethedeepend.com>`_
PEAR channel and can be installed using the following commands:
.. code-block:: bash
sudo pear channel-discover pear.survivethedeepend.com
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps deepend/Mockery
Git
---
The Git repository hosts the development version in its master branch. You can
install this using Composer by referencing ``dev-master`` as your preferred
version in your project's ``composer.json`` file as the earlier example shows.
You may also install this development version using PEAR:
.. code-block:: bash
git clone git://github.com/padraic/mockery.git
cd mockery
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps package.xml
The above processes will install both Mockery and Hamcrest. While omitting
Hamcrest will not break Mockery, Hamcrest is recommended as it adds a wider
variety of functionality for argument matching.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Getting Started Simple Example (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/getting_started/simple_example.rst`)
.. index::
single: Getting Started; Simple Example
Simple Example
==============
Imagine we have a ``Temperature`` class which samples the temperature of a
locale before reporting an average temperature. The data could come from a web
service or any other data source, but we do not have such a class at present.
We can, however, assume some basic interactions with such a class based on its
interaction with the ``Temperature`` class:
.. code-block:: php
class Temperature
{
public function __construct($service)
{
$this->_service = $service;
}
public function average()
{
$total = 0;
for ($i=0;$i<3;$i++) {
$total += $this->_service->readTemp();
}
return $total/3;
}
}
Even without an actual service class, we can see how we expect it to operate.
When writing a test for the ``Temperature`` class, we can now substitute a
mock object for the real service which allows us to test the behaviour of the
``Temperature`` class without actually needing a concrete service instance.
.. code-block:: php
use \Mockery as m;
class TemperatureTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testGetsAverageTemperatureFromThreeServiceReadings()
{
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
$this->assertEquals(12, $temperature->average());
}
}
.. note::
PHPUnit integration can remove the need for a ``tearDown()`` method. See
":doc:`/reference/phpunit_integration`" for more information.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Getting Started Upgrading (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/getting_started/upgrading.rst`)
.. index::
single: Upgrading
Upgrading
=========
Upgrading to 0.9
----------------
The generator was completely rewritten, so any code with a deep integration to
mockery will need evaluating
Upgrading to 0.8
----------------
Since the release of 0.8.0 the following behaviours were altered:
1. The ``shouldIgnoreMissing()`` behaviour optionally applied to mock objects
returned an instance of ``\Mockery\Undefined`` when methods called did not
match a known expectation. Since 0.8.0, this behaviour was switched to
returning ``null`` instead. You can restore the 0.7.2 behavour by using the
following:
.. code-block:: php
$mock = \Mockery::mock('stdClass')->shouldIgnoreMissing()->asUndefined();
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Argument Validation (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/argument_validation.rst`)
.. index::
single: Argument Validation
Argument Validation
===================
The arguments passed to the ``with()`` declaration when setting up an
expectation determine the criteria for matching method calls to expectations.
Thus, you can setup up many expectations for a single method, each
differentiated by the expected arguments. Such argument matching is done on a
"best fit" basis. This ensures explicit matches take precedence over
generalised matches.
An explicit match is merely where the expected argument and the actual
argument are easily equated (i.e. using ``===`` or ``==``). More generalised
matches are possible using regular expressions, class hinting and the
available generic matchers. The purpose of generalised matchers is to allow
arguments be defined in non-explicit terms, e.g. ``Mockery::any()`` passed to
``with()`` will match **any** argument in that position.
Mockery's generic matchers do not cover all possibilities but offers optional
support for the Hamcrest library of matchers. Hamcrest is a PHP port of the
similarly named Java library (which has been ported also to Python, Erlang,
etc). I strongly recommend using Hamcrest since Mockery simply does not need
to duplicate Hamcrest's already impressive utility which itself promotes a
natural English DSL.
The example below show Mockery matchers and their Hamcrest equivalent.
Hamcrest uses functions (no namespacing).
Here's a sample of the possibilities.
.. code-block:: php
with(1)
Matches the integer ``1``. This passes the ``===`` test (identical). It does
facilitate a less strict ``==`` check (equals) where the string ``'1'`` would
also match the
argument.
.. code-block:: php
with(\Mockery::any()) OR with(anything())
Matches any argument. Basically, anything and everything passed in this
argument slot is passed unconstrained.
.. code-block:: php
with(\Mockery::type('resource')) OR with(resourceValue()) OR with(typeOf('resource'))
Matches any resource, i.e. returns true from an ``is_resource()`` call. The
Type matcher accepts any string which can be attached to ``is_`` to form a
valid type check. For example, ``\Mockery::type('float')`` or Hamcrest's
``floatValue()`` and ``typeOf('float')`` checks using ``is_float()``, and
``\Mockery::type('callable')`` or Hamcrest's ``callable()`` uses
``is_callable()``.
The Type matcher also accepts a class or interface name to be used in an
``instanceof`` evaluation of the actual argument (similarly Hamcrest uses
``anInstanceOf()``).
You may find a full list of the available type checkers at
`php.net <http://www.php.net/manual/en/ref.var.php>`_ or browse Hamcrest's function
list in
`the Hamcrest code <http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-php/hamcrest/Hamcrest.php>`_.
.. code-block:: php
with(\Mockery::on(closure))
The On matcher accepts a closure (anonymous function) to which the actual
argument will be passed. If the closure evaluates to (i.e. returns) boolean
``true`` then the argument is assumed to have matched the expectation. This is
invaluable where your argument expectation is a bit too complex for or simply
not implemented in the current default matchers.
There is no Hamcrest version of this functionality.
.. code-block:: php
with('/^foo/') OR with(matchesPattern('/^foo/'))
The argument declarator also assumes any given string may be a regular
expression to be used against actual arguments when matching. The regex option
is only used when a) there is no ``===`` or ``==`` match and b) when the regex
is verified to be a valid regex (i.e. does not return false from
``preg_match()``). If the regex detection doesn't suit your tastes, Hamcrest
offers the more explicit ``matchesPattern()`` function.
.. code-block:: php
with(\Mockery::ducktype('foo', 'bar'))
The Ducktype matcher is an alternative to matching by class type. It simply
matches any argument which is an object containing the provided list of
methods to call.
There is no Hamcrest version of this functionality.
.. code-block:: php
with(\Mockery::mustBe(2)) OR with(identicalTo(2))
The MustBe matcher is more strict than the default argument matcher. The
default matcher allows for PHP type casting, but the MustBe matcher also
verifies that the argument must be of the same type as the expected value.
Thus by default, the argument `'2'` matches the actual argument 2 (integer)
but the MustBe matcher would fail in the same situation since the expected
argument was a string and instead we got an integer.
Note: Objects are not subject to an identical comparison using this matcher
since PHP would fail the comparison if both objects were not the exact same
instance. This is a hindrance when objects are generated prior to being
returned, since an identical match just would never be possible.
.. code-block:: php
with(\Mockery::not(2)) OR with(not(2))
The Not matcher matches any argument which is not equal or identical to the
matcher's parameter.
.. code-block:: php
with(\Mockery::anyOf(1, 2)) OR with(anyOf(1,2))
Matches any argument which equals any one of the given parameters.
.. code-block:: php
with(\Mockery::notAnyOf(1, 2))
Matches any argument which is not equal or identical to any of the given
parameters.
There is no Hamcrest version of this functionality.
.. code-block:: php
with(\Mockery::subset(array(0 => 'foo')))
Matches any argument which is any array containing the given array subset.
This enforces both key naming and values, i.e. both the key and value of each
actual element is compared.
There is no Hamcrest version of this functionality, though Hamcrest can check
a single entry using ``hasEntry()`` or ``hasKeyValuePair()``.
.. code-block:: php
with(\Mockery::contains(value1, value2))
Matches any argument which is an array containing the listed values. The
naming of keys is ignored.
.. code-block:: php
with(\Mockery::hasKey(key));
Matches any argument which is an array containing the given key name.
.. code-block:: php
with(\Mockery::hasValue(value));
Matches any argument which is an array containing the given value.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Demeter Chains (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/demeter_chains.rst`)
.. index::
single: Mocking; Demeter Chains
Mocking Demeter Chains And Fluent Interfaces
============================================
Both of these terms refer to the growing practice of invoking statements
similar to:
.. code-block:: php
$object->foo()->bar()->zebra()->alpha()->selfDestruct();
The long chain of method calls isn't necessarily a bad thing, assuming they
each link back to a local object the calling class knows. Just as a fun
example, Mockery's long chains (after the first ``shouldReceive()`` method)
all call to the same instance of ``\Mockery\Expectation``. However, sometimes
this is not the case and the chain is constantly crossing object boundaries.
In either case, mocking such a chain can be a horrible task. To make it easier
Mockery support demeter chain mocking. Essentially, we shortcut through the
chain and return a defined value from the final call. For example, let's
assume ``selfDestruct()`` returns the string "Ten!" to $object (an instance of
``CaptainsConsole``). Here's how we could mock it.
.. code-block:: php
$mock = \Mockery::mock('CaptainsConsole');
$mock->shouldReceive('foo->bar->zebra->alpha->selfDestruct')->andReturn('Ten!');
The above expectation can follow any previously seen format or expectation,
except that the method name is simply the string of all expected chain calls
separated by ``->``. Mockery will automatically setup the chain of expected
calls with its final return values, regardless of whatever intermediary object
might be used in the real implementation.
Arguments to all members of the chain (except the final call) are ignored in
this process.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Expectations (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/expectations.rst`)
.. index::
single: Expectations
Expectation Declarations
========================
Once you have created a mock object, you'll often want to start defining how
exactly it should behave (and how it should be called). This is where the
Mockery expectation declarations take over.
.. code-block:: php
shouldReceive(method_name)
Declares that the mock expects a call to the given method name. This is the
starting expectation upon which all other expectations and constraints are
appended.
.. code-block:: php
shouldReceive(method1, method2, ...)
Declares a number of expected method calls, all of which will adopt any
chained expectations or constraints.
.. code-block:: php
shouldReceive(array('method1'=>1, 'method2'=>2, ...))
Declares a number of expected calls but also their return values. All will
adopt any additional chained expectations or constraints.
.. code-block:: php
shouldReceive(closure)
Creates a mock object (only from a partial mock) which is used to create a
mock object recorder. The recorder is a simple proxy to the original object
passed in for mocking. This is passed to the closure, which may run it through
a set of operations which are recorded as expectations on the partial mock. A
simple use case is automatically recording expectations based on an existing
usage (e.g. during refactoring). See examples in a later section.
.. code-block:: php
shouldNotReceive(method_name)
Declares that the mock should not expect a call to the given method name. This
method is a convenience method for calling ``shouldReceive()->never()``.
.. code-block:: php
with(arg1, arg2, ...) / withArgs(array(arg1, arg2, ...))
Adds a constraint that this expectation only applies to method calls which
match the expected argument list. You can add a lot more flexibility to
argument matching using the built in matcher classes (see later). For example,
``\Mockery::any()`` matches any argument passed to that position in the
``with()`` parameter list. Mockery also allows Hamcrest library matchers - for
example, the Hamcrest function ``anything()`` is equivalent to
``\Mockery::any()``.
It's important to note that this means all expectations attached only apply to
the given method when it is called with these exact arguments. This allows for
setting up differing expectations based on the arguments provided to expected
calls.
.. code-block:: php
withAnyArgs()
Declares that this expectation matches a method call regardless of what
arguments are passed. This is set by default unless otherwise specified.
.. code-block:: php
withNoArgs()
Declares this expectation matches method calls with zero arguments.
.. code-block:: php
andReturn(value)
Sets a value to be returned from the expected method call.
.. code-block:: php
andReturn(value1, value2, ...)
Sets up a sequence of return values or closures. For example, the first call
will return value1 and the second value2. Note that all subsequent calls to a
mocked method will always return the final value (or the only value) given to
this declaration.
.. code-block:: php
andReturnNull() / andReturn([NULL])
Both of the above options are primarily for communication to test readers.
They mark the mock object method call as returning ``null`` or nothing.
.. code-block:: php
andReturnValues(array)
Alternative syntax for ``andReturn()`` that accepts a simple array instead of
a list of parameters. The order of return is determined by the numerical
index of the given array with the last array member being return on all calls
once previous return values are exhausted.
.. code-block:: php
andReturnUsing(closure, ...)
Sets a closure (anonymous function) to be called with the arguments passed to
the method. The return value from the closure is then returned. Useful for
some dynamic processing of arguments into related concrete results. Closures
can queued by passing them as extra parameters as for ``andReturn()``.
.. note::
You cannot currently mix ``andReturnUsing()`` with ``andReturn()``.
.. code-block:: php
andThrow(Exception)
Declares that this method will throw the given ``Exception`` object when
called.
.. code-block:: php
andThrow(exception_name, message)
Rather than an object, you can pass in the ``Exception`` class and message to
use when throwing an ``Exception`` from the mocked method.
.. code-block:: php
andSet(name, value1) / set(name, value1)
Used with an expectation so that when a matching method is called, one can
also cause a mock object's public property to be set to a specified value.
.. code-block:: php
passthru()
Tells the expectation to bypass a return queue and instead call the real
method of the class that was mocked and return the result. Basically, it
allows expectation matching and call count validation to be applied against
real methods while still calling the real class method with the expected
arguments.
.. code-block:: php
zeroOrMoreTimes()
Declares that the expected method may be called zero or more times. This is
the default for all methods unless otherwise set.
.. code-block:: php
once()
Declares that the expected method may only be called once. Like all other call
count constraints, it will throw a ``\Mockery\CountValidator\Exception`` if
breached and can be modified by the ``atLeast()`` and ``atMost()``
constraints.
.. code-block:: php
twice()
Declares that the expected method may only be called twice.
.. code-block:: php
times(n)
Declares that the expected method may only be called n times.
.. code-block:: php
never()
Declares that the expected method may never be called. Ever!
.. code-block:: php
atLeast()
Adds a minimum modifier to the next call count expectation. Thus
``atLeast()->times(3)`` means the call must be called at least three times
(given matching method args) but never less than three times.
.. code-block:: php
atMost()
Adds a maximum modifier to the next call count expectation. Thus
``atMost()->times(3)`` means the call must be called no more than three times.
This also means no calls are acceptable.
.. code-block:: php
between(min, max)
Sets an expected range of call counts. This is actually identical to using
``atLeast()->times(min)->atMost()->times(max)`` but is provided as a
shorthand. It may be followed by a ``times()`` call with no parameter to
preserve the APIs natural language readability.
.. code-block:: php
ordered()
Declares that this method is expected to be called in a specific order in
relation to similarly marked methods. The order is dictated by the order in
which this modifier is actually used when setting up mocks.
.. code-block:: php
ordered(group)
Declares the method as belonging to an order group (which can be named or
numbered). Methods within a group can be called in any order, but the ordered
calls from outside the group are ordered in relation to the group, i.e. you
can set up so that method1 is called before group1 which is in turn called
before method 2.
.. code-block:: php
globally()
When called prior to ``ordered()`` or ``ordered(group)``, it declares this
ordering to apply across all mock objects (not just the current mock). This
allows for dictating order expectations across multiple mocks.
.. code-block:: php
byDefault()
Marks an expectation as a default. Default expectations are applied unless a
non-default expectation is created. These later expectations immediately
replace the previously defined default. This is useful so you can setup
default mocks in your unit test ``setup()`` and later tweak them in specific
tests as needed.
.. code-block:: php
getMock()
Returns the current mock object from an expectation chain. Useful where you
prefer to keep mock setups as a single statement, e.g.
.. code-block:: php
$mock = \Mockery::mock('foo')->shouldReceive('foo')->andReturn(1)->getMock();
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Final Methods Classes (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/final_methods_classes.rst`)
.. index::
single: Mocking; Final Classes/Methods
Dealing with Final Classes/Methods
==================================
One of the primary restrictions of mock objects in PHP, is that mocking
classes or methods marked final is hard. The final keyword prevents methods so
marked from being replaced in subclasses (subclassing is how mock objects can
inherit the type of the class or object being mocked.
The simplest solution is not to mark classes or methods as final!
However, in a compromise between mocking functionality and type safety,
Mockery does allow creating "proxy mocks" from classes marked final, or from
classes with methods marked final. This offers all the usual mock object
goodness but the resulting mock will not inherit the class type of the object
being mocked, i.e. it will not pass any instanceof comparison.
You can create a proxy mock by passing the instantiated object you wish to
mock into ``\Mockery::mock()``, i.e. Mockery will then generate a Proxy to the
real object and selectively intercept method calls for the purposes of setting
and meeting expectations.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Index (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/index.rst`)
Reference
=========
.. toctree::
:hidden:
startup_methods
expectations
argument_validation
partial_mocks
public_properties
public_static_properties
pass_by_reference_behaviours
demeter_chains
object_recording
final_methods_classes
magic_methods
mockery/index
.. include:: map.rst.inc
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Instance Mocking (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/instance_mocking.rst`)
.. index::
single: Mocking; Instance
Instance Mocking
================
Instance mocking means that a statement like:
.. code-block:: php
$obj = new \MyNamespace\Foo;
...will actually generate a mock object. This is done by replacing the real
class with an instance mock (similar to an alias mock), as with mocking public
methods. The alias will import its expectations from the original mock of
that type (note that the original is never verified and should be ignored
after its expectations are setup). This lets you intercept instantiation where
you can't simply inject a replacement object.
As before, this does not prevent a require statement from including the real
class and triggering a fatal PHP error. It's intended for use where
autoloading is the primary class loading mechanism.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Magic Methods (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/magic_methods.rst`)
.. index::
single: Mocking; Magic Methods
PHP Magic Methods
=================
PHP magic methods which are prefixed with a double underscore, e.g.
``__set()``, pose a particular problem in mocking and unit testing in general.
It is strongly recommended that unit tests and mock objects do not directly
refer to magic methods. Instead, refer only to the virtual methods and
properties these magic methods simulate.
Following this piece of advice will ensure you are testing the real API of
classes and also ensures there is no conflict should Mockery override these
magic methods, which it will inevitably do in order to support its role in
intercepting method calls and properties.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Object Recording (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/object_recording.rst`)
.. index::
single: Mocking; Object Recording
Mock Object Recording
=====================
In certain cases, you may find that you are testing against an already
established pattern of behaviour, perhaps during refactoring. Rather then hand
crafting mock object expectations for this behaviour, you could instead use
the existing source code to record the interactions a real object undergoes
onto a mock object as expectations - expectations you can then verify against
an alternative or refactored version of the source code.
To record expectations, you need a concrete instance of the class to be
mocked. This can then be used to create a partial mock to which is given the
necessary code to execute the object interactions to be recorded. A simple
example is outline below (we use a closure for passing instructions to the
mock).
Here we have a very simple setup, a class (``SubjectUser``) which uses another
class (``Subject``) to retrieve some value. We want to record as expectations
on our mock (which will replace ``Subject`` later) all the calls and return
values of a Subject instance when interacting with ``SubjectUser``.
.. code-block:: php
class Subject
{
public function execute() {
return 'executed!';
}
}
class SubjectUser
{
public function use(Subject $subject) {
return $subject->execute();
}
}
Here's the test case showing the recording:
.. code-block:: php
class SubjectUserTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
\Mockery::close();
}
public function testSomething()
{
$mock = \Mockery::mock(new Subject);
$mock->shouldExpect(function ($subject) {
$user = new SubjectUser;
$user->use($subject);
});
/**
* Assume we have a replacement SubjectUser called NewSubjectUser.
* We want to verify it behaves identically to SubjectUser, i.e.
* it uses Subject in the exact same way
*/
$newSubject = new NewSubjectUser;
$newSubject->use($mock);
}
}
After the ``\Mockery::close()`` call in ``tearDown()`` validates the mock
object, we should have zero exceptions if ``NewSubjectUser`` acted on
`Subject` in a similar way to ``SubjectUser``. By default the order of calls
are not enforced, and loose argument matching is enabled, i.e. arguments may
be equal (``==``) but not necessarily identical (``===``).
If you wished to be more strict, for example ensuring the order of calls and
the final call counts were identical, or ensuring arguments are completely
identical, you can invoke the recorder's strict mode from the closure block,
e.g.
.. code-block:: php
$mock->shouldExpect(function ($subject) {
$subject->shouldBeStrict();
$user = new SubjectUser;
$user->use($subject);
});
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Partial Mocks (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/partial_mocks.rst`)
.. index::
single: Mocking; Partial Mocks
Creating Partial Mocks
======================
Partial mocks are useful when you only need to mock several methods of an
object leaving the remainder free to respond to calls normally (i.e. as
implemented). Mockery implements three distinct strategies for creating
partials. Each has specific advantages and disadvantages so which strategy you
use will depend on your own preferences and the source code in need of
mocking.
#. Traditional Partial Mock
#. Passive Partial Mock
#. Proxied Partial Mock
Traditional Partial Mock
------------------------
A traditional partial mock, defines ahead of time which methods of a class are
to be mocked and which are to be left unmocked (i.e. callable as normal). The
syntax for creating traditional mocks is:
.. code-block:: php
$mock = \Mockery::mock('MyClass[foo,bar]');
In the above example, the ``foo()`` and ``bar()`` methods of MyClass will be
mocked but no other MyClass methods are touched. You will need to define
expectations for the ``foo()`` and ``bar()`` methods to dictate their mocked
behaviour.
Don't forget that you can pass in constructor arguments since unmocked methods
may rely on those!
.. code-block:: php
$mock = \Mockery::mock('MyNamespace\MyClass[foo]', array($arg1, $arg2));
Passive Partial Mock
--------------------
A passive partial mock is more of a default state of being.
.. code-block:: php
$mock = \Mockery::mock('MyClass')->makePartial();
In a passive partial, we assume that all methods will simply defer to the
parent class (``MyClass``) original methods unless a method call matches a
known expectation. If you have no matching expectation for a specific method
call, that call is deferred to the class being mocked. Since the division
between mocked and unmocked calls depends entirely on the expectations you
define, there is no need to define which methods to mock in advance. The
``makePartial()`` method is identical to the original ``shouldDeferMissing()``
method which first introduced this Partial Mock type.
Proxied Partial Mock
--------------------
A proxied partial mock is a partial of last resort. You may encounter a class
which is simply not capable of being mocked because it has been marked as
final. Similarly, you may find a class with methods marked as final. In such a
scenario, we cannot simply extend the class and override methods to mock - we
need to get creative.
.. code-block:: php
$mock = \Mockery::mock(new MyClass);
Yes, the new mock is a Proxy. It intercepts calls and reroutes them to the
proxied object (which you construct and pass in) for methods which are not
subject to any expectations. Indirectly, this allows you to mock methods
marked final since the Proxy is not subject to those limitations. The tradeoff
should be obvious - a proxied partial will fail any typehint checks for the
class being mocked since it cannot extend that class.
Special Internal Cases
----------------------
All mock objects, with the exception of Proxied Partials, allow you to make
any expectation call the underlying real class method using the ``passthru()``
expectation call. This will return values from the real call and bypass any
mocked return queue (which can simply be omitted obviously).
There is a fourth kind of partial mock reserved for internal use. This is
automatically generated when you attempt to mock a class containing methods
marked final. Since we cannot override such methods, they are simply left
unmocked. Typically, you don't need to worry about this but if you really
really must mock a final method, the only possible means is through a Proxied
Partial Mock. SplFileInfo, for example, is a common class subject to this form
of automatic internal partial since it contains public final methods used
internally.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Pass By Reference Behaviours (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/pass_by_reference_behaviours.rst`)
.. index::
single: Pass-By-Reference Method Parameter Behaviour
Preserving Pass-By-Reference Method Parameter Behaviour
=======================================================
PHP Class method may accept parameters by reference. In this case, changes
made to the parameter (a reference to the original variable passed to the
method) are reflected in the original variable. A simple example:
.. code-block:: php
class Foo
{
public function bar(&$a)
{
$a++;
}
}
$baz = 1;
$foo = new Foo;
$foo->bar($baz);
echo $baz; // will echo the integer 2
In the example above, the variable $baz is passed by reference to
``Foo::bar()`` (notice the ``&`` symbol in front of the parameter?). Any
change ``bar()`` makes to the parameter reference is reflected in the original
variable, ``$baz``.
Mockery 0.7+ handles references correctly for all methods where it can analyse
the parameter (using ``Reflection``) to see if it is passed by reference. To
mock how a reference is manipulated by the class method, you can use a closure
argument matcher to manipulate it, i.e. ``\Mockery::on()`` - see the
":doc:`argument_validation`" chapter.
There is an exception for internal PHP classes where Mockery cannot analyse
method parameters using ``Reflection`` (a limitation in PHP). To work around
this, you can explicitly declare method parameters for an internal class using
``/Mockery/Configuration::setInternalClassMethodParamMap()``.
Here's an example using ``MongoCollection::insert()``. ``MongoCollection`` is
an internal class offered by the mongo extension from PECL. Its ``insert()``
method accepts an array of data as the first parameter, and an optional
options array as the second parameter. The original data array is updated
(i.e. when a ``insert()`` pass-by-reference parameter) to include a new
``_id`` field. We can mock this behaviour using a configured parameter map (to
tell Mockery to expect a pass by reference parameter) and a ``Closure``
attached to the expected method parameter to be updated.
Here's a PHPUnit unit test verifying that this pass-by-reference behaviour is
preserved:
.. code-block:: php
public function testCanOverrideExpectedParametersOfInternalPHPClassesToPreserveRefs()
{
\Mockery::getConfiguration()->setInternalClassMethodParamMap(
'MongoCollection',
'insert',
array('&$data', '$options = array()')
);
$m = \Mockery::mock('MongoCollection');
$m->shouldReceive('insert')->with(
\Mockery::on(function(&$data) {
if (!is_array($data)) return false;
$data['_id'] = 123;
return true;
}),
\Mockery::any()
);
$data = array('a'=>1,'b'=>2);
$m->insert($data);
$this->assertTrue(isset($data['_id']));
$this->assertEquals(123, $data['_id']);
\Mockery::resetContainer();
}
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Phpunit Integration (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/phpunit_integration.rst`)
.. index::
single: PHPUnit Integration
PHPUnit Integration
===================
Mockery was designed as a simple-to-use *standalone* mock object framework, so
its need for integration with any testing framework is entirely optional. To
integrate Mockery, you just need to define a ``tearDown()`` method for your
tests containing the following (you may use a shorter ``\Mockery`` namespace
alias):
.. code-block:: php
public function tearDown() {
\Mockery::close();
}
This static call cleans up the Mockery container used by the current test, and
run any verification tasks needed for your expectations.
For some added brevity when it comes to using Mockery, you can also explicitly
use the Mockery namespace with a shorter alias. For example:
.. code-block:: php
use \Mockery as m;
class SimpleTest extends PHPUnit_Framework_TestCase
{
public function testSimpleMock() {
$mock = m::mock('simplemock');
$mock->shouldReceive('foo')->with(5, m::any())->once()->andReturn(10);
$this->assertEquals(10, $mock->foo(5));
}
public function tearDown() {
m::close();
}
}
Mockery ships with an autoloader so you don't need to litter your tests with
``require_once()`` calls. To use it, ensure Mockery is on your
``include_path`` and add the following to your test suite's ``Bootstrap.php``
or ``TestHelper.php`` file:
.. code-block:: php
require_once 'Mockery/Loader.php';
require_once 'Hamcrest/Hamcrest.php';
$loader = new \Mockery\Loader;
$loader->register();
If you are using Composer, you can simplify this to just including the
Composer generated autoloader file:
.. code-block:: php
require __DIR__ . '/../vendor/autoload.php'; // assuming vendor is one directory up
.. caution::
Prior to Hamcrest 1.0.0, the ``Hamcrest.php`` file name had a small "h"
(i.e. ``hamcrest.php``). If upgrading Hamcrest to 1.0.0 remember to check
the file name is updated for all your projects.)
To integrate Mockery into PHPUnit and avoid having to call the close method
and have Mockery remove itself from code coverage reports, use this in you
suite:
.. code-block:: php
// Create Suite
$suite = new PHPUnit_Framework_TestSuite();
// Create a result listener or add it
$result = new PHPUnit_Framework_TestResult();
$result->addListener(new \Mockery\Adapter\Phpunit\TestListener());
// Run the tests.
$suite->run($result);
If you are using PHPUnit's XML configuration approach, you can include the
following to load the ``TestListener``:
.. code-block:: xml
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>
Make sure Composer's or Mockery's autoloader is present in the bootstrap file
or you will need to also define a "file" attribute pointing to the file of the
above ``TestListener`` class.
.. caution::
PHPUnit provides a functionality that allows
`tests to run in a separated process <http://phpunit.de/manual/4.0/en/appendixes.annotations.html#appendixes.annotations.runTestsInSeparateProcesses>`_,
to ensure better isolation. Mockery verifies the mocks expectations using the
``Mockery::close()`` method, and provides a PHPUnit listener, that automatically
calls this method for you after every test.
However, this listener is not called in the right process when using PHPUnit's process
isolation, resulting in expectations that might not be respected, but without raising
any ``Mockery\Exception``. To avoid this, you cannot rely on the supplied Mockery PHPUnit
``TestListener``, and you need to explicitly calls ``Mockery::close``. The easiest solution
to include this call in the ``tearDown()`` method, as explained previously.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Public Properties (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/public_properties.rst`)
.. index::
single: Mocking; Public Properties
Mocking Public Properties
=========================
Mockery allows you to mock properties in several ways. The simplest is that
you can simply set a public property and value on any mock object. The second
is that you can use the expectation methods ``set()`` and ``andSet()`` to set
property values if that expectation is ever met.
You should note that, in general, Mockery does not support mocking any magic
methods since these are generally not considered a public API (and besides
they are a PITA to differentiate when you badly need them for mocking!). So
please mock virtual properties (those relying on ``__get()`` and ``__set()``)
as if they were actually declared on the class.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Public Static Properties (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/public_static_properties.rst`)
.. index::
single: Mocking; Public Static Methods
Mocking Public Static Methods
=============================
Static methods are not called on real objects, so normal mock objects can't
mock them. Mockery supports class aliased mocks, mocks representing a class
name which would normally be loaded (via autoloading or a require statement)
in the system under test. These aliases block that loading (unless via a
require statement - so please use autoloading!) and allow Mockery to intercept
static method calls and add expectations for them.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Quick Examples (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/quick_examples.rst`)
.. index::
single: Reference; Examples
Quick Examples
==============
Create a mock object to return a sequence of values from a set of method
calls.
.. code-block:: php
class SimpleTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
\Mockery::close();
}
public function testSimpleMock()
{
$mock = \Mockery::mock(array('pi' => 3.1416, 'e' => 2.71));
$this->assertEquals(3.1416, $mock->pi());
$this->assertEquals(2.71, $mock->e());
}
}
Create a mock object which returns a self-chaining Undefined object for a
method call.
.. code-block:: php
use \Mockery as m;
class UndefinedTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testUndefinedValues()
{
$mock = m::mock('mymock');
$mock->shouldReceive('divideBy')->with(0)->andReturnUndefined();
$this->assertTrue($mock->divideBy(0) instanceof \Mockery\Undefined);
}
}
Creates a mock object which multiple query calls and a single update call.
.. code-block:: php
use \Mockery as m;
class DbTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testDbAdapter()
{
$mock = m::mock('db');
$mock->shouldReceive('query')->andReturn(1, 2, 3);
$mock->shouldReceive('update')->with(5)->andReturn(NULL)->once();
// ... test code here using the mock
}
}
Expect all queries to be executed before any updates.
.. code-block:: php
use \Mockery as m;
class DbTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testQueryAndUpdateOrder()
{
$mock = m::mock('db');
$mock->shouldReceive('query')->andReturn(1, 2, 3)->ordered();
$mock->shouldReceive('update')->andReturn(NULL)->once()->ordered();
// ... test code here using the mock
}
}
Create a mock object where all queries occur after startup, but before finish,
and where queries are expected with several different params.
.. code-block:: php
use \Mockery as m;
class DbTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testOrderedQueries()
{
$db = m::mock('db');
$db->shouldReceive('startup')->once()->ordered();
$db->shouldReceive('query')->with('CPWR')->andReturn(12.3)->once()->ordered('queries');
$db->shouldReceive('query')->with('MSFT')->andReturn(10.0)->once()->ordered('queries');
$db->shouldReceive('query')->with("/^....$/")->andReturn(3.3)->atLeast()->once()->ordered('queries');
$db->shouldReceive('finish')->once()->ordered();
// ... test code here using the mock
}
}
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Startup Methods (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/startup_methods.rst`)
.. index::
single: Reference; Quick Reference
Quick Reference
===============
Mockery implements a shorthand API when creating a mock. Here's a sampling of
the possible startup methods.
.. code-block:: php
$mock = \Mockery::mock('foo');
Creates a mock object named "foo". In this case, "foo" is a name (not
necessarily a class name) used as a simple identifier when raising exceptions.
This creates a mock object of type ``\Mockery\Mock`` and is the loosest form
of mock possible.
.. code-block:: php
$mock = \Mockery::mock(array('foo'=>1,'bar'=>2));
Creates an mock object named unknown since we passed no name. However we did
pass an expectation array, a quick method of setting up methods to expect with
their return values.
.. code-block:: php
$mock = \Mockery::mock('foo', array('foo'=>1,'bar'=>2));
Similar to the previous examples and all examples going forward, expectation
arrays can be passed for all mock objects as the second parameter to
``mock()``.
.. code-block:: php
$mock = \Mockery::mock('foo', function($mock) {
$mock->shouldReceive(method_name);
});
In addition to expectation arrays, you can also pass in a closure which
contains reusable expectations. This can be passed as the second parameter, or
as the third parameter if partnered with an expectation array. This is one
method for creating reusable mock expectations.
.. code-block:: php
$mock = \Mockery::mock('stdClass');
Creates a mock identical to a named mock, except the name is an actual class
name. Creates a simple mock as previous examples show, except the mock object
will inherit the class type (via inheritance), i.e. it will pass type hints or
instanceof evaluations for stdClass. Useful where a mock object must be of a
specific type.
.. code-block:: php
$mock = \Mockery::mock('FooInterface');
You can create mock objects based on any concrete class, abstract class or
even an interface. Again, the primary purpose is to ensure the mock object
inherits a specific type for type hinting. There is an exception in that
classes marked final, or with methods marked final, cannot be mocked fully. In
these cases a partial mock (explained later) must be utilised.
.. code-block:: php
$mock = \Mockery::mock('alias:MyNamespace\MyClass');
Prefixing the valid name of a class (which is NOT currently loaded) with
"alias:" will generate an "alias mock". Alias mocks create a class alias with
the given classname to stdClass and are generally used to enable the mocking
of public static methods. Expectations set on the new mock object which refer
to static methods will be used by all static calls to this class.
.. code-block:: php
$mock = \Mockery::mock('overload:MyNamespace\MyClass');
Prefixing the valid name of a class (which is NOT currently loaded) with
"overload:" will generate an alias mock (as with "alias:") except that created
new instances of that class will import any expectations set on the origin
mock (``$mock``). The origin mock is never verified since it's used an
expectation store for new instances. For this purpose we use the term
"instance mock" to differentiate it from the simpler "alias mock".
.. note::
Using alias/instance mocks across more than one test will generate a fatal
error since you can't have two classes of the same name. To avoid this,
run each test of this kind in a separate PHP process (which is supported
out of the box by both PHPUnit and PHPT).
.. code-block:: php
$mock = \Mockery::mock('stdClass, MyInterface1, MyInterface2');
The first argument can also accept a list of interfaces that the mock object
must implement, optionally including no more than one existing class to be
based on. The class name doesn't need to be the first member of the list but
it's a friendly convention to use for readability. All subsequent arguments
remain unchanged from previous examples.
If the given class does not exist, you must define and include it beforehand
or a ``\Mockery\Exception`` will be thrown.
.. code-block:: php
$mock = \Mockery::mock('MyNamespace\MyClass[foo,bar]');
The syntax above tells Mockery to partially mock the ``MyNamespace\MyClass``
class, by mocking the ``foo()`` and ``bar()`` methods only. Any other method
will be not be overridden by Mockery. This traditional form of "partial mock"
can be applied to any class or abstract class (e.g. mocking abstract methods
where a concrete implementation does not exist yet). If you attempt to partial
mock a method marked final, it will actually be ignored in that instance
leaving the final method untouched. This is necessary since mocking of final
methods is, by definition in PHP, impossible.
Please refer to ":doc:`partial_mocks`" for a detailed explanation on how to
create Partial Mocks in Mockery.
.. code-block:: php
$mock = \Mockery::mock("MyNamespace\MyClass[foo]", array($arg1, $arg2));
If Mockery encounters an indexed array as the second or third argument, it
will assume they are constructor parameters and pass them when constructing
the mock object. The syntax above will create a new partial mock, particularly
useful if method ``bar`` calls method ``foo`` internally with
``$this->foo()``.
.. code-block:: php
$mock = \Mockery::mock(new Foo);
Passing any real object into Mockery will create a Proxied Partial Mock. This
can be useful if real partials are impossible, e.g. a final class or class
where you absolutely must override a method marked final. Since you can
already create a concrete object, so all we need to do is selectively override
a subset of existing methods (or add non-existing methods!) for our
expectations.
A little revision: All mock methods accept the class, object or alias name to
be mocked as the first parameter. The second parameter can be an expectation
array of methods and their return values, or an expectation closure (which can
be the third param if used in conjunction with an expectation array).
.. code-block:: php
\Mockery::self()
At times, you will discover that expectations on a mock include methods which
need to return the same mock object (e.g. a common case when designing a
Domain Specific Language (DSL) such as the one Mockery itself uses!). To
facilitate this, calling ``\Mockery::self()`` will always return the last Mock
Object created by calling ``\Mockery::mock()``. For example:
.. code-block:: php
$mock = \Mockery::mock('BazIterator')
->shouldReceive('next')
->andReturn(\Mockery::self())
->mock();
The above class being mocked, as the ``next()`` method suggests, is an
iterator. In many cases, you can replace all the iterated elements (since they
are the same type many times) with just the one mock object which is
programmed to act as discrete iterated elements.
.. code-block:: php
$mock = \Mockery::namedMock('MyClassName', 'DateTime');
The ``namedMock`` method will generate a class called by the first argument,
so in this example ``MyClassName``. The rest of the arguments are treat in the
same way as the ``mock`` method, so again, this example would create a class
called ``MyClassName`` that extends ``DateTime``.
Named mocks are quite an edge case, but they can be useful when code depends
on the ``__CLASS__`` magic constant, or when you need two derivatives of an
abstract type, that are actually different classes.
.. caution::
You can only create a named mock once, any subsequent calls to
``namedMock``, with different arguments are likely to cause exceptions.
Behaviour Modifiers
-------------------
When creating a mock object, you may wish to use some commonly preferred
behaviours that are not the default in Mockery.
.. code-block:: php
\Mockery::mock('MyClass')->shouldIgnoreMissing()
The use of the ``shouldIgnoreMissing()`` behaviour modifier will label this
mock object as a Passive Mock. In such a mock object, calls to methods which
are not covered by expectations will return ``null`` instead of the usual
complaining about there being no expectation matching the call.
You can optionally prefer to return an object of type ``\Mockery\Undefined``
(i.e. a ``null`` object) (which was the 0.7.2 behaviour) by using an
additional modifier:
.. code-block:: php
\Mockery::mock('MyClass')->shouldIgnoreMissing()->asUndefined()
The returned object is nothing more than a placeholder so if, by some act of
fate, it's erroneously used somewhere it shouldn't it will likely not pass a
logic check.
.. code-block:: php
\Mockery::mock('MyClass')->makePartial()
also
.. code-block:: php
\Mockery::mock('MyClass')->shouldDeferMissing()
Known as a Passive Partial Mock (not to be confused with real partial mock
objects discussed later), this form of mock object will defer all methods not
subject to an expectation to the parent class of the mock, i.e. ``MyClass``.
Whereas the previous ``shouldIgnoreMissing()`` returned ``null``, this
behaviour simply calls the parent's matching method.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Mockery Configuration (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/mockery/configuration.rst`)
.. index::
single: Mockery; Configuration
Mockery Global Configuration
============================
To allow for a degree of fine-tuning, Mockery utilises a singleton
configuration object to store a small subset of core behaviours. The three
currently present include:
* Option to allow/disallow the mocking of methods which do not actually exist
* Option to allow/disallow the existence of expectations which are never
fulfilled (i.e. unused)
* Setter/Getter for added a parameter map for internal PHP class methods
(``Reflection`` cannot detect these automatically)
By default, the first two behaviours are enabled. Of course, there are
situations where this can lead to unintended consequences. The mocking of
non-existent methods may allow mocks based on real classes/objects to fall out
of sync with the actual implementations, especially when some degree of
integration testing (testing of object wiring) is not being performed.
Allowing unfulfilled expectations means unnecessary mock expectations go
unnoticed, cluttering up test code, and potentially confusing test readers.
You may allow or disallow these behaviours (whether for whole test suites or
just select tests) by using one or both of the following two calls:
.. code-block:: php
\Mockery::getConfiguration()->allowMockingNonExistentMethods(bool);
\Mockery::getConfiguration()->allowMockingMethodsUnnecessarily(bool);
Passing a true allows the behaviour, false disallows it. Both take effect
immediately until switched back. In both cases, if either behaviour is
detected when not allowed, it will result in an Exception being thrown at that
point. Note that disallowing these behaviours should be carefully considered
since they necessarily remove at least some of Mockery's flexibility.
The other two methods are:
.. code-block:: php
\Mockery::getConfiguration()->setInternalClassMethodParamMap($class, $method, array $paramMap)
\Mockery::getConfiguration()->getInternalClassMethodParamMap($class, $method)
These are used to define parameters (i.e. the signature string of each) for the
methods of internal PHP classes (e.g. SPL, or PECL extension classes like
ext/mongo's MongoCollection. Reflection cannot analyse the parameters of internal
classes. Most of the time, you never need to do this. It's mainly needed where an
internal class method uses pass-by-reference for a parameter - you MUST in such
cases ensure the parameter signature includes the ``&`` symbol correctly as Mockery
won't correctly add it automatically for internal classes.
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Mockery Exceptions (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/mockery/exceptions.rst`)
.. index::
single: Mockery; Exceptions
Mockery Exceptions
==================
Mockery throws three types of exceptions when it cannot verify a mock object.
#. ``\Mockery\Exception\InvalidCountException``
#. ``\Mockery\Exception\InvalidOrderException``
#. ``\Mockery\Exception\NoMatchingExpectationException``
You can capture any of these exceptions in a try...catch block to query them
for specific information which is also passed along in the exception message
but is provided separately from getters should they be useful when logging or
reformatting output.
\Mockery\Exception\InvalidCountException
----------------------------------------
The exception class is used when a method is called too many (or too few)
times and offers the following methods:
* ``getMock()`` - return actual mock object
* ``getMockName()`` - return the name of the mock object
* ``getMethodName()`` - return the name of the method the failing expectation
is attached to
* ``getExpectedCount()`` - return expected calls
* ``getExpectedCountComparative()`` - returns a string, e.g. ``<=`` used to
compare to actual count
* ``getActualCount()`` - return actual calls made with given argument
constraints
\Mockery\Exception\InvalidOrderException
----------------------------------------
The exception class is used when a method is called outside the expected order
set using the ``ordered()`` and ``globally()`` expectation modifiers. It
offers the following methods:
* ``getMock()`` - return actual mock object
* ``getMockName()`` - return the name of the mock object
* ``getMethodName()`` - return the name of the method the failing expectation
is attached to
* ``getExpectedOrder()`` - returns an integer represented the expected index
for which this call was expected
* ``getActualOrder()`` - return the actual index at which this method call
occurred.
\Mockery\Exception\NoMatchingExpectationException
-------------------------------------------------
The exception class is used when a method call does not match any known
expectation. All expectations are uniquely identified in a mock object by the
method name and the list of expected arguments. You can disable this exception
and opt for returning NULL from all unexpected method calls by using the
earlier mentioned shouldIgnoreMissing() behaviour modifier. This exception
class offers the following methods:
* ``getMock()`` - return actual mock object
* ``getMockName()`` - return the name of the mock object
* ``getMethodName()`` - return the name of the method the failing expectation
is attached to
* ``getActualArguments()`` - return actual arguments used to search for a
matching expectation
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Mockery Gotchas (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/mockery/gotchas.rst`)
.. index::
single: Mockery; Gotchas
Gotchas!
========
Mocking objects in PHP has its limitations and gotchas. Some functionality
can't be mocked or can't be mocked YET! If you locate such a circumstance,
please please (pretty please with sugar on top) create a new issue on GitHub
so it can be documented and resolved where possible. Here is a list to note:
1. Classes containing public ``__wakeup()`` methods can be mocked but the
mocked ``__wakeup()`` method will perform no actions and cannot have
expectations set for it. This is necessary since Mockery must serialize and
unserialize objects to avoid some ``__construct()`` insanity and attempting
to mock a ``__wakeup()`` method as normal leads to a
``BadMethodCallException`` been thrown.
2. Classes using non-real methods, i.e. where a method call triggers a
``__call()`` method, will throw an exception that the non-real method does
not exist unless you first define at least one expectation (a simple
``shouldReceive()`` call would suffice). This is necessary since there is
no other way for Mockery to be aware of the method name.
3. Mockery has two scenarios where real classes are replaced: Instance mocks
and alias mocks. Both will generate PHP fatal errors if the real class is
loaded, usually via a require or include statement. Only use these two mock
types where autoloading is in place and where classes are not explicitly
loaded on a per-file basis using ``require()``, ``require_once()``, etc.
4. Internal PHP classes are not entirely capable of being fully analysed using
``Reflection``. For example, ``Reflection`` cannot reveal details of
expected parameters to the methods of such internal classes. As a result,
there will be problems where a method parameter is defined to accept a
value by reference (Mockery cannot detect this condition and will assume a
pass by value on scalars and arrays). If references as internal class
method parameters are needed, you should use the
``\Mockery\Configuration::setInternalClassMethodParamMap()`` method.
The gotchas noted above are largely down to PHP's architecture and are assumed
to be unavoidable. But - if you figure out a solution (or a better one than
what may exist), let us know!
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Mockery Index (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/mockery/index.rst`)
Mockery
=======
.. toctree::
:maxdepth: 2
configuration
exceptions
reserved_method_names
gotchas
---
### Samples Development Frameworks Laravel Vendor Mockery Mockery Docs Reference Mockery Reserved Method Names (`samples/development-frameworks/laravel/vendor/mockery/mockery/docs/reference/mockery/reserved_method_names.rst`)
.. index::
single: Reserved Method Names
Reserved Method Names
=====================
As you may have noticed, Mockery uses a number of methods called directly on
all mock objects, for example ``shouldReceive()``. Such methods are necessary
in order to setup expectations on the given mock, and so they cannot be
implemented on the classes or objects being mocked without creating a method
name collision (reported as a PHP fatal error). The methods reserved by
Mockery are:
* ``shouldReceive()``
* ``shouldBeStrict()``
In addition, all mocks utilise a set of added methods and protected properties
which cannot exist on the class or object being mocked. These are far less
likely to cause collisions. All properties are prefixed with ``_mockery`` and
all method names with ``mockery_``.
---
--- METRICS ---
- Files Extracted: 97
- Estimated Token Budget: ~83719 tokens
- Canonical Reference: https://codewiki.google/github.com/microsoft/sql-server-samples