summaryrefslogtreecommitdiffstats log msg author committer range
path: root/core/core.api.php
blob: 4fc3ea2983b9c3be189ce52eb2357acb8be709bc (plain)
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651  .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */get('system.cron_last'); * // Set the cron run time to the current request time. * $state->set('system.cron_last', REQUEST_TIME); * @endcode * * For more on the State API, see https://www.drupal.org/developing/api/8/state * @} */ /** * @defgroup config_api Configuration API * @{ * Information about the Configuration API. * * The Configuration API is one of several methods in Drupal for storing * information. See the @link info_types Information types topic @endlink for * an overview of the different types of information. The sections below have * more information about the configuration API; see * https://www.drupal.org/developing/api/8/configuration for more details. * * @section sec_storage Configuration storage * In Drupal, there is a concept of the "active" configuration, which is the * configuration that is currently in use for a site. The storage used for the * active configuration is configurable: it could be in the database, in files * in a particular directory, or in other storage backends; the default storage * is in the database. Module developers must use the configuration API to * access the active configuration, rather than being concerned about the * details of where and how it is stored. * * Configuration is divided into individual objects, each of which has a * unique name or key. Some modules will have only one configuration object, * typically called 'mymodule.settings'; some modules will have many. Within * a configuration object, configuration settings have data types (integer, * string, Boolean, etc.) and settings can also exist in a nested hierarchy, * known as a "mapping". * * Configuration can also be overridden on a global, per-language, or * per-module basis. See https://www.drupal.org/node/1928898 for more * information. * * @section sec_yaml Configuration YAML files * Whether or not configuration files are being used for the active * configuration storage on a particular site, configuration files are always * used for: * - Defining the default configuration for an extension (module, theme, or * profile), which is imported to the active storage when the extension is * enabled. These configuration items are located in the config/install * sub-directory of the extension. Note that changes to this configuration * after a module or theme is already enabled have no effect; to make a * configuration change after a module or theme is enabled, you would need to * uninstall/reinstall or use a hook_update_N() function. * - Defining optional configuration for a module or theme. Optional * configuration items are located in the config/optional sub-directory of the * extension. These configuration items have dependencies that are not * explicit dependencies of the extension, so they are only installed if all * dependencies are met. For example, in the scenario that module A defines a * dependency which requires module B, but module A is installed first and * module B some time later, then module A's config/optional directory will be * scanned at that time for newly met dependencies, and the configuration will * be installed then. If module B is never installed, the configuration item * will not be installed either. * - Exporting and importing configuration. * * The file storage format for configuration information in Drupal is * @link http://wikipedia.org/wiki/YAML YAML files. @endlink Configuration is * divided into files, each containing one configuration object. The file name * for a configuration object is equal to the unique name of the configuration, * with a '.yml' extension. The default configuration files for each module are * placed in the config/install directory under the top-level module directory, * so look there in most Core modules for examples. * * @section sec_schema Configuration schema and translation * Each configuration file has a specific structure, which is expressed as a * YAML-based configuration schema. The configuration schema details the * structure of the configuration, its data types, and which of its values need * to be translatable. Each module needs to define its configuration schema in * files in the config/schema directory under the top-level module directory, so * look there in most Core modules for examples. * * Configuration can be internationalized; see the * @link i18n Internationalization topic @endlink for more information. Data * types label, text, and date_format in configuration schema are translatable; * string is non-translatable text (the 'translatable' property on a schema * data type definition indicates that it is translatable). * * @section sec_simple Simple configuration * The simple configuration API should be used for information that will always * have exactly one copy or version. For instance, if your module has a * setting that is either on or off, then this is only defined once, and it * would be a Boolean-valued simple configuration setting. * * The first task in using the simple configuration API is to define the * configuration file structure, file name, and schema of your settings (see * @ref sec_yaml above). Once you have done that, you can retrieve the active * configuration object that corresponds to configuration file mymodule.foo.yml * with a call to: * @code *$config = \Drupal::config('mymodule.foo'); * @endcode * * This will be an object of class \Drupal\Core\Config\Config, which has methods * for getting configuration information. For instance, if your YAML file * structure looks like this: * @code * enabled: '0' * bar: * baz: 'string1' * boo: 34 * @endcode * you can make calls such as: * @code * // Get a single value. * $enabled =$config->get('enabled'); * // Get an associative array. * $bar =$config->get('bar'); * // Get one element of the array. * $bar_baz =$config->get('bar.baz'); * @endcode * * The Config object that was obtained and used in the previous examples does * not allow you to change configuration. If you want to change configuration, * you will instead need to get the Config object by making a call to * getEditable() on the config factory: * @code * $config =\Drupal::service('config.factory')->getEditable('mymodule.foo'); * @endcode * * Individual configuration values can be changed or added using the set() * method and saved using the save() method: * @code * // Set a scalar value. *$config->set('enabled', 1); * // Save the configuration. * $config->save(); * @endcode * * Configuration values can also be unset using the clear() method, which is * also chainable: * @code *$config->clear('bar.boo')->save(); * $config_data =$config->get('bar'); * @endcode * In this example $config_data would return an array with one key - 'baz' - * because 'boo' was unset. * * @section sec_entity Configuration entities * In contrast to the simple configuration settings described in the previous * section, if your module allows users to create zero or more items (where * "items" are things like content type definitions, view definitions, and the * like), then you need to define a configuration entity type to store your * configuration. Creating an entity type, loading entities, and querying them * are outlined in the @link entity_api Entity API topic. @endlink Here are a * few additional steps and notes specific to configuration entities: * - For examples, look for classes that implement * \Drupal\Core\Config\Entity\ConfigEntityInterface -- one good example is * the \Drupal\user\Entity\Role entity type. * - In the entity type annotation, you will need to define a 'config_prefix' * string. When Drupal stores a configuration item, it will be given a name * composed of your module name, your chosen config prefix, and the ID of * the individual item, separated by '.'. For example, in the Role entity, * the config prefix is 'role', so one configuration item might be named * user.role.anonymous, with configuration file user.role.anonymous.yml. * - You will need to define the schema for your configuration in your * modulename.schema.yml file, with an entry for 'modulename.config_prefix.*'. * For example, for the Role entity, the file user.schema.yml has an entry * user.role.*; see @ref sec_yaml above for more information. * - Your module can provide default/optional configuration entities in YAML * files; see @ref sec_yaml above for more information. * - Some configuration entities have dependencies on other configuration * entities, and module developers need to consider this so that configuration * can be imported, uninstalled, and synchronized in the right order. For * example, a field display configuration entity would need to depend on * field configuration, which depends on field and bundle configuration. * Configuration entity classes expose dependencies by overriding the * \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies() * method. * - On routes for paths starting with '/admin' or otherwise designated as * administration paths (such as node editing when it is set as an admin * operation), if they have configuration entity placeholders, configuration * entities are normally loaded in their original language, without * translations or other overrides. This is usually desirable, because most * admin paths are for editing configuration, and you need that to be in the * source language and to lack possibly dynamic overrides. If for some reason * you need to have your configuration entity loaded in the currently-selected * language on an admin path (for instance, if you go to * example.com/es/admin/your_path and you need the entity to be in Spanish), * then you can add a 'with_config_overrides' parameter option to your route. * The same applies if you need to load the entity with overrides (or * translated) on an admin path like '/node/add/article' (when configured to * be an admin path). Here's an example using the configurable_language config * entity: * @code * mymodule.myroute: * path: '/admin/mypath/{configurable_language}' * defaults: * _controller: '\Drupal\mymodule\MyController::myMethod' * options: * parameters: * configurable_language: * type: entity:configurable_language * with_config_overrides: TRUE * @endcode * With the route defined this way, the$configurable_language parameter to * your controller method will come in translated to the current language. * Without the parameter options section, it would be in the original * language, untranslated. * * @see i18n * * @} */ /** * @defgroup cache Cache API * @{ * Information about the Drupal Cache API * * @section basics Basics * * Note: If not specified, all of the methods mentioned here belong to * \Drupal\Core\Cache\CacheBackendInterface. * * The Cache API is used to store data that takes a long time to compute. * Caching can either be permanent or valid only for a certain time span, and * the cache can contain any type of data. * * To use the Cache API: * - Request a cache object through \Drupal::cache() or by injecting a cache * service. * - Define a Cache ID (cid) value for your data. A cid is a string, which must * contain enough information to uniquely identify the data. For example, if * your data contains translated strings, then your cid value must include the * interface text language selected for page. * - Call the get() method to attempt a cache read, to see if the cache already * contains your data. * - If your data is not already in the cache, compute it and add it to the * cache using the set() method. The third argument of set() can be used to * control the lifetime of your cache item. * * Example: * @code * $cid = 'mymodule_example:' . \Drupal::languageManager()->getCurrentLanguage()->getId(); * *$data = NULL; * if ($cache = \Drupal::cache()->get($cid)) { * $data =$cache->data; * } * else { * $data = my_module_complicated_calculation(); * \Drupal::cache()->set($cid, $data); * } * @endcode * * Note the use of$data and $cache->data in the above example. Calls to * \Drupal::cache()->get() return a record that contains the information stored * by \Drupal::cache()->set() in the data property as well as additional meta * information about the cached data. In order to make use of the cached data * you can access it via$cache->data. * * @section bins Cache bins * * Cache storage is separated into "bins", each containing various cache items. * Each bin can be configured separately; see @ref configuration. * * When you request a cache object, you can specify the bin name in your call to * \Drupal::cache(). Alternatively, you can request a bin by getting service * "cache.nameofbin" from the container. The default bin is called "default", with * service name "cache.default", it is used to store common and frequently used * caches. * * Other common cache bins are the following: * - bootstrap: Data needed from the beginning to the end of most requests, * that has a very strict limit on variations and is invalidated rarely. * - render: Contains cached HTML strings like cached pages and blocks, can * grow to large size. * - data: Contains data that can vary by path or similar context. * - discovery: Contains cached discovery data for things such as plugins, * views_data, or YAML discovered data such as library info. * * A module can define a cache bin by defining a service in its * modulename.services.yml file as follows (substituting the desired name for * "nameofbin"): * @code * cache.nameofbin: * class: Drupal\Core\Cache\CacheBackendInterface * tags: * - { name: cache.bin } * factory: cache_factory:get * arguments: [nameofbin] * @endcode * See the @link container Services topic @endlink for more on defining * services. * * @section delete Deletion * * There are two ways to remove an item from the cache: * - Deletion (using delete(), deleteMultiple() or deleteAll()) permanently * removes the item from the cache. * - Invalidation (using invalidate(), invalidateMultiple() or invalidateAll()) * is a "soft" delete that only marks items as "invalid", meaning "not fresh" * or "not fresh enough". Invalid items are not usually returned from the * cache, so in most ways they behave as if they have been deleted. However, * it is possible to retrieve invalid items, if they have not yet been * permanently removed by the garbage collector, by passing TRUE as the second * argument for get($cid,$allow_invalid). * * Use deletion if a cache item is no longer useful; for instance, if the item * contains references to data that has been deleted. Use invalidation if the * cached item may still be useful to some callers until it has been updated * with fresh data. The fact that it was fresh a short while ago may often be * sufficient. * * Invalidation is particularly useful to protect against stampedes. Rather than * having multiple concurrent requests updating the same cache item when it * expires or is deleted, there can be one request updating the cache, while the * other requests can proceed using the stale value. As soon as the cache item * has been updated, all future requests will use the updated value. * * @section tags Cache Tags * * The fourth argument of the set() method can be used to specify cache tags, * which are used to identify which data is included in each cache item. A cache * item can have multiple cache tags (an array of cache tags), and each cache * tag is a string. The convention is to generate cache tags of the form * [prefix]:[suffix]. Usually, you'll want to associate the cache tags of * entities, or entity listings. You won't have to manually construct cache tags * for them — just get their cache tags via * \Drupal\Core\Cache\CacheableDependencyInterface::getCacheTags() and * \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags(). * Data that has been tagged can be invalidated as a group: no matter the Cache * ID (cid) of the cache item, no matter in which cache bin a cache item lives; * as long as it is tagged with a certain cache tag, it will be invalidated. * * Because of that, cache tags are a solution to the cache invalidation problem: * - For caching to be effective, each cache item must only be invalidated when * absolutely necessary. (i.e. maximizing the cache hit ratio.) * - For caching to be correct, each cache item that depends on a certain thing * must be invalidated whenever that certain thing is modified. * * A typical scenario: a user has modified a node that appears in two views, * three blocks and on twelve pages. Without cache tags, we couldn't possibly * know which cache items to invalidate, so we'd have to invalidate everything: * we had to sacrifice effectiveness to achieve correctness. With cache tags, we * can have both. * * Example: * @code * // A cache item with nodes, users, and some custom module data. * $tags = array( * 'my_custom_tag', * 'node:1', * 'node:3', * 'user:7', * ); * \Drupal::cache()->set($cid, $data, CacheBackendInterface::CACHE_PERMANENT,$tags); * * // Invalidate all cache items with certain tags. * \Drupal\Core\Cache\Cache::invalidateTags(array('user:1')); * @endcode * * Drupal is a content management system, so naturally you want changes to your * content to be reflected everywhere, immediately. That's why we made sure that * every entity type in Drupal 8 automatically has support for cache tags: when * you save an entity, you can be sure that the cache items that have the * corresponding cache tags will be invalidated. * This also is the case when you define your own entity types: you'll get the * exact same cache tag invalidation as any of the built-in entity types, with * the ability to override any of the default behavior if needed. * See \Drupal\Core\Cache\CacheableDependencyInterface::getCacheTags(), * \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags(), * \Drupal\Core\Entity\Entity::invalidateTagsOnSave() and * \Drupal\Core\Entity\Entity::invalidateTagsOnDelete(). * * @section context Cache contexts * * Some computed data depends on contextual data, such as the user roles of the * logged-in user who is viewing a page, the language the page is being rendered * in, the theme being used, etc. When caching the output of such a calculation, * you must cache each variation separately, along with information about which * variation of the contextual data was used in the calculation. The next time * the computed data is needed, if the context matches that for an existing * cached data set, the cached data can be reused; if no context matches, a new * data set can be calculated and cached for later use. * * Cache contexts are services tagged with 'cache.context', whose classes * implement \Drupal\Core\Cache\Context\CacheContextInterface. See * https://www.drupal.org/developing/api/8/cache/contexts for more information * on cache contexts, including a list of the contexts that exist in Drupal * core, and information on how to define your own contexts. See the * @link container Services and the Dependency Injection Container @endlink * topic for more information about services. * * Typically, the cache context is specified as part of the #cache property * of a render array; see the Caching section of the * @link theme_render Render API overview topic @endlink for details. * * @section configuration Configuration * * By default cached data is stored in the database. This can be configured * though so that all cached data, or that of an individual cache bin, uses a * different cache backend, such as APCu or Memcache, for storage. * * In a settings.php file, you can override the service used for a particular * cache bin. For example, if your service implementation of * \Drupal\Core\Cache\CacheBackendInterface was called cache.custom, the * following line would make Drupal use it for the 'cache_render' bin: * @code * $settings['cache']['bins']['render'] = 'cache.custom'; * @endcode * * Additionally, you can register your cache implementation to be used by * default for all cache bins with: * @code *$settings['cache']['default'] = 'cache.custom'; * @endcode * * For cache bins that are stored in the database, the number of rows is limited * to 5000 by default. This can be changed for all database cache bins. For * example, to instead limit the number of rows to 50000: * @code * $settings['database_cache_max_rows']['default'] = 50000; * @endcode * * Or per bin (in this example we allow infinite entries): * @code *$settings['database_cache_max_rows']['bins']['dynamic_page_cache'] = -1; * @endcode * * For monitoring reasons it might be useful to figure out the amount of data * stored in tables. The following SQL snippet can be used for that: * @code * SELECT table_name AS Table, table_rows AS 'Num. of Rows', * ROUND(((data_length + index_length) / 1024 / 1024), 2) Size in MB FROM * information_schema.TABLES WHERE table_schema = '***DATABASE_NAME***' AND * table_name LIKE 'cache_%' ORDER BY (data_length + index_length) DESC * LIMIT 10; * @endcode * * @see \Drupal\Core\Cache\DatabaseBackend * * Finally, you can chain multiple cache backends together, see * \Drupal\Core\Cache\ChainedFastBackend and \Drupal\Core\Cache\BackendChain. * * @see https://www.drupal.org/node/1884796 * @} */ /** * @defgroup user_api User accounts, permissions, and roles * @{ * API for user accounts, access checking, roles, and permissions. * * @section sec_overview Overview and terminology * Drupal's permission system is based on the concepts of accounts, roles, * and permissions. * * Users (site visitors) have accounts, which include a user name, an email * address, a password (or some other means of authentication), and possibly * other fields (if defined on the site). Anonymous users have an implicit * account that does not have a real user name or any account information. * * Each user account is assigned one or more roles. The anonymous user account * automatically has the anonymous user role; real user accounts * automatically have the authenticated user role, plus any roles defined on * the site that they have been assigned. * * Each role, including the special anonymous and authenticated user roles, is * granted one or more named permissions, which allow them to perform certain * tasks or view certain content on the site. It is possible to designate a * role to be the "administrator" role; if this is set up, this role is * automatically granted all available permissions whenever a module is * enabled that defines permissions. * * All code in Drupal that allows users to perform tasks or view content must * check that the current user has the correct permission before allowing the * action. In the standard case, access checking consists of answering the * question "Does the current user have permission 'foo'?", and allowing or * denying access based on the answer. Note that access checking should nearly * always be done at the permission level, not by checking for a particular role * or user ID, so that site administrators can set up user accounts and roles * appropriately for their particular sites. * * @section sec_define Defining permissions * Modules define permissions via a $module.permissions.yml file. See * \Drupal\user\PermissionHandler for documentation of permissions.yml files. * * @section sec_access Access permission checking * Depending on the situation, there are several methods for ensuring that * access checks are done properly in Drupal: * - Routes: When you register a route, include a 'requirements' section that * either gives the machine name of the permission that is needed to visit the * URL of the route, or tells Drupal to use an access check method or service * to check access. See the @link menu Routing topic @endlink for more * information. * - Entities: Access for various entity operations is designated either with * simple permissions or access control handler classes in the entity * annotation. See the @link entity_api Entity API topic @endlink for more * information. * - Other code: There is a 'current_user' service, which can be injected into * classes to provide access to the current user account (see the * @link container Services and Dependency Injection topic @endlink for more * information on dependency injection). In code that cannot use dependency * injection, you can access this service and retrieve the current user * account object by calling \Drupal::currentUser(). Once you have a user * object for the current user (implementing \Drupal\user\UserInterface), you * can call inherited method * \Drupal\Core\Session\AccountInterface::hasPermission() to check * permissions, or pass this object into other functions/methods. * - Forms: Each element of a form array can have a Boolean '#access' property, * which determines whether that element is visible and/or usable. This is a * common need in forms, so the current user service (described above) is * injected into the form base class as method * \Drupal\Core\Form\FormBase::currentUser(). * * @section sec_entities User and role objects * User objects in Drupal are entity items, implementing * \Drupal\user\UserInterface. Role objects in Drupal are also entity items, * implementing \Drupal\user\RoleInterface. See the * @link entity_api Entity API topic @endlink for more information about * entities in general (including how to load, create, modify, and query them). * * Roles often need to be manipulated in automated test code, such as to add * permissions to them. Here's an example: * @code *$role = \Drupal\user\Entity\Role::load('authenticated'); * $role->grantPermission('access comments'); *$role->save(); * @endcode * * Other important interfaces: * - \Drupal\Core\Session\AccountInterface: The part of UserInterface that * deals with access checking. In writing code that checks access, your * method parameters should use this interface, not UserInterface. * - \Drupal\Core\Session\AccountProxyInterface: The interface for the * current_user service (described above). * @} */ /** * @defgroup container Services and Dependency Injection Container * @{ * Overview of the Dependency Injection Container and Services. * * @section sec_overview Overview of container, injection, and services * The Services and Dependency Injection Container concepts have been adopted by * Drupal from the @link http://symfony.com/ Symfony framework. @endlink A * "service" (such as accessing the database, sending email, or translating user * interface text) is defined (given a name and an interface or at least a * class that defines the methods that may be called), and a default class is * designated to provide the service. These two steps must be done together, and * can be done by Drupal Core or a module. Other modules can then define * alternative classes to provide the same services, overriding the default * classes. Classes and functions that need to use the service should always * instantiate the class via the dependency injection container (also known * simply as the "container"), rather than instantiating a particular service * provider class directly, so that they get the correct class (default or * overridden). * * See https://www.drupal.org/node/2133171 for more detailed information on * services and the dependency injection container. * * @section sec_discover Discovering existing services * Drupal core defines many core services in the core.services.yml file (in the * top-level core directory). Some Drupal Core modules and contributed modules * also define services in modulename.services.yml files. API reference sites * (such as https://api.drupal.org) generate lists of all existing services from * these files. Look for the Services link in the API Navigation block. * Alternatively you can look through the individual files manually. * * A typical service definition in a *.services.yml file looks like this: * @code * path.alias_manager: * class: Drupal\Core\Path\AliasManager * arguments: ['@path.crud', '@path.alias_whitelist', '@language_manager'] * @endcode * Some services use other services as factories; a typical service definition * is: * @code * cache.entity: * class: Drupal\Core\Cache\CacheBackendInterface * tags: * - { name: cache.bin } * factory: cache_factory:get * arguments: [entity] * @endcode * * The first line of a service definition gives the unique machine name of the * service. This is often prefixed by the module name if provided by a module; * however, by convention some service names are prefixed by a group name * instead, such as cache.* for cache bins and plugin.manager.* for plugin * managers. * * The class line either gives the default class that provides the service, or * if the service uses a factory class, the interface for the service. If the * class depends on other services, the arguments line lists the machine * names of the dependencies (preceded by '@'); objects for each of these * services are instantiated from the container and passed to the class * constructor when the service class is instantiated. Other arguments can also * be passed in; see the section at https://www.drupal.org/node/2133171 for more * detailed information. * * Services using factories can be defined as shown in the above example, if the * factory is itself a service. The factory can also be a class; details of how * to use service factories can be found in the section at * https://www.drupal.org/node/2133171. * * @section sec_container Accessing a service through the container * As noted above, if you need to use a service in your code, you should always * instantiate the service class via a call to the container, using the machine * name of the service, so that the default class can be overridden. There are * several ways to make sure this happens: * - For service-providing classes, see other sections of this documentation * describing how to pass services as arguments to the constructor. * - Plugin classes, controllers, and similar classes have create() or * createInstance() methods that are used to create an instance of the class. * These methods come from different interfaces, and have different * arguments, but they all include an argument $container of type * \Symfony\Component\DependencyInjection\ContainerInterface. * If you are defining one of these classes, in the create() or * createInstance() method, call$container->get('myservice.name') to * instantiate a service. The results of these calls are generally passed to * the class constructor and saved as member variables in the class. * - For functions and class methods that do not have access to either of * the above methods of dependency injection, you can use service location to * access services, via a call to the global \Drupal class. This class has * special methods for accessing commonly-used services, or you can call a * generic method to access any service. Examples: * @code * // Retrieve the entity.manager service object (special method exists). * $manager = \Drupal::entityManager(); * // Retrieve the service object for machine name 'foo.bar'. *$foobar = \Drupal::service('foo.bar'); * @endcode * * As a note, you should always use dependency injection (via service arguments * or create()/createInstance() methods) if possible to instantiate services, * rather than service location (via the \Drupal class), because: * - Dependency injection facilitates writing unit tests, since the container * argument can be mocked and the create() method can be bypassed by using * the class constructor. If you use the \Drupal class, unit tests are much * harder to write and your code has more dependencies. * - Having the service interfaces on the class constructor and member variables * is useful for IDE auto-complete and self-documentation. * * @section sec_define Defining a service * If your module needs to define a new service, here are the steps: * - Choose a unique machine name for your service. Typically, this should * start with your module name. Example: mymodule.myservice. * - Create a PHP interface to define what your service does. * - Create a default class implementing your interface that provides your * service. If your class needs to use existing services (such as database * access), be sure to make these services arguments to your class * constructor, and save them in member variables. Also, if the needed * services are provided by other modules and not Drupal Core, you'll want * these modules to be dependencies of your module. * - Add an entry to a modulename.services.yml file for the service. See * @ref sec_discover above, or existing *.services.yml files in Core, for the * syntax; it will start with your machine name, refer to your default class, * and list the services that need to be passed into your constructor. * * Services can also be defined dynamically, as in the * \Drupal\Core\CoreServiceProvider class, but this is less common for modules. * * @section sec_tags Service tags * Some services have tags, which are defined in the service definition. See * @link service_tag Service Tags @endlink for usage. * * @section sec_injection Overriding the default service class * Modules can override the default classes used for services. Here are the * steps: * - Define a class in the top-level namespace for your module * (Drupal\my_module), whose name is the camel-case version of your module's * machine name followed by "ServiceProvider" (for example, if your module * machine name is my_module, the class must be named * MyModuleServiceProvider). * - The class needs to implement * \Drupal\Core\DependencyInjection\ServiceModifierInterface, which is * typically done by extending * \Drupal\Core\DependencyInjection\ServiceProviderBase. * - The class needs to contain one method: alter(). This method does the * actual work of telling Drupal to use your class instead of the default. * Here's an example: * @code * public function alter(ContainerBuilder $container) { * // Override the language_manager class with a new class. *$definition = $container->getDefinition('language_manager'); *$definition->setClass('Drupal\my_module\MyLanguageManager'); * } * @endcode * Note that $container here is an instance of * \Drupal\Core\DependencyInjection\ContainerBuilder. * * @see https://www.drupal.org/node/2133171 * @see core.services.yml * @see \Drupal * @see \Symfony\Component\DependencyInjection\ContainerInterface * @see plugin_api * @see menu * @} */ /** * @defgroup listing_page_service Page header for Services page * @{ * Introduction to services * * A "service" (such as accessing the database, sending email, or translating * user interface text) can be defined by a module or Drupal core. Defining a * service means giving it a name and designating a default class to provide the * service; ideally, there should also be an interface that defines the methods * that may be called. Services are collected into the Dependency Injection * Container, and can be overridden to use different classes or different * instantiation by modules. See the * @link container Services and Dependency Injection Container topic @endlink * for details. * * Some services have tags, which are defined in the service definition. Tags * are used to define a group of related services, or to specify some aspect of * how the service behaves. See the * @link service_tag Service Tags topic @endlink for more information. * * @see container * @see service_tag * * @} */ /** * @defgroup typed_data Typed Data API * @{ * API for describing data based on a set of available data types. * * PHP has data types, such as int, string, float, array, etc., and it is an * object-oriented language that lets you define classes and interfaces. * However, in some cases, it is useful to be able to define an abstract * type (as in an interface, free of implementation details), that still has * properties (which an interface cannot) as well as meta-data. The Typed Data * API provides this abstraction. * * @section sec_overview Overview * Each data type in the Typed Data API is a plugin class (annotation class * example: \Drupal\Core\TypedData\Annotation\DataType); these plugins are * managed by the typed_data_manager service (by default * \Drupal\Core\TypedData\TypedDataManager). Each data object encapsulates a * single piece of data, provides access to the metadata, and provides * validation capability. Also, the typed data plugins have a shorthand * for easily accessing data values, described in @ref sec_tree. * * The metadata of a data object is defined by an object based on a class called * the definition class (see \Drupal\Core\TypedData\DataDefinitionInterface). * The class used can vary by data type and can be specified in the data type's * plugin definition, while the default is set in the$definition_class property * of the annotation class. The default class is * \Drupal\Core\TypedData\DataDefinition. For data types provided by a plugin * deriver, the plugin deriver can set the definition_class property too. * The metadata object provides information about the data, such as the data * type, whether it is translatable, the names of its properties (for complex * types), and who can access it. * * See https://www.drupal.org/node/1794140 for more information about the Typed * Data API. * * @section sec_varieties Varieties of typed data * There are three kinds of typed data: primitive, complex, and list. * * @subsection sub_primitive Primitive data types * Primitive data types wrap PHP data types and also serve as building blocks * for complex and list typed data. Each primitive data type has an interface * that extends \Drupal\Core\TypedData\PrimitiveInterface, with getValue() * and setValue() methods for accessing the data value, and a default plugin * implementation. Here's a list: * - \Drupal\Core\TypedData\Type\IntegerInterface: Plugin ID integer, * corresponds to PHP type int. * - \Drupal\Core\TypedData\Type\StringInterface: Plugin ID string, * corresponds to PHP type string. * - \Drupal\Core\TypedData\Type\FloatInterface: Plugin ID float, * corresponds to PHP type float. * - \Drupal\Core\TypedData\Type\BooleanInterface: Plugin ID bool, * corresponds to PHP type bool. * - \Drupal\Core\TypedData\Type\BinaryInterface: Plugin ID binary, * corresponds to a PHP file resource. * - \Drupal\Core\TypedData\Type\UriInterface: Plugin ID uri. * * @subsection sec_complex Complex data * Complex data types, with interface * \Drupal\Core\TypedData\ComplexDataInterface, represent data with named * properties; the properties can be accessed with get() and set() methods. * The value of each property is itself a typed data object, which can be * primitive, complex, or list data. * * The base type for most complex data is the * \Drupal\Core\TypedData\Plugin\DataType\Map class, which represents an * associative array. Map provides its own definition class in the annotation, * \Drupal\Core\TypedData\MapDataDefinition, and most complex data classes * extend this class. The getValue() and setValue() methods on the Map class * enforce the data definition and its property structure. * * The Drupal Field API uses complex typed data for its field items, with * definition class \Drupal\Core\Field\TypedData\FieldItemDataDefinition. * * @section sec_list Lists * List data types, with interface \Drupal\Core\TypedData\ListInterface, * represent data that is an ordered list of typed data, all of the same type. * More precisely, the plugins in the list must have the same base plugin ID; * however, some types (for example field items and entities) are provided by * plugin derivatives and the sub IDs can be different. * * @section sec_tree Tree handling * Typed data allows you to use shorthand to get data values nested in the * implicit tree structure of the data. For example, to get the value from * an entity field item, the Entity Field API allows you to call: * @code * $value =$entity->fieldName->propertyName; * @endcode * This is really shorthand for: * @code * $field_item_list =$entity->get('fieldName'); * $field_item =$field_item_list->get(0); * $property =$field_item->get('propertyName'); * $value =$property->getValue(); * @endcode * Some notes: * - $property,$field_item, and $field_item_list are all typed data objects, * while$value is a raw PHP value. * - You can call $property->getParent() to get$field_item, * $field_item->getParent() to get$field_item_list, or * $field_item_list->getParent() to get$typed_entity ($entity wrapped in a * typed data object).$typed_entity->getParent() is NULL. * - For all of these ->getRoot() returns $typed_entity. * - The langcode property is on$field_item_list, but you can access it * on $property as well, so that all items will report the same langcode. * - When the value of$property is changed by calling $property->setValue(), *$property->onChange() will fire, which in turn calls the parent object's * onChange() method and so on. This allows parent objects to react upon * changes of contained properties or list items. * * @section sec_defining Defining data types * To define a new data type: * - Create a class that implements one of the Typed Data interfaces. * Typically, you will want to extend one of the classes listed in the * sections above as a starting point. * - Make your class into a DataType plugin. To do that, put it in namespace * \Drupal\yourmodule\Plugin\DataType (where "yourmodule" is your module's * short name), and add annotation of type * \Drupal\Core\TypedData\Annotation\DataType to the documentation header. * See the @link plugin_api Plugin API topic @endlink and the * @link annotation Annotations topic @endlink for more information. * * @section sec_using Using data types * The data types of the Typed Data API can be used in several ways, once they * have been defined: * - In the Field API, data types can be used as the class in the property * definition of the field. See the @link field Field API topic @endlink for * more information. * - In configuration schema files, you can use the unique ID ('id' annotation) * from any DataType plugin class as the 'type' value for an entry. See the * @link config_api Confuration API topic @endlink for more information. * - If you need to create a typed data object in code, first get the * typed_data_manager service from the container or by calling * \Drupal::typedDataManager(). Then pass the plugin ID to * $manager::createDataDefinition() to create an appropriate data definition * object. Then pass the data definition object and the value of the data to *$manager::create() to create a typed data object. * * @see plugin_api * @see container * @} */ /** * @defgroup testing Automated tests * @{ * Overview of PHPUnit tests and Simpletest tests. * * The Drupal project has embraced a philosophy of using automated tests, * consisting of both unit tests (which test the functionality of classes at a * low level) and functional tests (which test the functionality of Drupal * systems at a higher level, usually involving web output). The goal is to * have test coverage for all or most of the components and features, and to * run the automated tests before any code is changed or added, to make sure * it doesn't break any existing functionality (regression testing). * * In order to implement this philosophy, developers need to do the following: * - When making a patch to fix a bug, make sure that the bug fix patch includes * a test that fails without the code change and passes with the code change. * This helps reviewers understand what the bug is, demonstrates that the code * actually fixes the bug, and ensures the bug will not reappear due to later * code changes. * - When making a patch to implement a new feature, include new unit and/or * functional tests in the patch. This serves to both demonstrate that the * code actually works, and ensure that later changes do not break the new * functionality. * * @section write_unit Writing PHPUnit tests for classes * PHPUnit tests for classes are written using the industry-standard PHPUnit * framework. Use a PHPUnit test to test functionality of a class if the Drupal * environment (database, settings, etc.) and web browser are not needed for the * test, or if the Drupal environment can be replaced by a "mock" object. To * write a PHPUnit test: * - Define a class that extends \Drupal\Tests\UnitTestCase. * - The class name needs to end in the word Test. * - The namespace must be a subspace/subdirectory of \Drupal\yourmodule\Tests, * where yourmodule is your module's machine name. * - The test class file must be named and placed under the * yourmodule/tests/src/Unit directory, according to the PSR-4 standard. * - Your test class needs a phpDoc comment block with a description and * a @group annotation, which gives information about the test. * - Add test cases by adding method names that start with 'test' and have no * arguments, for example testYourTestCase(). Each one should test a logical * subset of the functionality. * For more details, see: * - https://www.drupal.org/phpunit for full documentation on how to write * PHPUnit tests for Drupal. * - http://phpunit.de for general information on the PHPUnit framework. * - @link oo_conventions Object-oriented programming topic @endlink for more * on PSR-4, namespaces, and where to place classes. * * @section write_functional Writing functional tests * Functional tests are written using a Drupal-specific framework that is, for * historical reasons, known as "Simpletest". Use a Simpletest test to test the * functionality of sub-system of Drupal, if the functionality depends on the * Drupal database and settings, or to test the web output of Drupal. To * write a Simpletest test: * - For functional tests of the web output of Drupal, define a class that * extends \Drupal\simpletest\WebTestBase, which contains an internal web * browser and defines many helpful test assertion methods that you can use * in your tests. You can specify modules to be enabled by defining a * $modules member variable -- keep in mind that by default, WebTestBase uses * a "testing" install profile, with a minimal set of modules enabled. * - For functional tests that do not test web output, define a class that * extends \Drupal\KernelTests\KernelTestBase. This class is much faster * than WebTestBase, because instead of making a full install of Drupal, it * uses an in-memory pseudo-installation (similar to what the installer and * update scripts use). To use this test class, you will need to create the * database tables you need and install needed modules manually. * - The namespace must be a subspace/subdirectory of \Drupal\yourmodule\Tests, * where yourmodule is your module's machine name. * - The test class file must be named and placed under the yourmodule/src/Tests * directory, according to the PSR-4 standard. * - Your test class needs a phpDoc comment block with a description and * a @group annotation, which gives information about the test. * - You may also override the default setUp() method, which can set be used to * set up content types and similar procedures. * - In some cases, you may need to write a test module to support your test; * put such modules under the yourmodule/tests/modules directory. * - Add test cases by adding method names that start with 'test' and have no * arguments, for example testYourTestCase(). Each one should test a logical * subset of the functionality. Each method runs in a new, isolated test * environment, so it can only rely on the setUp() method, not what has * been set up by other test methods. * For more details, see: * - https://www.drupal.org/simpletest for full documentation on how to write * functional tests for Drupal. * - @link oo_conventions Object-oriented programming topic @endlink for more * on PSR-4, namespaces, and where to place classes. * * @section write_functional_phpunit Write functional PHP tests (phpunit) * Functional tests extend the BrowserTestBase base class, and use PHPUnit as * their underlying framework. They use a simulated browser, in which the test * can click links, visit URLs, post to forms, etc. To write a functional test: * - Extend \Drupal\Tests\BrowserTestBase. * - Place the test in the yourmodule/tests/src/Functional/ directory and use * the \Drupal\Tests\yourmodule\Functional namespace. * - Add a @group annotation. For example, if the test is for a Drupal 6 * migration process, the group core uses is migrate_drupal_6. Use yourmodule * as the group name if the test does not belong to another larger group. * - You may also override the default setUp() method, which can be used to set * up content types and similar procedures. Don't forget to call the parent * method. * - In some cases, you may need to write a test module to support your test; * put such modules under the yourmodule/tests/modules directory. * - Add test cases by adding method names that start with 'test' and have no * arguments, for example testYourTestCase(). Each one should test a logical * subset of the functionality. Each method runs in a new, isolated test * environment, so it can only rely on the setUp() method, not what has * been set up by other test methods. * For more details, see: * - https://www.drupal.org/docs/8/phpunit/phpunit-browser-test-tutorial for * a full tutorial on how to write functional PHPUnit tests for Drupal. * - https://www.drupal.org/phpunit for the full documentation on how to write * PHPUnit tests for Drupal. * * @section write_jsfunctional_phpunit Write functional JavaScript tests (phpunit) * To write a functional test that relies on JavaScript: * - Extend \Drupal\FunctionalJavaScriptTests\JavascriptTestBase. * - Place the test into the yourmodule/tests/src/FunctionalJavascript/ * directory and use the \Drupal\Tests\yourmodule\FunctionalJavascript * namespace. * - Add a @group annotation. Use yourmodule as the group name if the test does * not belong to another larger group. * - Set up PhantomJS; see http://phantomjs.org/download.html. * - To run tests, see core/tests/README.md. * - When clicking a link/button with Ajax behavior attached, keep in mind that * the underlying browser might take time to deliver changes to the HTML. Use *$this->assertSession()->assertWaitOnAjaxRequest() to wait for the Ajax * request to finish. * For more details, see: * - https://www.drupal.org/docs/8/phpunit/phpunit-javascript-testing-tutorial * for a full tutorial on how to write PHPUnit JavaScript tests for Drupal. * - https://www.drupal.org/phpunit for the full documentation on how to write * PHPUnit tests for Drupal. * * @section running Running tests * You can run both Simpletest and PHPUnit tests by enabling the core Testing * module (core/modules/simpletest). Once that module is enabled, tests can be * run using the core/scripts/run-tests.sh script, using * @link https://www.drupal.org/project/drush Drush @endlink, or from the * Testing module user interface. * * PHPUnit tests can also be run from the command line, using the PHPUnit * framework. See https://www.drupal.org/node/2116263 for more information. * @} */ /** * @defgroup php_assert PHP Runtime Assert Statements * @{ * Use of the assert() statement in Drupal. * * Unit tests also use the term "assertion" to refer to test conditions, so to * avoid confusion the term "runtime assertion" will be used for the assert() * statement throughout the documentation. * * A runtime assertion is a statement that is expected to always be true at * the point in the code it appears at. They are tested using PHP's internal * @link http://php.net/assert assert() @endlink statement. If an * assertion is ever FALSE it indicates an error in the code or in module or * theme configuration files. User-provided configuration files should be * verified with standard control structures at all times, not just checked in * development environments with assert() statements on. * * The Drupal project primarily uses runtime assertions to enforce the * expectations of the API by failing when incorrect calls are made by code * under development. While PHP type hinting does this for objects and arrays, * runtime assertions do this for scalars (strings, integers, floats, etc.) and * complex data structures such as cache and render arrays. They ensure that * methods' return values are the documented data types. They also verify that * objects have been properly configured and set up by the service container. * They supplement unit tests by checking scenarios that do not have unit tests * written for them. * * There are two php settings which affect runtime assertions. The first, * assert.exception, should always be set to 1. The second is zend.assertions. * Set this to -1 in production and 1 in development. * * See https://www.drupal.org/node/2492225 for more information on runtime * assertions. * @} */ /** * @defgroup info_types Information types * @{ * Types of information in Drupal. * * Drupal has several distinct types of information, each with its own methods * for storage and retrieval: * - Content: Information meant to be displayed on your site: articles, basic * pages, images, files, custom blocks, etc. Content is stored and accessed * using @link entity_api Entities @endlink. * - Session: Information about individual users' interactions with the site, * such as whether they are logged in. This is really "state" information, but * it is not stored the same way so it's a separate type here. Session data is * accessed via \Symfony\Component\HttpFoundation\Request::getSession(), which * returns an instance of * \Symfony\Component\HttpFoundation\Session\SessionInterface. * See the @link session Sessions topic @endlink for more information. * - State: Information of a temporary nature, generally machine-generated and * not human-edited, about the current state of your site. Examples: the time * when Cron was last run, whether node access permissions need rebuilding, * etc. See @link state_api the State API topic @endlink for more information. * - Configuration: Information about your site that is generally (or at least * can be) human-edited, but is not Content, and is meant to be relatively * permanent. Examples: the name of your site, the content types and views * you have defined, etc. See * @link config_api the Configuration API topic @endlink for more information. * * @see cache * @see i18n * @} */ /** * @defgroup extending Extending and altering Drupal * @{ * Overview of extensions and alteration methods for Drupal. * * @section sec_types Types of extensions * Drupal's core behavior can be extended and altered via these three basic * types of extensions: * - Themes: Themes alter the appearance of Drupal sites. They can include * template files, which alter the HTML markup and other raw output of the * site; CSS files, which alter the styling applied to the HTML; and * JavaScript, Flash, images, and other files. For more information, see the * @link theme_render Theme system and render API topic @endlink and * https://www.drupal.org/docs/8/theming * - Modules: Modules add to or alter the behavior and functionality of Drupal, * by using one or more of the methods listed below. For more information * about creating modules, see https://www.drupal.org/developing/modules/8 * - Installation profiles: Installation profiles can be used to * create distributions, which are complete specific-purpose packages of * Drupal including additional modules, themes, and data. For more * information, see https://www.drupal.org/developing/distributions. * * @section sec_alter Alteration methods for modules * Here is a list of the ways that modules can alter or extend Drupal's core * behavior, or the behavior of other modules: * - Hooks: Specially-named functions that a module defines, which are * discovered and called at specific times, usually to alter behavior or data. * See the @link hooks Hooks topic @endlink for more information. * - Plugins: Classes that a module defines, which are discovered and * instantiated at specific times to add functionality. See the * @link plugin_api Plugin API topic @endlink for more information. * - Entities: Special plugins that define entity types for storing new types * of content or configuration in Drupal. See the * @link entity_api Entity API topic @endlink for more information. * - Services: Classes that perform basic operations within Drupal, such as * accessing the database and sending email. See the * @link container Dependency Injection Container and Services topic @endlink * for more information. * - Routing: Providing or altering "routes", which are URLs that Drupal * responds to, or altering routing behavior with event listener classes. * See the @link menu Routing and menu topic @endlink for more information. * - Events: Modules can register as event subscribers; when an event is * dispatched, a method is called on each registered subscriber, allowing each * one to react. See the @link events Events topic @endlink for more * information. * * @section sec_sample *.info.yml files * Extensions must each be located in a directory whose name matches the short * name (or machine name) of the extension, and this directory must contain a * file named machine_name.info.yml (where machine_name is the machine name of * the extension). See \Drupal\Core\Extension\InfoParserInterface::parse() for * documentation of the format of .info.yml files. * @} */ /** * @defgroup plugin_api Plugin API * @{ * Using the Plugin API * * @section sec_overview Overview and terminology * * The basic idea of plugins is to allow a particular module or subsystem of * Drupal to provide functionality in an extensible, object-oriented way. The * controlling module or subsystem defines the basic framework (interface) for * the functionality, and other modules can create plugins (implementing the * interface) with particular behaviors. The controlling module instantiates * existing plugins as needed, and calls methods to invoke their functionality. * Examples of functionality in Drupal Core that use plugins include: the block * system (block types are plugins), the entity/field system (entity types, * field types, field formatters, and field widgets are plugins), the image * manipulation system (image effects and image toolkits are plugins), and the * search system (search page types are plugins). * * Plugins are grouped into plugin types, each generally defined by an * interface. Each plugin type is managed by a plugin manager service, which * uses a plugin discovery method to discover provided plugins of that type and * instantiate them using a plugin factory. * * Some plugin types make use of the following concepts or components: * - Plugin derivatives: Allows a single plugin class to present itself as * multiple plugins. Example: the Menu module provides a block for each * defined menu via a block plugin derivative. * - Plugin mapping: Allows a plugin class to map a configuration string to an * instance, and have the plugin automatically instantiated without writing * additional code. * - Plugin collections: Provide a way to lazily instantiate a set of plugin * instances from a single plugin definition. * * There are several things a module developer may need to do with plugins: * - Define a completely new plugin type: see @ref sec_define below. * - Create a plugin of an existing plugin type: see @ref sec_create below. * - Perform tasks that involve plugins: see @ref sec_use below. * * See https://www.drupal.org/developing/api/8/plugins for more detailed * documentation on the plugin system. There are also topics for a few * of the many existing types of plugins: * - @link block_api Block API @endlink * - @link entity_api Entity API @endlink * - @link field Various types of field-related plugins @endlink * - @link views_plugins Views plugins @endlink (has links to topics covering * various specific types of Views plugins). * - @link search Search page plugins @endlink * * @section sec_define Defining a new plugin type * To define a new plugin type: * - Define an interface for the plugin. This describes the common set of * behavior, and the methods you will call on each plugin class that is * instantiated. Usually this interface will extend one or more of the * following interfaces: * - \Drupal\Component\Plugin\PluginInspectionInterface * - \Drupal\Component\Plugin\ConfigurablePluginInterface * - \Drupal\Component\Plugin\ContextAwarePluginInterface * - \Drupal\Core\Plugin\PluginFormInterface * - \Drupal\Core\Executable\ExecutableInterface * - (optional) Create a base class that provides a partial implementation of * the interface, for the convenience of developers wishing to create plugins * of your type. The base class usually extends * \Drupal\Core\Plugin\PluginBase, or one of the base classes that extends * this class. * - Choose a method for plugin discovery, and define classes as necessary. * See @ref sub_discovery below. * - Create a plugin manager/factory class and service, which will discover and * instantiate plugins. See @ref sub_manager below. * - Use the plugin manager to instantiate plugins. Call methods on your plugin * interface to perform the tasks of your plugin type. * - (optional) If appropriate, define a plugin collection. See @ref * sub_collection below for more information. * * @subsection sub_discovery Plugin discovery * Plugin discovery is the process your plugin manager uses to discover the * individual plugins of your type that have been defined by your module and * other modules. Plugin discovery methods are classes that implement * \Drupal\Component\Plugin\Discovery\DiscoveryInterface. Most plugin types use * one of the following discovery mechanisms: * - Annotation: Plugin classes are annotated and placed in a defined namespace * subdirectory. Most Drupal Core plugins use this method of discovery. * - Hook: Plugin modules need to implement a hook to tell the manager about * their plugins. * - YAML: Plugins are listed in YAML files. Drupal Core uses this method for * discovering local tasks and local actions. This is mainly useful if all * plugins use the same class, so it is kind of like a global derivative. * - Static: Plugin classes are registered within the plugin manager class * itself. Static discovery is only useful if modules cannot define new * plugins of this type (if the list of available plugins is static). * * It is also possible to define your own custom discovery mechanism or mix * methods together. And there are many more details, such as annotation * decorators, that apply to some of the discovery methods. See * https://www.drupal.org/developing/api/8/plugins for more details. * * The remainder of this documentation will assume Annotation-based discovery, * since this is the most common method. * * @subsection sub_manager Defining a plugin manager class and service * To define an annotation-based plugin manager: * - Choose a namespace subdirectory for your plugin. For example, search page * plugins go in directory Plugin/Search under the module namespace. * - Define an annotation class for your plugin type. This class should extend * \Drupal\Component\Annotation\Plugin, and for most plugin types, it should * contain member variables corresponding to the annotations plugins will * need to provide. All plugins have at least $id: a unique string * identifier. * - Define an alter hook for altering the discovered plugin definitions. You * should document the hook in a *.api.php file. * - Define a plugin manager class. This class should implement * \Drupal\Component\Plugin\PluginManagerInterface; most plugin managers do * this by extending \Drupal\Core\Plugin\DefaultPluginManager. If you do * extend the default plugin manager, the only method you will probably need * to define is the class constructor, which will need to call the parent * constructor to provide information about the annotation class and plugin * namespace for discovery, set up the alter hook, and possibly set up * caching. See classes that extend DefaultPluginManager for examples. * - Define a service for your plugin manager. See the * @link container Services topic for more information. @endlink Your service * definition should look something like this, referencing your manager * class and the parent (default) plugin manager service to inherit * constructor arguments: * @code * plugin.manager.mymodule: * class: Drupal\mymodule\MyPluginManager * parent: default_plugin_manager * @endcode * - If your plugin is configurable, you will also need to define the * configuration schema and possibly a configuration entity type. See the * @link config_api Configuration API topic @endlink for more information. * * @subsection sub_collection Defining a plugin collection * Some configurable plugin types allow administrators to create zero or more * instances of each plugin, each with its own configuration. For example, * a single block plugin can be configured several times, to display in * different regions of a theme, with different visibility settings, a * different title, or other plugin-specific settings. To make this possible, * a plugin type can make use of what's known as a plugin collection. * * A plugin collection is a class that extends * \Drupal\Component\Plugin\LazyPluginCollection or one of its subclasses; there * are several examples in Drupal Core. If your plugin type uses a plugin * collection, it will usually also have a configuration entity, and the entity * class should implement * \Drupal\Core\Entity\EntityWithPluginCollectionInterface. Again, there are * several examples in Drupal Core; see also the @link config_api Configuration * API topic @endlink for more information about configuration entities. * * @section sec_create Creating a plugin of an existing type * Assuming the plugin type uses annotation-based discovery, in order to create * a plugin of an existing type, you will be creating a class. This class must: * - Implement the plugin interface, so that it has the required methods * defined. Usually, you'll want to extend the plugin base class, if one has * been provided. * - Have the right annotation in its documentation header. See the * @link annotation Annotation topic @endlink for more information about * annotation. * - Be in the right plugin namespace, in order to be discovered. * Often, the easiest way to make sure this happens is to find an existing * example of a working plugin class of the desired type, and copy it into your * module as a starting point. * * You can also create a plugin derivative, which allows your plugin class * to present itself to the user interface as multiple plugins. To do this, * in addition to the plugin class, you'll need to create a separate plugin * derivative class implementing * \Drupal\Component\Plugin\Derivative\DerivativeInterface. The classes * \Drupal\system\Plugin\Block\SystemMenuBlock (plugin class) and * \Drupal\system\Plugin\Derivative\SystemMenuBlock (derivative class) are a * good example to look at. * * @section sec_use Performing tasks involving plugins * Here are the steps to follow to perform a task that involves plugins: * - Locate the machine name of the plugin manager service, and instantiate the * service. See the @link container Services topic @endlink for more * information on how to do this. * - On the plugin manager class, use methods like getDefinition(), * getDefinitions(), or other methods specific to particular plugin managers * to retrieve information about either specific plugins or the entire list of * defined plugins. * - Call the createInstance() method on the plugin manager to instantiate * individual plugin objects. * - Call methods on the plugin objects to perform the desired tasks. * * @see annotation * @} */ /** * @defgroup oo_conventions Objected-oriented programming conventions * @{ * PSR-4, namespaces, class naming, and other conventions. * * A lot of the PHP code in Drupal is object oriented (OO), making use of * @link http://php.net/manual/language.oop5.php PHP classes, interfaces, and traits @endlink * (which are loosely referred to as "classes" in the rest of this topic). The * following conventions and standards apply to this version of Drupal: * - Each class must be in its own file. * - Classes must be namespaced. If a module defines a class, the namespace * must start with \Drupal\module_name. If it is defined by Drupal Core for * use across many modules, the namespace should be \Drupal\Core or * \Drupal\Component, with the exception of the global class \Drupal. See * https://www.drupal.org/node/1353118 for more about namespaces. * - In order for the PSR-4-based class auto-loader to find the class, it must * be located in a directory corresponding to the namespace. For * module-defined classes, if the namespace is \Drupal\module_name\foo\bar, * then the class goes under the main module directory in directory * src/foo/bar. For Drupal-wide classes, if the namespace is * \Drupal\Core\foo\bar, then it goes in directory * core/lib/Drupal/Core/foo/bar. See https://www.drupal.org/node/2156625 for * more information about PSR-4. * - Some classes have annotations added to their documentation headers. See * the @link annotation Annotation topic @endlink for more information. * - Standard plugin discovery requires particular namespaces and annotation * for most plugin classes. See the * @link plugin_api Plugin API topic @endlink for more information. * - There are project-wide coding standards for OO code, including naming: * https://www.drupal.org/node/608152 * - Documentation standards for classes are covered on: * https://www.drupal.org/coding-standards/docs#classes * @} */ /** * @defgroup listing_page_class Page header for Classes page * @{ * Introduction to classes * * A lot of the PHP code in Drupal is object oriented (OO), making use of * @link http://php.net/manual/language.oop5.php PHP classes, interfaces, and traits. @endlink * See the * @link oo_conventions Objected-oriented programming conventions @endlink * for more information. * * @see oo_conventions * * @} */ /** * @defgroup listing_page_namespace Page header for Namespaces page * @{ * Introduction to namespaces * * PHP classes, interfaces, and traits in Drupal are * @link http://php.net/manual/language.namespaces.rationale.php namespaced. @endlink * See the * @link oo_conventions Objected-oriented programming conventions @endlink * for more information. * * @see oo_conventions * * @} */ /** * @defgroup best_practices Best practices for developers * @{ * Overview of standards and best practices for developers * * Ideally, all code that is included in Drupal Core and contributed modules, * themes, and distributions will be secure, internationalized, maintainable, * and efficient. In order to facilitate this, the Drupal community has * developed a set of guidelines and standards for developers to follow. Most of * these standards can be found under * @link https://www.drupal.org/developing/best-practices Best practices on Drupal.org @endlink * * Standards and best practices that developers should be aware of include: * - Security: https://www.drupal.org/writing-secure-code and the * @link sanitization Sanitization functions topic @endlink * - Coding standards: https://www.drupal.org/coding-standards * and https://www.drupal.org/coding-standards/docs * - Accessibility: https://www.drupal.org/node/1637990 (modules) and * https://www.drupal.org/node/464472 (themes) * - Usability: https://www.drupal.org/ui-standards * - Internationalization: @link i18n Internationalization topic @endlink * - Automated testing: @link testing Automated tests topic @endlink * @} */ /** * @defgroup utility Utility classes and functions * @{ * Overview of utility classes and functions for developers. * * Drupal provides developers with a variety of utility functions that make it * easier and more efficient to perform tasks that are either really common, * tedious, or difficult. Utility functions help to reduce code duplication and * should be used in place of one-off code whenever possible. * * @see common.inc * @see file * @see format * @see php_wrappers * @see sanitization * @see transliteration * @see validation * @} */ /** * @defgroup hooks Hooks * @{ * Define functions that alter the behavior of Drupal core. * * One way for modules to alter the core behavior of Drupal (or another module) * is to use hooks. Hooks are specially-named functions that a module defines * (this is known as "implementing the hook"), which are discovered and called * at specific times to alter or add to the base behavior or data (this is * known as "invoking the hook"). Each hook has a name (example: * hook_batch_alter()), a defined set of parameters, and a defined return value. * Your modules can implement hooks that are defined by Drupal core or other * modules that they interact with. Your modules can also define their own * hooks, in order to let other modules interact with them. * * To implement a hook: * - Locate the documentation for the hook. Hooks are documented in *.api.php * files, by defining functions whose name starts with "hook_" (these * files and their functions are never loaded by Drupal -- they exist solely * for documentation). The function should have a documentation header, as * well as a sample function body. For example, in the core file * system.api.php, you can find hooks such as hook_batch_alter(). Also, if * you are viewing this documentation on an API reference site, the Core * hooks will be listed in this topic. * - Copy the function to your module's .module file. * - Change the name of the function, substituting your module's short name * (name of the module's directory, and .info.yml file without the extension) * for the "hook" part of the sample function name. For instance, to implement * hook_batch_alter(), you would rename it to my_module_batch_alter(). * - Edit the documentation for the function (normally, your implementation * should just have one line saying "Implements hook_batch_alter()."). * - Edit the body of the function, substituting in what you need your module * to do. * * To define a hook: * - Choose a unique name for your hook. It should start with "hook_", followed * by your module's short name. * - Provide documentation in a *.api.php file in your module's main * directory. See the "implementing" section above for details of what this * should contain (parameters, return value, and sample function body). * - Invoke the hook in your module's code. * * To invoke a hook, use methods on * \Drupal\Core\Extension\ModuleHandlerInterface such as alter(), invoke(), * and invokeAll(). You can obtain a module handler by calling * \Drupal::moduleHandler(), or getting the 'module_handler' service on an * injected container. * * @see extending * @see themeable * @see callbacks * @see \Drupal\Core\Extension\ModuleHandlerInterface * @see \Drupal::moduleHandler() * * @} */ /** * @defgroup callbacks Callbacks * @{ * Callback function signatures. * * Drupal's API sometimes uses callback functions to allow you to define how * some type of processing happens. A callback is a function with a defined * signature, which you define in a module. Then you pass the function name as * a parameter to a Drupal API function or return it as part of a hook * implementation return value, and your function is called at an appropriate * time. For instance, when setting up batch processing you might need to * provide a callback function for each processing step and/or a callback for * when processing is finished; you would do that by defining these functions * and passing their names into the batch setup function. * * Callback function signatures, like hook definitions, are described by * creating and documenting dummy functions in a *.api.php file; normally, the * dummy callback function's name should start with "callback_", and you should * document the parameters and return value and provide a sample function body. * Then your API documentation can refer to this callback function in its * documentation. A user of your API can usually name their callback function * anything they want, although a standard name would be to replace "callback_" * with the module name. * * @see hooks * @see themeable * * @} */ /** * @defgroup form_api Form generation * @{ * Describes how to generate and manipulate forms and process form submissions. * * Drupal provides a Form API in order to achieve consistency in its form * processing and presentation, while simplifying code and reducing the amount * of HTML that must be explicitly generated by a module. * * @section generating_forms Creating forms * Forms are defined as classes that implement the * \Drupal\Core\Form\FormInterface and are built using the * \Drupal\Core\Form\FormBuilder class. Drupal provides a couple of utility * classes that can be extended as a starting point for most basic forms, the * most commonly used of which is \Drupal\Core\Form\FormBase. FormBuilder * handles the low level processing of forms such as rendering the necessary * HTML, initial processing of incoming$_POST data, and delegating to your * implementation of FormInterface for validation and processing of submitted * data. * * Here is an example of a Form class: * @code * namespace Drupal\mymodule\Form; * * use Drupal\Core\Form\FormBase; * use Drupal\Core\Form\FormStateInterface; * * class ExampleForm extends FormBase { * public function getFormId() { * // Unique ID of the form. * return 'example_form'; * } * * public function buildForm(array $form, FormStateInterface$form_state) { * // Create a $form API array. *$form['phone_number'] = array( * '#type' => 'tel', * '#title' => $this->t('Your phone number'), * ); *$form['save'] = array( * '#type' => 'submit', * '#value' => $this->t('Save'), * ); * return$form; * } * * public function validateForm(array &$form, FormStateInterface$form_state) { * // Validate submitted form data. * } * * public function submitForm(array &$form, FormStateInterface$form_state) { * // Handle submitted form data. * } * } * @endcode * * @section retrieving_forms Retrieving and displaying forms * \Drupal::formBuilder()->getForm() should be used to handle retrieving, * processing, and displaying a rendered HTML form. Given the ExampleForm * defined above, * \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm') would * return the rendered HTML of the form defined by ExampleForm::buildForm(), or * call the validateForm() and submitForm(), methods depending on the current * processing state. * * The argument to \Drupal::formBuilder()->getForm() is the name of a class that * implements FormInterface. Any additional arguments passed to the getForm() * method will be passed along as additional arguments to the * ExampleForm::buildForm() method. * * For example: * @code * $extra = '612-123-4567'; *$form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm', $extra); * ... * public function buildForm(array$form, FormStateInterface $form_state,$extra = NULL) * $form['phone_number'] = array( * '#type' => 'tel', * '#title' =>$this->t('Your phone number'), * '#value' => $extra, * ); * return$form; * } * @endcode * * Alternatively, forms can be built directly via the routing system which will * take care of calling \Drupal::formBuilder()->getForm(). The following example * demonstrates the use of a routing.yml file to display a form at the given * route. * * @code * example.form: * path: '/example-form' * defaults: * _title: 'Example form' * _form: '\Drupal\mymodule\Form\ExampleForm' * @endcode * * The $form argument to form-related functions is a specialized render array * containing the elements and properties of the form. For more about render * arrays, see the @link theme_render Render API topic. @endlink For more * detailed explanations of the Form API workflow, see the * @link https://www.drupal.org/node/2117411 Form API documentation section. @endlink * In addition, there is a set of Form API tutorials in the * @link https://www.drupal.org/project/examples Examples for Developers project. @endlink * * In the form builder, validation, submission, and other form methods, *$form_state is the primary influence on the processing of the form and is * passed to most methods, so they can use it to communicate with the form * system and each other. $form_state is an object that implements * \Drupal\Core\Form\FormStateInterface. * @} */ /** * @defgroup queue Queue operations * @{ * Queue items to allow later processing. * * The queue system allows placing items in a queue and processing them later. * The system tries to ensure that only one consumer can process an item. * * Before a queue can be used it needs to be created by * Drupal\Core\Queue\QueueInterface::createQueue(). * * Items can be added to the queue by passing an arbitrary data object to * Drupal\Core\Queue\QueueInterface::createItem(). * * To process an item, call Drupal\Core\Queue\QueueInterface::claimItem() and * specify how long you want to have a lease for working on that item. * When finished processing, the item needs to be deleted by calling * Drupal\Core\Queue\QueueInterface::deleteItem(). If the consumer dies, the * item will be made available again by the Drupal\Core\Queue\QueueInterface * implementation once the lease expires. Another consumer will then be able to * receive it when calling Drupal\Core\Queue\QueueInterface::claimItem(). * Due to this, the processing code should be aware that an item might be handed * over for processing more than once. * * The$item object used by the Drupal\Core\Queue\QueueInterface can contain * arbitrary metadata depending on the implementation. Systems using the * interface should only rely on the data property which will contain the * information passed to Drupal\Core\Queue\QueueInterface::createItem(). * The full queue item returned by Drupal\Core\Queue\QueueInterface::claimItem() * needs to be passed to Drupal\Core\Queue\QueueInterface::deleteItem() once * processing is completed. * * There are two kinds of queue backends available: reliable, which preserves * the order of messages and guarantees that every item will be executed at * least once. The non-reliable kind only does a best effort to preserve order * in messages and to execute them at least once but there is a small chance * that some items get lost. For example, some distributed back-ends like * Amazon SQS will be managing jobs for a large set of producers and consumers * where a strict FIFO ordering will likely not be preserved. Another example * would be an in-memory queue backend which might lose items if it crashes. * However, such a backend would be able to deal with significantly more writes * than a reliable queue and for many tasks this is more important. See * aggregator_cron() for an example of how to effectively use a non-reliable * queue. Another example is doing Twitter statistics -- the small possibility * of losing a few items is insignificant next to power of the queue being able * to keep up with writes. As described in the processing section, regardless * of the queue being reliable or not, the processing code should be aware that * an item might be handed over for processing more than once (because the * processing code might time out before it finishes). * @} */ /** * @defgroup annotation Annotations * @{ * Annotations for class discovery and metadata description. * * The Drupal plugin system has a set of reusable components that developers * can use, override, and extend in their modules. Most of the plugins use * annotations, which let classes register themselves as plugins and describe * their metadata. (Annotations can also be used for other purposes, though * at the moment, Drupal only uses them for the plugin system.) * * To annotate a class as a plugin, add code similar to the following to the * end of the documentation block immediately preceding the class declaration: * @code * * @ContentEntityType( * * id = "comment", * * label = @Translation("Comment"), * * ... * * base_table = "comment" * * ) * @endcode * * Note that you must use double quotes; single quotes will not work in * annotations. * * Some annotation types, which extend the "@ PluginID" annotation class, have * only a single 'id' key in their annotation. For these, it is possible to use * a shorthand annotation. For example: * @code * * @ViewsArea("entity") * @endcode * in place of * @code * * @ViewsArea( * * id = "entity" * *) * @endcode * * The available annotation classes are listed in this topic, and can be * identified when you are looking at the Drupal source code by having * "@ Annotation" in their documentation blocks (without the space after @). To * find examples of annotation for a particular annotation class, such as * EntityType, look for class files that have an @ annotation section using the * annotation class. * * @see plugin_translatable * @see plugin_context * * @} */ /** * @addtogroup hooks * @{ */ /** * Perform periodic actions. * * Modules that require some commands to be executed periodically can * implement hook_cron(). The engine will then call the hook whenever a cron * run happens, as defined by the administrator. Typical tasks managed by * hook_cron() are database maintenance, backups, recalculation of settings * or parameters, automated mailing, and retrieving remote data. * * Short-running or non-resource-intensive tasks can be executed directly in * the hook_cron() implementation. * * Long-running tasks and tasks that could time out, such as retrieving remote * data, sending email, and intensive file tasks, should use the queue API * instead of executing the tasks directly. To do this, first define one or * more queues via a \Drupal\Core\Annotation\QueueWorker plugin. Then, add items * that need to be processed to the defined queues. */ function hook_cron() { // Short-running operation example, not using a queue: // Delete all expired records since the last cron run. $expires = \Drupal::state()->get('mymodule.last_check', 0); \Drupal::database()->delete('mymodule_table') ->condition('expires',$expires, '>=') ->execute(); \Drupal::state()->set('mymodule.last_check', REQUEST_TIME); // Long-running operation example, leveraging a queue: // Queue news feeds for updates once their refresh interval has elapsed. $queue = \Drupal::queue('aggregator_feeds');$ids = \Drupal::entityManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh(); foreach (Feed::loadMultiple($ids) as$feed) { if ($queue->createItem($feed)) { // Add timestamp to avoid queueing item more than once. $feed->setQueuedTime(REQUEST_TIME);$feed->save(); } } $ids = \Drupal::entityQuery('aggregator_feed') ->condition('queued', REQUEST_TIME - (3600 * 6), '<') ->execute(); if ($ids) { $feeds = Feed::loadMultiple($ids); foreach ($feeds as$feed) { $feed->setQueuedTime(0);$feed->save(); } } } /** * Alter available data types for typed data wrappers. * * @param array $data_types * An array of data type information. * * @see hook_data_type_info() */ function hook_data_type_info_alter(&$data_types) { $data_types['email']['class'] = '\Drupal\mymodule\Type\Email'; } /** * Alter cron queue information before cron runs. * * Called by \Drupal\Core\Cron to allow modules to alter cron queue settings * before any jobs are processed. * * @param array$queues * An array of cron queue information. * * @see \Drupal\Core\Queue\QueueWorkerInterface * @see \Drupal\Core\Annotation\QueueWorker * @see \Drupal\Core\Cron */ function hook_queue_info_alter(&$queues) { // This site has many feeds so let's spend 90 seconds on each cron run // updating feeds instead of the default 60.$queues['aggregator_feeds']['cron']['time'] = 90; } /** * Alter an email message created with MailManagerInterface->mail(). * * Hook hook_mail_alter() allows modification of email messages created and sent * with MailManagerInterface->mail(). Usage examples include adding and/or * changing message text, message fields, and message headers. * * Email messages sent using functions other than MailManagerInterface->mail() * will not invoke hook_mail_alter(). For example, a contributed module directly * calling the MailInterface->mail() or PHP mail() function will not invoke * this hook. All core modules use MailManagerInterface->mail() for messaging, * it is best practice but not mandatory in contributed modules. * * @param $message * An array containing the message data. Keys in this array include: * - 'id': * The MailManagerInterface->mail() id of the message. Look at module source * code or MailManagerInterface->mail() for possible id values. * - 'to': * The address or addresses the message will be sent to. The * formatting of this string must comply with RFC 2822. * - 'from': * The address the message will be marked as being from, which is * either a custom address or the site-wide default email address. * - 'subject': * Subject of the email to be sent. This must not contain any newline * characters, or the email may not be sent properly. * - 'body': * An array of strings or objects that implement * \Drupal\Component\Render\MarkupInterface containing the message text. The * message body is created by concatenating the individual array strings * into a single text string using "\n\n" as a separator. * - 'headers': * Associative array containing mail headers, such as From, Sender, * MIME-Version, Content-Type, etc. * - 'params': * An array of optional parameters supplied by the caller of * MailManagerInterface->mail() that is used to build the message before * hook_mail_alter() is invoked. * - 'language': * The language object used to build the message before hook_mail_alter() * is invoked. * - 'send': * Set to FALSE to abort sending this email message. * * @see \Drupal\Core\Mail\MailManagerInterface::mail() */ function hook_mail_alter(&$message) { if ($message['id'] == 'modulename_messagekey') { if (!example_notifications_optin($message['to'], $message['id'])) { // If the recipient has opted to not receive such messages, cancel // sending.$message['send'] = FALSE; return; } $message['body'][] = "--\nMail sent out from " . \Drupal::config('system.site')->get('name'); } } /** * Prepares a message based on parameters; * * This hook is called from MailManagerInterface->mail(). Note that hook_mail(), * unlike hook_mail_alter(), is only called on the$module argument to * MailManagerInterface->mail(), not all modules. * * @param $key * An identifier of the mail. * @param$message * An array to be filled in. Elements in this array include: * - id: An ID to identify the mail sent. Look at module source code or * MailManagerInterface->mail() for possible id values. * - to: The address or addresses the message will be sent to. The * formatting of this string must comply with RFC 2822. * - subject: Subject of the email to be sent. This must not contain any * newline characters, or the mail may not be sent properly. * MailManagerInterface->mail() sets this to an empty * string when the hook is invoked. * - body: An array of lines containing the message to be sent. Drupal will * format the correct line endings for you. MailManagerInterface->mail() * sets this to an empty array when the hook is invoked. The array may * contain either strings or objects implementing * \Drupal\Component\Render\MarkupInterface. * - from: The address the message will be marked as being from, which is * set by MailManagerInterface->mail() to either a custom address or the * site-wide default email address when the hook is invoked. * - headers: Associative array containing mail headers, such as From, * Sender, MIME-Version, Content-Type, etc. * MailManagerInterface->mail() pre-fills several headers in this array. * @param $params * An array of parameters supplied by the caller of * MailManagerInterface->mail(). * * @see \Drupal\Core\Mail\MailManagerInterface::mail() */ function hook_mail($key, &$message,$params) { $account =$params['account']; $context =$params['context']; $variables = [ '%site_name' => \Drupal::config('system.site')->get('name'), '%username' =>$account->getDisplayName(), ]; if ($context['hook'] == 'taxonomy') {$entity = $params['entity'];$vocabulary = Vocabulary::load($entity->id());$variables += [ '%term_name' => $entity->name, '%term_description' =>$entity->description, '%term_id' => $entity->id(), '%vocabulary_name' =>$vocabulary->label(), '%vocabulary_description' => $vocabulary->getDescription(), '%vocabulary_id' =>$vocabulary->id(), ]; } // Node-based variable translation is only available if we have a node. if (isset($params['node'])) { /** @var \Drupal\node\NodeInterface$node */ $node =$params['node']; $variables += [ '%uid' =>$node->getOwnerId(), '%url' => $node->url('canonical', ['absolute' => TRUE]), '%node_type' => node_get_type_label($node), '%title' => $node->getTitle(), '%teaser' =>$node->teaser, '%body' => $node->body, ]; }$subject = strtr($context['subject'],$variables); $body = strtr($context['message'], $variables);$message['subject'] .= str_replace(["\r", "\n"], '', $subject);$message['body'][] = MailFormatHelper::htmlToText($body); } /** * Alter the list of mail backend plugin definitions. * * @param array$info * The mail backend plugin definitions to be altered. * * @see \Drupal\Core\Annotation\Mail * @see \Drupal\Core\Mail\MailManager */ function hook_mail_backend_info_alter(&$info) { unset($info['test_mail_collector']); } /** * Alter the default country list. * * @param $countries * The associative array of countries keyed by two-letter country code. * * @see \Drupal\Core\Locale\CountryManager::getList() */ function hook_countries_alter(&$countries) { // Elbonia is now independent, so add it to the country list. $countries['EB'] = 'Elbonia'; } /** * Alter display variant plugin definitions. * * @param array$definitions * The array of display variant definitions, keyed by plugin ID. * * @see \Drupal\Core\Display\VariantManager * @see \Drupal\Core\Display\Annotation\DisplayVariant */ function hook_display_variant_plugin_alter(array &$definitions) {$definitions['full_page']['admin_label'] = t('Block layout'); } /** * Allow modules to alter layout plugin definitions. * * @param \Drupal\Core\Layout\LayoutDefinition[] $definitions * The array of layout definitions, keyed by plugin ID. */ function hook_layout_alter(&$definitions) { // Remove a layout. unset($definitions['twocol']); } /** * Flush all persistent and static caches. * * This hook asks your module to clear all of its static caches, * in order to ensure a clean environment for subsequently * invoked data rebuilds. * * Do NOT use this hook for rebuilding information. Only use it to flush custom * caches. * * Static caches using drupal_static() do not need to be reset manually. * However, all other static variables that do not use drupal_static() must be * manually reset. * * This hook is invoked by drupal_flush_all_caches(). It runs before module data * is updated and before hook_rebuild(). * * @see drupal_flush_all_caches() * @see hook_rebuild() */ function hook_cache_flush() { if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') { _update_cache_clear(); } } /** * Rebuild data based upon refreshed caches. * * This hook allows your module to rebuild its data based on the latest/current * module data. It runs after hook_cache_flush() and after all module data has * been updated. * * This hook is only invoked after the system has been completely cleared; * i.e., all previously cached data is known to be gone and every API in the * system is known to return current information, so your module can safely rely * on all available data to rebuild its own. * * @see hook_cache_flush() * @see drupal_flush_all_caches() */ function hook_rebuild() {$themes = \Drupal::service('theme_handler')->listInfo(); foreach ($themes as$theme) { _block_rehash($theme->getName()); } } /** * Alter the configuration synchronization steps. * * @param array$sync_steps * A one-dimensional array of \Drupal\Core\Config\ConfigImporter method names * or callables that are invoked to complete the import, in the order that * they will be processed. Each callable item defined in $sync_steps should * either be a global function or a public static method. The callable should * accept a$context array by reference. For example: * @code * function _additional_configuration_step(&$context) { * // Do stuff. * // If finished set$context['finished'] = 1. * } * @endcode * For more information on creating batches, see the * @link batch Batch operations @endlink documentation. * * @see callback_batch_operation() * @see \Drupal\Core\Config\ConfigImporter::initialize() */ function hook_config_import_steps_alter(&$sync_steps, \Drupal\Core\Config\ConfigImporter$config_importer) { $deletes =$config_importer->getUnprocessedConfiguration('delete'); if (isset($deletes['field.storage.node.body'])) {$sync_steps[] = '_additional_configuration_step'; } } /** * Alter config typed data definitions. * * For example you can alter the typed data types representing each * configuration schema type to change default labels or form element renderers * used for configuration translation. * * If implementations of this hook add or remove configuration schema a * ConfigSchemaAlterException will be thrown. Keep in mind that there are tools * that may use the configuration schema for static analysis of configuration * files, like the string extractor for the localization system. Such systems * won't work with dynamically defined configuration schemas. * * For adding new data types use configuration schema YAML files instead. * * @param $definitions * Associative array of configuration type definitions keyed by schema type * names. The elements are themselves array with information about the type. * * @see \Drupal\Core\Config\TypedConfigManager * @see \Drupal\Core\Config\Schema\ConfigSchemaAlterException */ function hook_config_schema_info_alter(&$definitions) { // Enhance the text and date type definitions with classes to generate proper // form elements in ConfigTranslationFormBase. Other translatable types will // appear as a one line textfield. $definitions['text']['form_element_class'] = '\Drupal\config_translation\FormElement\Textarea';$definitions['date_format']['form_element_class'] = '\Drupal\config_translation\FormElement\DateFormat'; } /** * Alter validation constraint plugin definitions. * * @param array[] $definitions * The array of validation constraint definitions, keyed by plugin ID. * * @see \Drupal\Core\Validation\ConstraintManager * @see \Drupal\Core\Validation\Annotation\Constraint */ function hook_validation_constraint_alter(array &$definitions) { $definitions['Null']['class'] = '\Drupal\mymodule\Validator\Constraints\MyClass'; } /** * @} End of "addtogroup hooks". */ /** * @defgroup ajax Ajax API * @{ * Overview for Drupal's Ajax API. * * @section sec_overview Overview of Ajax * Ajax is the process of dynamically updating parts of a page's HTML based on * data from the server. When a specified event takes place, a PHP callback is * triggered, which performs server-side logic and may return updated markup or * JavaScript commands to run. After the return, the browser runs the JavaScript * or updates the markup on the fly, with no full page refresh necessary. * * Many different events can trigger Ajax responses, including: * - Clicking a button * - Pressing a key * - Moving the mouse * * @section sec_framework Ajax responses in forms * Forms that use the Drupal Form API (see the * @link form_api Form API topic @endlink for more information about forms) can * trigger AJAX responses. Here is an outline of the steps: * - Add property '#ajax' to a form element in your form array, to trigger an * Ajax response. * - Write an Ajax callback to process the input and respond. * See sections below for details on these two steps. * * @subsection sub_form Adding Ajax triggers to a form * As an example of adding Ajax triggers to a form, consider editing a date * format, where the user is provided with a sample of the generated date output * as they type. To accomplish this, typing in the text field should trigger an * Ajax response. This is done in the text field form array element * in \Drupal\config_translation\FormElement\DateFormat::getFormElement(): * @code * '#ajax' => array( * 'callback' => 'Drupal\config_translation\FormElement\DateFormat::ajaxSample', * 'event' => 'keyup', * 'progress' => array( * 'type' => 'throbber', * 'message' => NULL, * ), * ), * @endcode * * As you can see from this example, the #ajax property for a form element is * an array. Here are the details of its elements, all of which are optional: * - callback: The callback to invoke to handle the server side of the * Ajax event. More information on callbacks is below in @ref sub_callback. * - wrapper: The HTML 'id' attribute of the area where the content returned by * the callback should be placed. Note that callbacks have a choice of * returning content or JavaScript commands; 'wrapper' is used for content * returns. * - method: The jQuery method for placing the new content (used with * 'wrapper'). Valid options are 'replaceWith' (default), 'append', 'prepend', * 'before', 'after', or 'html'. See * http://api.jquery.com/category/manipulation/ for more information on these * methods. * - effect: The jQuery effect to use when placing the new HTML (used with * 'wrapper'). Valid options are 'none' (default), 'slide', or 'fade'. * - speed: The effect speed to use (used with 'effect' and 'wrapper'). Valid * options are 'slow' (default), 'fast', or the number of milliseconds the * effect should run. * - event: The JavaScript event to respond to. This is selected automatically * for the type of form element; provide a value to override the default. * - prevent: A JavaScript event to prevent when the event is triggered. For * example, if you use event 'mousedown' on a button, you might want to * prevent 'click' events from also being triggered. * - progress: An array indicating how to show Ajax processing progress. Can * contain one or more of these elements: * - type: Type of indicator: 'throbber' (default) or 'bar'. * - message: Translated message to display. * - url: For a bar progress indicator, URL path for determining progress. * - interval: For a bar progress indicator, how often to update it. * - url: A \Drupal\Core\Url to which to submit the Ajax request. If omitted, * defaults to either the same URL as the form or link destination is for * someone with JavaScript disabled, or a slightly modified version (e.g., * with a query parameter added, removed, or changed) of that URL if * necessary to support Drupal's content negotiation. It is recommended to * omit this key and use Drupal's content negotiation rather than using * substantially different URLs between Ajax and non-Ajax. * * @subsection sub_callback Setting up a callback to process Ajax * Once you have set up your form to trigger an Ajax response (see @ref sub_form * above), you need to write some PHP code to process the response. If you use * 'path' in your Ajax set-up, your route controller will be triggered with only * the information you provide in the URL. If you use 'callback', your callback * method is a function, which will receive the$form and $form_state from the * triggering form. You can use$form_state to get information about the * data the user has entered into the form. For instance, in the above example * for the date format preview, * \Drupal\config_translation\FormElement\DateFormat\ajaxSample() does this to * get the format string entered by the user: * @code * $format_value = \Drupal\Component\Utility\NestedArray::getValue( *$form_state->getValues(), * $form_state->getTriggeringElement()['#array_parents']); * @endcode * * Once you have processed the input, you have your choice of returning HTML * markup or a set of Ajax commands. If you choose to return HTML markup, you * can return it as a string or a renderable array, and it will be placed in * the defined 'wrapper' element (see documentation above in @ref sub_form). * In addition, any messages returned by * \Drupal\Core\Messenger\Messenger::all(), themed as in * status-messages.html.twig, will be prepended. * * To return commands, you need to set up an object of class * \Drupal\Core\Ajax\AjaxResponse, and then use its addCommand() method to add * individual commands to it. In the date format preview example, the format * output is calculated, and then it is returned as replacement markup for a div * like this: * @code *$response = new AjaxResponse(); * $response->addCommand(new ReplaceCommand( * '#edit-date-format-suffix', * '' .$format . '')); * return $response; * @endcode * * The individual commands that you can return implement interface * \Drupal\Core\Ajax\CommandInterface. Available commands provide the ability * to pop up alerts, manipulate text and markup in various ways, redirect * to a new URL, and the generic \Drupal\Core\Ajax\InvokeCommand, which * invokes an arbitrary jQuery command. * * As noted above, status messages are prepended automatically if you use the * 'wrapper' method and return HTML markup. This is not the case if you return * commands, but if you would like to show status messages, you can add * @code * array('#type' => 'status_messages') * @endcode * to a render array, use drupal_render() to render it, and add a command to * place the messages in an appropriate location. * * @section sec_other Other methods for triggering Ajax * Here are some additional methods you can use to trigger Ajax responses in * Drupal: * - Add class 'use-ajax' to a link. The link will be loaded using an Ajax * call. When using this method, the href of the link can contain '/nojs/' as * part of the path. When the Ajax JavaScript processes the page, it will * convert this to '/ajax/'. The server is then able to easily tell if this * request was made through an actual Ajax request or in a degraded state, and * respond appropriately. * - Add class 'use-ajax-submit' to a submit button in a form. The form will * then be submitted via Ajax to the path specified in the #action. Like the * ajax-submit class on links, this path will have '/nojs/' replaced with * '/ajax/' so that the submit handler can tell if the form was submitted in a * degraded state or not. * - Add property '#autocomplete_route_name' to a text field in a form. The * route controller for this route must return an array of options for * autocomplete, as a \Symfony\Component\HttpFoundation\JsonResponse object. * See the @link menu Routing topic @endlink for more information about * routing. */ /** * @} End of "defgroup ajax". */ /** * @defgroup service_tag Service Tags * @{ * Service tags overview * * Some services have tags, which are defined in the service definition. Tags * are used to define a group of related services, or to specify some aspect of * how the service behaves. Typically, if you tag a service, your service class * must also implement a corresponding interface. Some common examples: * - access_check: Indicates a route access checking service; see the * @link menu Menu and routing system topic @endlink for more information. * - cache.bin: Indicates a cache bin service; see the * @link cache Cache topic @endlink for more information. * - event_subscriber: Indicates an event subscriber service. Event subscribers * can be used for dynamic routing and route altering; see the * @link menu Menu and routing system topic @endlink for more information. * They can also be used for other purposes; see * http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html * for more information. * - needs_destruction: Indicates that a destruct() method needs to be called * at the end of a request to finalize operations, if this service was * instantiated. Services should implement \Drupal\Core\DestructableInterface * in this case. * - context_provider: Indicates a block context provider, used for example * by block conditions. It has to implement * \Drupal\Core\Plugin\Context\ContextProviderInterface. * - http_client_middleware: Indicates that the service provides a guzzle * middleware, see * https://guzzle.readthedocs.org/en/latest/handlers-and-middleware.html for * more information. * * Creating a tag for a service does not do anything on its own, but tags * can be discovered or queried in a compiler pass when the container is built, * and a corresponding action can be taken. See * \Drupal\Core\Render\MainContent\MainContentRenderersPass for an example of * finding tagged services. * * See @link container Services and Dependency Injection Container @endlink for * information on services and the dependency injection container. * * @} */ /** * @defgroup events Events * @{ * Overview of event dispatch and subscribing * * @section sec_intro Introduction and terminology * Events are part of the Symfony framework: they allow for different components * of the system to interact and communicate with each other. Each event has a * unique string name. One system component dispatches the event at an * appropriate time; many events are dispatched by Drupal core and the Symfony * framework in every request. Other system components can register as event * subscribers; when an event is dispatched, a method is called on each * registered subscriber, allowing each one to react. For more on the general * concept of events, see * http://symfony.com/doc/current/components/event_dispatcher/introduction.html * * @section sec_dispatch Dispatching events * To dispatch an event, call the * \Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch() * method on the 'event_dispatcher' service (see the * @link container Services topic @endlink for more information about how to * interact with services). The first argument is the unique event name, which * you should normally define as a constant in a separate static class (see * \Symfony\Component\HttpKernel\KernelEvents and * \Drupal\Core\Config\ConfigEvents for examples). The second argument is a * \Symfony\Component\EventDispatcher\Event object; normally you will need to * extend this class, so that your event class can provide data to the event * subscribers. * * @section sec_subscribe Registering event subscribers * Here are the steps to register an event subscriber: * - Define a service in your module, tagged with 'event_subscriber' (see the * @link container Services topic @endlink for instructions). * - Define a class for your subscriber service that implements * \Symfony\Component\EventDispatcher\EventSubscriberInterface * - In your class, the getSubscribedEvents method returns a list of the events * this class is subscribed to, and which methods on the class should be * called for each one. Example: * @code * public static function getSubscribedEvents() { * // Subscribe to kernel terminate with priority 100. *$events[KernelEvents::TERMINATE][] = array('onTerminate', 100); * // Subscribe to kernel request with default priority of 0. * $events[KernelEvents::REQUEST][] = array('onRequest'); * return$events; * } * @endcode * - Write the methods that respond to the events; each one receives the * event object provided in the dispatch as its one argument. In the above * example, you would need to write onTerminate() and onRequest() methods. * * Note that in your getSubscribedEvents() method, you can optionally set the * priority of your event subscriber (see terminate example above). Event * subscribers with higher priority numbers get executed first; the default * priority is zero. If two event subscribers for the same event have the same * priority, the one defined in a module with a lower module weight will fire * first. Subscribers defined in the same services file are fired in * definition order. If order matters defining a priority is strongly advised * instead of relying on these two tie breaker rules as they might change in a * minor release. * @} */ /** * @defgroup session Sessions * @{ * Store and retrieve data associated with a user's browsing session. * * @section sec_intro Overview * The Drupal session management subsystem is built on top of the Symfony * session component. It is optimized in order to minimize the impact of * anonymous sessions on caching proxies. A session is only started if necessary * and the session cookie is removed from the browser as soon as the session * has no data. For this reason it is important for contributed and custom * code to remove session data if it is not used anymore. * * @section sec_usage Usage * Session data is accessed via the * \Symfony\Component\HttpFoundation\Request::getSession() * method, which returns an instance of * \Symfony\Component\HttpFoundation\Session\SessionInterface. The most * important methods on SessionInterface are set(), get(), and remove(). * * The following code fragment shows the implementation of a counter controller * relying on the session: * @code * public function counter(Request $request) { *$session = $request->getSession(); *$count = $session->get('mymodule.counter', 0) + 1; *$session->set('mymodule.counter', $count); * * return [ * '#markup' =>$this->t('Page Views: @count', ['@count' => $count]), * '#cache' => [ * 'max-age' => 0, * ], * ]; * } * * public function reset(Request$request) { * $session =$request->getSession(); * \$session->remove('mymodule.counter'); * } * @endcode * * It is important to keep the amount of data stored inside the session to a * minimum, as the complete session is loaded on every request. Also third * party session storage backends do not necessarily allow objects of unlimited * size. If it is necessary to collect a non-trivial amount of data specific to * a user's session, use the Key/Value store to save the serialized data and * only store the key to the entry in the session. * * @section sec_reserved Reserved attributes and namespacing * Contributed modules relying on the session are encouraged to namespace * session attributes by prefixing them with their project name or an * abbreviation thereof. * * Some attributes are reserved for Drupal core and must not be accessed from * within contributed and custom code. Reserved attributes include: * - uid: The user ID for an authenticated user. The value of this attribute * cannot be modified. * @} */