Download the PHP package calisero/calisero-symfony without Composer

On this page you can find all versions of the php package calisero/calisero-symfony. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package calisero-symfony

Calisero SMS Bundle for Symfony

Packagist version CI Coverage PHP Symfony PHPStan Calisero PHP SDK Code style: Symfony Downloads

Official Symfony bundle for the Calisero transactional SMS API.

It wraps the Calisero PHP SDK and brings it into Symfony the Symfony way: semantic configuration, autowired services, a Notifier transport, a delivery webhook dispatching events, console commands and validation constraints. Supports Symfony 6.4, 7.x and 8.x on PHP 8.2 to 8.5.

Features

Requirements

Bundle Symfony PHP Calisero PHP SDK Calisero API
^1.0 6.4, 7.x, 8.x 8.2 โ€“ 8.5 (Symfony 8 requires PHP 8.4+) ^2.3 1.0.14

Composer picks the Symfony release your PHP version allows: on PHP 8.2 and 8.3 you get Symfony 6.4 or 7.x, on PHP 8.4 and 8.5 any of the three. The SDK needs ext-curl and ext-json.

The Notifier transport needs symfony/notifier, the constraints symfony/validator; both are optional.

Installation

With Symfony Flex the bundle is registered for you. Otherwise add it to config/bundles.php:

Configure the bundle

Create config/packages/calisero.yaml:

Declare the variables in .env, committed, without their values:

and set their values in .env.local, in your secrets vault (bin/console secrets:set CALISERO_API_KEY) or in your platform's environment:

That is all you need to send. The Configuration Reference lists every option; the webhook, the Notifier and the constraints are set up in their own sections below.

Getting Your API Key

  1. Log in to your Calisero account at https://calisero.ro
  2. Open the API Keys section of the dashboard and click Add Key
  3. Name it after the application and the environment (one key per environment), set IP filters if you need them
  4. Copy the key: it is shown only once

Security Note: never commit an API key. Keep it in .env.local, in Symfony's secrets vault or in your platform's environment. A sandbox key sends no real message and costs nothing: use one in development.

Usage

Quick Start: Send an SMS

Autowire SmsClientInterface:

Sending Options

Every optional parameter accepts snake_case or camelCase (shorten_urls or shortenUrls):

Verification Codes (2FA)

Calisero generates the code (6 characters, case-insensitive), sends it by SMS and checks it:

A wrong, expired or exhausted code is refused with a ValidationException (422), whose message says which. Either brand or template is required. A code's SMS counts towards the daily sending limit. See examples/verification_controller.php for a whole flow.

Messages and the Account

Through the Notifier

With symfony/notifier, Calisero becomes an SMS transport (TexterInterface, and the sms channel of notifications):

DSN Means
calisero://default The configured API key (calisero.api_key) and base URI
calisero://API_KEY@default Its own API key
?from=MyBrand The sender of the messages that do not set one (optional)
calisero://[email protected] Another host: https://staging.example.com/api/v1 (a port and a path may follow)

The transport applies the bundle's configuration like SmsClientInterface does: timeouts, User-Agent and the webhook's callback_url. It sends through the SDK, so it needs no symfony/http-client.

The sender is the SmsMessage's from (third constructor argument), else the DSN's, else Calisero's default.

Notifications go out the same way, through the sms channel:

A notification implementing SmsNotificationInterface shapes its own SmsMessage, Calisero options included: see examples/notification_example.php.

When the API refuses a message, the transport throws a CaliseroTransportException, a TransportExceptionInterface of the Notifier: getApiException() (also its previous exception) gives the SDK's, to tell a DailyLimitExceededException from a ValidationException, and getDebug() the HTTP status, the trace ID and the error body.

Sending Asynchronously

Route the SMS of the Notifier through Messenger to send them from a worker:

The bundle never retries a request: the API takes no idempotency key, so a send retried after a timeout could deliver the message twice. The API refuses (422) the same message to the same recipient sent again within a few seconds. Retry from your own code when a failure means nothing was sent: a DailyLimitExceededException (after getResetsAt()), a RateLimitedException (after getRetryAfter() seconds), an UnauthorizedException...

A worker has no request to build absolute URLs from: set framework.router.default_uri (see Webhook Handling).

The SDK's Services

SmsClientInterface covers what an application needs most. The Calisero PHP SDK's services are autowired too, built on the bundle configuration (base URI, timeouts, User-Agent), for everything else:

Autowire Service Gives
Calisero\Sms\Services\MessageService calisero.messages create(), get(), list(), delete()
Calisero\Sms\Services\VerificationService calisero.verifications create(), get(), list($page, $status), validate()
Calisero\Sms\Services\OptOutService calisero.opt_outs create(), get(), list(), update(), delete()
Calisero\Sms\Services\AccountService calisero.accounts get($accountId)
Calisero\SymfonySms\Client\SdkClient calisero.sdk_client The four, and the SDK's HttpClient (getLastResponse())
Calisero\SymfonySms\Client\ClientFactory calisero.client_factory make($apiKey): the same on another API key

