Compare commits
637 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ec057ca45 | |||
| fbc50fb699 | |||
| b0ec2d8cb5 | |||
| eee61675f0 | |||
| 4bc5dd3217 | |||
| d9596365e5 | |||
| 7748e17207 | |||
| aea324963d | |||
| fd4b7f5739 | |||
| ae0ec61180 | |||
| b97e5658ea | |||
| c3083344ec | |||
| b186033382 | |||
| a3edb5252a | |||
| b268d4a05c | |||
| e50a4e2386 | |||
| 9b19a46099 | |||
| 77f8c68f44 | |||
| 798b7b04af | |||
| 88c96fd2f3 | |||
| 16ae4b809d | |||
| 35f6017d21 | |||
| 085abbb371 | |||
| c3cd5e1db9 | |||
| 1f771e4103 | |||
| cc18262792 | |||
| ba7340108e | |||
| 9dadea2557 | |||
| 832d5b682d | |||
| a2c9045867 | |||
| 76b9a9407f | |||
| 532df04583 | |||
| f8d0e9ad5b | |||
| a4a01b4b96 | |||
| 93d224f333 | |||
| 09aa9e90b9 | |||
| 143dc29e0d | |||
| cf51a722c7 | |||
| 076792a3f1 | |||
| 32d89e0c0d | |||
| 8b2dca7427 | |||
| a4720e016e | |||
| f8acb4a7de | |||
| 31a70002d3 | |||
| 506bae6791 | |||
| e9576ab6b4 | |||
| a902db80d6 | |||
| b8ac884f9d | |||
| 6e2745d238 | |||
| b9bdec3f35 | |||
| 87f62d8e09 | |||
| 76f354d196 | |||
| fb327938c9 | |||
| 6cafb62b1e | |||
| 73c8dc3692 | |||
| 6537f3525e | |||
| 199ca97486 | |||
| adf8e5ce6e | |||
| 14d1f4e42e | |||
| 52c4f06af3 | |||
| 27b1ba527a | |||
| 085c2fd228 | |||
| 235b5a0c1d | |||
| 04d6be9bb2 | |||
| f66f661ce0 | |||
| 7f4fa839fe | |||
| faf4e51da9 | |||
| a7dae3ef8e | |||
| a35428cf86 | |||
| f06d89b2b5 | |||
| 346ef562dc | |||
| 2718718464 | |||
| 05c42f7539 | |||
| 05ca6dadf8 | |||
| 4226a54d53 | |||
| 02d052026c | |||
| 19ef016778 | |||
| 5e64cff4f1 | |||
| e575b2f6d1 | |||
| 3cc1d4b9fe | |||
| a7b9ce4caf | |||
| 17d617dc66 | |||
| ceb23943ee | |||
| 44eaae9610 | |||
| 47358bdaa5 | |||
| a39ff69d58 | |||
| c70955dfa9 | |||
| 8187097dc0 | |||
| 3d947610a0 | |||
| 003638cb8d | |||
| c30533cfed | |||
| 6af74e102c | |||
| 18559a0df6 | |||
| eb17e8ecd5 | |||
| 96e60a978e | |||
| 1b5fea23bd | |||
| 00621ce929 | |||
| 1ed22de511 | |||
| 48ffd4c677 | |||
| 4a59b3b555 | |||
| 00f2669025 | |||
| 4d3ee68536 | |||
| 0034080028 | |||
| c8d061208d | |||
| 5df656cadd | |||
| 6a68b92cff | |||
| 1ce52ce8db | |||
| 7d07632f7a | |||
| 34965b0d31 | |||
| 7105ca55cb | |||
| 0d3e293c5c | |||
| f4776ae40a | |||
| c9a3d370c4 | |||
| ebe7179a88 | |||
| aec655131b | |||
| 0291a8b492 | |||
| fca50b95ef | |||
| 5506f0482c | |||
| 410fff85d0 | |||
| 9a5af14929 | |||
| a847569195 | |||
| 7cbba9b175 | |||
| c21708e5e4 | |||
| 133870d759 | |||
| 690c28e94a | |||
| 82882a9034 | |||
| 172321d7d8 | |||
| bf139ab2c2 | |||
| bea3c273a3 | |||
| 143c8e7489 | |||
| 10f476e3a5 | |||
| de1982ca05 | |||
| 79205746bc | |||
| 71e7d2552b | |||
| 2c4120360a | |||
| 780a21f62a | |||
| 9b378f3dc5 | |||
| ada23f968a | |||
| 1da6855d1c | |||
| 3f007ca625 | |||
| 71660782eb | |||
| 8c5ca6531b | |||
| 98f4a31ce0 | |||
| 9aeef50434 | |||
| a6a85dc49b | |||
| f2858a669a | |||
| 2c7a4204e7 | |||
| 8ecbc00c77 | |||
| 45c03504ad | |||
| e7698992b7 | |||
| 309481dde0 | |||
| 532a6ba83c | |||
| 5267a05191 | |||
| 7183b0f995 | |||
| 16d88af2ab | |||
| cf569389ab | |||
| dc76ce70b2 | |||
| 4818244d27 | |||
| 838a2120fb | |||
| d8d43cdc18 | |||
| e623b9afcc | |||
| db217f006c | |||
| 60aae880a4 | |||
| 22bf788f6b | |||
| 7842d36f71 | |||
| fc9a82669f | |||
| e88938d9cc | |||
| d7b0846147 | |||
| 95b732848e | |||
| afab006332 | |||
| 71d414b090 | |||
| 828aff67d9 | |||
| 83f506da1e | |||
| 553672355c | |||
| eaccc920db | |||
| 416d7a94be | |||
| 70f62d8944 | |||
| c96069566a | |||
| da568835a5 | |||
| 9bd1ba9ee6 | |||
| f0cfc08699 | |||
| 62daeecc11 | |||
| 7d784e4ade | |||
| e5ca507c6e | |||
| 10123d02f6 | |||
| 3476a15b0f | |||
| 689c45e54e | |||
| 117c147757 | |||
| 45d9d6d710 | |||
| 717612c7aa | |||
| ccdfa44df0 | |||
| 0ecaebd487 | |||
| 709752225c | |||
| 70127f1f3c | |||
| a61d4eff50 | |||
| 9c3bfbfa3f | |||
| 9e46c17505 | |||
| 6cf0f60c7d | |||
| f0a9fb36a3 | |||
| 8fb24d2b43 | |||
| 7da998aee8 | |||
| c577657600 | |||
| 4dba407997 | |||
| 183c7cb3f5 | |||
| 5ba78ea1ff | |||
| b6ebf8d770 | |||
| 199e6445f8 | |||
| 3cf10869b6 | |||
| 2e0a4ca447 | |||
| 12bba6cc09 | |||
| c53ee31d46 | |||
| 7bfd342445 | |||
| 7d181fd82d | |||
| 34f1a739f1 | |||
| f7a061c2c1 | |||
| 67c0ced049 | |||
| 0b0e98d794 | |||
| e0a4008f4e | |||
| cade07b451 | |||
| 00d737bbe8 | |||
| 24e3e96a78 | |||
| 6c6ae7361c | |||
| 9f887be6a6 | |||
| c250a0d330 | |||
| 546a27cb50 | |||
| edab808254 | |||
| 3d4c212f85 | |||
| 48488ae1d7 | |||
| dd031e7462 | |||
| 28177a0a07 | |||
| 2847f9c8fc | |||
| a761cef6df | |||
| 3699331396 | |||
| 1ef6b2298e | |||
| f77c1d2098 | |||
| 61a9dd5cd9 | |||
| e39e0243b2 | |||
| ef2a27eac1 | |||
| 903c5bf341 | |||
| 32ef8734a9 | |||
| e87d98d541 | |||
| eba496e2ae | |||
| 715cd44d3a | |||
| 50a946f5bb | |||
| 50e9f0e048 | |||
| bf2324ef15 | |||
| 53d3cd568c | |||
| 49202ec3e6 | |||
| 42d72f3297 | |||
| be56d390b7 | |||
| 2f5768b983 | |||
| 65930a0593 | |||
| 560c1c8ea3 | |||
| 7922f118db | |||
| f8872ff3e8 | |||
| d4edd6c99f | |||
| 301e79acae | |||
| baad460c91 | |||
| c3cf690cee | |||
| 6cc4b72fb9 | |||
| d311f9cc75 | |||
| bc6f61fe9f | |||
| b1455d0d74 | |||
| 01a2722f32 | |||
| 711f77e4ca | |||
| 615e2caf67 | |||
| cad44b4778 | |||
| c3cefce21c | |||
| 393133707a | |||
| 0fb12db343 | |||
| b1e4d7afc8 | |||
| eca84ae277 | |||
| c578a134fa | |||
| 53661a6767 | |||
| 3d115053d2 | |||
| 27db0b4376 | |||
| 45c79022ac | |||
| e15c728434 | |||
| 2c1fc0e086 | |||
| 35662296e5 | |||
| f5c99c5144 | |||
| 82efa6c9f2 | |||
| e02256507c | |||
| 794f42d81d | |||
| add479a88e | |||
| 429d0d711b | |||
| 47b2416012 | |||
| a01bd41865 | |||
| 555ad195a0 | |||
| 62b41d8dda | |||
| 1ba20f5594 | |||
| d0890a7791 | |||
| bcad5fa2de | |||
| b7a1f71911 | |||
| 7fd34aa0e6 | |||
| a78bb0cc83 | |||
| 2acdf0af6b | |||
| ba5ecbc72a | |||
| 4bb2eaa7d0 | |||
| 55e3c2cd82 | |||
| d320d0b285 | |||
| 9424bcb66e | |||
| 08a8eb917e | |||
| df78a7902b | |||
| 43fa28331e | |||
| c512b7cc65 | |||
| 8a7078b28b | |||
| dcb6e4169b | |||
| 8cd148efe0 | |||
| e2fb6ffa24 | |||
| 71a5c487ce | |||
| 23ea3287ea | |||
| a3e6f40dbe | |||
| 42cc95c245 | |||
| 9ea075bb32 | |||
| 08839bbcb8 | |||
| abfdce235b | |||
| 70427c648e | |||
| 5287178537 | |||
| abaaa8cdae | |||
| 9312fbe16e | |||
| d120a7baf2 | |||
| fb494ae9c8 | |||
| 09f2963373 | |||
| 6917b452bf | |||
| 919efdf632 | |||
| b3e58b7d0b | |||
| 4844fc124c | |||
| d98f1751e8 | |||
| 9ab44b3f99 | |||
| 6c32a2f003 | |||
| f23a63b545 | |||
| 6758c0fa99 | |||
| eef875e0c1 | |||
| 150735fbdb | |||
| accfa102fe | |||
| e5663dfd70 | |||
| 91d309074f | |||
| 5b09d5e8cf | |||
| 9a3f511056 | |||
| de4d45ce8e | |||
| 2d22a9d474 | |||
| c64eea0a51 | |||
| 0e099cc444 | |||
| fda6ef7a1f | |||
| 7b8dba0b52 | |||
| c3673c5531 | |||
| 1efa930202 | |||
| 87c3a9fd9f | |||
| 1f26c7053a | |||
| fff86d45c1 | |||
| 54a0a16b53 | |||
| 8cb63784e5 | |||
| 9ac938636f | |||
| 3bdbe1b08b | |||
| eaccd0d486 | |||
| 0bc9604212 | |||
| 17a0f7350f | |||
| 0ed5fa3b88 | |||
| 34b3aa4d49 | |||
| 5f22097114 | |||
| 43fed596e5 | |||
| acb1bf6fac | |||
| 6a748d5e8b | |||
| d0a9524463 | |||
| 42e7fb5e49 | |||
| 5c550aaafc | |||
| ea6e1851e9 | |||
| bd0d739550 | |||
| 75d8d06ffb | |||
| 8c92e24434 | |||
| cbd0157d66 | |||
| c9bcb47d54 | |||
| c58f3ed7ff | |||
| 3b34d79d36 | |||
| 8f19a957e2 | |||
| 94cc2c769c | |||
| 4f718dc60c | |||
| d1b0786a51 | |||
| 1cdd43b12b | |||
| b807cc6334 | |||
| 8cbfc9614a | |||
| 9de894db2d | |||
| 7a2db63954 | |||
| 8a3894de89 | |||
| 60ca7d5b07 | |||
| 697ecc6db1 | |||
| e2536570a3 | |||
| af90211efd | |||
| 78855a6c7b | |||
| 1640389bcf | |||
| a70c9434d7 | |||
| 441b8d6e69 | |||
| de61d99ad1 | |||
| f311ba2714 | |||
| 06032cd928 | |||
| d05a5b126c | |||
| 45e4351ade | |||
| 2811b3d262 | |||
| 0cb2846998 | |||
| 4db1863687 | |||
| 4a256d6e8e | |||
| 44666a2d31 | |||
| a122d95343 | |||
| af11bd26b6 | |||
| b8aa36a063 | |||
| a10d621fc5 | |||
| a322a0ab53 | |||
| 969d8f0e3f | |||
| 36cfbfe841 | |||
| 314cc22a28 | |||
| bd1fae5fc0 | |||
| ac23be5d24 | |||
| 6e72e0a6aa | |||
| 57bafe6ebc | |||
| 4ae00d74bc | |||
| 60293b276a | |||
| 4673a6a8fc | |||
| ce5a85c354 | |||
| ff952aa064 | |||
| 675fa4b813 | |||
| 73b0524202 | |||
| 58c57f94d6 | |||
| b6ced2f7e4 | |||
| 6123c76bc7 | |||
| 8beb495df4 | |||
| 90b46f39a4 | |||
| 1f3a85aa54 | |||
| 98e4f24ff6 | |||
| 48763c4d21 | |||
| d91225aae4 | |||
| a5436ae8ce | |||
| 7a9000b1ff | |||
| 85d47590cc | |||
| 8789750cc5 | |||
| b15478526a | |||
| 8786deb033 | |||
| 59e8879130 | |||
| e81aa9e8e6 | |||
| 8a2e491ee7 | |||
| 3a6857090e | |||
| d2ff78d173 | |||
| ef37c13e29 | |||
| a8d816982a | |||
| ac7f6f4b96 | |||
| 6da08c0e2c | |||
| f72e3fbbf2 | |||
| 8afe4de645 | |||
| 1fc88334a6 | |||
| 7643bd4ca9 | |||
| 1b9f0beaf3 | |||
| 993612b00e | |||
| 4eb084f1a2 | |||
| 34b3d144fe | |||
| c61decc816 | |||
| 5864eb6017 | |||
| d9131593c7 | |||
| 16e566b99f | |||
| bd010f8854 | |||
| a364f61121 | |||
| cf2fb7579b | |||
| 945aa97617 | |||
| ca4349c1ce | |||
| 267b45e0a1 | |||
| 4c53ec3355 | |||
| 7bd19d562d | |||
| 49e3cda704 | |||
| e8ec840f3c | |||
| 0c018318c6 | |||
| 3bd02768df | |||
| 39adfbde72 | |||
| a42e313460 | |||
| d6b99cf123 | |||
| 77eb24f886 | |||
| d4609de200 | |||
| 6c2d9137b3 | |||
| 5dc182dd6e | |||
| 88e2d12038 | |||
| b6a84b6fdd | |||
| 3e2821e6f5 | |||
| d93610d4b0 | |||
| 34d55059cb | |||
| 6257097a3f | |||
| cd35f43eac | |||
| 788105dd3d | |||
| 80cee53996 | |||
| dd94734d9a | |||
| 786538f74f | |||
| 925ec67b22 | |||
| b159b57207 | |||
| c01c608fdc | |||
| ca887bc9bc | |||
| 2ff9ac5608 | |||
| f63fc5c41a | |||
| d276541169 | |||
| 72b266d54e | |||
| 8f3702ee1a | |||
| 54b951fb5f | |||
| 9844660858 | |||
| d0012b72ad | |||
| 623b678c3e | |||
| 75f6d03855 | |||
| 236a2fca9b | |||
| a7c5e2d24d | |||
| 4ae75c1847 | |||
| d7788d69f6 | |||
| a033a6b4c1 | |||
| 0626a71686 | |||
| 756fbd91fd | |||
| 3b5c7727f2 | |||
| e5b13b7fc0 | |||
| 49c29a3f46 | |||
| 92fdea041d | |||
| a7fd949571 | |||
| 32d77062b4 | |||
| 92416730d1 | |||
| 4b95721a26 | |||
| 29d526b495 | |||
| 227d3fcbd3 | |||
| 05c3b5dd2f | |||
| cf55843d07 | |||
| c7c613b45b | |||
| 06450ed398 | |||
| 3d986cf8cd | |||
| 6e3013be7c | |||
| 63b66cf276 | |||
| aaf95d0161 | |||
| 473aab4ffb | |||
| 2504a9d2ec | |||
| a24c22cd12 | |||
| 2ccad8f967 | |||
| b152769f44 | |||
| 77b4970559 | |||
| 8492c192af | |||
| f621e8e3d8 | |||
| 5a804c0f54 | |||
| bfff058cc8 | |||
| 9e72a16e14 | |||
| 90317c258b | |||
| fcb5548c38 | |||
| 654f0c0cf7 | |||
| 402469ce8b | |||
| fb092979bf | |||
| 768779972e | |||
| b0124c9703 | |||
| d2674929ba | |||
| 47ba8d481e | |||
| 814054616f | |||
| 7bc37de925 | |||
| 0f00c5c594 | |||
| 4b8ed14f54 | |||
| 9840da227e | |||
| 4948ac2e0c | |||
| 954b1b5504 | |||
| 9e81532432 | |||
| 6726f0073e | |||
| 5011fb91ff | |||
| 657beb8924 | |||
| 1d5c188798 | |||
| ac7cbc012e | |||
| 05f1cccc37 | |||
| 1081b8ec84 | |||
| af0a06b521 | |||
| 9963b0b6a6 | |||
| d7b20f1650 | |||
| 694cb9b053 | |||
| 14dcbdb0f4 | |||
| 38753adc60 | |||
| da7c844c30 | |||
| 0f6d896e43 | |||
| 0137a13d55 | |||
| 254bf485f1 | |||
| e81fce929a | |||
| c1536ff1ef | |||
| 43e1ed2cf3 | |||
| 46f15f03d2 | |||
| 0cddce2c56 | |||
| 18cbf0db95 | |||
| 3b2c61fdb8 | |||
| d64a0e9173 | |||
| c88b113c1f | |||
| aa6699f4db | |||
| 1e557db89d | |||
| 5e99c1f9a1 | |||
| 84197f41ca | |||
| b604cb81e4 | |||
| 05f853e2db | |||
| a77864208e | |||
| 4b3521ec69 | |||
| 294673628e | |||
| 081e303415 | |||
| b14d0e4713 | |||
| d2dc75fb4e | |||
| 7c95cf02af | |||
| a7f3f08722 | |||
| 5db72d63c5 | |||
| d58d0239db | |||
| e9ea8e9b63 | |||
| e523503fb8 | |||
| 4da2fefa4d | |||
| 0f85e6ba0b | |||
| 8baa0cab98 | |||
| 5a730d0a80 | |||
| 5a36d6292d | |||
| b7a4701d1f | |||
| 6cb665f18c | |||
| eae5890112 | |||
| fd9ecb595f | |||
| 1fdc20cbdb | |||
| 1830fc428c | |||
| c53069c60a | |||
| 97a0c05d46 | |||
| 700e92b8d4 | |||
| 2d124e8f4e | |||
| eb57e9e60b | |||
| 5f8e23c1a9 | |||
| 7ed78289b5 | |||
| 77458d700b | |||
| 52b617673c | |||
| efcbed9b73 | |||
| 2dd8a44c20 | |||
| 3b8005fae7 | |||
| 097abcc59c | |||
| f257805573 | |||
| 2e5d19ddfc | |||
| 708a1cec00 | |||
| 53165cbc05 | |||
| 557b8de4cf | |||
| f68ebb8282 | |||
| 30d3f1d220 | |||
| a7f94caa2e | |||
| aadac9873b | |||
| 4a3728ee50 | |||
| c959f27415 | |||
| e727d2aa2a | |||
| 5f11ce035d | |||
| 004f868825 |
@@ -1007,4 +1007,127 @@
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
</MOODLE>
|
||||
<MOODLE version="2.7" requires="2.2">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -16,8 +16,6 @@ require_login();
|
||||
|
||||
admin_externalpage_setup('ssoaccesscontrol');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
if (!extension_loaded('openssl')) {
|
||||
print_error('requiresopenssl', 'mnet');
|
||||
}
|
||||
@@ -65,9 +63,11 @@ if (!empty($action) and confirm_sesskey()) {
|
||||
|
||||
if (mnet_update_sso_access_control($idrec->username, $idrec->mnet_host_id, $accessctrl)) {
|
||||
if ($accessctrl == 'allow') {
|
||||
redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('uset'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
|
||||
} elseif ($accessctrl == 'deny') {
|
||||
redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
|
||||
redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('user' => $idrec->username,
|
||||
'host' => $mnethosts[$idrec->mnet_host_id])));
|
||||
} else if ($accessctrl == 'deny') {
|
||||
redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user' => $idrec->username,
|
||||
'host' => $mnethosts[$idrec->mnet_host_id])));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -118,6 +118,8 @@ if ($form = data_submitted() and confirm_sesskey()) {
|
||||
exit;
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Explain
|
||||
echo $OUTPUT->box(get_string('ssoacldescr','mnet'));
|
||||
// Are the needed bits enabled?
|
||||
|
||||
@@ -288,9 +288,9 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
|
||||
// Get list of used plug-ins
|
||||
$instances = repository::get_types();
|
||||
// Array to store plugins being used
|
||||
$alreadyplugins = array();
|
||||
if (!empty($instances)) {
|
||||
// Array to store plugins being used
|
||||
$alreadyplugins = array();
|
||||
$totalinstances = count($instances);
|
||||
$updowncount = 1;
|
||||
foreach ($instances as $i) {
|
||||
|
||||
@@ -139,9 +139,15 @@ if ($capability) {
|
||||
// Put the contexts into a tree structure.
|
||||
foreach ($contexts as $conid => $con) {
|
||||
$context = context::instance_by_id($conid);
|
||||
$parentcontextid = get_parent_contextid($context);
|
||||
if ($parentcontextid) {
|
||||
$contexts[$parentcontextid]->children[] = $conid;
|
||||
try {
|
||||
$parentcontext = $context->get_parent_context();
|
||||
if ($parentcontext) { // Will be false if $context is the system context.
|
||||
$contexts[$parentcontext->id]->children[] = $conid;
|
||||
}
|
||||
} catch (dml_missing_record_exception $e) {
|
||||
// Ignore corrupt context tree structure here. Don't let it break
|
||||
// showing the rest of the report.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ $string['nolangupdateneeded'] = 'All your language packs are up to date, no upda
|
||||
$string['pluginname'] = 'Language packs';
|
||||
$string['purgestringcaches'] = 'Purge string caches';
|
||||
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="http://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
|
||||
$string['uninstall'] = 'Uninstall selected language pack(s)';
|
||||
$string['uninstall'] = 'Uninstall selected language pack';
|
||||
$string['uninstallconfirm'] = 'You are about to completely uninstall language pack {$a}, are you sure?';
|
||||
$string['updatelangs'] = 'Update all installed language packs';
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class tool_qeupgradehelper_extract_options_form extends moodleform {
|
||||
|
||||
$qtypes = get_plugin_list('qtype');
|
||||
foreach ($qtypes as $qtype => $notused) {
|
||||
$qtypes[$qtype] = get_string($qtype, 'qtype_' . $qtype);
|
||||
$qtypes[$qtype] = get_string('pluginname', 'qtype_' . $qtype);
|
||||
}
|
||||
|
||||
$mform->addElement('header', 'h1', 'Either extract a specific question_session');
|
||||
|
||||
@@ -179,12 +179,12 @@ function search_spammers($keywords) {
|
||||
$conditions7 = '( '.implode(' OR ', $keywordfull7).' )';
|
||||
|
||||
$sql = "SELECT * FROM {user} WHERE deleted = 0 AND id <> :userid AND $conditions"; // Exclude oneself
|
||||
$sql2 = "SELECT u.*, p.summary FROM {user} AS u, {post} AS p WHERE $conditions2 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
|
||||
$sql3 = "SELECT u.*, p.subject as postsubject FROM {user} AS u, {post} AS p WHERE $conditions3 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
|
||||
$sql4 = "SELECT u.*, c.content FROM {user} AS u, {comments} AS c WHERE $conditions4 AND u.deleted = 0 AND u.id=c.userid AND u.id <> :userid";
|
||||
$sql5 = "SELECT u.*, m.fullmessage FROM {user} AS u, {message} AS m WHERE $conditions5 AND u.deleted = 0 AND u.id=m.useridfrom AND u.id <> :userid";
|
||||
$sql6 = "SELECT u.*, fp.message FROM {user} AS u, {forum_posts} AS fp WHERE $conditions6 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
|
||||
$sql7 = "SELECT u.*, fp.subject FROM {user} AS u, {forum_posts} AS fp WHERE $conditions7 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
|
||||
$sql2 = "SELECT u.*, p.summary FROM {user} u, {post} p WHERE $conditions2 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
|
||||
$sql3 = "SELECT u.*, p.subject as postsubject FROM {user} u, {post} p WHERE $conditions3 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
|
||||
$sql4 = "SELECT u.*, c.content FROM {user} u, {comments} c WHERE $conditions4 AND u.deleted = 0 AND u.id=c.userid AND u.id <> :userid";
|
||||
$sql5 = "SELECT u.*, m.fullmessage FROM {user} u, {message} m WHERE $conditions5 AND u.deleted = 0 AND u.id=m.useridfrom AND u.id <> :userid";
|
||||
$sql6 = "SELECT u.*, fp.message FROM {user} u, {forum_posts} fp WHERE $conditions6 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
|
||||
$sql7 = "SELECT u.*, fp.subject FROM {user} u, {forum_posts} fp WHERE $conditions7 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
|
||||
|
||||
$spamusers_desc = $DB->get_recordset_sql($sql, $params);
|
||||
$spamusers_blog = $DB->get_recordset_sql($sql2, $params);
|
||||
|
||||
@@ -98,12 +98,16 @@ $STD_FIELDS = array('id', 'firstname', 'lastname', 'username', 'email',
|
||||
|
||||
$PRF_FIELDS = array();
|
||||
|
||||
if ($prof_fields = $DB->get_records('user_info_field')) {
|
||||
foreach ($prof_fields as $prof_field) {
|
||||
$PRF_FIELDS[] = 'profile_field_'.$prof_field->shortname;
|
||||
if ($proffields = $DB->get_records('user_info_field')) {
|
||||
foreach ($proffields as $key => $proffield) {
|
||||
$profilefieldname = 'profile_field_'.$proffield->shortname;
|
||||
$PRF_FIELDS[] = $profilefieldname;
|
||||
// Re-index $proffields with key as shortname. This will be
|
||||
// used while checking if profile data is key and needs to be converted (eg. menu profile field)
|
||||
$proffields[$profilefieldname] = $proffield;
|
||||
unset($proffields[$key]);
|
||||
}
|
||||
}
|
||||
unset($prof_fields);
|
||||
|
||||
if (empty($iid)) {
|
||||
$mform1 = new admin_uploaduser_form1();
|
||||
@@ -227,10 +231,10 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
$user->$key['text'] = $value;
|
||||
$user->$key['format'] = FORMAT_MOODLE;
|
||||
} else {
|
||||
$user->$key = $value;
|
||||
$user->$key = trim($value);
|
||||
}
|
||||
} else {
|
||||
$user->$key = $value;
|
||||
$user->$key = trim($value);
|
||||
}
|
||||
|
||||
if (in_array($key, $upt->columns)) {
|
||||
@@ -331,6 +335,16 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
if (isset($formdata->$field)) {
|
||||
// process templates
|
||||
$user->$field = uu_process_template($formdata->$field, $user);
|
||||
|
||||
// Form contains key and later code expects value.
|
||||
// Convert key to value for required profile fields.
|
||||
require_once($CFG->dirroot.'/user/profile/field/'.$proffields[$field]->datatype.'/field.class.php');
|
||||
$profilefieldclass = 'profile_field_'.$proffields[$field]->datatype;
|
||||
$profilefield = new $profilefieldclass($proffields[$field]->id);
|
||||
if (method_exists($profilefield, 'convert_external_data')) {
|
||||
$user->$field = $profilefield->edit_save_data_preprocess($user->$field, null);
|
||||
}
|
||||
|
||||
$formdefaults[$field] = true;
|
||||
}
|
||||
}
|
||||
@@ -856,6 +870,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
if ($rid) {
|
||||
// find duration
|
||||
$timeend = 0;
|
||||
|
||||
if (!empty($user->{'enrolperiod'.$i})) {
|
||||
$duration = (int)$user->{'enrolperiod'.$i} * 60*60*24; // convert days to seconds
|
||||
if ($duration > 0) { // sanity check
|
||||
@@ -987,7 +1002,7 @@ while ($linenum <= $previewrows and $fields = $cir->next()) {
|
||||
$rowcols = array();
|
||||
$rowcols['line'] = $linenum;
|
||||
foreach($fields as $key => $field) {
|
||||
$rowcols[$filecolumns[$key]] = s($field);
|
||||
$rowcols[$filecolumns[$key]] = s(trim($field));
|
||||
}
|
||||
$rowcols['status'] = array();
|
||||
|
||||
@@ -1013,7 +1028,7 @@ while ($linenum <= $previewrows and $fields = $cir->next()) {
|
||||
}
|
||||
|
||||
if (isset($rowcols['city'])) {
|
||||
$rowcols['city'] = trim($rowcols['city']);
|
||||
$rowcols['city'] = $rowcols['city'];
|
||||
if (empty($rowcols['city'])) {
|
||||
$rowcols['status'][] = get_string('fieldrequired', 'error', 'city');
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
'noviolatedforeignkeysfound' => 'tool_xmldb',
|
||||
'violatedforeignkeysfound' => 'tool_xmldb',
|
||||
'violations' => 'tool_xmldb',
|
||||
'unknowntable' => 'tool_xmldb',
|
||||
'unknownfield' => 'tool_xmldb',
|
||||
));
|
||||
}
|
||||
|
||||
@@ -75,6 +77,19 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
}
|
||||
$o.=' <li>' . $this->str['key'] . ': ' . $xmldb_key->readableInfo() . ' ';
|
||||
|
||||
$reftable = $xmldb_key->getRefTable();
|
||||
if (!$dbman->table_exists($reftable)) {
|
||||
$o.='<font color="red">' . $this->str['unknowntable'] . '</font>';
|
||||
// Add the missing index to the list
|
||||
$violation = new stdClass();
|
||||
$violation->string = 'fkunknowntable';
|
||||
$violation->table = $xmldb_table;
|
||||
$violation->key = $xmldb_key;
|
||||
$violation->reftable = $reftable;
|
||||
$violatedkeys[] = $violation;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Work out the SQL to find key violations.
|
||||
$keyfields = $xmldb_key->getFields();
|
||||
$reffields = $xmldb_key->getRefFields();
|
||||
@@ -82,6 +97,19 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
$nullnessconditions = array();
|
||||
$params = array();
|
||||
foreach ($keyfields as $i => $field) {
|
||||
if (!$dbman->field_exists($reftable, $reffields[$i])) {
|
||||
$o.='<font color="red">' . $this->str['unknownfield'] . '</font>';
|
||||
// Add the missing index to the list
|
||||
$violation = new stdClass();
|
||||
$violation->string = 'fkunknownfield';
|
||||
$violation->table = $xmldb_table;
|
||||
$violation->key = $xmldb_key;
|
||||
$violation->reftable = $reftable;
|
||||
$violation->reffield = $reffields[$i];
|
||||
$violatedkeys[] = $violation;
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$joinconditions[] = 't1.' . $field . ' = t2.' . $reffields[$i];
|
||||
$xmldb_field = $xmldb_table->getField($field);
|
||||
$default = $xmldb_field->getDefault();
|
||||
@@ -97,7 +125,7 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
}
|
||||
$nullnessconditions[] = 't2.id IS NULL';
|
||||
$sql = 'SELECT count(1) FROM {' . $xmldb_table->getName() .
|
||||
'} t1 LEFT JOIN {' . $xmldb_key->getRefTable() . '} t2 ON ' .
|
||||
'} t1 LEFT JOIN {' . $reftable . '} t2 ON ' .
|
||||
implode(' AND ', $joinconditions) . ' WHERE ' .
|
||||
implode(' AND ', $nullnessconditions);
|
||||
|
||||
@@ -109,6 +137,7 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
$o.='<font color="red">' . $this->str['violations'] . '</font>';
|
||||
// Add the missing index to the list
|
||||
$violation = new stdClass;
|
||||
$violation->string = 'fkviolationdetails';
|
||||
$violation->table = $xmldb_table;
|
||||
$violation->key = $xmldb_key;
|
||||
$violation->numviolations = $violations;
|
||||
@@ -145,8 +174,11 @@ class check_foreign_keys extends XMLDBCheckAction {
|
||||
$violation->tablename = $violation->table->getName();
|
||||
$violation->keyname = $violation->key->getName();
|
||||
|
||||
$r.= ' <li>' .get_string('fkviolationdetails', 'tool_xmldb', $violation) .
|
||||
'<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre></li>';
|
||||
$r.= ' <li>' .get_string($violation->string, 'tool_xmldb', $violation);
|
||||
if (!empty($violation->sql)) {
|
||||
$r.= '<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre>';
|
||||
}
|
||||
$r.= '</li>';
|
||||
}
|
||||
$r.= ' </ul>';
|
||||
} else {
|
||||
|
||||
@@ -106,6 +106,8 @@ $string['fieldsusedinindex'] = 'This field is used as index';
|
||||
$string['fieldsusedinkey'] = 'This field is used as key.';
|
||||
$string['filemodifiedoutfromeditor'] = 'Warning: File locally modified while using the XMLDB Editor. Saving will overwrite local changes.';
|
||||
$string['filenotwriteable'] = 'File not writeable';
|
||||
$string['fkunknownfield'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent field {$a->reffield} in referenced table {$a->reftable}.';
|
||||
$string['fkunknowntable'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent table {$a->reftable}.';
|
||||
$string['fkviolationdetails'] = 'Foreign key {$a->keyname} on table {$a->tablename} is violated by {$a->numviolations} out of {$a->numrows} rows.';
|
||||
$string['floatincorrectdecimals'] = 'Incorrect number of decimals for float field';
|
||||
$string['floatincorrectlength'] = 'Incorrect length for float field';
|
||||
@@ -183,6 +185,8 @@ $string['selecttable'] = 'Select table:';
|
||||
$string['table'] = 'Table';
|
||||
$string['tablenameempty'] = 'The table name cannot be empty';
|
||||
$string['tables'] = 'Tables';
|
||||
$string['unknownfield'] = 'Refers to an unknown field';
|
||||
$string['unknowntable'] = 'Refers to an unknown table';
|
||||
$string['unload'] = 'Unload';
|
||||
$string['up'] = 'Up';
|
||||
$string['view'] = 'View';
|
||||
|
||||
@@ -376,7 +376,9 @@
|
||||
echo $OUTPUT->heading('<a href="'.$securewwwroot.'/user/editadvanced.php?id=-1">'.get_string('addnewuser').'</a>');
|
||||
}
|
||||
if (!empty($table)) {
|
||||
echo html_writer::start_tag('div', array('class'=>'no-overflow'));
|
||||
echo html_writer::table($table);
|
||||
echo html_writer::end_tag('div');
|
||||
echo $OUTPUT->paging_bar($usercount, $page, $perpage, $baseurl);
|
||||
if (has_capability('moodle/user:create', $sitecontext)) {
|
||||
echo $OUTPUT->heading('<a href="'.$securewwwroot.'/user/editadvanced.php?id=-1">'.get_string('addnewuser').'</a>');
|
||||
|
||||
@@ -1370,7 +1370,7 @@ class CASClient
|
||||
|
||||
/**
|
||||
* This method is used to validate a ST; halt on failure, and sets $validate_url,
|
||||
* $text_reponse and $tree_response on success. These parameters are used later
|
||||
* $text_response and $tree_response on success. These parameters are used later
|
||||
* by CASClient::validatePGT() for CAS proxies.
|
||||
* Used for all CAS 1.0 validations
|
||||
* @param $validate_url the URL of the request to the CAS server.
|
||||
@@ -1500,7 +1500,7 @@ class CASClient
|
||||
|
||||
/**
|
||||
* This method is used to validate a SAML TICKET; halt on failure, and sets $validate_url,
|
||||
* $text_reponse and $tree_response on success. These parameters are used later
|
||||
* $text_response and $tree_response on success. These parameters are used later
|
||||
* by CASClient::validatePGT() for CAS proxies.
|
||||
*
|
||||
* @param $validate_url the URL of the request to the CAS server.
|
||||
@@ -2160,7 +2160,7 @@ class CASClient
|
||||
if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
|
||||
// This branch added by IDMS. Seems phpCAS implementor got a bit confused about the curl options CURLOPT_SSLCERT and CURLOPT_CAINFO
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
|
||||
curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, '1');
|
||||
@@ -2172,7 +2172,7 @@ class CASClient
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
// test pgtIou parameter for proxy mode (https connection
|
||||
// in background from CAS server to the php server)
|
||||
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
|
||||
$PAGE->set_url('/auth/cas/auth.php');
|
||||
$PAGE->set_url('/login/index.php');
|
||||
$PAGE->navbar->add($CASform);
|
||||
$PAGE->set_title("$site->fullname: $CASform");
|
||||
$PAGE->set_heading($site->fullname);
|
||||
|
||||
@@ -307,7 +307,7 @@ if (!ldap_paged_results_supported($config->ldap_version)) {
|
||||
<label for="bind_pw"><?php print_string('auth_ldap_bind_pw_key', 'auth_ldap') ?></label>
|
||||
</td>
|
||||
<td>
|
||||
<input name="bind_pw" id="bind_pw" type="password" size="30" value="<?php echo $config->bind_pw?>" />
|
||||
<input name="bind_pw" id="bind_pw" type="password" size="30" value="<?php echo $config->bind_pw?>" autocomplete="off"/>
|
||||
<?php if (isset($err['bind_pw'])) { echo $OUTPUT->error_text($err['bind_pw']); } ?>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@
|
||||
<tr valign="top" class="required">
|
||||
<td align="right"><label for="pass"><?php print_string("auth_dbpass_key", "auth_db") ?></label></td>
|
||||
<td>
|
||||
<input id="pass" name="pass" type="text" size="30" value="<?php echo $config->pass?>" />
|
||||
<input id="pass" name="pass" type="password" size="30" value="<?php p($config->pass)?>" autocomplete="off"/>
|
||||
<?php
|
||||
|
||||
if (isset($err["pass"])) {
|
||||
|
||||
@@ -36,13 +36,13 @@ $string['auth_dbfieldpass'] = 'Name of the field containing passwords';
|
||||
$string['auth_dbfieldpass_key'] = 'Password field';
|
||||
$string['auth_dbfielduser'] = 'Name of the field containing usernames';
|
||||
$string['auth_dbfielduser_key'] = 'Username field';
|
||||
$string['auth_dbhost'] = 'The computer hosting the database server.';
|
||||
$string['auth_dbhost'] = 'The computer hosting the database server. Use a system DSN entry if using ODBC.';
|
||||
$string['auth_dbhost_key'] = 'Host';
|
||||
$string['auth_dbchangepasswordurl_key'] = 'Password-change URL';
|
||||
$string['auth_dbinsertuser'] = 'Inserted user {$a->name} id {$a->id}';
|
||||
$string['auth_dbinsertuserduplicate'] = 'Error inserting user {$a->username} - user with this username was already created through \'{$a->auth}\' plugin.';
|
||||
$string['auth_dbinsertusererror'] = 'Error inserting user {$a}';
|
||||
$string['auth_dbname'] = 'Name of the database itself';
|
||||
$string['auth_dbname'] = 'Name of the database itself. Leave empty if using an ODBC DSN.';
|
||||
$string['auth_dbname_key'] = 'DB name';
|
||||
$string['auth_dbpass'] = 'Password matching the above username';
|
||||
$string['auth_dbpass_key'] = 'Password';
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@
|
||||
<tr valign="top" class="required">
|
||||
<td align="right"><label for="passwd"><?php print_string("auth_fcpasswd_key", "auth_fc") ?>:</label></td>
|
||||
<td>
|
||||
<input name="passwd" id="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" />
|
||||
<input name="passwd" id="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" autocomplete="off"/>
|
||||
<?php if (isset($err["passwd"])) echo $OUTPUT->error_text($err["passwd"]); ?>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -209,7 +209,7 @@ if (!ldap_paged_results_supported($config->ldap_version)) {
|
||||
<label for="bind_pw"><?php print_string('auth_ldap_bind_pw_key', 'auth_ldap') ?></label>
|
||||
</td>
|
||||
<td>
|
||||
<input name="bind_pw" id="bind_pw" type="password" size="30" value="<?php echo $config->bind_pw?>" />
|
||||
<input name="bind_pw" id="bind_pw" type="password" size="30" value="<?php echo $config->bind_pw?>" autocomplete="off"/>
|
||||
<?php if (isset($err['bind_pw'])) { echo $OUTPUT->error_text($err['bind_pw']); } ?>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -941,7 +941,6 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
// run the keepalive client
|
||||
$this->keepalive_client();
|
||||
|
||||
// admin/cron.php should have run srand for us
|
||||
$random100 = rand(0,100);
|
||||
if ($random100 < 10) { // Approximately 10% of the time.
|
||||
// nuke olden sessions
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
This files describes API changes in /auth/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 2.4.6 ===
|
||||
|
||||
* can_be_manually_set() - This function was introduced in the base class and returns false by default. If overriden by
|
||||
an authentication plugin to return true, the authentication plugin will be able to be manually set for users. For example,
|
||||
when bulk uploading users you will be able to select it as the authentication method they use.
|
||||
|
||||
=== 2.4 ===
|
||||
|
||||
required changes in code:
|
||||
|
||||
@@ -309,7 +309,6 @@ class entities {
|
||||
$source = str_split($source, 1);
|
||||
|
||||
for ($i = 1; $i <= $length; $i++) {
|
||||
mt_srand((double) microtime() * 1000000);
|
||||
$num = mt_rand(1, count($source));
|
||||
$response .= $source[$num - 1];
|
||||
}
|
||||
|
||||
@@ -335,6 +335,9 @@ class restore_controller extends backup implements loggable {
|
||||
if ($this->status != backup::STATUS_NEED_PRECHECK) {
|
||||
throw new restore_controller_exception('cannot_precheck_wrong_status', $this->status);
|
||||
}
|
||||
// Basic/initial prevention against time/memory limits
|
||||
set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
$this->precheck = restore_prechecks_helper::execute_prechecks($this, $droptemptablesafter);
|
||||
if (!array_key_exists('errors', $this->precheck)) { // No errors, can be executed
|
||||
$this->set_status(backup::STATUS_AWAITING);
|
||||
|
||||
@@ -139,7 +139,7 @@ class imscc11_backup_convert extends backup_execution_step {
|
||||
|
||||
require_once($CFG->dirroot . '/backup/cc/cc_includes.php');
|
||||
|
||||
$tempdir = $CFG->dataroot . '/temp/backup/' . uniqid('', true);
|
||||
$tempdir = $CFG->tempdir . '/backup/' . uniqid('', true);
|
||||
|
||||
if (mkdir($tempdir, 0777, true)) {
|
||||
|
||||
|
||||
@@ -129,20 +129,37 @@ class backup_course_task extends backup_task {
|
||||
/**
|
||||
* Code the transformations to perform in the course in
|
||||
* order to get transportable (encoded) links
|
||||
* @param string $content content in which to encode links.
|
||||
* @return string content with links encoded.
|
||||
*/
|
||||
static public function encode_content_links($content) {
|
||||
global $CFG;
|
||||
|
||||
$base = preg_quote($CFG->wwwroot, '/');
|
||||
|
||||
// Link to the course main page (it also covers "&topic=xx" and "&week=xx"
|
||||
// because they don't become transformed (section number) in backup/restore
|
||||
$search = '/(' . $base . '\/course\/view.php\?id\=)([0-9]+)/';
|
||||
$content= preg_replace($search, '$@COURSEVIEWBYID*$2@$', $content);
|
||||
// because they don't become transformed (section number) in backup/restore.
|
||||
$content = self::encode_links_helper($content, 'COURSEVIEWBYID', '/course/view.php?id=');
|
||||
|
||||
// A few other key course links.
|
||||
$content = self::encode_links_helper($content, 'GRADEINDEXBYID', '/grade/index.php?id=');
|
||||
$content = self::encode_links_helper($content, 'GRADEREPORTINDEXBYID', '/grade/report/index.php?id=');
|
||||
$content = self::encode_links_helper($content, 'USERINDEXVIEWBYID', '/user/index.php?id=');
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method, used by encode_content_links.
|
||||
* @param string $content content in which to encode links.
|
||||
* @param unknown_type $name the name of this type of encoded link.
|
||||
* @param unknown_type $path the path that identifies this type of link, up
|
||||
* to the ?paramname= bit.
|
||||
* @return string content with one type of link encoded.
|
||||
*/
|
||||
static private function encode_links_helper($content, $name, $path) {
|
||||
global $CFG;
|
||||
$base = preg_quote($CFG->wwwroot . $path, '/');
|
||||
return preg_replace('/(' . $base . ')([0-9]+)/', '$@' . $name . '*$2@$', $content);
|
||||
}
|
||||
|
||||
// Protected API starts here
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
|
||||
backup_helper::clear_backup_dir($this->get_backupid()); // Empty temp dir, just in case
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
|
||||
backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
|
||||
backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
|
||||
}
|
||||
}
|
||||
@@ -209,7 +210,7 @@ abstract class backup_questions_activity_structure_step extends backup_activity_
|
||||
|
||||
$qas = new backup_nested_element($nameprefix . 'question_attempts');
|
||||
$qa = new backup_nested_element($nameprefix . 'question_attempt', array('id'), array(
|
||||
'slot', 'behaviour', 'questionid', 'maxmark', 'minfraction',
|
||||
'slot', 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction',
|
||||
'flagged', 'questionsummary', 'rightanswer', 'responsesummary',
|
||||
'timemodified'));
|
||||
|
||||
@@ -1626,7 +1627,20 @@ class backup_zip_contents extends backup_execution_step {
|
||||
$zippacker = get_file_packer('application/zip');
|
||||
|
||||
// Zip files
|
||||
$zippacker->archive_to_pathname($files, $zipfile);
|
||||
$result = $zippacker->archive_to_pathname($files, $zipfile, true, $this);
|
||||
|
||||
// Something went wrong.
|
||||
if ($result === false) {
|
||||
@unlink($zipfile);
|
||||
throw new backup_step_exception('error_zip_packing', '', 'An error was encountered while trying to generate backup zip');
|
||||
}
|
||||
// Read to make sure it is a valid backup. Refer MDL-37877 . Delete it, if found not to be valid.
|
||||
try {
|
||||
backup_general_helper::get_backup_information_from_mbz($zipfile);
|
||||
} catch (backup_helper_exception $e) {
|
||||
@unlink($zipfile);
|
||||
throw new backup_step_exception('error_zip_packing', '', $e->debuginfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ global $LINKS_ENCODERS_CACHE;
|
||||
$LINKS_ENCODERS_CACHE = array();
|
||||
|
||||
/**
|
||||
* Class implementing the @xml_contenttrasnformed logic to be applied in moodle2 backups
|
||||
* Class implementing the @xml_contenttransformed logic to be applied in moodle2 backups
|
||||
*
|
||||
* TODO: Finish phpdocs
|
||||
*/
|
||||
@@ -61,13 +61,13 @@ class backup_xml_transformer extends xml_contenttransformer {
|
||||
|
||||
// Array or object, debug and try our best recursively, shouldn't happen but...
|
||||
if (is_array($content)) {
|
||||
debugging('Backup XML transformer should process arrays but plain content always', DEBUG_DEVELOPER);
|
||||
debugging('Backup XML transformer should not process arrays but plain content only', DEBUG_DEVELOPER);
|
||||
foreach($content as $key => $plaincontent) {
|
||||
$content[$key] = $this->process($plaincontent);
|
||||
}
|
||||
return $content;
|
||||
} else if (is_object($content)) {
|
||||
debugging('Backup XML transformer should not process objects but plain content always', DEBUG_DEVELOPER);
|
||||
debugging('Backup XML transformer should not process objects but plain content only', DEBUG_DEVELOPER);
|
||||
foreach((array)$content as $key => $plaincontent) {
|
||||
$content[$key] = $this->process($plaincontent);
|
||||
}
|
||||
|
||||
@@ -135,10 +135,16 @@ class restore_course_task extends restore_task {
|
||||
static public function define_decode_rules() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_decode_rule('COURSEVIEWBYID', '/course/view.php?id=$1', 'course');
|
||||
// Link to the course main page (it also covers "&topic=xx" and "&week=xx"
|
||||
// because they don't become transformed (section number) in backup/restore.
|
||||
$rules[] = new restore_decode_rule('COURSEVIEWBYID', '/course/view.php?id=$1', 'course');
|
||||
|
||||
// A few other key course links.
|
||||
$rules[] = new restore_decode_rule('GRADEINDEXBYID', '/grade/index.php?id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('GRADEREPORTINDEXBYID', '/grade/report/index.php?id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('USERINDEXVIEWBYID', '/user/index.php?id=$1', 'course');
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
||||
// Protected API starts here
|
||||
|
||||
@@ -161,6 +161,9 @@ class restore_section_task extends restore_task {
|
||||
$section_included = new restore_section_included_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
if (is_number($this->info->title)) {
|
||||
$label = get_string('includesection', 'backup', $this->info->title);
|
||||
} elseif (empty($this->info->title)) { // Don't throw error if title is empty, gracefully continue restore.
|
||||
$this->log('Section title missing in backup for section id '.$this->info->sectionid, backup::LOG_WARNING, $this->name);
|
||||
$label = get_string('unnamedsection', 'backup');
|
||||
} else {
|
||||
$label = $this->info->title;
|
||||
}
|
||||
|
||||
@@ -3837,6 +3837,9 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
|
||||
$data->questionusageid = $this->get_new_parentid($nameprefix . 'question_usage');
|
||||
$data->questionid = $question->newitemid;
|
||||
if (!property_exists($data, 'variant')) {
|
||||
$data->variant = 1;
|
||||
}
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
$newitemid = $DB->insert_record('question_attempts', $data);
|
||||
|
||||
@@ -164,8 +164,10 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
$dbman = $DB->get_manager(); // We are going to use database_manager services
|
||||
|
||||
$targettablename = 'backup_ids_temp';
|
||||
$table = new xmldb_table($targettablename);
|
||||
$dbman->drop_table($table); // And drop it
|
||||
if ($dbman->table_exists($targettablename)) {
|
||||
$table = new xmldb_table($targettablename);
|
||||
$dbman->drop_table($table); // And drop it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -908,6 +908,15 @@ abstract class restore_dbops {
|
||||
}
|
||||
|
||||
if (empty($file->repositoryid)) {
|
||||
// If contenthash is empty then gracefully skip adding file.
|
||||
if (empty($file->contenthash)) {
|
||||
$result = new stdClass();
|
||||
$result->code = 'file_missing_in_backup';
|
||||
$result->message = sprintf('missing file (%s) contenthash in backup for component %s', $file->filename, $component);
|
||||
$result->level = backup::LOG_WARNING;
|
||||
$results[] = $result;
|
||||
continue;
|
||||
}
|
||||
// this is a regular file, it must be present in the backup pool
|
||||
$backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*/
|
||||
abstract class backup_cron_automated_helper {
|
||||
|
||||
/** automated backups are active and ready to run */
|
||||
/** Automated backups are active and ready to run */
|
||||
const STATE_OK = 0;
|
||||
/** automated backups are disabled and will not be run */
|
||||
/** Automated backups are disabled and will not be run */
|
||||
const STATE_DISABLED = 1;
|
||||
/** automated backups are all ready running! */
|
||||
/** Automated backups are all ready running! */
|
||||
const STATE_RUNNING = 2;
|
||||
|
||||
/** Course automated backup completed successfully */
|
||||
@@ -49,6 +49,8 @@ abstract class backup_cron_automated_helper {
|
||||
const BACKUP_STATUS_SKIPPED = 3;
|
||||
/** Course automated backup had warnings */
|
||||
const BACKUP_STATUS_WARNING = 4;
|
||||
/** Course automated backup has yet to be run */
|
||||
const BACKUP_STATUS_NOTYETRUN = 5;
|
||||
|
||||
/** Run if required by the schedule set in config. Default. **/
|
||||
const RUN_ON_SCHEDULE = 0;
|
||||
@@ -119,12 +121,13 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
$rs = $DB->get_recordset('course');
|
||||
foreach ($rs as $course) {
|
||||
$backupcourse = $DB->get_record('backup_courses', array('courseid'=>$course->id));
|
||||
$backupcourse = $DB->get_record('backup_courses', array('courseid' => $course->id));
|
||||
if (!$backupcourse) {
|
||||
$backupcourse = new stdClass;
|
||||
$backupcourse->courseid = $course->id;
|
||||
$DB->insert_record('backup_courses',$backupcourse);
|
||||
$backupcourse = $DB->get_record('backup_courses', array('courseid'=>$course->id));
|
||||
$backupcourse->laststatus = self::BACKUP_STATUS_NOTYETRUN;
|
||||
$DB->insert_record('backup_courses', $backupcourse);
|
||||
$backupcourse = $DB->get_record('backup_courses', array('courseid' => $course->id));
|
||||
}
|
||||
|
||||
// The last backup is considered as successful when OK or SKIPPED.
|
||||
@@ -132,19 +135,23 @@ abstract class backup_cron_automated_helper {
|
||||
$backupcourse->laststatus == self::BACKUP_STATUS_OK) && (
|
||||
$backupcourse->laststarttime > 0 && $backupcourse->lastendtime > 0);
|
||||
|
||||
// Skip courses that do not yet need backup.
|
||||
$skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
|
||||
$skippedmessage = 'Does not require backup';
|
||||
// Assume that we are not skipping anything.
|
||||
$skipped = false;
|
||||
$skippedmessage = '';
|
||||
|
||||
// Check if we are going to be running the backup now.
|
||||
$shouldrunnow = (($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now)
|
||||
|| $rundirective == self::RUN_IMMEDIATELY);
|
||||
|
||||
// If config backup_auto_skip_hidden is set to true, skip courses that are not visible.
|
||||
if (!$skipped && $config->backup_auto_skip_hidden) {
|
||||
if ($shouldrunnow && $config->backup_auto_skip_hidden) {
|
||||
$skipped = ($config->backup_auto_skip_hidden && !$course->visible);
|
||||
$skippedmessage = 'Not visible';
|
||||
}
|
||||
|
||||
// If config backup_auto_skip_modif_days is set to true, skip courses
|
||||
// that have not been modified since the number of days defined.
|
||||
if (!$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_days) {
|
||||
if ($shouldrunnow && !$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_days) {
|
||||
$sqlwhere = "course=:courseid AND time>:time AND ".$DB->sql_like('action', ':action', false, true, true);
|
||||
$timenotmodifsincedays = $now - ($config->backup_auto_skip_modif_days * DAYSECS);
|
||||
// Check log if there were any modifications to the course content.
|
||||
@@ -159,8 +166,9 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
// If config backup_auto_skip_modif_prev is set to true, skip courses
|
||||
// that have not been modified since previous backup.
|
||||
if (!$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_prev) {
|
||||
if ($shouldrunnow && !$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_prev) {
|
||||
// Check log if there were any modifications to the course content.
|
||||
$sqlwhere = "course=:courseid AND time>:time AND ".$DB->sql_like('action', ':action', false, true, true);
|
||||
$params = array('courseid' => $course->id,
|
||||
'time' => $backupcourse->laststarttime,
|
||||
'action' => '%view%');
|
||||
@@ -170,16 +178,17 @@ abstract class backup_cron_automated_helper {
|
||||
$skippedmessage = 'Not modified since previous backup';
|
||||
}
|
||||
|
||||
// Skip courses not needed for backup.
|
||||
if ($skipped) {
|
||||
// Output the next execution time when it has been updated.
|
||||
if ($backupcourse->nextstarttime != $nextstarttime) {
|
||||
mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
|
||||
}
|
||||
// Check if the course is not scheduled to run right now.
|
||||
if (!$shouldrunnow) {
|
||||
$backupcourse->nextstarttime = $nextstarttime;
|
||||
$DB->update_record('backup_courses', $backupcourse);
|
||||
mtrace('Skipping ' . $course->fullname . ' (Not scheduled for backup until ' . $showtime . ')');
|
||||
} else if ($skipped) { // Must have been skipped for a reason.
|
||||
$backupcourse->laststatus = self::BACKUP_STATUS_SKIPPED;
|
||||
$backupcourse->nextstarttime = $nextstarttime;
|
||||
$DB->update_record('backup_courses', $backupcourse);
|
||||
mtrace('Skipping '.$course->fullname.' ('.$skippedmessage.')');
|
||||
mtrace('Skipping ' . $course->fullname . ' (' . $skippedmessage . ')');
|
||||
mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
|
||||
} else {
|
||||
// Backup every non-skipped courses.
|
||||
mtrace('Backing up '.$course->fullname.'...');
|
||||
@@ -223,16 +232,17 @@ abstract class backup_cron_automated_helper {
|
||||
$count = backup_cron_automated_helper::get_backup_status_array();
|
||||
$haserrors = ($count[self::BACKUP_STATUS_ERROR] != 0 || $count[self::BACKUP_STATUS_UNFINISHED] != 0);
|
||||
|
||||
//Build the message text
|
||||
//Summary
|
||||
$message .= get_string('summary')."\n";
|
||||
// Build the message text.
|
||||
// Summary.
|
||||
$message .= get_string('summary') . "\n";
|
||||
$message .= "==================================================\n";
|
||||
$message .= " ".get_string('courses').": ".array_sum($count)."\n";
|
||||
$message .= " ".get_string('ok').": ".$count[self::BACKUP_STATUS_OK]."\n";
|
||||
$message .= " ".get_string('skipped').": ".$count[self::BACKUP_STATUS_SKIPPED]."\n";
|
||||
$message .= " ".get_string('error').": ".$count[self::BACKUP_STATUS_ERROR]."\n";
|
||||
$message .= " ".get_string('unfinished').": ".$count[self::BACKUP_STATUS_UNFINISHED]."\n";
|
||||
$message .= " ".get_string('warning').": ".$count[self::BACKUP_STATUS_WARNING]."\n\n";
|
||||
$message .= ' ' . get_string('courses') . '; ' . array_sum($count) . "\n";
|
||||
$message .= ' ' . get_string('ok') . '; ' . $count[self::BACKUP_STATUS_OK] . "\n";
|
||||
$message .= ' ' . get_string('skipped') . '; ' . $count[self::BACKUP_STATUS_SKIPPED] . "\n";
|
||||
$message .= ' ' . get_string('error') . '; ' . $count[self::BACKUP_STATUS_ERROR] . "\n";
|
||||
$message .= ' ' . get_string('unfinished') . '; ' . $count[self::BACKUP_STATUS_UNFINISHED] . "\n";
|
||||
$message .= ' ' . get_string('warning') . '; ' . $count[self::BACKUP_STATUS_WARNING] . "\n";
|
||||
$message .= ' ' . get_string('backupnotyetrun') . '; ' . $count[self::BACKUP_STATUS_NOTYETRUN]."\n\n";
|
||||
|
||||
//Reference
|
||||
if ($haserrors) {
|
||||
@@ -295,7 +305,8 @@ abstract class backup_cron_automated_helper {
|
||||
self::BACKUP_STATUS_OK => 0,
|
||||
self::BACKUP_STATUS_UNFINISHED => 0,
|
||||
self::BACKUP_STATUS_SKIPPED => 0,
|
||||
self::BACKUP_STATUS_WARNING => 0
|
||||
self::BACKUP_STATUS_WARNING => 0,
|
||||
self::BACKUP_STATUS_NOTYETRUN => 0
|
||||
);
|
||||
|
||||
$statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
|
||||
@@ -371,7 +382,11 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
$outcome = self::BACKUP_STATUS_OK;
|
||||
$config = get_config('backup');
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
|
||||
$dir = $config->backup_auto_destination;
|
||||
$storage = (int)$config->backup_auto_storage;
|
||||
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO,
|
||||
backup::MODE_AUTOMATED, $userid);
|
||||
|
||||
try {
|
||||
|
||||
@@ -392,27 +407,28 @@ abstract class backup_cron_automated_helper {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the default filename
|
||||
// Set the default filename.
|
||||
$format = $bc->get_format();
|
||||
$type = $bc->get_type();
|
||||
$id = $bc->get_id();
|
||||
$users = $bc->get_plan()->get_setting('users')->get_value();
|
||||
$anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
|
||||
$bc->get_plan()->get_setting('filename')->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
|
||||
$bc->get_plan()->get_setting('filename')->set_value(backup_plan_dbops::get_default_backup_filename($format, $type,
|
||||
$id, $users, $anonymised));
|
||||
|
||||
$bc->set_status(backup::STATUS_AWAITING);
|
||||
|
||||
$bc->execute_plan();
|
||||
$results = $bc->get_results();
|
||||
$outcome = self::outcome_from_results($results);
|
||||
$file = $results['backup_destination']; // may be empty if file already moved to target location
|
||||
$dir = $config->backup_auto_destination;
|
||||
$storage = (int)$config->backup_auto_storage;
|
||||
$file = $results['backup_destination']; // May be empty if file already moved to target location.
|
||||
if (!file_exists($dir) || !is_dir($dir) || !is_writable($dir)) {
|
||||
$dir = null;
|
||||
}
|
||||
if ($file && !empty($dir) && $storage !== 0) {
|
||||
$filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
|
||||
// Copy file only if there was no error.
|
||||
if ($file && !empty($dir) && $storage !== 0 && $outcome != self::BACKUP_STATUS_ERROR) {
|
||||
$filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised,
|
||||
!$config->backup_shortname);
|
||||
if (!$file->copy_content_to($dir.'/'.$filename)) {
|
||||
$outcome = self::BACKUP_STATUS_ERROR;
|
||||
}
|
||||
@@ -428,6 +444,20 @@ abstract class backup_cron_automated_helper {
|
||||
$outcome = self::BACKUP_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Delete the backup file immediately if something went wrong.
|
||||
if ($outcome === self::BACKUP_STATUS_ERROR) {
|
||||
|
||||
// Delete the file from file area if exists.
|
||||
if (!empty($file)) {
|
||||
$file->delete();
|
||||
}
|
||||
|
||||
// Delete file from external storage if exists.
|
||||
if ($storage !== 0 && !empty($filename) && file_exists($dir.'/'.$filename)) {
|
||||
@unlink($dir.'/'.$filename);
|
||||
}
|
||||
}
|
||||
|
||||
$bc->destroy();
|
||||
unset($bc);
|
||||
|
||||
@@ -524,7 +554,7 @@ abstract class backup_cron_automated_helper {
|
||||
public static function set_state_running($running = true) {
|
||||
if ($running === true) {
|
||||
if (self::get_automated_backup_state() === self::STATE_RUNNING) {
|
||||
throw new backup_exception('backup_automated_already_running');
|
||||
throw new backup_helper_exception('backup_automated_already_running');
|
||||
}
|
||||
set_config('backup_auto_running', '1', 'backup');
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package core_backup
|
||||
* @category phpunit
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/moodle2/backup_course_task.class.php');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for encoding content links in backup_course_task.
|
||||
*
|
||||
* The code that this tests is acutally in backup/moodle2/backup_course_task.class.php,
|
||||
* but there is no place for unit tests near there, and perhaps one day it will
|
||||
* be refactored so it becomes more generic.
|
||||
*/
|
||||
class backup_course_task_testcase extends basic_testcase {
|
||||
|
||||
/**
|
||||
* Test the encode_content_links method for course.
|
||||
*/
|
||||
public function test_course_encode_content_links() {
|
||||
global $CFG;
|
||||
$encoded = backup_course_task::encode_content_links(
|
||||
$CFG->wwwroot . '/course/view.php?id=123, ' .
|
||||
$CFG->wwwroot . '/grade/index.php?id=123, ' .
|
||||
$CFG->wwwroot . '/grade/report/index.php?id=123 and ' .
|
||||
$CFG->wwwroot . '/user/index.php?id=123.');
|
||||
$this->assertEquals('$@COURSEVIEWBYID*123@$, $@GRADEINDEXBYID*123@$, ' .
|
||||
'$@GRADEREPORTINDEXBYID*123@$ and $@USERINDEXVIEWBYID*123@$.', $encoded);
|
||||
}
|
||||
}
|
||||
@@ -60,13 +60,17 @@ abstract class base_plan implements checksumable, executable {
|
||||
$task->set_plan($this);
|
||||
// Append task settings to plan array, if not present, for comodity
|
||||
foreach ($task->get_settings() as $key => $setting) {
|
||||
if (!in_array($setting, $this->settings)) {
|
||||
$name = $setting->get_name();
|
||||
if (!isset($this->settings[$name])) {
|
||||
$this->settings[$name] = $setting;
|
||||
} else {
|
||||
throw new base_plan_exception('multiple_settings_by_name_found', $name);
|
||||
}
|
||||
// Check if there is already a setting for this name.
|
||||
$name = $setting->get_name();
|
||||
if (!isset($this->settings[$name])) {
|
||||
// There is no setting, so add it.
|
||||
$this->settings[$name] = $setting;
|
||||
} else if ($this->settings[$name] != $setting) {
|
||||
// If the setting already exists AND it is not the same setting,
|
||||
// then throw an error. (I.e. you're allowed to add the same
|
||||
// setting twice, but cannot add two different ones with same
|
||||
// name.)
|
||||
throw new base_plan_exception('multiple_settings_by_name_found', $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ abstract class base_moodleform extends moodleform {
|
||||
*/
|
||||
function __construct(base_ui_stage $uistage, $action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) {
|
||||
$this->uistage = $uistage;
|
||||
$attributes = (array)$attributes;
|
||||
if (!isset($attributes['enctype'])) {
|
||||
$attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
|
||||
}
|
||||
|
||||
parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function backup_details($details, $nextstageurl) {
|
||||
$yestick = $this->output->pix_icon('i/valid', get_string('yes'));
|
||||
$notick = $this->output->pix_icon('i/valid', get_string('no'));
|
||||
$notick = $this->output->pix_icon('i/invalid', get_string('no'));
|
||||
|
||||
$html = html_writer::start_tag('div', array('class'=>'backup-restore'));
|
||||
|
||||
|
||||
@@ -475,8 +475,9 @@ class restore_ui_stage_schema extends restore_ui_stage {
|
||||
if ($this->stageform === null) {
|
||||
$form = new restore_schema_form($this, $PAGE->url);
|
||||
$tasks = $this->ui->get_tasks();
|
||||
$content = '';
|
||||
$courseheading = false;
|
||||
|
||||
$allsettings = array();
|
||||
foreach ($tasks as $task) {
|
||||
if (!($task instanceof restore_root_task)) {
|
||||
if (!$courseheading) {
|
||||
@@ -484,13 +485,11 @@ class restore_ui_stage_schema extends restore_ui_stage {
|
||||
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
|
||||
$courseheading = true;
|
||||
}
|
||||
// First add each setting
|
||||
// Put each setting into an array of settings to add. Adding
|
||||
// a setting individually is a very slow operation, so we add
|
||||
// them all in a batch later on.
|
||||
foreach ($task->get_settings() as $setting) {
|
||||
$form->add_setting($setting, $task);
|
||||
}
|
||||
// The add all the dependencies
|
||||
foreach ($task->get_settings() as $setting) {
|
||||
$form->add_dependencies($setting);
|
||||
$allsettings[] = array($setting, $task);
|
||||
}
|
||||
} else if ($this->ui->enforce_changed_dependencies()) {
|
||||
// Only show these settings if dependencies changed them.
|
||||
@@ -505,6 +504,15 @@ class restore_ui_stage_schema extends restore_ui_stage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actually add all the settings that we put in the array.
|
||||
$form->add_settings($allsettings);
|
||||
|
||||
// Add the dependencies for all the settings.
|
||||
foreach ($allsettings as $settingtask) {
|
||||
$form->add_dependencies($settingtask[0]);
|
||||
}
|
||||
|
||||
$this->stageform = $form;
|
||||
}
|
||||
return $this->stageform;
|
||||
@@ -689,6 +697,7 @@ class restore_ui_stage_process extends restore_ui_stage {
|
||||
$html .= html_writer::start_tag('form', array(
|
||||
'action' => $url->out_omit_querystring(),
|
||||
'class' => 'backup-restore',
|
||||
'enctype' => 'application/x-www-form-urlencoded', // Enforce compatibility with our max_input_vars hack.
|
||||
'method' => 'post'));
|
||||
foreach ($url->params() as $name => $value) {
|
||||
$html .= html_writer::empty_tag('input', array(
|
||||
|
||||
@@ -83,6 +83,7 @@ class block_blog_recent extends block_base {
|
||||
|
||||
$this->content = new stdClass();
|
||||
$this->content->footer = '';
|
||||
$this->content->text = '';
|
||||
|
||||
$context = $this->page->context;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ $communityid = optional_param('communityid', '', PARAM_INT);
|
||||
if ($remove != -1 and !empty($communityid) and confirm_sesskey()) {
|
||||
$communitymanager->block_community_remove_course($communityid, $USER->id);
|
||||
echo $OUTPUT->header();
|
||||
echo $renderer->remove_success(new moodle_url(get_referer(false)));
|
||||
echo $renderer->remove_success(new moodle_url('/course/view.php', array('id' => $courseid)));
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class block_community_manager {
|
||||
$community = $this->block_community_get_course($course->url, $userid);
|
||||
|
||||
if (empty($community)) {
|
||||
$community = new stdClass();
|
||||
$community->userid = $userid;
|
||||
$community->coursename = $course->name;
|
||||
$community->coursedescription = $course->description;
|
||||
|
||||
@@ -34,7 +34,14 @@ class block_course_list extends block_list {
|
||||
|
||||
if (empty($CFG->disablemycourses) and isloggedin() and !isguestuser() and
|
||||
!(has_capability('moodle/course:update', context_system::instance()) and $adminseesall)) { // Just print My Courses
|
||||
if ($courses = enrol_get_my_courses(NULL, 'visible DESC, fullname ASC')) {
|
||||
// As this is producing navigation sort order should default to $CFG->navsortmycoursessort instead
|
||||
// of using the default.
|
||||
if (!empty($CFG->navsortmycoursessort)) {
|
||||
$sortorder = 'visible DESC, ' . $CFG->navsortmycoursessort . ' ASC';
|
||||
} else {
|
||||
$sortorder = 'visible DESC, sortorder ASC';
|
||||
}
|
||||
if ($courses = enrol_get_my_courses(NULL, $sortorder)) {
|
||||
foreach ($courses as $course) {
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$linkcss = $course->visible ? "" : " class=\"dimmed\" ";
|
||||
@@ -120,8 +127,7 @@ class block_course_list extends block_list {
|
||||
$this->content->items[] = get_string('remotecourses','mnet');
|
||||
$this->content->icons[] = '';
|
||||
foreach ($courses as $course) {
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$this->content->items[]="<a title=\"" . format_string($course->shortname, true, array('context' => $coursecontext)) . "\" ".
|
||||
$this->content->items[]="<a title=\"" . format_string($course->shortname, true) . "\" ".
|
||||
"href=\"{$CFG->wwwroot}/auth/mnet/jump.php?hostid={$course->hostid}&wantsurl=/course/view.php?id={$course->remoteid}\">"
|
||||
.$icon. format_string($course->fullname) . "</a>";
|
||||
}
|
||||
|
||||
@@ -46,5 +46,14 @@ class block_mentees extends block_base {
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the block can be docked.
|
||||
* The mentees block can only be docked if it has a non-empty title.
|
||||
* @return bool
|
||||
*/
|
||||
public function instance_can_be_docked() {
|
||||
return parent::instance_can_be_docked() && isset($this->config->title) && !empty($this->config->title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/* RSS Feeds
|
||||
-------------------------*/
|
||||
.block_rss_client .list li:first-child {
|
||||
border-top-width: 0;
|
||||
}
|
||||
.block_rss_client .list li {
|
||||
border-top: 1px solid;
|
||||
padding: 5px;
|
||||
}
|
||||
@@ -81,6 +81,7 @@ class block_tags extends block_base {
|
||||
}
|
||||
|
||||
$this->content = new stdClass;
|
||||
$this->content->text = '';
|
||||
$this->content->footer = '';
|
||||
|
||||
// Get a list of tags.
|
||||
@@ -110,12 +111,12 @@ class block_tags extends block_base {
|
||||
$content = '';
|
||||
$moretags = new moodle_url('/tag/coursetags_more.php', array('show'=>$tagtype));
|
||||
if ($tagtype == 'all') {
|
||||
$tags = coursetag_get_tags(0, 0, $this->config->tagtype, $this->config->numberoftags, 'name');
|
||||
$tags = coursetag_get_tags(0, 0, $this->config->tagtype, $this->config->numberoftags);
|
||||
} else if ($tagtype == 'course') {
|
||||
$tags = coursetag_get_tags($this->page->course->id, 0, $this->config->tagtype, $this->config->numberoftags, 'name');
|
||||
$tags = coursetag_get_tags($this->page->course->id, 0, $this->config->tagtype, $this->config->numberoftags);
|
||||
$moretags->param('courseid', $this->page->course->id);
|
||||
} else if ($tagtype == 'my') {
|
||||
$tags = coursetag_get_tags(0, $USER->id, $this->config->tagtype, $this->config->numberoftags, 'name');
|
||||
$tags = coursetag_get_tags(0, $USER->id, $this->config->tagtype, $this->config->numberoftags);
|
||||
}
|
||||
$tagcloud = tag_print_cloud($tags, 150, true);
|
||||
if (!$tagcloud) {
|
||||
|
||||
@@ -120,6 +120,7 @@ if ($action === 'delete'){
|
||||
print_error('nopermissionstodeleteentry', 'blog');
|
||||
} else {
|
||||
$entry->delete();
|
||||
blog_rss_delete_file($userid);
|
||||
redirect($returnurl);
|
||||
}
|
||||
} else if (blog_user_can_edit_entry($entry)) {
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ if (empty($CFG->enableblogs)) {
|
||||
|
||||
//correct tagid if a text tag is provided as a param
|
||||
if (!empty($tag)) {
|
||||
if ($tagrec = $DB->get_record_sql("SELECT * FROM {tag} WHERE ". $DB->sql_like('name', '?', false), array("%$tag%"))) {
|
||||
if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
|
||||
$tagid = $tagrec->id;
|
||||
} else {
|
||||
unset($tagid);
|
||||
|
||||
+6
-2
@@ -957,8 +957,12 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
|
||||
$tagrec = $DB->get_record('tag', array('id'=>$tagid));
|
||||
$PAGE->navbar->add($tagrec->name, $blogurl);
|
||||
} elseif (!empty($tag)) {
|
||||
$blogurl->param('tag', $tag);
|
||||
$PAGE->navbar->add(get_string('tagparam', 'blog', $tag), $blogurl);
|
||||
if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
|
||||
$tagid = $tagrec->id;
|
||||
$headers['filters']['tag'] = $tagid;
|
||||
$blogurl->param('tag', $tag);
|
||||
$PAGE->navbar->add(get_string('tagparam', 'blog', $tag), $blogurl);
|
||||
}
|
||||
}
|
||||
|
||||
// Append Search info
|
||||
|
||||
@@ -330,3 +330,17 @@ function blog_rss_save_file($type, $id, $tagid=0, $contents='') {
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the supplied user's cached blog post RSS feed.
|
||||
* Only user blogs are available by RSS.
|
||||
* This doesn't call rss_delete_file() as blog RSS caching uses it's own file structure.
|
||||
*
|
||||
* @param int $userid
|
||||
*/
|
||||
function blog_rss_delete_file($userid) {
|
||||
$filename = blog_rss_file_name('user', $userid);
|
||||
if (file_exists($filename)) {
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+7
-8
@@ -24,8 +24,8 @@ A definition:
|
||||
'overrideclassfile' => null, // Optional
|
||||
'datasource' => null, // Optional
|
||||
'datasourcefile' => null, // Optional
|
||||
'persistent' => false, // Optional
|
||||
'persistentmaxsize' => false, // Optional
|
||||
'staticacceleration' => false, // Optional
|
||||
'staticaccelerationsize' => false, // Optional
|
||||
'ttl' => 0, // Optional
|
||||
'mappingsonly' => false // Optional
|
||||
'invalidationevents' => array( // Optional
|
||||
@@ -142,19 +142,18 @@ The following optional settings can also be defined:
|
||||
* overrideclassfile - Included if required when using the overrideclass param.
|
||||
* datasource - If provided this class will be used as a data source for the definition. It must implement the cache_data_source interface.
|
||||
* datasourcefile - Included if required when using the datasource param.
|
||||
* persistent - If set to true the loader will be stored when first created and provided to subsequent requests. More on this later.
|
||||
* persistentmaxsize - If set to an int this will be the maximum number of items stored in the persistent cache.
|
||||
* staticacceleration - Any data passing through the cache will be held onto to make subsequent requests for it faster.
|
||||
* staticaccelerationsize - If set to an int this will be the maximum number of items stored in the static acceleration array.
|
||||
* ttl - Can be used to set a ttl value for data being set for this cache.
|
||||
* mappingsonly - This definition can only be used if there is a store mapping for it. More on this later.
|
||||
* invalidationevents - An array of events that should trigger this cache to invalidate.
|
||||
|
||||
It's important to note that internally the definition is also aware of the component. This is picked up when the definition is read, based upon the location of the caches.php file.
|
||||
|
||||
The persist option.
|
||||
As noted the persist option causes the loader generated for this definition to be stored when first created. Subsequent requests for this definition will be given the original loader instance.
|
||||
The staticacceleration option.
|
||||
Data passed to or retrieved from the loader and its chained loaders gets cached by the instance.
|
||||
This option should be used when you know you will require the loader several times and perhaps in different areas of code.
|
||||
Because it caches key=>value data it avoids the need to re-fetch things from stores after the first request. Its good for performance, bad for memory.
|
||||
Memory use can be controlled by setting the staticaccelerationsize option.
|
||||
It should be used sparingly.
|
||||
|
||||
The mappingsonly option.
|
||||
@@ -227,4 +226,4 @@ Cache information can be invalidated in two ways.
|
||||
The first method is designed to be used when you have a single known definition you want to invalidate entries within.
|
||||
The second method is a lot more intensive for the system. There are defined invalidation events that definitions can "subscribe" to (through the definitions invalidationevents option).
|
||||
When you invalidate by event the cache API finds all of the definitions that subscribe to the event, it then loads the stores for each of those definitions and purges the keys from each store.
|
||||
This is obviously a recursive, and therefore, intense process.
|
||||
This is obviously a recursive, and therefore, intense process.
|
||||
|
||||
Vendored
+1
@@ -177,6 +177,7 @@ if (!empty($action) && confirm_sesskey()) {
|
||||
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
/* @var core_cache_renderer $renderer */
|
||||
$renderer = $PAGE->get_renderer('core_cache');
|
||||
|
||||
echo $renderer->header();
|
||||
|
||||
Vendored
+117
-30
@@ -75,19 +75,14 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* [string] A class to use as the data loader for this definition.
|
||||
* Any class used here must inherit the cache_data_loader interface.
|
||||
* + datasourcefile
|
||||
* [string] Suplements the above setting indicated the file containing the class to be used. This file is included when
|
||||
* [string] Supplements the above setting indicating the file containing the class to be used. This file is included when
|
||||
* required.
|
||||
* + persistent
|
||||
* [bool] This setting does two important things. First it tells the cache API to only instantiate the cache structure for
|
||||
* this definition once, further requests will be given the original instance.
|
||||
* Second the cache loader will keep an array of the items set and retrieved to the cache during the request.
|
||||
* This has several advantages including better performance without needing to start passing the cache instance between
|
||||
* function calls, the downside is that the cache instance + the items used stay within memory.
|
||||
* Consider using this setting when you know that there are going to be many calls to the cache for the same information
|
||||
* or when you are converting existing code to the cache and need to access the cache within functions but don't want
|
||||
* to add it as an argument to the function.
|
||||
* + persistentmaxsize
|
||||
* [int] This supplements the above setting by limiting the number of items in the caches persistent array of items.
|
||||
* + staticacceleration
|
||||
* The cache loader will keep an array of the items set and retrieved to the cache during the request.
|
||||
* Consider using this setting when you know that there are going to be many calls to the cache for the same information.
|
||||
* Requests for data in this array will be ultra fast, but it will cost memory.
|
||||
* + staticaccelerationsize
|
||||
* [int] This supplements the above setting by limiting the number of items in the static acceleration array.
|
||||
* Tweaking this setting lower will allow you to minimise the memory implications above while hopefully still managing to
|
||||
* offset calls to the cache store.
|
||||
* + ttl
|
||||
@@ -228,16 +223,16 @@ class cache_definition {
|
||||
protected $datasourceaggregate = null;
|
||||
|
||||
/**
|
||||
* Set to true if the definitions cache should be persistent
|
||||
* Set to true if the cache should hold onto items passing through it to speed up subsequent requests.
|
||||
* @var bool
|
||||
*/
|
||||
protected $persistent = false;
|
||||
protected $staticacceleration = false;
|
||||
|
||||
/**
|
||||
* The persistent item array max size.
|
||||
* The maximum number of items that static acceleration cache should hold onto.
|
||||
* @var int
|
||||
*/
|
||||
protected $persistentmaxsize = false;
|
||||
protected $staticaccelerationsize = false;
|
||||
|
||||
/**
|
||||
* The TTL for data in this cache. Please don't use this, instead use event driven invalidation.
|
||||
@@ -261,7 +256,7 @@ class cache_definition {
|
||||
* An array of identifiers provided to this cache when it was initialised.
|
||||
* @var array
|
||||
*/
|
||||
protected $identifiers = array();
|
||||
protected $identifiers = null;
|
||||
|
||||
/**
|
||||
* Key prefix for use with single key cache stores
|
||||
@@ -320,8 +315,8 @@ class cache_definition {
|
||||
$overrideclassfile = null;
|
||||
$datasource = null;
|
||||
$datasourcefile = null;
|
||||
$persistent = false;
|
||||
$persistentmaxsize = false;
|
||||
$staticacceleration = false;
|
||||
$staticaccelerationsize = false;
|
||||
$ttl = 0;
|
||||
$mappingsonly = false;
|
||||
$invalidationevents = array();
|
||||
@@ -373,10 +368,18 @@ class cache_definition {
|
||||
}
|
||||
|
||||
if (array_key_exists('persistent', $definition)) {
|
||||
$persistent = (bool)$definition['persistent'];
|
||||
// Ahhh this is the legacy persistent option.
|
||||
$staticacceleration = (bool)$definition['persistent'];
|
||||
}
|
||||
if (array_key_exists('staticacceleration', $definition)) {
|
||||
$staticacceleration = (bool)$definition['staticacceleration'];
|
||||
}
|
||||
if (array_key_exists('persistentmaxsize', $definition)) {
|
||||
$persistentmaxsize = (int)$definition['persistentmaxsize'];
|
||||
// Ahhh this is the legacy persistentmaxsize option.
|
||||
$staticaccelerationsize = (int)$definition['persistentmaxsize'];
|
||||
}
|
||||
if (array_key_exists('staticaccelerationsize', $definition)) {
|
||||
$staticaccelerationsize = (int)$definition['staticaccelerationsize'];
|
||||
}
|
||||
if (array_key_exists('ttl', $definition)) {
|
||||
$ttl = (int)$definition['ttl'];
|
||||
@@ -452,8 +455,8 @@ class cache_definition {
|
||||
$cachedefinition->datasource = $datasource;
|
||||
$cachedefinition->datasourcefile = $datasourcefile;
|
||||
$cachedefinition->datasourceaggregate = $datasourceaggregate;
|
||||
$cachedefinition->persistent = $persistent;
|
||||
$cachedefinition->persistentmaxsize = $persistentmaxsize;
|
||||
$cachedefinition->staticacceleration = $staticacceleration;
|
||||
$cachedefinition->staticaccelerationsize = $staticaccelerationsize;
|
||||
$cachedefinition->ttl = $ttl;
|
||||
$cachedefinition->mappingsonly = $mappingsonly;
|
||||
$cachedefinition->invalidationevents = $invalidationevents;
|
||||
@@ -474,7 +477,8 @@ class cache_definition {
|
||||
* - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
|
||||
* - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
|
||||
* - overrideclass : The class to use as the loader.
|
||||
* - persistent : If set to true the cache will persist construction requests.
|
||||
* - staticacceleration : If set to true the cache will hold onto data passing through it.
|
||||
* - staticaccelerationsize : Set it to an int to limit the size of the staticacceleration cache.
|
||||
* @return cache_application|cache_session|cache_request
|
||||
*/
|
||||
public static function load_adhoc($mode, $component, $area, array $options = array()) {
|
||||
@@ -491,7 +495,14 @@ class cache_definition {
|
||||
$definition['simpledata'] = $options['simpledata'];
|
||||
}
|
||||
if (!empty($options['persistent'])) {
|
||||
$definition['persistent'] = $options['persistent'];
|
||||
// Ahhh this is the legacy persistent option.
|
||||
$definition['staticacceleration'] = (bool)$options['persistent'];
|
||||
}
|
||||
if (!empty($options['staticacceleration'])) {
|
||||
$definition['staticacceleration'] = (bool)$options['staticacceleration'];
|
||||
}
|
||||
if (!empty($options['staticaccelerationsize'])) {
|
||||
$definition['staticaccelerationsize'] = (int)$options['staticaccelerationsize'];
|
||||
}
|
||||
if (!empty($options['overrideclass'])) {
|
||||
$definition['overrideclass'] = $options['overrideclass'];
|
||||
@@ -571,6 +582,9 @@ class cache_definition {
|
||||
* @return array
|
||||
*/
|
||||
public function get_identifiers() {
|
||||
if (!isset($this->identifiers)) {
|
||||
return array();
|
||||
}
|
||||
return $this->identifiers;
|
||||
}
|
||||
|
||||
@@ -683,11 +697,22 @@ class cache_definition {
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function set_identifiers(array $identifiers = array()) {
|
||||
// If we are setting the exact same identifiers then just return as nothing really changed.
|
||||
// We don't care about order as cache::make will use the same definition order all the time.
|
||||
if ($identifiers === $this->identifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->requireidentifiers as $identifier) {
|
||||
if (!array_key_exists($identifier, $identifiers)) {
|
||||
throw new coding_exception('Identifier required for cache has not been provided: '.$identifier);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->identifiers === null) {
|
||||
// Initialize identifiers if they have not been.
|
||||
$this->identifiers = array();
|
||||
}
|
||||
foreach ($identifiers as $name => $value) {
|
||||
$this->identifiers[$name] = (string)$value;
|
||||
}
|
||||
@@ -716,18 +741,53 @@ class cache_definition {
|
||||
|
||||
/**
|
||||
* Returns true if this definitions cache should be made persistent.
|
||||
*
|
||||
* Please call {@link cache_definition::use_static_acceleration()} instead.
|
||||
*
|
||||
* @deprecated since 2.4.7
|
||||
* @return bool
|
||||
*/
|
||||
public function should_be_persistent() {
|
||||
return $this->persistent || $this->mode === cache_store::MODE_SESSION;
|
||||
debugging('Please upgrade your code to use cache_definition::use_static_acceleration', DEBUG_DEVELOPER);
|
||||
return $this->use_static_acceleration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max size for the persistent item array in the cache.
|
||||
* Returns true if we should hold onto the data flowing through the cache.
|
||||
*
|
||||
* If set to true data flowing through the cache will be stored in a static variable
|
||||
* to make subsequent requests for the data much faster.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function use_static_acceleration() {
|
||||
if ($this->mode === cache_store::MODE_REQUEST) {
|
||||
// Request caches should never use static acceleration - it just doesn't make sense.
|
||||
return false;
|
||||
}
|
||||
return $this->staticacceleration || $this->mode === cache_store::MODE_SESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max size for the static acceleration array.
|
||||
*
|
||||
* Please call {@link cache_definition::get_static_acceleration_size()} instead.
|
||||
*
|
||||
* @see cache_definition::get_static_acceleration_size()
|
||||
* @deprecated since 2.4.7
|
||||
* @return int
|
||||
*/
|
||||
public function get_persistent_max_size() {
|
||||
return $this->persistentmaxsize;
|
||||
debugging('Please upgrade your code to call cache_definition::get_static_acceleration_size', DEBUG_DEVELOPER);
|
||||
return $this->get_static_acceleration_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max size for the static acceleration array.
|
||||
* @return int
|
||||
*/
|
||||
public function get_static_acceleration_size() {
|
||||
return $this->staticaccelerationsize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -774,7 +834,7 @@ class cache_definition {
|
||||
'area' => $this->area,
|
||||
'siteidentifier' => $this->get_cache_identifier()
|
||||
);
|
||||
if (!empty($this->identifiers)) {
|
||||
if (isset($this->identifiers) && !empty($this->identifiers)) {
|
||||
$identifiers = array();
|
||||
foreach ($this->identifiers as $key => $value) {
|
||||
$identifiers[] = htmlentities($key, ENT_QUOTES, 'UTF-8').'='.htmlentities($value, ENT_QUOTES, 'UTF-8');
|
||||
@@ -821,4 +881,31 @@ class cache_definition {
|
||||
protected function get_cache_identifier() {
|
||||
return cache_helper::get_site_identifier();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the possible sharing options that can be used with this defintion.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_sharing_options() {
|
||||
return $this->sharingoptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user entered sharing key for this definition.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_user_input_sharing_key() {
|
||||
return $this->userinputsharingkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user selected sharing option for this definition.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_selected_sharing_option() {
|
||||
return $this->selectedsharingoption;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+9
-8
@@ -46,14 +46,15 @@ class cachestore_dummy extends cache_store {
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* Gets set to true if this store is going to persist data.
|
||||
* This happens when the definition doesn't require it as the loader will not be persisting information and something has to.
|
||||
* Gets set to true if this store is going to store data.
|
||||
* This happens when the definition doesn't require static acceleration as the loader will not be storing information and
|
||||
* something has to.
|
||||
* @var bool
|
||||
*/
|
||||
protected $persist = false;
|
||||
|
||||
/**
|
||||
* The persistent store array
|
||||
* The stored data array
|
||||
* @var array
|
||||
*/
|
||||
protected $store = array();
|
||||
@@ -106,13 +107,13 @@ class cachestore_dummy extends cache_store {
|
||||
* @param cache_definition $definition
|
||||
*/
|
||||
public function initialise(cache_definition $definition) {
|
||||
// If the definition isn't persistent then we need to be persistent here.
|
||||
// If the definition isn't using static acceleration then we need to be store data here.
|
||||
// The reasoning behind this is that:
|
||||
// - If the definition is persistent then the cache loader is going to
|
||||
// store things in its persistent cache.
|
||||
// - If the definition is not persistent then the cache loader won't try to store anything
|
||||
// - If the definition is using static acceleration then the cache loader is going to
|
||||
// store things in its static array.
|
||||
// - If the definition is not using static acceleration then the cache loader won't try to store anything
|
||||
// and we will need to store it here in order to make sure it is accessible.
|
||||
$this->persist = !$definition->should_be_persistent();
|
||||
$this->persist = !$definition->use_static_acceleration();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+38
-18
@@ -150,9 +150,7 @@ class cache_factory {
|
||||
*/
|
||||
public static function reset() {
|
||||
$factory = self::instance();
|
||||
$factory->cachesfromdefinitions = array();
|
||||
$factory->cachesfromparams = array();
|
||||
$factory->stores = array();
|
||||
$factory->reset_cache_instances();
|
||||
$factory->configs = array();
|
||||
$factory->definitions = array();
|
||||
$factory->lockplugins = array(); // MUST be null in order to force its regeneration.
|
||||
@@ -160,6 +158,18 @@ class cache_factory {
|
||||
$factory->state = self::STATE_UNINITIALISED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stores, clearing the array of created stores.
|
||||
*
|
||||
* Cache objects still held onto by the code that initialised them will remain as is
|
||||
* however all future requests for a cache/store will lead to a new instance being re-initialised.
|
||||
*/
|
||||
public function reset_cache_instances() {
|
||||
$this->cachesfromdefinitions = array();
|
||||
$this->cachesfromparams = array();
|
||||
$this->stores = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache object given the parameters for a definition.
|
||||
*
|
||||
@@ -181,9 +191,8 @@ class cache_factory {
|
||||
$definition = $this->create_definition($component, $area, $aggregate);
|
||||
$definition->set_identifiers($identifiers);
|
||||
$cache = $this->create_cache($definition, $identifiers);
|
||||
if ($definition->should_be_persistent()) {
|
||||
$this->cachesfromdefinitions[$definitionname] = $cache;
|
||||
}
|
||||
// Loaders are always held onto to speed up subsequent requests.
|
||||
$this->cachesfromdefinitions[$definitionname] = $cache;
|
||||
return $cache;
|
||||
}
|
||||
|
||||
@@ -199,7 +208,8 @@ class cache_factory {
|
||||
* @param array $options An array of options, available options are:
|
||||
* - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
|
||||
* - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
|
||||
* - persistent : If set to true the cache will persist construction requests.
|
||||
* - staticacceleration : If set to true the cache will hold onto data passing through it.
|
||||
* - staticaccelerationsize : The maximum number of items to hold onto for acceleration purposes.
|
||||
* @return cache_application|cache_session|cache_request
|
||||
*/
|
||||
public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
|
||||
@@ -210,9 +220,7 @@ class cache_factory {
|
||||
$definition = cache_definition::load_adhoc($mode, $component, $area, $options);
|
||||
$definition->set_identifiers($identifiers);
|
||||
$cache = $this->create_cache($definition, $identifiers);
|
||||
if ($definition->should_be_persistent()) {
|
||||
$this->cachesfromparams[$key] = $cache;
|
||||
}
|
||||
$this->cachesfromparams[$key] = $cache;
|
||||
return $cache;
|
||||
}
|
||||
|
||||
@@ -227,14 +235,14 @@ class cache_factory {
|
||||
*/
|
||||
public function create_cache(cache_definition $definition) {
|
||||
$class = $definition->get_cache_class();
|
||||
if ($this->is_initialising()) {
|
||||
// Do nothing we just want the dummy store.
|
||||
$stores = array();
|
||||
} else {
|
||||
$stores = cache_helper::get_cache_stores($definition);
|
||||
$stores = cache_helper::get_stores_suitable_for_definition($definition);
|
||||
foreach ($stores as $key => $store) {
|
||||
if (!$store::are_requirements_met()) {
|
||||
unset($stores[$key]);
|
||||
}
|
||||
}
|
||||
if (count($stores) === 0) {
|
||||
// Hmm no stores, better provide a dummy store to mimick functionality. The dev will be none the wiser.
|
||||
// Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
|
||||
$stores[] = $this->create_dummy_store($definition);
|
||||
}
|
||||
$loader = null;
|
||||
@@ -250,7 +258,7 @@ class cache_factory {
|
||||
/**
|
||||
* Creates a store instance given its name and configuration.
|
||||
*
|
||||
* If the store has already been instantiated then the original objetc will be returned. (reused)
|
||||
* If the store has already been instantiated then the original object will be returned. (reused)
|
||||
*
|
||||
* @param string $name The name of the store (must be unique remember)
|
||||
* @param array $details
|
||||
@@ -264,8 +272,9 @@ class cache_factory {
|
||||
$store = new $class($details['name'], $details['configuration']);
|
||||
$this->stores[$name] = $store;
|
||||
}
|
||||
/* @var cache_store $store */
|
||||
$store = $this->stores[$name];
|
||||
if (!$store->is_ready() || !$store->is_supported_mode($definition->get_mode())) {
|
||||
if (!$store::are_requirements_met() || !$store->is_ready() || !$store->is_supported_mode($definition->get_mode())) {
|
||||
return false;
|
||||
}
|
||||
// We always create a clone of the original store.
|
||||
@@ -297,6 +306,15 @@ class cache_factory {
|
||||
return $this->definitionstores[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache instances that have been used within this request.
|
||||
* @since 2.4.7
|
||||
* @return array
|
||||
*/
|
||||
public function get_caches_in_use() {
|
||||
return $this->cachesfromdefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache config instance with the ability to write if required.
|
||||
*
|
||||
@@ -585,7 +603,9 @@ class cache_factory {
|
||||
* </code>
|
||||
*/
|
||||
public static function disable_stores() {
|
||||
// First reset to clear any static acceleration array.
|
||||
$factory = self::instance();
|
||||
$factory->reset_cache_instances();
|
||||
$factory->set_state(self::STATE_STORES_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+97
-28
@@ -143,7 +143,7 @@ class cache_helper {
|
||||
*
|
||||
* @param array $stores
|
||||
* @param cache_definition $definition
|
||||
* @return array
|
||||
* @return cache_store[]
|
||||
*/
|
||||
protected static function initialise_cachestore_instances(array $stores, cache_definition $definition) {
|
||||
$return = array();
|
||||
@@ -238,19 +238,24 @@ class cache_helper {
|
||||
$instance = cache_config::instance();
|
||||
$invalidationeventset = false;
|
||||
$factory = cache_factory::instance();
|
||||
$inuse = $factory->get_caches_in_use();
|
||||
foreach ($instance->get_definitions() as $name => $definitionarr) {
|
||||
$definition = cache_definition::load($name, $definitionarr);
|
||||
if ($definition->invalidates_on_event($event)) {
|
||||
// OK at this point we know that the definition has information to invalidate on the event.
|
||||
// There are two routes, either its an application cache in which case we can invalidate it now.
|
||||
// or it is a persistent cache that also needs to be invalidated now.
|
||||
if ($definition->get_mode() === cache_store::MODE_APPLICATION || $definition->should_be_persistent()) {
|
||||
$cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
|
||||
$cache->delete_many($keys);
|
||||
// First up check if there is a cache loader for this definition already.
|
||||
// If there is we need to invalidate the keys from there.
|
||||
$definitionkey = $definition->get_component().'/'.$definition->get_area();
|
||||
if (isset($inuse[$definitionkey])) {
|
||||
$inuse[$definitionkey]->delete_many($keys);
|
||||
}
|
||||
|
||||
// We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
|
||||
if ($invalidationeventset === false) {
|
||||
// We should only log events for application and session caches.
|
||||
// Request caches shouldn't have events as all data is lost at the end of the request.
|
||||
// Events should only be logged once of course and likely several definitions are watching so we
|
||||
// track its logging with $invalidationeventset.
|
||||
$logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
|
||||
|
||||
if ($logevent) {
|
||||
// Get the event invalidation cache.
|
||||
$cache = cache::make('core', 'eventinvalidation');
|
||||
// Get any existing invalidated keys for this cache.
|
||||
@@ -307,23 +312,25 @@ class cache_helper {
|
||||
$instance = cache_config::instance();
|
||||
$invalidationeventset = false;
|
||||
$factory = cache_factory::instance();
|
||||
$inuse = $factory->get_caches_in_use();
|
||||
foreach ($instance->get_definitions() as $name => $definitionarr) {
|
||||
$definition = cache_definition::load($name, $definitionarr);
|
||||
if ($definition->invalidates_on_event($event)) {
|
||||
// Check if this definition would result in a persistent loader being in use.
|
||||
if ($definition->should_be_persistent()) {
|
||||
// There may be a persistent cache loader. Lets purge that first so that any persistent data is removed.
|
||||
$cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
|
||||
$cache->purge();
|
||||
}
|
||||
// Get all of the store instances that are in use for this store.
|
||||
$stores = $factory->get_store_instances_in_use($definition);
|
||||
foreach ($stores as $store) {
|
||||
// Purge each store individually.
|
||||
$store->purge();
|
||||
// First up check if there is a cache loader for this definition already.
|
||||
// If there is we need to invalidate the keys from there.
|
||||
$definitionkey = $definition->get_component().'/'.$definition->get_area();
|
||||
if (isset($inuse[$definitionkey])) {
|
||||
$inuse[$definitionkey]->purge();
|
||||
}
|
||||
|
||||
// We should only log events for application and session caches.
|
||||
// Request caches shouldn't have events as all data is lost at the end of the request.
|
||||
// Events should only be logged once of course and likely several definitions are watching so we
|
||||
// track its logging with $invalidationeventset.
|
||||
$logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
|
||||
|
||||
// We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
|
||||
if ($invalidationeventset === false) {
|
||||
if ($logevent && $invalidationeventset === false) {
|
||||
// Get the event invalidation cache.
|
||||
$cache = cache::make('core', 'eventinvalidation');
|
||||
// Create a key to invalidate all.
|
||||
@@ -370,34 +377,40 @@ class cache_helper {
|
||||
/**
|
||||
* Record a cache hit in the stats for the given store and definition.
|
||||
*
|
||||
* @internal
|
||||
* @param string $store
|
||||
* @param string $definition
|
||||
* @param int $hits The number of hits to record (by default 1)
|
||||
*/
|
||||
public static function record_cache_hit($store, $definition) {
|
||||
public static function record_cache_hit($store, $definition, $hits = 1) {
|
||||
self::ensure_ready_for_stats($store, $definition);
|
||||
self::$stats[$definition][$store]['hits']++;
|
||||
self::$stats[$definition][$store]['hits'] += $hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a cache miss in the stats for the given store and definition.
|
||||
*
|
||||
* @internal
|
||||
* @param string $store
|
||||
* @param string $definition
|
||||
* @param int $misses The number of misses to record (by default 1)
|
||||
*/
|
||||
public static function record_cache_miss($store, $definition) {
|
||||
public static function record_cache_miss($store, $definition, $misses = 1) {
|
||||
self::ensure_ready_for_stats($store, $definition);
|
||||
self::$stats[$definition][$store]['misses']++;
|
||||
self::$stats[$definition][$store]['misses'] += $misses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a cache set in the stats for the given store and definition.
|
||||
*
|
||||
* @internal
|
||||
* @param string $store
|
||||
* @param string $definition
|
||||
* @param int $sets The number of sets to record (by default 1)
|
||||
*/
|
||||
public static function record_cache_set($store, $definition) {
|
||||
public static function record_cache_set($store, $definition, $sets = 1) {
|
||||
self::ensure_ready_for_stats($store, $definition);
|
||||
self::$stats[$definition][$store]['sets']++;
|
||||
self::$stats[$definition][$store]['sets'] += $sets;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,8 +455,9 @@ class cache_helper {
|
||||
$class = $store['class'];
|
||||
|
||||
// Found the store: is it ready?
|
||||
/* @var cache_store $instance */
|
||||
$instance = new $class($store['name'], $store['configuration']);
|
||||
if (!$instance->is_ready()) {
|
||||
if (!$instance::are_requirements_met() || !$instance->is_ready()) {
|
||||
unset($instance);
|
||||
return false;
|
||||
}
|
||||
@@ -631,4 +645,59 @@ class cache_helper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of stores that would meet the requirements for every definition.
|
||||
*
|
||||
* These stores would be 100% suitable to map as defaults for cache modes.
|
||||
*
|
||||
* @return array[] An array of stores, keys are the store names.
|
||||
*/
|
||||
public static function get_stores_suitable_for_mode_default() {
|
||||
$factory = cache_factory::instance();
|
||||
$config = $factory->create_config_instance();
|
||||
$requirements = 0;
|
||||
foreach ($config->get_definitions() as $definition) {
|
||||
$definition = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
|
||||
$requirements = $requirements | $definition->get_requirements_bin();
|
||||
}
|
||||
$stores = array();
|
||||
foreach ($config->get_all_stores() as $name => $store) {
|
||||
if (!empty($store['features']) && ($store['features'] & $requirements)) {
|
||||
$stores[$name] = $store;
|
||||
}
|
||||
}
|
||||
return $stores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stores suitable for use with a given definition.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return cache_store[]
|
||||
*/
|
||||
public static function get_stores_suitable_for_definition(cache_definition $definition) {
|
||||
$factory = cache_factory::instance();
|
||||
$stores = array();
|
||||
if ($factory->is_initialising() || $factory->stores_disabled()) {
|
||||
// No suitable stores here.
|
||||
return $stores;
|
||||
} else {
|
||||
$stores = self::get_cache_stores($definition);
|
||||
if (count($stores) === 0) {
|
||||
// No suitable stores we found for the definition. We need to come up with a sensible default.
|
||||
// If this has happened we can be sure that the user has mapped custom stores to either the
|
||||
// mode of the definition. The first alternative to try is the system default for the mode.
|
||||
// e.g. the default file store instance for application definitions.
|
||||
$config = $factory->create_config_instance();
|
||||
foreach ($config->get_stores($definition->get_mode()) as $name => $details) {
|
||||
if (!empty($details['default'])) {
|
||||
$stores[] = $factory->create_store_from_config($name, $details, $definition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $stores;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+118
-75
@@ -93,43 +93,46 @@ class cache implements cache_loader {
|
||||
private $supportsnativettl = null;
|
||||
|
||||
/**
|
||||
* Gets set to true if the cache is going to be using the build in static "persist" cache.
|
||||
* The persist cache statically caches items used during the lifetime of the request. This greatly speeds up interaction
|
||||
* Gets set to true if the cache is going to be using a static array for acceleration.
|
||||
* The array statically caches items used during the lifetime of the request. This greatly speeds up interaction
|
||||
* with the cache in areas where it will be repetitively hit for the same information such as with strings.
|
||||
* There are several other variables to control how this persist cache works.
|
||||
* There are several other variables to control how this static acceleration array works.
|
||||
* @var bool
|
||||
*/
|
||||
private $persist = false;
|
||||
private $staticacceleration = false;
|
||||
|
||||
/**
|
||||
* The persist cache itself.
|
||||
* The static acceleration array.
|
||||
* Items will be stored in this cache as they were provided. This ensure there is no unnecessary processing taking place.
|
||||
* @var array
|
||||
*/
|
||||
private $persistcache = array();
|
||||
private $staticaccelerationarray = array();
|
||||
|
||||
/**
|
||||
* The number of items in the persist cache. Avoids count calls like you wouldn't believe.
|
||||
* The number of items in the static acceleration array. Avoids count calls like you wouldn't believe.
|
||||
* @var int
|
||||
*/
|
||||
private $persistcount = 0;
|
||||
private $staticaccelerationcount = 0;
|
||||
|
||||
/**
|
||||
* An array containing just the keys being used in the persist cache.
|
||||
* This seems redundant perhaps but is used when managing the size of the persist cache.
|
||||
* An array containing just the keys being used in the static acceleration array.
|
||||
* This seems redundant perhaps but is used when managing the size of the static acceleration array.
|
||||
* Items are added to the end of the array and the when we need to reduce the size of the cache we use the
|
||||
* key that is first on this array.
|
||||
* @var array
|
||||
*/
|
||||
private $persistkeys = array();
|
||||
private $staticaccelerationkeys = array();
|
||||
|
||||
/**
|
||||
* The maximum size of the persist cache. If set to false there is no max size.
|
||||
* Caches that make use of the persist cache should seriously consider setting this to something reasonably small, but
|
||||
* The maximum size of the static acceleration array.
|
||||
*
|
||||
* If set to false there is no max size.
|
||||
* Caches that make use of static acceleration should seriously consider setting this to something reasonably small, but
|
||||
* still large enough to offset repetitive calls.
|
||||
*
|
||||
* @var int|false
|
||||
*/
|
||||
private $persistmaxsize = false;
|
||||
private $staticaccelerationsize = false;
|
||||
|
||||
/**
|
||||
* Gets set to true during initialisation if the definition is making use of a ttl.
|
||||
@@ -181,7 +184,8 @@ class cache implements cache_loader {
|
||||
* @param array $options An array of options, available options are:
|
||||
* - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
|
||||
* - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
|
||||
* - persistent : If set to true the cache will persist construction requests.
|
||||
* - staticacceleration : If set to true the cache will hold onto data passing through it.
|
||||
* - staticaccelerationsize : The max size for the static acceleration array.
|
||||
* @return cache_application|cache_session|cache_store
|
||||
*/
|
||||
public static function make_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
|
||||
@@ -218,9 +222,9 @@ class cache implements cache_loader {
|
||||
$this->datasource = $loader;
|
||||
}
|
||||
$this->definition->generate_definition_hash();
|
||||
$this->persist = $this->definition->should_be_persistent();
|
||||
if ($this->persist) {
|
||||
$this->persistmaxsize = $this->definition->get_persistent_max_size();
|
||||
$this->staticacceleration = $this->definition->use_static_acceleration();
|
||||
if ($this->staticacceleration) {
|
||||
$this->staticaccelerationsize = $this->definition->get_static_acceleration_size();
|
||||
}
|
||||
$this->hasattl = ($this->definition->get_ttl() > 0);
|
||||
}
|
||||
@@ -228,7 +232,7 @@ class cache implements cache_loader {
|
||||
/**
|
||||
* Used to inform the loader of its state as a sub loader, or as the top of the chain.
|
||||
*
|
||||
* This is important as it ensures that we do not have more than one loader keeping persistent data.
|
||||
* This is important as it ensures that we do not have more than one loader keeping static acceleration data.
|
||||
* Subloaders need to be "pure" loaders in the sense that they are used to store and retrieve information from stores or the
|
||||
* next loader/data source in the chain.
|
||||
* Nothing fancy, nothing flash.
|
||||
@@ -238,14 +242,14 @@ class cache implements cache_loader {
|
||||
protected function set_is_sub_loader($setting = true) {
|
||||
if ($setting) {
|
||||
$this->subloader = true;
|
||||
// Subloaders should not keep persistent data.
|
||||
$this->persist = false;
|
||||
$this->persistmaxsize = false;
|
||||
// Subloaders should not keep static acceleration data.
|
||||
$this->staticacceleration = false;
|
||||
$this->staticaccelerationsize = false;
|
||||
} else {
|
||||
$this->subloader = true;
|
||||
$this->persist = $this->definition->should_be_persistent();
|
||||
if ($this->persist) {
|
||||
$this->persistmaxsize = $this->definition->get_persistent_max_size();
|
||||
$this->staticacceleration = $this->definition->use_static_acceleration();
|
||||
if ($this->staticacceleration) {
|
||||
$this->staticaccelerationsize = $this->definition->get_static_acceleration_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,7 +280,7 @@ class cache implements cache_loader {
|
||||
public function get($key, $strictness = IGNORE_MISSING) {
|
||||
// 1. Parse the key.
|
||||
$parsedkey = $this->parse_key($key);
|
||||
// 2. Get it from the persist cache if we can (only when persist is enabled and it has already been requested/set).
|
||||
// 2. Get it from the static acceleration array if we can (only when it is enabled and it has already been requested/set).
|
||||
$result = false;
|
||||
if ($this->is_using_persist_cache()) {
|
||||
$result = $this->get_from_persist_cache($parsedkey);
|
||||
@@ -291,7 +295,7 @@ class cache implements cache_loader {
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
// 3. Get it from the store. Obviously wasn't in the persist cache.
|
||||
// 3. Get it from the store. Obviously wasn't in the static acceleration array.
|
||||
$result = $this->store->get($parsedkey);
|
||||
if ($result !== false) {
|
||||
if ($result instanceof cache_ttl_wrapper) {
|
||||
@@ -404,6 +408,9 @@ class cache implements cache_loader {
|
||||
if ($value instanceof cache_cached_object) {
|
||||
$value = $value->restore_object();
|
||||
}
|
||||
if ($value !== false && $this->is_using_persist_cache()) {
|
||||
$this->set_in_persist_cache($key, $value);
|
||||
}
|
||||
$resultstore[$key] = $value;
|
||||
}
|
||||
}
|
||||
@@ -456,6 +463,20 @@ class cache implements cache_loader {
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->perfdebug) {
|
||||
$hits = 0;
|
||||
$misses = 0;
|
||||
foreach ($fullresult as $value) {
|
||||
if ($value === false) {
|
||||
$misses++;
|
||||
} else {
|
||||
$hits++;
|
||||
}
|
||||
}
|
||||
cache_helper::record_cache_hit($this->storetype, $this->definition->get_id(), $hits);
|
||||
cache_helper::record_cache_miss($this->storetype, $this->definition->get_id(), $misses);
|
||||
}
|
||||
|
||||
// Return the result. Phew!
|
||||
return $fullresult;
|
||||
}
|
||||
@@ -604,7 +625,7 @@ class cache implements cache_loader {
|
||||
}
|
||||
$data = array();
|
||||
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
|
||||
$usepersistcache = $this->is_using_persist_cache();
|
||||
$usestaticaccelerationarray = $this->is_using_persist_cache();
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (is_object($value) && $value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
@@ -622,14 +643,15 @@ class cache implements cache_loader {
|
||||
'key' => $this->parse_key($key),
|
||||
'value' => $value
|
||||
);
|
||||
if ($usepersistcache) {
|
||||
if ($usestaticaccelerationarray) {
|
||||
$this->set_in_persist_cache($data[$key]['key'], $value);
|
||||
}
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->storetype, $this->definition->get_id());
|
||||
$successfullyset = $this->store->set_many($data);
|
||||
if ($this->perfdebug && $successfullyset) {
|
||||
cache_helper::record_cache_set($this->storetype, $this->definition->get_id(), $successfullyset);
|
||||
}
|
||||
return $this->store->set_many($data);
|
||||
return $successfullyset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -656,7 +678,7 @@ class cache implements cache_loader {
|
||||
public function has($key, $tryloadifpossible = false) {
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($this->is_in_persist_cache($parsedkey)) {
|
||||
// Hoorah, that was easy. It exists in the persist cache so we definitely have it.
|
||||
// Hoorah, that was easy. It exists in the static acceleration array so we definitely have it.
|
||||
return true;
|
||||
}
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
@@ -798,8 +820,12 @@ class cache implements cache_loader {
|
||||
* @return bool True on success, false otherwise
|
||||
*/
|
||||
public function purge() {
|
||||
// 1. Purge the persist cache.
|
||||
$this->persistcache = array();
|
||||
// 1. Purge the static acceleration array.
|
||||
$this->staticaccelerationarray = array();
|
||||
if ($this->staticaccelerationsize !== false) {
|
||||
$this->staticaccelerationkeys = array();
|
||||
$this->staticaccelerationcount = 0;
|
||||
}
|
||||
// 2. Purge the store.
|
||||
$this->store->purge();
|
||||
// 3. Optionally pruge any stacked loaders.
|
||||
@@ -908,16 +934,16 @@ class cache implements cache_loader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this cache is making use of the persist cache.
|
||||
* Returns true if this cache is making use of the static acceleration array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_using_persist_cache() {
|
||||
return $this->persist;
|
||||
return $this->staticacceleration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the requested key exists within the persist cache.
|
||||
* Returns true if the requested key exists within the static acceleration array.
|
||||
*
|
||||
* @param string $key The parsed key
|
||||
* @return bool
|
||||
@@ -929,20 +955,21 @@ class cache implements cache_loader {
|
||||
}
|
||||
// This could be written as a single line, however it has been split because the ttl check is faster than the instanceof
|
||||
// and has_expired calls.
|
||||
if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
|
||||
if (!$this->staticacceleration || !array_key_exists($key, $this->staticaccelerationarray)) {
|
||||
return false;
|
||||
}
|
||||
if ($this->has_a_ttl() && $this->store_supports_native_ttl()) {
|
||||
return !($this->persistcache[$key] instanceof cache_ttl_wrapper && $this->persistcache[$key]->has_expired());
|
||||
return !($this->staticaccelerationarray[$key] instanceof cache_ttl_wrapper &&
|
||||
$this->staticaccelerationarray[$key]->has_expired());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item from the persist cache if it exists there.
|
||||
* Returns the item from the static acceleration array if it exists there.
|
||||
*
|
||||
* @param string $key The parsed key
|
||||
* @return mixed|false The data from the persist cache or false if it wasn't there.
|
||||
* @return mixed|false The data from the static acceleration array or false if it wasn't there.
|
||||
*/
|
||||
protected function get_from_persist_cache($key) {
|
||||
// This method of checking if an array was supplied is faster than is_array.
|
||||
@@ -951,12 +978,12 @@ class cache implements cache_loader {
|
||||
}
|
||||
// This isset check is faster than array_key_exists but will return false
|
||||
// for null values, meaning null values will come from backing store not
|
||||
// the persist cache. We think this okay because null usage should be
|
||||
// the static acceleration array. We think this okay because null usage should be
|
||||
// very rare (see comment in MDL-39472).
|
||||
if (!$this->persist || !isset($this->persistcache[$key])) {
|
||||
if (!$this->staticacceleration || !isset($this->staticaccelerationarray[$key])) {
|
||||
$result = false;
|
||||
} else {
|
||||
$data = $this->persistcache[$key];
|
||||
$data = $this->staticaccelerationarray[$key];
|
||||
if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
|
||||
if ($data instanceof cache_cached_object) {
|
||||
$data = $data->restore_object();
|
||||
@@ -974,28 +1001,28 @@ class cache implements cache_loader {
|
||||
}
|
||||
if ($result) {
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
|
||||
cache_helper::record_cache_hit('** static acceleration **', $this->definition->get_id());
|
||||
}
|
||||
if ($this->persistmaxsize > 1 && $this->persistcount > 1) {
|
||||
// Check to see if this is the last item on the persist keys array.
|
||||
if (end($this->persistkeys) !== $key) {
|
||||
if ($this->staticaccelerationsize > 1 && $this->staticaccelerationcount > 1) {
|
||||
// Check to see if this is the last item on the static acceleration keys array.
|
||||
if (end($this->staticaccelerationkeys) !== $key) {
|
||||
// It isn't the last item.
|
||||
// Move the item to the end of the array so that it is last to be removed.
|
||||
unset($this->persistkeys[$key]);
|
||||
$this->persistkeys[$key] = $key;
|
||||
unset($this->staticaccelerationkeys[$key]);
|
||||
$this->staticaccelerationkeys[$key] = $key;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
} else {
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
|
||||
cache_helper::record_cache_miss('** static acceleration **', $this->definition->get_id());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a key value pair into the persist cache.
|
||||
* Sets a key value pair into the static acceleration array.
|
||||
*
|
||||
* @param string $key The parsed key
|
||||
* @param mixed $data
|
||||
@@ -1006,32 +1033,36 @@ class cache implements cache_loader {
|
||||
if ($key === (array)$key) {
|
||||
$key = $key['key'];
|
||||
}
|
||||
$this->persistcache[$key] = $data;
|
||||
if ($this->persistmaxsize !== false) {
|
||||
$this->persistcount++;
|
||||
$this->persistkeys[$key] = $key;
|
||||
if ($this->persistcount > $this->persistmaxsize) {
|
||||
$dropkey = array_shift($this->persistkeys);
|
||||
unset($this->persistcache[$dropkey]);
|
||||
$this->persistcount--;
|
||||
if ($this->staticaccelerationsize !== false && isset($this->staticaccelerationkeys[$key])) {
|
||||
$this->staticaccelerationcount--;
|
||||
unset($this->staticaccelerationkeys[$key]);
|
||||
}
|
||||
$this->staticaccelerationarray[$key] = $data;
|
||||
if ($this->staticaccelerationsize !== false) {
|
||||
$this->staticaccelerationcount++;
|
||||
$this->staticaccelerationkeys[$key] = $key;
|
||||
if ($this->staticaccelerationcount > $this->staticaccelerationsize) {
|
||||
$dropkey = array_shift($this->staticaccelerationkeys);
|
||||
unset($this->staticaccelerationarray[$dropkey]);
|
||||
$this->staticaccelerationcount--;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an item from the persist cache.
|
||||
* Deletes an item from the static acceleration array.
|
||||
*
|
||||
* @param string|int $key As given to get|set|delete
|
||||
* @return bool True on success, false otherwise.
|
||||
*/
|
||||
protected function delete_from_persist_cache($key) {
|
||||
unset($this->persistcache[$key]);
|
||||
if ($this->persistmaxsize !== false) {
|
||||
$dropkey = array_search($key, $this->persistkeys);
|
||||
unset($this->staticaccelerationarray[$key]);
|
||||
if ($this->staticaccelerationsize !== false) {
|
||||
$dropkey = array_search($key, $this->staticaccelerationkeys);
|
||||
if ($dropkey) {
|
||||
unset($this->persistkeys[$dropkey]);
|
||||
$this->persistcount--;
|
||||
unset($this->staticaccelerationkeys[$dropkey]);
|
||||
$this->staticaccelerationcount--;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1448,9 +1479,8 @@ class cache_application extends cache implements cache_loader_with_locking {
|
||||
* This class is used for session caches returned by the cache::make methods.
|
||||
*
|
||||
* It differs from the application loader in a couple of noteable ways:
|
||||
* 1. Sessions are always expected to be persistent.
|
||||
* Because of this we don't ever use the persist cache and instead a session array
|
||||
* containing all of the data is maintained by this object.
|
||||
* 1. Sessions are always expected to exist.
|
||||
* Because of this we don't ever use the static acceleration array.
|
||||
* 2. Session data for a loader instance (store + definition) is consolidate into a
|
||||
* single array for storage within the store.
|
||||
* Along with this we embed a lastaccessed time with the data. This way we can
|
||||
@@ -1857,7 +1887,19 @@ class cache_session extends cache {
|
||||
if ($hasmissingkeys && $strictness === MUST_EXIST) {
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
|
||||
if ($this->perfdebug) {
|
||||
$hits = 0;
|
||||
$misses = 0;
|
||||
foreach ($return as $value) {
|
||||
if ($value === false) {
|
||||
$misses++;
|
||||
} else {
|
||||
$hits++;
|
||||
}
|
||||
}
|
||||
cache_helper::record_cache_hit($this->storetype, $this->get_definition()->get_id(), $hits);
|
||||
cache_helper::record_cache_miss($this->storetype, $this->get_definition()->get_id(), $misses);
|
||||
}
|
||||
return $return;
|
||||
|
||||
}
|
||||
@@ -1931,10 +1973,11 @@ class cache_session extends cache {
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->storetype, $definitionid);
|
||||
$successfullyset = $this->get_store()->set_many($data);
|
||||
if ($this->perfdebug && $successfullyset) {
|
||||
cache_helper::record_cache_set($this->storetype, $definitionid, $successfullyset);
|
||||
}
|
||||
return $this->get_store()->set_many($data);
|
||||
return $successfullyset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2063,7 +2106,7 @@ class cache_session extends cache {
|
||||
}
|
||||
|
||||
/**
|
||||
* The session loader never uses the persist cache.
|
||||
* The session loader never uses static acceleration.
|
||||
* Instead it stores things in the static $session variable. Shared between all session loaders.
|
||||
*
|
||||
* @return bool
|
||||
|
||||
Vendored
+3
-3
@@ -49,8 +49,7 @@ class cache_disabled extends cache {
|
||||
* @param null $loader Unused.
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
$this->definition = $definition;
|
||||
$this->store = $store;
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +227,8 @@ class cache_factory_disabled extends cache_factory {
|
||||
* @param array $options An array of options, available options are:
|
||||
* - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
|
||||
* - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
|
||||
* - persistent : If set to true the cache will persist construction requests.
|
||||
* - staticacceleration : If set to true the cache will hold onto all data passing through it.
|
||||
* - staticaccelerationsize : Sets the max size of the static acceleration array.
|
||||
* @return cache_application|cache_session|cache_request
|
||||
*/
|
||||
public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
|
||||
|
||||
Vendored
+20
-41
@@ -672,59 +672,32 @@ abstract class cache_administration_helper extends cache_helper {
|
||||
* @return array
|
||||
*/
|
||||
public static function get_definition_summaries() {
|
||||
$instance = cache_config::instance();
|
||||
$definitions = $instance->get_definitions();
|
||||
|
||||
$factory = cache_factory::instance();
|
||||
$config = $factory->create_config_instance();
|
||||
$storenames = array();
|
||||
foreach ($instance->get_all_stores() as $key => $store) {
|
||||
foreach ($config->get_all_stores() as $key => $store) {
|
||||
if (!empty($store['default'])) {
|
||||
$storenames[$key] = new lang_string('store_'.$key, 'cache');
|
||||
}
|
||||
}
|
||||
|
||||
$modemappings = array();
|
||||
foreach ($instance->get_mode_mappings() as $mapping) {
|
||||
$mode = $mapping['mode'];
|
||||
if (!array_key_exists($mode, $modemappings)) {
|
||||
$modemappings[$mode] = array();
|
||||
}
|
||||
if (array_key_exists($mapping['store'], $storenames)) {
|
||||
$modemappings[$mode][] = $storenames[$mapping['store']];
|
||||
} else {
|
||||
$modemappings[$mode][] = $mapping['store'];
|
||||
$storenames[$store['name']] = $store['name'];
|
||||
}
|
||||
}
|
||||
|
||||
$definitionmappings = array();
|
||||
foreach ($instance->get_definition_mappings() as $mapping) {
|
||||
$definition = $mapping['definition'];
|
||||
if (!array_key_exists($definition, $definitionmappings)) {
|
||||
$definitionmappings[$definition] = array();
|
||||
}
|
||||
if (array_key_exists($mapping['store'], $storenames)) {
|
||||
$definitionmappings[$definition][] = $storenames[$mapping['store']];
|
||||
} else {
|
||||
$definitionmappings[$definition][] = $mapping['store'];
|
||||
}
|
||||
/* @var cache_definition[] $definitions */
|
||||
$definitions = array();
|
||||
foreach ($config->get_definitions() as $key => $definition) {
|
||||
$definitions[$key] = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
|
||||
}
|
||||
|
||||
$return = array();
|
||||
|
||||
foreach ($definitions as $id => $definition) {
|
||||
|
||||
$mappings = array();
|
||||
if (array_key_exists($id, $definitionmappings)) {
|
||||
$mappings = $definitionmappings[$id];
|
||||
} else if (empty($definition['mappingsonly'])) {
|
||||
$mappings = $modemappings[$definition['mode']];
|
||||
foreach (cache_helper::get_stores_suitable_for_definition($definition) as $store) {
|
||||
$mappings[] = $storenames[$store->my_name()];
|
||||
}
|
||||
|
||||
$return[$id] = array(
|
||||
'id' => $id,
|
||||
'name' => cache_helper::get_definition_name($definition),
|
||||
'mode' => $definition['mode'],
|
||||
'component' => $definition['component'],
|
||||
'area' => $definition['area'],
|
||||
'name' => $definition->get_name(),
|
||||
'mode' => $definition->get_mode(),
|
||||
'component' => $definition->get_component(),
|
||||
'area' => $definition->get_area(),
|
||||
'mappings' => $mappings
|
||||
);
|
||||
}
|
||||
@@ -976,7 +949,10 @@ abstract class cache_administration_helper extends cache_helper {
|
||||
* @return array An array containing sub-arrays, one for each mode.
|
||||
*/
|
||||
public static function get_default_mode_stores() {
|
||||
global $OUTPUT;
|
||||
$instance = cache_config::instance();
|
||||
$adequatestores = cache_helper::get_stores_suitable_for_mode_default();
|
||||
$icon = new pix_icon('i/warning', new lang_string('inadequatestoreformapping', 'cache'));
|
||||
$storenames = array();
|
||||
foreach ($instance->get_all_stores() as $key => $store) {
|
||||
if (!empty($store['default'])) {
|
||||
@@ -999,6 +975,9 @@ abstract class cache_administration_helper extends cache_helper {
|
||||
} else {
|
||||
$modemappings[$mode][$mapping['store']] = $mapping['store'];
|
||||
}
|
||||
if (!array_key_exists($mapping['store'], $adequatestores)) {
|
||||
$modemappings[$mode][$mapping['store']] = $modemappings[$mode][$mapping['store']].' '.$OUTPUT->render($icon);
|
||||
}
|
||||
}
|
||||
return $modemappings;
|
||||
}
|
||||
|
||||
Vendored
+7
-2
@@ -131,7 +131,7 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
|
||||
|
||||
$this->connection = new Memcache;
|
||||
foreach ($this->servers as $server) {
|
||||
$this->connection->addServer($server[0], $server[1], true, $server[2]);
|
||||
$this->connection->addServer($server[0], (int) $server[1], true, (int) $server[2]);
|
||||
}
|
||||
// Test the connection to the pool of servers.
|
||||
$this->isready = @$this->connection->set($this->parse_key('ping'), 'ping', MEMCACHE_COMPRESSED, 1);
|
||||
@@ -350,7 +350,12 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
|
||||
$lines = explode("\n", $data->servers);
|
||||
$servers = array();
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line, ':');
|
||||
// Trim surrounding colons and default whitespace.
|
||||
$line = trim(trim($line), ":");
|
||||
// Skip blank lines.
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$servers[] = explode(':', $line, 3);
|
||||
}
|
||||
return array(
|
||||
|
||||
Vendored
+6
-1
@@ -374,7 +374,12 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
$lines = explode("\n", $data->servers);
|
||||
$servers = array();
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line, ':');
|
||||
// Trim surrounding colons and default whitespace.
|
||||
$line = trim(trim($line), ":");
|
||||
// Skip blank lines.
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$servers[] = explode(':', $line, 3);
|
||||
}
|
||||
return array(
|
||||
|
||||
Vendored
+173
-15
@@ -149,8 +149,8 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'test_default_application_cache',
|
||||
'persistent' => true,
|
||||
'persistentmaxsize' => 1
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 1
|
||||
));
|
||||
$cache = cache::make('phpunit', 'test_default_application_cache');
|
||||
$this->assertInstanceOf('cache_application', $cache);
|
||||
@@ -189,7 +189,7 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'nostoretest2',
|
||||
'persistent' => true
|
||||
'staticacceleration' => true
|
||||
));
|
||||
$instance->phpunit_remove_stores();
|
||||
|
||||
@@ -907,11 +907,11 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
'crazyevent'
|
||||
)
|
||||
));
|
||||
$instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
|
||||
$instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'eventpurgetestpersistent',
|
||||
'persistent' => true,
|
||||
'area' => 'eventpurgetestaccelerated',
|
||||
'staticacceleration' => true,
|
||||
'invalidationevents' => array(
|
||||
'crazyevent'
|
||||
)
|
||||
@@ -930,8 +930,8 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
$this->assertFalse($cache->get('testkey1'));
|
||||
$this->assertFalse($cache->get('testkey2'));
|
||||
|
||||
// Now test the persistent cache.
|
||||
$cache = cache::make('phpunit', 'eventpurgetestpersistent');
|
||||
// Now test the static acceleration array.
|
||||
$cache = cache::make('phpunit', 'eventpurgetestaccelerated');
|
||||
$this->assertTrue($cache->set('testkey1', 'test data 1'));
|
||||
$this->assertEquals('test data 1', $cache->get('testkey1'));
|
||||
$this->assertTrue($cache->set('testkey2', 'test data 2'));
|
||||
@@ -958,11 +958,11 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
'crazyevent'
|
||||
)
|
||||
));
|
||||
$instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
|
||||
$instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
|
||||
'mode' => cache_store::MODE_SESSION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'eventpurgetestpersistent',
|
||||
'persistent' => true,
|
||||
'area' => 'eventpurgetestaccelerated',
|
||||
'staticacceleration' => true,
|
||||
'invalidationevents' => array(
|
||||
'crazyevent'
|
||||
)
|
||||
@@ -981,8 +981,8 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
$this->assertFalse($cache->get('testkey1'));
|
||||
$this->assertFalse($cache->get('testkey2'));
|
||||
|
||||
// Now test the persistent cache.
|
||||
$cache = cache::make('phpunit', 'eventpurgetestpersistent');
|
||||
// Now test the static acceleration array.
|
||||
$cache = cache::make('phpunit', 'eventpurgetestaccelerated');
|
||||
$this->assertTrue($cache->set('testkey1', 'test data 1'));
|
||||
$this->assertEquals('test data 1', $cache->get('testkey1'));
|
||||
$this->assertTrue($cache->set('testkey2', 'test data 2'));
|
||||
@@ -1383,8 +1383,8 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'test_application_locking',
|
||||
'persistent' => true,
|
||||
'persistentmaxsize' => 1,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 1,
|
||||
'requirelockingread' => true,
|
||||
'requirelockingwrite' => true
|
||||
));
|
||||
@@ -1449,4 +1449,162 @@ class cache_phpunit_tests extends advanced_testcase {
|
||||
$this->assertInstanceOf('cache_request', $cache);
|
||||
$this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
|
||||
}
|
||||
|
||||
public function test_static_acceleration() {
|
||||
$instance = cache_config_phpunittest::instance();
|
||||
$instance->phpunit_add_definition('phpunit/accelerated', array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'accelerated',
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 3,
|
||||
));
|
||||
$instance->phpunit_add_definition('phpunit/accelerated2', array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'accelerated2',
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 3,
|
||||
));
|
||||
$instance->phpunit_add_definition('phpunit/accelerated3', array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'accelerated3',
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 3,
|
||||
));
|
||||
$instance->phpunit_add_definition('phpunit/accelerated4', array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'accelerated4',
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 4,
|
||||
));
|
||||
$cache = cache::make('phpunit', 'accelerated');
|
||||
$this->assertInstanceOf('cache_phpunit_application', $cache);
|
||||
|
||||
// Set and get three elements.
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('b', 'B'));
|
||||
$this->assertTrue($cache->set('c', 'C'));
|
||||
$this->assertEquals('A', $cache->get('a'));
|
||||
$this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
|
||||
|
||||
// Make sure all items are in static acceleration array.
|
||||
$this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('B', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
|
||||
// Add new value and make sure it is in cache and it is in array.
|
||||
$this->assertTrue($cache->set('d', 'D'));
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('D', $cache->get('d'));
|
||||
|
||||
// Now the least recent accessed item (a) is no longer in acceleration array.
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('B', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
|
||||
// Adding and deleting element.
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->delete('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->has('a'));
|
||||
|
||||
// Make sure "purge" deletes from the array as well.
|
||||
$cache->purge();
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
|
||||
// Check that the array holds the last accessed items by get/set.
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('b', 'B'));
|
||||
$this->assertTrue($cache->set('c', 'C'));
|
||||
$this->assertTrue($cache->set('d', 'D'));
|
||||
$this->assertTrue($cache->set('e', 'E'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
|
||||
/** @var cache_phpunit_application $cache */
|
||||
$cache = cache::make('phpunit', 'accelerated2');
|
||||
$this->assertInstanceOf('cache_phpunit_application', $cache);
|
||||
|
||||
// Check that the array holds the last accessed items by get/set.
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('b', 'B'));
|
||||
$this->assertTrue($cache->set('c', 'C'));
|
||||
$this->assertTrue($cache->set('d', 'D'));
|
||||
$this->assertTrue($cache->set('e', 'E'));
|
||||
// Current keys in the array: c, d, e.
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
|
||||
$this->assertEquals('A', $cache->get('a'));
|
||||
// Current keys in the array: d, e, a.
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
$this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
|
||||
// Current keys in the array: d, e, a.
|
||||
$this->assertEquals(array('c' => 'C'), $cache->get_many(array('c')));
|
||||
// Current keys in the array: e, a, c.
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
$this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
|
||||
|
||||
$cache = cache::make('phpunit', 'accelerated3');
|
||||
$this->assertInstanceOf('cache_phpunit_application', $cache);
|
||||
|
||||
// Check that the array holds the last accessed items by get/set.
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('b', 'B'));
|
||||
$this->assertTrue($cache->set('c', 'C'));
|
||||
$this->assertTrue($cache->set('d', 'D'));
|
||||
$this->assertTrue($cache->set('e', 'E'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
|
||||
$this->assertTrue($cache->set('b', 'B2'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('B2', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
|
||||
$this->assertEquals(2, $cache->set_many(array('b' => 'B3', 'c' => 'C3')));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('B3', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
|
||||
$this->assertEquals('C3', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
|
||||
$this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
|
||||
$this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
|
||||
|
||||
$cache = cache::make('phpunit', 'accelerated4');
|
||||
$this->assertInstanceOf('cache_phpunit_application', $cache);
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertTrue($cache->set('a', 'A'));
|
||||
$this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
|
||||
$this->assertEquals('A', $cache->get('a'));
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+11
@@ -243,6 +243,17 @@ class cache_phpunit_application extends cache_application {
|
||||
public function phpunit_get_store_implements() {
|
||||
return class_implements($this->get_store());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given key directly from the static acceleration array.
|
||||
*
|
||||
* @param string $key
|
||||
* @return false|mixed
|
||||
*/
|
||||
public function phpunit_get_directly_from_staticaccelerationarray($key) {
|
||||
$key = $this->parse_key($key);
|
||||
return $this->get_from_persist_cache($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+10
-2
@@ -1,8 +1,16 @@
|
||||
This files describes API changes in /cache/stores/* - cache store plugins.
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
=== 2.5 ===
|
||||
=== 2.4.7 ===
|
||||
* All cache instances are recorded and subsequent requests are given a reference to the original instance.
|
||||
* The persistent option for the cache definition has been deprecated. Please use the staticacceleration option instead.
|
||||
* There is a new static acceleration option. If enabled data passing through the cache is held onto.
|
||||
* The persistentmaxsize option has been renamed to staticaccelerationsize. It does the same thing.
|
||||
* cache_definition::should_be_persistent has been deprecated. Please call cache_definition::use_static_acceleration instead.
|
||||
* cache_definition::get_persistent_max_size has been deprecated. Please call cache_definition::get_static_acceleration_size instead.
|
||||
|
||||
=== 2.4.2 ===
|
||||
* cleanup method renamed to instance_deleted.
|
||||
It is now called when the store is deleted as all comments suggested anyway.
|
||||
* instance_created method added.
|
||||
It is called when the store is created for the very first time.
|
||||
It is called when the store is created for the very first time.
|
||||
|
||||
+2
-2
@@ -106,8 +106,8 @@ $PAGE->navbar->add($pagetitle);
|
||||
|
||||
$PAGE->set_title($course->shortname.': '.get_string('calendar', 'calendar').': '.$pagetitle);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_button(calendar_preferences_button($course));
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_button(calendar_preferences_button($course));
|
||||
|
||||
$renderer = $PAGE->get_renderer('core_calendar');
|
||||
$calendar->add_sidecalendar_blocks($renderer);
|
||||
@@ -125,7 +125,7 @@ switch($action) {
|
||||
$weekend = intval($CFG->calendar_weekend);
|
||||
}
|
||||
|
||||
$authtoken = sha1($USER->id . $USER->password . $CFG->calendar_exportsalt);
|
||||
$authtoken = sha1($USER->id . $DB->get_field('user', 'password', array('id'=>$USER->id)). $CFG->calendar_exportsalt);
|
||||
// Let's populate some vars to let "common tasks" be somewhat smart...
|
||||
// If today it's weekend, give the "next week" option
|
||||
$allownextweek = $weekend & (1 << $now['wday']);
|
||||
|
||||
+2
-2
@@ -366,7 +366,7 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
|
||||
} else if(isset($typesbyday[$day]['startuser'])) {
|
||||
$class .= ' calendar_event_user';
|
||||
}
|
||||
$cell = html_writer::link($dayhref, $day, array('aria-controls' => $popupid.'_panel', 'id' => $popupid));
|
||||
$cell = html_writer::link($dayhref, $day, array('id' => $popupid));
|
||||
} else {
|
||||
$cell = $day;
|
||||
}
|
||||
@@ -409,7 +409,7 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
|
||||
if(! isset($eventsbyday[$day])) {
|
||||
$class .= ' eventnone';
|
||||
$popupid = calendar_get_popup(true, false);
|
||||
$cell = html_writer::link('#', $day, array('aria-controls' => $popupid.'_panel', 'id' => $popupid));
|
||||
$cell = html_writer::link('#', $day, array('id' => $popupid));
|
||||
}
|
||||
$cell = get_accesshide($today.' ').$cell;
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function event(calendar_event $event, $showactions=true) {
|
||||
$event = calendar_add_event_metadata($event);
|
||||
$context = $event->context;
|
||||
|
||||
$anchor = html_writer::tag('a', '', array('name'=>'event_'.$event->id));
|
||||
|
||||
@@ -302,7 +303,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
if (!empty($event->referer)) {
|
||||
$table->data[0]->cells[1]->text .= html_writer::tag('div', $event->referer, array('class'=>'referer'));
|
||||
} else {
|
||||
$table->data[0]->cells[1]->text .= html_writer::tag('div', $event->name, array('class'=>'name'));
|
||||
$table->data[0]->cells[1]->text .= html_writer::tag('div', format_string($event->name, false, array('context' => $context)), array('class'=>'name'));
|
||||
}
|
||||
if (!empty($event->courselink)) {
|
||||
$table->data[0]->cells[1]->text .= html_writer::tag('div', $event->courselink, array('class'=>'course'));
|
||||
@@ -316,7 +317,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
$table->data[1]->cells[0] = new html_table_cell(' ');
|
||||
$table->data[1]->cells[0]->attributes['class'] .= 'side';
|
||||
|
||||
$table->data[1]->cells[1] = new html_table_cell($event->description);
|
||||
$table->data[1]->cells[1] = new html_table_cell(format_text($event->description, $event->format, array('context' => $context)));
|
||||
$table->data[1]->cells[1]->attributes['class'] .= ' description';
|
||||
if (isset($event->cssclass)) {
|
||||
$table->data[1]->cells[1]->attributes['class'] .= ' '.$event->cssclass;
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ if (!empty($CFG->enablecalendarexport)) {
|
||||
echo $OUTPUT->single_button(new moodle_url('/calendar/managesubscriptions.php', array('course'=>$courseid)), get_string('managesubscriptions', 'calendar'));
|
||||
}
|
||||
if (isloggedin()) {
|
||||
$authtoken = sha1($USER->id . $USER->password . $CFG->calendar_exportsalt);
|
||||
$authtoken = sha1($USER->id . $DB->get_field('user', 'password', array('id'=>$USER->id)) . $CFG->calendar_exportsalt);
|
||||
$link = new moodle_url('/calendar/export_execute.php', array('preset_what'=>'all', 'preset_time'=>'recentupcoming', 'userid' => $USER->id, 'authtoken'=>$authtoken));
|
||||
$icon = html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('i/ical'), 'height'=>'14', 'width'=>'36', 'alt'=>get_string('ical', 'calendar'), 'title'=>get_string('quickdownloadcalendar', 'calendar')));
|
||||
echo html_writer::tag('a', $icon, array('href'=>$link));
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ YUI.add('moodle-calendar-eventmanager', function(Y) {
|
||||
width : Math.floor(constraint.get('offsetWidth')*0.9)+"px"
|
||||
});
|
||||
panel.render(td);
|
||||
node.setAttribute('aria-controls', panel.get('id'));
|
||||
panel.get('boundingBox').addClass('calendar-event-panel');
|
||||
panel.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
this.on('showevent', panel.show, panel);
|
||||
|
||||
+13
-9
@@ -328,19 +328,23 @@ class course_edit_form extends moodleform {
|
||||
|
||||
/// perform some extra moodle validation
|
||||
function validation($data, $files) {
|
||||
global $DB, $CFG;
|
||||
global $DB;
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
if ($foundcourses = $DB->get_records('course', array('shortname'=>$data['shortname']))) {
|
||||
if (!empty($data['id'])) {
|
||||
unset($foundcourses[$data['id']]);
|
||||
|
||||
// Add field validation check for duplicate shortname.
|
||||
if ($course = $DB->get_record('course', array('shortname' => $data['shortname']), '*', IGNORE_MULTIPLE)) {
|
||||
if (empty($data['id']) || $course->id != $data['id']) {
|
||||
$errors['shortname'] = get_string('shortnametaken', '', $course->fullname);
|
||||
}
|
||||
if (!empty($foundcourses)) {
|
||||
foreach ($foundcourses as $foundcourse) {
|
||||
$foundcoursenames[] = $foundcourse->fullname;
|
||||
}
|
||||
|
||||
// Add field validation check for duplicate idnumber.
|
||||
if (!empty($data['idnumber']) && (empty($data['id']) || $this->course->idnumber != $data['idnumber'])) {
|
||||
if ($course = $DB->get_record('course', array('idnumber' => $data['idnumber']), '*', IGNORE_MULTIPLE)) {
|
||||
if (empty($data['id']) || $course->id != $data['id']) {
|
||||
$errors['idnumber'] = get_string('idnumbertaken', 'error');
|
||||
}
|
||||
$foundcoursenamestring = implode(',', $foundcoursenames);
|
||||
$errors['shortname']= get_string('shortnametaken', '', $foundcoursenamestring);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@ class editsection_form extends moodleform {
|
||||
$course = $this->_customdata['course'];
|
||||
|
||||
$elementgroup = array();
|
||||
$elementgroup[] = $mform->createElement('text', 'name', '', array('size' => '30'));
|
||||
$elementgroup[] = $mform->createElement('text', 'name', '', array('size' => '30', 'maxlength' => '255'));
|
||||
$elementgroup[] = $mform->createElement('checkbox', 'usedefaultname', '', get_string('sectionusedefaultname'));
|
||||
$mform->addGroup($elementgroup, 'name_group', get_string('sectionname'), ' ', false);
|
||||
$mform->addGroupRule('name_group', array('name' => array(array(get_string('maximumchars', '', 255), 'maxlength', 255))));
|
||||
|
||||
$mform->setDefault('usedefaultname', true);
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
@@ -554,7 +554,7 @@ abstract class format_base {
|
||||
$sectionid = $section->id;
|
||||
} else if ($this->courseid && is_int($section) &&
|
||||
($sectionobj = $DB->get_record('course_sections',
|
||||
array('section' => $section, 'courseid' => $this->courseid), 'id'))) {
|
||||
array('section' => $section, 'course' => $this->courseid), 'id'))) {
|
||||
// course section format options will be returned
|
||||
$sectionid = $sectionobj->id;
|
||||
} else {
|
||||
|
||||
@@ -515,7 +515,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
$o.= html_writer::tag('div', '', array('class' => 'left side'));
|
||||
$o.= html_writer::tag('div', '', array('class' => 'right side'));
|
||||
$o.= html_writer::start_tag('div', array('class' => 'content'));
|
||||
$o.= $this->output->heading(get_string('orphanedactivities'), 3, 'sectionname');
|
||||
$o.= $this->output->heading(get_string('orphanedactivitiesinsectionno', '', $sectionno), 3, 'sectionname');
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
+39
-12
@@ -2917,14 +2917,6 @@ function set_coursemodule_visible($id, $visible) {
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
|
||||
$grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
|
||||
if ($grade_items) {
|
||||
foreach ($grade_items as $grade_item) {
|
||||
$grade_item->set_hidden(!$visible);
|
||||
}
|
||||
}
|
||||
|
||||
// Updating visible and visibleold to keep them in sync. Only changing a section visibility will
|
||||
// affect visibleold to allow for an original visibility restore. See set_section_visible().
|
||||
$cminfo = new stdClass();
|
||||
@@ -2933,6 +2925,25 @@ function set_coursemodule_visible($id, $visible) {
|
||||
$cminfo->visibleold = $visible;
|
||||
$DB->update_record('course_modules', $cminfo);
|
||||
|
||||
require_once($CFG->dirroot . '/mod/' . $modulename . '/lib.php');
|
||||
$functionname = $modulename . '_grade_item_update';
|
||||
|
||||
// Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
|
||||
// Note that this must be done after updating the row in course_modules, in case
|
||||
// the modules grade_item_update function needs to access $cm->visible.
|
||||
if (plugin_supports('mod', $modulename, FEATURE_CONTROLS_GRADE_VISIBILITY) &&
|
||||
function_exists($functionname)) {
|
||||
$instance = $DB->get_record($modulename, array('id' => $cm->instance), '*', MUST_EXIST);
|
||||
$functionname($instance);
|
||||
} else {
|
||||
$grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
|
||||
if ($grade_items) {
|
||||
foreach ($grade_items as $grade_item) {
|
||||
$grade_item->set_hidden(!$visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rebuild_course_cache($cm->course, true);
|
||||
return true;
|
||||
}
|
||||
@@ -3962,6 +3973,20 @@ function update_course($data, $editoroptions = NULL) {
|
||||
$data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course', 'summary', 0);
|
||||
}
|
||||
|
||||
// Check we don't have a duplicate shortname.
|
||||
if (!empty($data->shortname) && $oldcourse->shortname != $data->shortname) {
|
||||
if ($DB->record_exists('course', array('shortname' => $data->shortname))) {
|
||||
throw new moodle_exception('shortnametaken', '', '', $data->shortname);
|
||||
}
|
||||
}
|
||||
|
||||
// Check we don't have a duplicate idnumber.
|
||||
if (!empty($data->idnumber) && $oldcourse->idnumber != $data->idnumber) {
|
||||
if ($DB->record_exists('course', array('idnumber' => $data->idnumber))) {
|
||||
throw new moodle_exception('idnumbertaken', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($data->category) or empty($data->category)) {
|
||||
// prevent nulls and 0 in category field
|
||||
unset($data->category);
|
||||
@@ -4001,7 +4026,9 @@ function update_course($data, $editoroptions = NULL) {
|
||||
context_moved($context, $newparent);
|
||||
}
|
||||
|
||||
fix_course_sortorder();
|
||||
if ($movecat || (isset($data->sortorder) && $oldcourse->sortorder != $data->sortorder)) {
|
||||
fix_course_sortorder();
|
||||
}
|
||||
|
||||
// Test for and remove blocks which aren't appropriate anymore
|
||||
blocks_remove_inappropriate($course);
|
||||
@@ -4542,7 +4569,7 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
|
||||
);
|
||||
|
||||
// Include course dragdrop
|
||||
if ($course->id != $SITE->id) {
|
||||
if (course_format_uses_sections($course->format)) {
|
||||
$PAGE->requires->yui_module('moodle-course-dragdrop', 'M.course.init_section_dragdrop',
|
||||
array(array(
|
||||
'courseid' => $course->id,
|
||||
@@ -4587,8 +4614,8 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
|
||||
'movesection',
|
||||
), 'moodle');
|
||||
|
||||
// Include format-specific strings
|
||||
if ($course->id != $SITE->id) {
|
||||
// Include section-specific strings for formats which support sections.
|
||||
if (course_format_uses_sections($course->format)) {
|
||||
$PAGE->requires->strings_for_js(array(
|
||||
'showfromothers',
|
||||
'hidefromothers',
|
||||
|
||||
@@ -60,6 +60,23 @@ if (has_capability('moodle/user:loginas', $systemcontext)) {
|
||||
print_error('usernotincourse');
|
||||
}
|
||||
$context = $coursecontext;
|
||||
|
||||
// Check if course has SEPARATEGROUPS and user is part of that group.
|
||||
if (groups_get_course_groupmode($course) == SEPARATEGROUPS &&
|
||||
!has_capability('moodle/site:accessallgroups', $context)) {
|
||||
$samegroup = false;
|
||||
if ($groups = groups_get_all_groups($course->id, $USER->id)) {
|
||||
foreach ($groups as $group) {
|
||||
if (groups_is_member($group->id, $userid)) {
|
||||
$samegroup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$samegroup) {
|
||||
print_error('nologinas');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Login as this user and return to course home page.
|
||||
|
||||
@@ -59,6 +59,11 @@ if (!empty($add)) {
|
||||
$context = context_course::instance($course->id);
|
||||
require_capability('moodle/course:manageactivities', $context);
|
||||
|
||||
// There is no page for this in the navigation. The closest we'll have is the course section.
|
||||
// If the course section isn't displayed on the navigation this will fall back to the course which
|
||||
// will be the closest match we have.
|
||||
navigation_node::override_active_url(course_get_url($course, $section));
|
||||
|
||||
course_create_sections_if_missing($course, $section);
|
||||
$cw = get_fast_modinfo($course)->get_section_info($section);
|
||||
|
||||
@@ -122,6 +127,7 @@ if (!empty($add)) {
|
||||
} else {
|
||||
$pageheading = get_string('addinganew', 'moodle', $fullmodulename);
|
||||
}
|
||||
$navbaraddition = $pageheading;
|
||||
|
||||
} else if (!empty($update)) {
|
||||
|
||||
@@ -228,6 +234,7 @@ if (!empty($add)) {
|
||||
} else {
|
||||
$pageheading = get_string('updatinga', 'moodle', $fullmodulename);
|
||||
}
|
||||
$navbaraddition = null;
|
||||
|
||||
} else {
|
||||
require_login();
|
||||
@@ -651,6 +658,11 @@ if ($mform->is_cancelled()) {
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_title($streditinga);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
if (isset($navbaraddition)) {
|
||||
$PAGE->navbar->add($navbaraddition);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
if (get_string_manager()->string_exists('modulename_help', $module->name)) {
|
||||
|
||||
@@ -52,7 +52,6 @@ foreach ($allmodules as $key=>$module) {
|
||||
}
|
||||
|
||||
$strresources = get_string('resources');
|
||||
$strsectionname = get_string('sectionname', 'format_'.$course->format);
|
||||
$strname = get_string('name');
|
||||
$strintro = get_string('moduleintro');
|
||||
$strlastmodified = get_string('lastmodified');
|
||||
@@ -100,6 +99,7 @@ $table = new html_table();
|
||||
$table->attributes['class'] = 'generaltable mod_index';
|
||||
|
||||
if ($usesections) {
|
||||
$strsectionname = get_string('sectionname', 'format_'.$course->format);
|
||||
$table->head = array ($strsectionname, $strname, $strintro);
|
||||
$table->align = array ('center', 'left', 'left');
|
||||
} else {
|
||||
|
||||
@@ -97,6 +97,53 @@ class courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals(range(0, $course->numsections + 1), $sectionscreated);
|
||||
}
|
||||
|
||||
public function test_update_course() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$defaultcategory = $DB->get_field_select('course_categories', 'MIN(id)', 'parent = 0');
|
||||
|
||||
$course = new stdClass();
|
||||
$course->fullname = 'Apu loves Unit Təsts';
|
||||
$course->shortname = 'test1';
|
||||
$course->idnumber = '1';
|
||||
$course->summary = 'Awesome!';
|
||||
$course->summaryformat = FORMAT_PLAIN;
|
||||
$course->format = 'topics';
|
||||
$course->newsitems = 0;
|
||||
$course->numsections = 5;
|
||||
$course->category = $defaultcategory;
|
||||
|
||||
$created = create_course($course);
|
||||
// Ensure the checks only work on idnumber/shortname that are not already ours.
|
||||
update_course($created);
|
||||
|
||||
$course->shortname = 'test2';
|
||||
$course->idnumber = '2';
|
||||
|
||||
$created2 = create_course($course);
|
||||
|
||||
// Test duplicate idnumber.
|
||||
$created2->idnumber = '1';
|
||||
try {
|
||||
update_course($created2);
|
||||
$this->fail('Expected exception when trying to update a course with duplicate idnumber');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals(get_string('idnumbertaken', 'error'), $e->getMessage());
|
||||
}
|
||||
|
||||
// Test duplicate shortname.
|
||||
$created2->idnumber = '2';
|
||||
$created2->shortname = 'test1';
|
||||
try {
|
||||
update_course($created2);
|
||||
$this->fail('Expected exception when trying to update a course with a duplicate shortname');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals(get_string('shortnametaken', 'error', $created2->shortname), $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function test_course_add_cm_to_section() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
@@ -239,6 +239,14 @@
|
||||
}
|
||||
|
||||
$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
|
||||
// If viewing a section, make the title more specific
|
||||
if ($section and $section > 0 and course_format_uses_sections($course->format)) {
|
||||
// Get section details and check it exists.
|
||||
$newtitle = $PAGE->title.', '.get_string('sectionname', "format_$course->format").': '.
|
||||
get_section_name($course, $section);
|
||||
$PAGE->set_title($newtitle);
|
||||
}
|
||||
|
||||
$PAGE->set_heading($course->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
Vendored
+59
-27
@@ -17,7 +17,8 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
SECTION : 'section',
|
||||
SECTIONADDMENUS : 'section_add_menus',
|
||||
SECTIONHANDLE : 'section-handle',
|
||||
SUMMARY : 'summary'
|
||||
SUMMARY : 'summary',
|
||||
SECTIONDRAGGABLE: 'sectiondraggable'
|
||||
};
|
||||
|
||||
var DRAGSECTION = function() {
|
||||
@@ -28,7 +29,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
|
||||
initializer : function(params) {
|
||||
// Set group for parent class
|
||||
this.groups = ['section'];
|
||||
this.groups = [ CSS.SECTIONDRAGGABLE ];
|
||||
this.samenodeclass = M.course.format.get_sectionwrapperclass();
|
||||
this.parentnodeclass = M.course.format.get_containerclass();
|
||||
|
||||
@@ -39,14 +40,16 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
// Initialise sections dragging
|
||||
this.sectionlistselector = M.course.format.get_section_wrapper(Y);
|
||||
if (this.sectionlistselector) {
|
||||
// We need both the list of all sections, and just those which are moveable.
|
||||
// When updating titles and orders, the immoveable sections may need to be updated too.
|
||||
this.sectionlistselector = '.'+CSS.COURSECONTENT+' '+this.sectionlistselector;
|
||||
|
||||
this.setup_for_section(this.sectionlistselector);
|
||||
|
||||
// Make each li element in the lists of sections draggable
|
||||
var nodeselector = this.sectionlistselector.slice(CSS.COURSECONTENT.length+2);
|
||||
var del = new Y.DD.Delegate({
|
||||
container: '.'+CSS.COURSECONTENT,
|
||||
nodes: nodeselector,
|
||||
nodes: '.' + CSS.SECTIONDRAGGABLE,
|
||||
target: true,
|
||||
handles: ['.'+CSS.LEFT],
|
||||
dragConfig: {groups: this.groups}
|
||||
@@ -95,6 +98,9 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
if (movedown) {
|
||||
movedown.remove();
|
||||
}
|
||||
|
||||
// This section can be moved - add the class to indicate this to Y.DD.
|
||||
sectionnode.addClass(CSS.SECTIONDRAGGABLE);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
@@ -129,20 +135,37 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
this.drop_hit(e);
|
||||
},
|
||||
|
||||
get_section_index: function(node) {
|
||||
var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.course.format.get_section_selector(Y),
|
||||
sectionList = Y.all(sectionlistselector),
|
||||
nodeIndex = sectionList.indexOf(node),
|
||||
zeroIndex = sectionList.indexOf(Y.one('#section-0'));
|
||||
|
||||
return (nodeIndex - zeroIndex);
|
||||
},
|
||||
|
||||
drop_hit : function(e) {
|
||||
var drag = e.drag;
|
||||
// Get a reference to our drag node
|
||||
var dragnode = drag.get('node');
|
||||
var dropnode = e.drop.get('node');
|
||||
// Prepare some variables
|
||||
var dragnodeid = Number(this.get_section_id(dragnode));
|
||||
var dropnodeid = Number(this.get_section_id(dropnode));
|
||||
|
||||
var loopstart = dragnodeid;
|
||||
var loopend = dropnodeid;
|
||||
// Get references to our nodes and their IDs.
|
||||
var dragnode = drag.get('node'),
|
||||
dragnodeid = this.get_section_id(dragnode),
|
||||
loopstart = dragnodeid,
|
||||
|
||||
if (this.goingup) {
|
||||
loopstart = dropnodeid;
|
||||
dropnodeindex = this.get_section_index(dragnode),
|
||||
loopend = dropnodeindex;
|
||||
|
||||
if (dragnodeid === dropnodeindex) {
|
||||
Y.log("Skipping move - same location moving " + dragnodeid + " to " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
|
||||
return;
|
||||
}
|
||||
|
||||
Y.log("Moving from position " + dragnodeid + " to position " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
|
||||
|
||||
if (loopstart > loopend) {
|
||||
// If we're going up, we need to swap the loop order
|
||||
// because loops can't go backwards.
|
||||
loopstart = dropnodeindex;
|
||||
loopend = dragnodeid;
|
||||
}
|
||||
|
||||
@@ -167,7 +190,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
params['class'] = 'section';
|
||||
params.field = 'move';
|
||||
params.id = dragnodeid;
|
||||
params.value = dropnodeid;
|
||||
params.value = dropnodeindex;
|
||||
|
||||
// Do AJAX request
|
||||
var uri = M.cfg.wwwroot + this.get('ajaxurl');
|
||||
@@ -190,27 +213,36 @@ YUI.add('moodle-course-dragdrop', function(Y) {
|
||||
M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
|
||||
} catch (e) {}
|
||||
|
||||
// Update all of the section IDs - first unset them, then set them
|
||||
// to avoid duplicates in the DOM.
|
||||
var index;
|
||||
|
||||
// Classic bubble sort algorithm is applied to the section
|
||||
// nodes between original drag node location and the new one.
|
||||
var swapped = false;
|
||||
do {
|
||||
var swapped = false;
|
||||
for (var i = loopstart; i <= loopend; i++) {
|
||||
if (this.get_section_id(sectionlist.item(i-1)) > this.get_section_id(sectionlist.item(i))) {
|
||||
// Swap section id
|
||||
var sectionid = sectionlist.item(i-1).get('id');
|
||||
sectionlist.item(i-1).set('id', sectionlist.item(i).get('id'));
|
||||
sectionlist.item(i).set('id', sectionid);
|
||||
// See what format needs to swap
|
||||
M.course.format.swap_sections(Y, i-1, i);
|
||||
// Update flag
|
||||
swapped = false;
|
||||
for (index = loopstart; index <= loopend; index++) {
|
||||
if (this.get_section_id(sectionlist.item(index - 1)) >
|
||||
this.get_section_id(sectionlist.item(index))) {
|
||||
Y.log("Swapping " + this.get_section_id(sectionlist.item(index - 1)) +
|
||||
" with " + this.get_section_id(sectionlist.item(index)));
|
||||
// Swap section id.
|
||||
var sectionid = sectionlist.item(index - 1).get('id');
|
||||
sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id'));
|
||||
sectionlist.item(index).set('id', sectionid);
|
||||
|
||||
// See what format needs to swap.
|
||||
M.course.format.swap_sections(Y, index - 1, index);
|
||||
|
||||
// Update flag.
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
loopend = loopend - 1;
|
||||
} while (swapped);
|
||||
|
||||
// Finally, hide the lightbox
|
||||
window.setTimeout(function(e) {
|
||||
window.setTimeout(function() {
|
||||
lightbox.hide();
|
||||
}, 250);
|
||||
},
|
||||
|
||||
@@ -46,6 +46,9 @@ class enrol_cohort_plugin extends enrol_plugin {
|
||||
} else if (empty($instance->name)) {
|
||||
$enrol = $this->get_name();
|
||||
$cohort = $DB->get_record('cohort', array('id'=>$instance->customint1));
|
||||
if (!$cohort) {
|
||||
return get_string('pluginname', 'enrol_'.$enrol);
|
||||
}
|
||||
$cohortname = format_string($cohort->name, true, array('context'=>context::instance_by_id($cohort->contextid)));
|
||||
if ($role = $DB->get_record('role', array('id'=>$instance->roleid))) {
|
||||
$role = role_get_name($role, context_course::instance($instance->courseid, IGNORE_MISSING));
|
||||
|
||||
@@ -25,8 +25,9 @@
|
||||
$string['database:unenrol'] = 'Unenrol suspended users';
|
||||
$string['dbencoding'] = 'Database encoding';
|
||||
$string['dbhost'] = 'Database host';
|
||||
$string['dbhost_desc'] = 'Type database server IP address or host name';
|
||||
$string['dbhost_desc'] = 'Type database server IP address or host name. Use a system DSN name if using ODBC.';
|
||||
$string['dbname'] = 'Database name';
|
||||
$string['dbname_desc'] = 'Leave empty if using a DSN name in database host.';
|
||||
$string['dbpass'] = 'Database password';
|
||||
$string['dbsetupsql'] = 'Database setup command';
|
||||
$string['dbsetupsql_desc'] = 'SQL command for special database setup, often used to setup communication encoding - example for MySQL and PostgreSQL: <em>SET NAMES \'utf8\'</em>';
|
||||
|
||||
@@ -41,7 +41,7 @@ if ($ADMIN->fulltree) {
|
||||
|
||||
$settings->add(new admin_setting_configpasswordunmask('enrol_database/dbpass', get_string('dbpass', 'enrol_database'), '', ''));
|
||||
|
||||
$settings->add(new admin_setting_configtext('enrol_database/dbname', get_string('dbname', 'enrol_database'), '', ''));
|
||||
$settings->add(new admin_setting_configtext('enrol_database/dbname', get_string('dbname', 'enrol_database'), get_string('dbname_desc', 'enrol_database'), ''));
|
||||
|
||||
$settings->add(new admin_setting_configtext('enrol_database/dbencoding', get_string('dbencoding', 'enrol_database'), '', 'utf-8'));
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
$string['allowguests'] = 'This course allows guest users to enter';
|
||||
$string['guest:config'] = 'Configure guest access instances';
|
||||
$string['guestaccess_withpassword'] = 'Guest access requires password';
|
||||
$string['guestaccess_withoutpassword'] = 'Guest access';
|
||||
$string['password'] = 'Password';
|
||||
$string['password_help'] = 'A password allows guest access to the course to be restricted to only those who know the password. Guests will be required to supply the password each time they access the course.';
|
||||
$string['passwordinvalid'] = 'Incorrect access password, please try again';
|
||||
|
||||
+2
-2
@@ -45,9 +45,9 @@ class enrol_guest_plugin extends enrol_plugin {
|
||||
public function get_info_icons(array $instances) {
|
||||
foreach ($instances as $instance) {
|
||||
if ($instance->password !== '') {
|
||||
return array(new pix_icon('withpassword', get_string('pluginname', 'enrol_guest'), 'enrol_guest'));
|
||||
return array(new pix_icon('withpassword', get_string('guestaccess_withpassword', 'enrol_guest'), 'enrol_guest'));
|
||||
} else {
|
||||
return array(new pix_icon('withoutpassword', get_string('pluginname', 'enrol_guest'), 'enrol_guest'));
|
||||
return array(new pix_icon('withoutpassword', get_string('guestaccess_withoutpassword', 'enrol_guest'), 'enrol_guest'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
|
||||
require_login(0, false);
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
require_sesskey();
|
||||
|
||||
$site = get_site();
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ function cron() {
|
||||
$this->logfp = fopen($logtolocation, 'a');
|
||||
}
|
||||
|
||||
$fileisnew = false;
|
||||
if ( file_exists($filename) ) {
|
||||
@set_time_limit(0);
|
||||
$starttime = time();
|
||||
@@ -106,10 +107,8 @@ function cron() {
|
||||
if(empty($prev_path) || ($filename != $prev_path)) {
|
||||
$fileisnew = true;
|
||||
} elseif(isset($prev_time) && ($filemtime <= $prev_time)) {
|
||||
$fileisnew = false;
|
||||
$this->log_line('File modification time is not more recent than last update - skipping processing.');
|
||||
} elseif(isset($prev_md5) && ($md5 == $prev_md5)) {
|
||||
$fileisnew = false;
|
||||
$this->log_line('File MD5 hash is same as on last update - skipping processing.');
|
||||
} else {
|
||||
$fileisnew = true; // Let's process it!
|
||||
@@ -216,7 +215,7 @@ function cron() {
|
||||
$this->log_line('File not found: '.$filename);
|
||||
}
|
||||
|
||||
if (!empty($mailadmins)) {
|
||||
if (!empty($mailadmins) && $fileisnew) {
|
||||
$msg = "An IMS enrolment has been carried out within Moodle.\nTime taken: $timeelapsed seconds.\n\n";
|
||||
if(!empty($logtolocation)){
|
||||
if($this->logfp){
|
||||
@@ -233,7 +232,7 @@ function cron() {
|
||||
|
||||
$eventdata = new stdClass();
|
||||
$eventdata->modulename = 'moodle';
|
||||
$eventdata->component = 'imsenterprise';
|
||||
$eventdata->component = 'enrol_imsenterprise';
|
||||
$eventdata->name = 'imsenterprise_enrolment';
|
||||
$eventdata->userfrom = get_admin();
|
||||
$eventdata->userto = get_admin();
|
||||
@@ -397,7 +396,7 @@ function process_group_tag($tagcontents) {
|
||||
// Insert default names for teachers/students, from the current language
|
||||
|
||||
// Handle course categorisation (taken from the group.org.orgunit field if present)
|
||||
if (strlen($group->category)>0) {
|
||||
if (!empty($group->category)) {
|
||||
// If the category is defined and exists in Moodle, we want to store it in that one
|
||||
if ($catid = $DB->get_field('course_categories', 'id', array('name'=>$group->category))) {
|
||||
$course->category = $catid;
|
||||
@@ -412,10 +411,10 @@ function process_group_tag($tagcontents) {
|
||||
} else {
|
||||
// If not found and not allowed to create, stick with default
|
||||
$this->log_line('Category '.$group->category.' not found in Moodle database, so using default category instead.');
|
||||
$course->category = 1;
|
||||
$course->category = $this->get_default_category_id();
|
||||
}
|
||||
} else {
|
||||
$course->category = 1;
|
||||
$course->category = $this->get_default_category_id();
|
||||
}
|
||||
$course->timecreated = time();
|
||||
$course->startdate = time();
|
||||
@@ -810,6 +809,24 @@ function load_role_mappings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default category id (often known as 'Miscellaneous'),
|
||||
* statically cached to avoid multiple DB lookups on big imports.
|
||||
*
|
||||
* @return int id of default category.
|
||||
*/
|
||||
private function get_default_category_id() {
|
||||
static $defaultcategoryid = null;
|
||||
|
||||
if ($defaultcategoryid === null) {
|
||||
$category = get_course_category();
|
||||
$defaultcategoryid = $category->id;
|
||||
}
|
||||
|
||||
return $defaultcategoryid;
|
||||
}
|
||||
|
||||
|
||||
} // end of class
|
||||
|
||||
|
||||
|
||||
@@ -83,6 +83,8 @@ if ($ADMIN->fulltree) {
|
||||
|
||||
$settings->add(new admin_setting_configcheckbox('enrol_imsenterprise/imscapitafix', get_string('usecapitafix', 'enrol_imsenterprise'), get_string('usecapitafix_desc', 'enrol_imsenterprise'), 0));
|
||||
|
||||
$importnowstring = get_string('aftersaving...', 'enrol_imsenterprise').' <a href="../enrol/imsenterprise/importnow.php">'.get_string('doitnow', 'enrol_imsenterprise').'</a>';
|
||||
$importurl = new moodle_url('/enrol/imsenterprise/importnow.php', array('sesskey' => sesskey()));
|
||||
$importnowstring = get_string('aftersaving...', 'enrol_imsenterprise').' '.
|
||||
html_writer::link($importurl, get_string('doitnow', 'enrol_imsenterprise'));
|
||||
$settings->add(new admin_setting_heading('enrol_imsenterprise_doitnowmessage', '', $importnowstring));
|
||||
}
|
||||
|
||||
+1
-1
@@ -950,7 +950,7 @@ class enrol_ldap_plugin extends enrol_plugin {
|
||||
$template->groupmodeforce = $courseconfig->groupmodeforce;
|
||||
$template->visible = $courseconfig->visible;
|
||||
$template->lang = $courseconfig->lang;
|
||||
$template->groupmodeforce = $courseconfig->groupmodeforce;
|
||||
$template->enablecompletion = $courseconfig->enablecompletion;
|
||||
}
|
||||
$course = $template;
|
||||
|
||||
|
||||
+1
-1
@@ -915,7 +915,7 @@ class course_enrolment_manager {
|
||||
continue;
|
||||
} else if ($ue->timestart and $ue->timeend) {
|
||||
$period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend)));
|
||||
$periodoutside = ($ue->timestart && $ue->timeend && $now < $ue->timestart && $now > $ue->timeend);
|
||||
$periodoutside = ($ue->timestart && $ue->timeend && ($now < $ue->timestart || $now > $ue->timeend));
|
||||
} else if ($ue->timestart) {
|
||||
$period = get_string('periodstart', 'enrol', userdate($ue->timestart));
|
||||
$periodoutside = ($ue->timestart && $now < $ue->timestart);
|
||||
|
||||
+2
-5
@@ -156,11 +156,8 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
|
||||
}
|
||||
|
||||
this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url(collapsedimage, 'moodle'));
|
||||
this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).once('click', function() {
|
||||
// We want to do this just once, the first time the controls are shown.
|
||||
this.populateStartDates();
|
||||
this.populateDuration();
|
||||
}, this);
|
||||
this.populateStartDates();
|
||||
this.populateDuration();
|
||||
this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).on('click', function(){
|
||||
this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).toggleClass(CSS.ACTIVE);
|
||||
this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).toggleClass(CSS.HIDDEN);
|
||||
|
||||
+6
-1
@@ -47,7 +47,12 @@ class enrol_meta_plugin extends enrol_plugin {
|
||||
} else if (empty($instance->name)) {
|
||||
$enrol = $this->get_name();
|
||||
$course = $DB->get_record('course', array('id'=>$instance->customint1));
|
||||
$coursename = format_string(get_course_display_name_for_list($course));
|
||||
if ($course) {
|
||||
$coursename = format_string(get_course_display_name_for_list($course));
|
||||
} else {
|
||||
// Use course id, if course is deleted.
|
||||
$coursename = $instance->customint1;
|
||||
}
|
||||
return get_string('pluginname', 'enrol_' . $enrol) . ' (' . $coursename . ')';
|
||||
} else {
|
||||
return format_string($instance->name);
|
||||
|
||||
+25
-2
@@ -29,6 +29,9 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// Disable moodle specific debug messages and any errors in output,
|
||||
// comment out when debugging or better look into error log!
|
||||
define('NO_DEBUG_DISPLAY', true);
|
||||
|
||||
require("../../config.php");
|
||||
require_once("lib.php");
|
||||
@@ -36,6 +39,9 @@ require_once($CFG->libdir.'/eventslib.php');
|
||||
require_once($CFG->libdir.'/enrollib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
// PayPal does not like when we return error messages here,
|
||||
// the custom handler just logs exceptions and stops.
|
||||
set_exception_handler('enrol_paypal_ipn_exception_handler');
|
||||
|
||||
/// Keep out casual intruders
|
||||
if (empty($_POST) or !empty($_GET)) {
|
||||
@@ -236,6 +242,7 @@ if (strlen($result) > 0) {
|
||||
|
||||
|
||||
if (!empty($mailstudents)) {
|
||||
$a = new stdClass();
|
||||
$a->coursename = format_string($course->fullname, true, array('context' => $coursecontext));
|
||||
$a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id";
|
||||
|
||||
@@ -243,7 +250,7 @@ if (strlen($result) > 0) {
|
||||
$eventdata->modulename = 'moodle';
|
||||
$eventdata->component = 'enrol_paypal';
|
||||
$eventdata->name = 'paypal_enrolment';
|
||||
$eventdata->userfrom = $teacher;
|
||||
$eventdata->userfrom = empty($teacher) ? get_admin() : $teacher;
|
||||
$eventdata->userto = $user;
|
||||
$eventdata->subject = get_string("enrolmentnew", 'enrol', $shortname);
|
||||
$eventdata->fullmessage = get_string('welcometocoursetext', '', $a);
|
||||
@@ -254,7 +261,7 @@ if (strlen($result) > 0) {
|
||||
|
||||
}
|
||||
|
||||
if (!empty($mailteachers)) {
|
||||
if (!empty($mailteachers) && !empty($teacher)) {
|
||||
$a->course = format_string($course->fullname, true, array('context' => $coursecontext));
|
||||
$a->user = fullname($user);
|
||||
|
||||
@@ -329,4 +336,20 @@ function message_paypal_error_to_admin($subject, $data) {
|
||||
message_send($eventdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Silent exception handler.
|
||||
*
|
||||
* @param Exception $ex
|
||||
* @return void - does not return. Terminates execution!
|
||||
*/
|
||||
function enrol_paypal_ipn_exception_handler($ex) {
|
||||
$info = get_exception_info($ex);
|
||||
|
||||
$logerrmsg = "enrol_paypal IPN exception handler: ".$info->message;
|
||||
if (debugging('', DEBUG_NORMAL)) {
|
||||
$logerrmsg .= ' Debug: '.$info->debuginfo."\n".format_backtrace($info->backtrace, true);
|
||||
}
|
||||
error_log($logerrmsg);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,11 @@ function xmldb_enrol_self_upgrade($oldversion) {
|
||||
|
||||
// Moodle v2.4.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
if ($oldversion < 2012112901) {
|
||||
// Set customint1 (group enrolment key) to 0 if it was not set (null).
|
||||
$DB->execute("UPDATE {enrol} SET customint1 = 0 WHERE enrol = 'self' AND customint1 IS NULL");
|
||||
upgrade_plugin_savepoint(true, 2012112901, 'enrol', 'self');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2012112900; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2012112901; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2012112900; // Requires this Moodle version
|
||||
$plugin->component = 'enrol_self'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->cron = 600;
|
||||
|
||||
+2
-2
@@ -399,7 +399,7 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
<button class="{!}fp-file-cancel">'.get_string('cancel').'</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fp-info">
|
||||
<div class="fp-info clearfix">
|
||||
<div class="fp-hr"></div>
|
||||
<p class="{!}fp-thumbnail"></p>
|
||||
<div class="fp-fileinfo">
|
||||
@@ -698,7 +698,7 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
<button class="{!}fp-select-cancel">'.get_string('cancel').'</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fp-info">
|
||||
<div class="fp-info clearfix">
|
||||
<div class="fp-hr"></div>
|
||||
<p class="{!}fp-thumbnail"></p>
|
||||
<div class="fp-fileinfo">
|
||||
|
||||
@@ -131,6 +131,11 @@ class filter_glossary extends moodle_text_filter {
|
||||
foreach ($concepts as $key => $concept) {
|
||||
// Trim empty or unlinkable concepts
|
||||
$currentconcept = trim(strip_tags($concept->concept));
|
||||
|
||||
// Concept must be HTML-escaped, so do the same as print_string
|
||||
// to turn ampersands into &.
|
||||
$currentconcept = replace_ampersands_not_followed_by_entity($currentconcept);
|
||||
|
||||
if (empty($currentconcept)) {
|
||||
unset($concepts[$key]);
|
||||
continue;
|
||||
@@ -168,10 +173,14 @@ class filter_glossary extends moodle_text_filter {
|
||||
'&mode=cat&hook='.$concept->id.'">';
|
||||
} else { // Link to entry or alias
|
||||
if (!empty($concept->originalconcept)) { // We are dealing with an alias (so show and point to original)
|
||||
$title = str_replace('"', "'", strip_tags($glossaryname.': '.$concept->originalconcept));
|
||||
$title = str_replace('"', "'", html_entity_decode(
|
||||
strip_tags($glossaryname.': '.$concept->originalconcept)));
|
||||
$concept->id = $concept->entryid;
|
||||
} else { // This is an entry
|
||||
$title = str_replace('"', "'", strip_tags($glossaryname.': '.$concept->concept));
|
||||
// We need to remove entities from the content here because it
|
||||
// will be escaped by html_writer below.
|
||||
$title = str_replace('"', "'", html_entity_decode(
|
||||
strip_tags($glossaryname.': '.$concept->concept)));
|
||||
}
|
||||
// hardcoding dictionary format in the URL rather than defaulting
|
||||
// to the current glossary format which may not work in a popup.
|
||||
|
||||
@@ -132,8 +132,13 @@ class filter_urltolink extends moodle_text_filter {
|
||||
$querystring = '(?:\?(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
|
||||
$fragment = '(?:\#(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
|
||||
|
||||
$regex = "(?<!=[\"'])$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
|
||||
"($port?$path$querystring?$fragment?)(?<![]),.;])";
|
||||
// Lookbehind assertions.
|
||||
// Is not HTML attribute or CSS URL property. Unfortunately legit text like "url(http://...)" will not be a link.
|
||||
$lookbehindstart = "(?<!=[\"']|\burl\([\"' ]|\burl\()";
|
||||
$lookbehindend = "(?<![]),.;])";
|
||||
|
||||
$regex = "$lookbehindstart$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
|
||||
"($port?$path$querystring?$fragment?)$lookbehindend";
|
||||
if ($unicoderegexp) {
|
||||
$regex = '#' . $regex . '#ui';
|
||||
} else {
|
||||
|
||||
@@ -31,19 +31,6 @@ require_once($CFG->dirroot . '/filter/urltolink/filter.php'); // Include the cod
|
||||
|
||||
class filter_urltolink_testcase extends basic_testcase {
|
||||
|
||||
/**
|
||||
* Helper function that represents the legacy implementation
|
||||
* of convert_urls_into_links()
|
||||
*/
|
||||
protected function old_convert_urls_into_links(&$text) {
|
||||
/// Make lone URLs into links. eg http://moodle.com/
|
||||
$text = preg_replace("%([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])%i",
|
||||
'$1<a href="$2://$3$4" target="_blank">$2://$3$4</a>', $text);
|
||||
/// eg www.moodle.com
|
||||
$text = preg_replace("%([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])%i",
|
||||
'$1<a href="http://www.$2$3" target="_blank">www.$2$3</a>', $text);
|
||||
}
|
||||
|
||||
function get_convert_urls_into_links_test_cases() {
|
||||
$texts = array (
|
||||
//just a url
|
||||
@@ -144,6 +131,11 @@ class filter_urltolink_testcase extends basic_testcase {
|
||||
'<td background="www.moodle.org"> </td>' => '<td background="www.moodle.org"> </td>',
|
||||
'<form name="input" action="http://moodle.org/submit.asp" method="get">'=>'<form name="input" action="http://moodle.org/submit.asp" method="get">',
|
||||
'<td background="https://www.moodle.org"> </td>' => '<td background="https://www.moodle.org"> </td>',
|
||||
// CSS URLs.
|
||||
'<table style="background-image: url(\'http://moodle.org/pic.jpg\');">' => '<table style="background-image: url(\'http://moodle.org/pic.jpg\');">',
|
||||
'<table style="background-image: url(http://moodle.org/pic.jpg);">' => '<table style="background-image: url(http://moodle.org/pic.jpg);">',
|
||||
'<table style="background-image: url("http://moodle.org/pic.jpg");">' => '<table style="background-image: url("http://moodle.org/pic.jpg");">',
|
||||
'<table style="background-image: url( http://moodle.org/pic.jpg );">' => '<table style="background-image: url( http://moodle.org/pic.jpg );">',
|
||||
//partially escaped img tag
|
||||
'partially escaped img tag <img src="http://moodle.org/logo/logo-240x60.gif" />' => 'partially escaped img tag <img src="http://moodle.org/logo/logo-240x60.gif" />',
|
||||
//fully escaped img tag. Commented out as part of MDL-21183
|
||||
@@ -181,32 +173,6 @@ class filter_urltolink_testcase extends basic_testcase {
|
||||
$this->assertEquals($correctresult, $text);
|
||||
}
|
||||
|
||||
function test_convert_urls_into_links_performance() {
|
||||
$testablefilter = new testable_filter_urltolink();
|
||||
|
||||
$reps = 1000;
|
||||
$text = file_get_contents(__DIR__ . '/fixtures/sample.txt');
|
||||
$time_start = microtime(true);
|
||||
for($i=0;$i<$reps;$i++) {
|
||||
$testablefilter->convert_urls_into_links($text);
|
||||
}
|
||||
$time_end = microtime(true);
|
||||
$new_time = $time_end - $time_start;
|
||||
|
||||
$time_start = microtime(true);
|
||||
for($i=0;$i<$reps;$i++) {
|
||||
$this->old_convert_urls_into_links($text);
|
||||
}
|
||||
$time_end = microtime(true);
|
||||
$old_time = $time_end - $time_start;
|
||||
|
||||
$fast_enough = false;
|
||||
if( $new_time < $old_time ) {
|
||||
$fast_enough = true;
|
||||
}
|
||||
|
||||
$this->assertEquals($fast_enough, true, 'Timing test: ' . $new_time . 'secs (new) < ' . $old_time . 'secs (old)');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ $action = optional_param('action', '', PARAM_ALPHA);
|
||||
$scope = optional_param('scope', 'custom', PARAM_ALPHA);
|
||||
|
||||
$PAGE->set_url('/grade/edit/outcome/import.php', array('courseid' => $courseid));
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
/// Make sure they can even access this course
|
||||
if ($courseid) {
|
||||
|
||||
@@ -38,7 +38,7 @@ class import_outcomes_form extends moodleform {
|
||||
$mform->addElement('hidden', 'action', 'upload');
|
||||
$mform->setType('action', PARAM_ALPHANUMEXT);
|
||||
$mform->addElement('hidden', 'courseid', $PAGE->course->id);
|
||||
$mform->setType('id', PARAM_INT);
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
|
||||
$scope = array();
|
||||
if (($PAGE->course->id > 1) && has_capability('moodle/grade:manage', context_system::instance())) {
|
||||
|
||||
@@ -793,9 +793,12 @@ class grade_edit_tree_column_range extends grade_edit_tree_column {
|
||||
public function get_item_cell($item, $params) {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
// If the parent aggregation is Sum of Grades, this cannot be changed
|
||||
// If the parent aggregation is Sum of Grades, we should show the number, even for scales, as that value is used...
|
||||
// ...in the computation. For text grades, the grademax is not used, so we can still show the no value string.
|
||||
$parent_cat = $item->get_parent_category();
|
||||
if ($parent_cat->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
if ($item->gradetype == GRADE_TYPE_TEXT) {
|
||||
$grademax = ' - ';
|
||||
} else if ($parent_cat->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
$grademax = format_float($item->grademax, $item->get_decimals());
|
||||
} elseif ($item->gradetype == GRADE_TYPE_SCALE) {
|
||||
$scale = $DB->get_record('scale', array('id' => $item->scaleid));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user