@@ -1294,6 +1294,131 @@ the closure::
1294
1294
// services depending on which environment you're on
1295
1295
};
1296
1296
1297
+ Generating Adapters for Functional Interfaces
1298
+ ---------------------------------------------
1299
+
1300
+ Functional interfaces are interfaces with a single method.
1301
+ They are conceptually very similar to a closure except that their only method
1302
+ has a name. Moreover, they can be used as type-hints across your code.
1303
+
1304
+ The :class: `Symfony\\ Component\\ DependencyInjection\\ Attribute\\ AutowireCallable `
1305
+ attribute can be used to generate an adapter for a functional interface.
1306
+ Let's say you have the following functional interface::
1307
+
1308
+ // src/Service/MessageFormatterInterface.php
1309
+ namespace App\Service;
1310
+
1311
+ interface MessageFormatterInterface
1312
+ {
1313
+ public function format(string $message, array $parameters): string;
1314
+ }
1315
+
1316
+ You also have a service that defines many methods and one of them is the same
1317
+ ``format() `` method of the previous interface::
1318
+
1319
+ // src/Service/MessageFormatterInterface.php
1320
+ namespace App\Service;
1321
+
1322
+ class MessageUtils
1323
+ {
1324
+ // other methods...
1325
+
1326
+ public function format($string $message, array $parameters): string
1327
+ {
1328
+ // ...
1329
+ }
1330
+ }
1331
+
1332
+ Thanks to the ``#[AutowireCallable] `` attribute, you can now inject this
1333
+ ``MessageUtils `` service as a functional interface implementation::
1334
+
1335
+ namespace App\Service\Mail;
1336
+
1337
+ use App\Service\MessageFormatterInterface;
1338
+ use App\Service\MessageUtils;
1339
+ use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;
1340
+
1341
+ class Mailer
1342
+ {
1343
+ public function __construct(
1344
+ #[AutowireCallable(service: MessageUtils::class, method: 'formatMessage')]
1345
+ private MessageFormatterInterface $formatter
1346
+ ) {
1347
+ }
1348
+
1349
+ public function sendMail($string $message, array $parameters): string
1350
+ {
1351
+ $formattedMessage = $this->formatter->format($message, $parameters);
1352
+
1353
+ // ...
1354
+ }
1355
+ }
1356
+
1357
+ .. versionadded :: 6.3
1358
+
1359
+ The :class: `Symfony\\ Component\\ DependencyInjection\\ Attribute\\ AutowireCallable `
1360
+ attribute was introduced in Symfony 6.3.
1361
+
1362
+ Instead of using the ``#[AutowireCallable] `` attribute, you can also generate
1363
+ an adapter for a functional interface through configuration:
1364
+
1365
+ .. configuration-block ::
1366
+
1367
+ .. code-block :: yaml
1368
+
1369
+ # config/services.yaml
1370
+ services :
1371
+
1372
+ # ...
1373
+
1374
+ app.message_formatter :
1375
+ class : App\Service\MessageFormatterInterface
1376
+ from_callable : [!service {class: 'App\Service\MessageUtils'}, 'formatMessage']
1377
+
1378
+ .. code-block :: xml
1379
+
1380
+ <!-- config/services.xml -->
1381
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
1382
+ <container xmlns =" http://symfony.com/schema/dic/services"
1383
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
1384
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
1385
+ https://symfony.com/schema/dic/services/services-1.0.xsd" >
1386
+
1387
+ <services >
1388
+ <!-- ... -->
1389
+
1390
+ <service id =" app.message_formatter" class =" App\Service\MessageFormatterInterface" >
1391
+ <from-callable method =" formatMessage" >
1392
+ <service class =" App\Service\MessageUtils" />
1393
+ </from-callable >
1394
+ </service >
1395
+
1396
+ </services >
1397
+ </container >
1398
+
1399
+ .. code-block :: php
1400
+
1401
+ // config/services.php
1402
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1403
+
1404
+ use App\Service\MessageFormatterInterface;
1405
+ use App\Service\MessageUtils;
1406
+
1407
+ return function(ContainerConfigurator $container) {
1408
+ // ...
1409
+
1410
+ $container
1411
+ ->set('app.message_formatter', MessageFormatterInterface::class)
1412
+ ->fromCallable([inline_service(MessageUtils::class), 'formatMessage'])
1413
+ ->alias(MessageFormatterInterface::class, 'app.message_formatter')
1414
+ ;
1415
+ };
1416
+
1417
+ By doing so, Symfony will generate a class (also called an *adapter *)
1418
+ implementing ``MessageFormatterInterface `` that will forward calls of
1419
+ ``MessageFormatterInterface::format() `` to your underlying service's method
1420
+ ``MessageUtils::format() ``, with all its arguments.
1421
+
1297
1422
Learn more
1298
1423
----------
1299
1424
0 commit comments