One API key per tenant? ClientFactory::make($apiKey) builds the services on it, and new SmsClient($sdkClient, null, $accountId) the client: see examples/multi_tenant_client.php. The SDK's README documents every service and DTO.

Validation Constraints

Constraint Options Error codes
PhoneE164 message PhoneE164::INVALID_FORMAT_ERROR
SenderId lengthMessage, charactersMessage SenderId::INVALID_LENGTH_ERROR, SenderId::INVALID_CHARACTERS_ERROR

Like Symfony's own constraints, both let null and '' through (add NotBlank to require a value) and report a value that is not a string as a type error. Their messages are translated into Romanian (validators domain); override them in your translations/validators.ro.xlf.

Webhook Handling

When a message has a callback_url, Calisero posts its delivery status there each time it changes. The bundle answers these callbacks and dispatches them as events.

1. Enable the webhook and set a token:

2. Import the bundle's routes:

The route, POST /calisero/webhook named calisero_webhook, is loaded only while the webhook is enabled.

3. Tell the router your public URL, for the messages sent outside a request (console commands, Messenger workers), where it has none to build the callback URL from:

While the webhook is enabled, every message that sets no callback_url, sent by SmsClientInterface or the Notifier, carries the webhook's absolute URL, e.g. https://shop.example.com/calisero/webhook?token=โ€ฆ. If the route is not loaded, the message is refused with a \LogicException, rather than sent with a callback URL nothing answers.

Securing the Webhook

With a token set, the callback URL carries it as ?token=, and the endpoint answers 401 to a callback without it, compared in constant time. If you set a callback_url yourself, add the ?token= to it. Without a token the endpoint is open to anyone who knows its URL (POST only): prefer a token, or other controls (IP allow-list, WAF).

To rotate the token, update CALISERO_WEBHOOK_TOKEN and deploy: messages sent from then on carry the new one, and the callbacks of the messages sent before still carry the old one, refused from then on.

Listening for the Events

Status Event Meaning
sent MessageSentEvent Accepted and handed to the network
delivered MessageDeliveredEvent The handset or the network confirmed the delivery
undelivered MessageFailedEvent The delivery failed for good (failed, posted by hand, too)

The three extend DeliveryStatusEvent: getPayload(), getMessage(), getMessageId(), getStatus(). The webhook also dispatches the monitoring events of Credit Monitoring and Daily Sending Limit.

The endpoint answers 200 {"ok": true}, 401 for a wrong token and 400 for a body that is not a JSON object. Calisero retries a callback only when the connection fails or your endpoint does not answer within 2 seconds (at most 5 attempts); a non-2xx answer is not retried. Keep the listeners fast: hand slow work to Messenger.

Payload example:

dailyLimit and dailyRemaining are null while the account has no daily sending limit. A failed delivery has "status": "undelivered" and a deliveredAt of null.

Console Commands

A refusal prints the API's message and the trace ID, tells the daily sending limit from the request rate limit, and lists the fields at fault in a 422; the command then exits with 1.

Configuration Reference

bin/console config:dump-reference calisero prints it, with the description of every option. Every value may come from an environment variable, read only when the application runs; cast the ones that are not strings: %env(bool:CALISERO_WEBHOOK_ENABLED)%, %env(float:CALISERO_TIMEOUT)%, %env(int:CALISERO_DAILY_LIMIT_LOW)%, and declare every variable in .env with its default (CALISERO_WEBHOOK_ENABLED=false, CALISERO_ACCOUNT_ID=): an empty account ID or token counts as none. An empty API key is checked by the first request, which then throws a \RuntimeException naming calisero.api_key: an application without one still boots, and fails only where it calls the API.

Suggested variable Option Description
CALISERO_API_KEY api_key Your API key, from the dashboard
CALISERO_ACCOUNT_ID account_id Your account ID, for getAccount(), getBalance() and calisero:account
CALISERO_WEBHOOK_ENABLED webhook.enabled Load the webhook route and send its URL as the callback_url
CALISERO_WEBHOOK_TOKEN webhook.token Shared secret required from every callback
CALISERO_DSN framework.notifier.texter_transports The Notifier transport, e.g. calisero://default?from=MyBrand

User-Agent

Every request names the bundle and its version, PHP, Symfony and the platform, as the other Calisero libraries do, so Calisero can tell the bundle's requests apart and see which versions sent them:

The header cannot be configured: a request whose User-Agent starts with Calisero-SMS-Symfony/ always comes from this bundle.

Sender ID (Alphanumeric) Requirements

Custom alphanumeric sender IDs (the from parameter) must be approved by Calisero before they can be used in production. With an unapproved sender the API may refuse the message (422), or the gateway substitute a default one.

Without an approved sender, leave from out and Calisero assigns its default one.

Credit Monitoring

Set thresholds, and every delivery callback compares the account's remaining balance with them:

At or below the critical threshold only CreditCriticalEvent is dispatched. Leave a threshold null to disable it. The webhook must be enabled.

Daily Sending Limit

Every Calisero account has its own daily sending limit. Each real message counts once, whatever its number of parts, verification codes included; test messages (a sandbox account or API key) never count. The day ends at midnight, Romania time (Europe/Bucharest).

Where to read it

When it is reached, the API answers 429 and the SDK throws DailyLimitExceededException: nothing was sent and nothing billed. It extends RateLimitedException, so catch it first to tell it from the request rate limit (240 requests a minute):

Before it is reached, set a threshold and listen for DailyLimitLowEvent, dispatched by the delivery webhook (which must be enabled) whenever the messages left today are at or below it:

To raise the limit, contact Calisero.

Error Handling

The SDK throws a typed exception for every error status, carrying the API's own message:

Exception Status
UnauthorizedException 401
ForbiddenException 403
NotFoundException 404
ValidationException 422
DailyLimitExceededException (extends RateLimitedException) 429, code: daily_limit_exceeded
RateLimitedException 429
ServerException 500, 502, 503, 504
ApiException (the parent of all of the above) any other error
TransportException no answer (connection failed, timeout)

All in Calisero\Sms\Exceptions. Every ApiException has getTraceId(): quote it to Calisero support, or look the request up in the dashboard under Developers โ†’ Debug. The bundle's own \InvalidArgumentException (a missing, unknown or wrongly typed parameter), \RuntimeException (a missing API key or account ID) and \LogicException (the webhook enabled without its route) report a mistake before any request is made. Through the Notifier, API errors arrive wrapped in a CaliseroTransportException.

Coming from calisero/laravel-sms

The client's methods and parameters are the same as the Laravel package's:

Laravel package This bundle
Calisero::sendSms([...]) (facade) SmsClientInterface::sendSms([...]) (autowired)
config/calisero.php, CALISERO_* variables config/packages/calisero.yaml, %env(CALISERO_*)%
Notification channel calisero, SmsMessage Notifier transport calisero://, SmsMessage + CaliseroOptions
MessageSent, MessageDelivered, MessageFailed MessageSentEvent, MessageDeliveredEvent, MessageFailedEvent
$event->messageData, $event->message() $event->getPayload(), $event->getMessage()
CreditLow, CreditCritical, DailyLimitLow CreditLowEvent, CreditCriticalEvent, DailyLimitLowEvent
Rule::phoneE164(), Rule::senderId() #[PhoneE164], #[SenderId]
php artisan calisero:โ€ฆ bin/console calisero:โ€ฆ (same names and options)
Route registered when enabled Routes imported once (type: calisero), loaded when enabled

Unlike the Laravel package, the bundle refuses unknown sendSms() parameters instead of ignoring them.

Testing Your Application

Mock SmsClientInterface in unit tests. In functional tests, replace the bundle's transport, the service calisero.http_transport, with a stub implementing Calisero\Sms\Contracts\HttpClientInterface: everything else (the client, the SDK's services, the Notifier transport) then runs for real, without a request leaving the test.

The bundle's own tests work the same way: see TESTING.md.

Examples

Copy-paste friendly examples for a Symfony application live in examples/:

Scenario File
Configuration: bundle, routes, Notifier examples/config/
Send from a service, with error handling examples/send_sms_service.php
Shortened URLs, scheduling, the daily limit left examples/send_sms_with_shortened_urls.php
Send through the Notifier examples/notifier_texter.php
A notification sent by SMS examples/notification_example.php
Two-factor authentication controller examples/verification_controller.php
Delivery webhook listeners examples/webhook_listeners.php
Credit monitoring listeners examples/credit_monitoring_listeners.php
Daily sending limit (account, refusal, DailyLimitLowEvent) examples/daily_limit.php
Validation constraints examples/validation_constraints.php
The SDK's services: opt-outs, verifications examples/sdk_services.php
One API key per tenant examples/multi_tenant_client.php

See the Examples README.

Development

The development environment runs in Docker: nothing but Docker is needed on your machine.

automation/README.md the environment, including a demo application to try the bundle against the real API.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email [email protected] instead of using the issue tracker.

License

The MIT License (MIT). Please see the License File for more information.

Support


All versions of calisero-symfony with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
calisero/calisero-php Version ^2.3
symfony/console Version ^6.4 || ^7.0 || ^8.0
symfony/framework-bundle Version ^6.4 || ^7.0 || ^8.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package calisero/calisero-symfony contains the following files

Loading the files please wait ...