Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Core\Update;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\DrupalKernel;
|
Chris@0
|
6 use Drupal\Core\Session\AnonymousUserSession;
|
Chris@0
|
7 use Drupal\Core\Site\Settings;
|
Chris@0
|
8 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
Chris@0
|
9 use Symfony\Component\HttpFoundation\ParameterBag;
|
Chris@0
|
10 use Symfony\Component\HttpFoundation\Request;
|
Chris@0
|
11 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * Defines a kernel which is used primarily to run the update of Drupal.
|
Chris@0
|
15 *
|
Chris@0
|
16 * We use a dedicated kernel + front controller (update.php) in order to be able
|
Chris@0
|
17 * to repair Drupal if it is in a broken state.
|
Chris@0
|
18 *
|
Chris@0
|
19 * @see update.php
|
Chris@0
|
20 * @see \Drupal\system\Controller\DbUpdateController
|
Chris@0
|
21 */
|
Chris@0
|
22 class UpdateKernel extends DrupalKernel {
|
Chris@0
|
23
|
Chris@0
|
24 /**
|
Chris@0
|
25 * {@inheritdoc}
|
Chris@0
|
26 */
|
Chris@0
|
27 public function discoverServiceProviders() {
|
Chris@0
|
28 parent::discoverServiceProviders();
|
Chris@0
|
29
|
Chris@0
|
30 $this->serviceProviderClasses['app']['update_kernel'] = 'Drupal\Core\Update\UpdateServiceProvider';
|
Chris@0
|
31 }
|
Chris@0
|
32
|
Chris@0
|
33 /**
|
Chris@0
|
34 * {@inheritdoc}
|
Chris@0
|
35 */
|
Chris@0
|
36 protected function initializeContainer() {
|
Chris@0
|
37 // Always force a container rebuild, in order to be able to override some
|
Chris@0
|
38 // services, see \Drupal\Core\Update\UpdateServiceProvider.
|
Chris@0
|
39 $this->containerNeedsRebuild = TRUE;
|
Chris@0
|
40 $container = parent::initializeContainer();
|
Chris@0
|
41 return $container;
|
Chris@0
|
42 }
|
Chris@0
|
43
|
Chris@0
|
44 /**
|
Chris@0
|
45 * {@inheritdoc}
|
Chris@0
|
46 */
|
Chris@0
|
47 protected function cacheDrupalContainer(array $container_definition) {
|
Chris@0
|
48 // Don't save this particular container to cache, so it does not leak into
|
Chris@0
|
49 // the main site at all.
|
Chris@0
|
50 return FALSE;
|
Chris@0
|
51 }
|
Chris@0
|
52
|
Chris@0
|
53 /**
|
Chris@0
|
54 * {@inheritdoc}
|
Chris@0
|
55 */
|
Chris@0
|
56 public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
|
Chris@0
|
57 try {
|
Chris@0
|
58 static::bootEnvironment();
|
Chris@0
|
59
|
Chris@0
|
60 // First boot up basic things, like loading the include files.
|
Chris@0
|
61 $this->initializeSettings($request);
|
Chris@0
|
62 $this->boot();
|
Chris@0
|
63 $container = $this->getContainer();
|
Chris@0
|
64 /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
|
Chris@0
|
65 $request_stack = $container->get('request_stack');
|
Chris@0
|
66 $request_stack->push($request);
|
Chris@0
|
67 $this->preHandle($request);
|
Chris@0
|
68
|
Chris@0
|
69 // Handle the actual request. We need the session both for authentication
|
Chris@0
|
70 // as well as the DB update, like
|
Chris@0
|
71 // \Drupal\system\Controller\DbUpdateController::batchFinished.
|
Chris@0
|
72 $this->bootSession($request, $type);
|
Chris@0
|
73 $result = $this->handleRaw($request);
|
Chris@0
|
74 $this->shutdownSession($request);
|
Chris@0
|
75
|
Chris@0
|
76 return $result;
|
Chris@0
|
77 }
|
Chris@0
|
78 catch (\Exception $e) {
|
Chris@0
|
79 return $this->handleException($e, $request, $type);
|
Chris@0
|
80 }
|
Chris@0
|
81 }
|
Chris@0
|
82
|
Chris@0
|
83 /**
|
Chris@0
|
84 * Generates the actual result of update.php.
|
Chris@0
|
85 *
|
Chris@0
|
86 * The actual logic of the update is done in the db update controller.
|
Chris@0
|
87 *
|
Chris@0
|
88 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
89 * The incoming request.
|
Chris@0
|
90 *
|
Chris@0
|
91 * @return \Symfony\Component\HttpFoundation\Response
|
Chris@0
|
92 * A response object.
|
Chris@0
|
93 *
|
Chris@0
|
94 * @see \Drupal\system\Controller\DbUpdateController
|
Chris@0
|
95 */
|
Chris@0
|
96 protected function handleRaw(Request $request) {
|
Chris@0
|
97 $container = $this->getContainer();
|
Chris@0
|
98
|
Chris@0
|
99 $this->handleAccess($request, $container);
|
Chris@0
|
100
|
Chris@0
|
101 /** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */
|
Chris@0
|
102 $controller_resolver = $container->get('controller_resolver');
|
Chris@0
|
103
|
Chris@0
|
104 /** @var callable $db_update_controller */
|
Chris@0
|
105 $db_update_controller = $controller_resolver->getControllerFromDefinition('\Drupal\system\Controller\DbUpdateController::handle');
|
Chris@0
|
106
|
Chris@0
|
107 $this->setupRequestMatch($request);
|
Chris@0
|
108
|
Chris@0
|
109 $arguments = $controller_resolver->getArguments($request, $db_update_controller);
|
Chris@0
|
110 return call_user_func_array($db_update_controller, $arguments);
|
Chris@0
|
111 }
|
Chris@0
|
112
|
Chris@0
|
113 /**
|
Chris@0
|
114 * Boots up the session.
|
Chris@0
|
115 *
|
Chris@0
|
116 * bootSession() + shutdownSession() basically simulates what
|
Chris@0
|
117 * \Drupal\Core\StackMiddleware\Session does.
|
Chris@0
|
118 *
|
Chris@0
|
119 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
120 * The incoming request.
|
Chris@0
|
121 */
|
Chris@0
|
122 protected function bootSession(Request $request) {
|
Chris@0
|
123 $container = $this->getContainer();
|
Chris@0
|
124 /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
|
Chris@0
|
125 $session = $container->get('session');
|
Chris@0
|
126 $session->start();
|
Chris@0
|
127 $request->setSession($session);
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 /**
|
Chris@0
|
131 * Ensures that the session is saved.
|
Chris@0
|
132 *
|
Chris@0
|
133 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
134 * The incoming request.
|
Chris@0
|
135 */
|
Chris@0
|
136 protected function shutdownSession(Request $request) {
|
Chris@0
|
137 if ($request->hasSession()) {
|
Chris@0
|
138 $request->getSession()->save();
|
Chris@0
|
139 }
|
Chris@0
|
140 }
|
Chris@0
|
141
|
Chris@0
|
142 /**
|
Chris@0
|
143 * Set up the request with fake routing data for update.php.
|
Chris@0
|
144 *
|
Chris@0
|
145 * This fake routing data is needed in order to make batch API work properly.
|
Chris@0
|
146 *
|
Chris@0
|
147 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
148 * The incoming request.
|
Chris@0
|
149 */
|
Chris@0
|
150 protected function setupRequestMatch(Request $request) {
|
Chris@0
|
151 $path = $request->getPathInfo();
|
Chris@0
|
152 $args = explode('/', ltrim($path, '/'));
|
Chris@0
|
153
|
Chris@0
|
154 $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'system.db_update');
|
Chris@0
|
155 $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $this->getContainer()->get('router.route_provider')->getRouteByName('system.db_update'));
|
Chris@0
|
156 $op = $args[0] ?: 'info';
|
Chris@0
|
157 $request->attributes->set('op', $op);
|
Chris@0
|
158 $request->attributes->set('_raw_variables', new ParameterBag(['op' => $op]));
|
Chris@0
|
159 }
|
Chris@0
|
160
|
Chris@0
|
161 /**
|
Chris@0
|
162 * Checks if the current user has rights to access updates page.
|
Chris@0
|
163 *
|
Chris@0
|
164 * If the current user does not have the rights, an exception is thrown.
|
Chris@0
|
165 *
|
Chris@0
|
166 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
167 * The incoming request.
|
Chris@0
|
168 *
|
Chris@0
|
169 * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
Chris@0
|
170 * Thrown when update.php should not be accessible.
|
Chris@0
|
171 */
|
Chris@0
|
172 protected function handleAccess(Request $request) {
|
Chris@0
|
173 /** @var \Drupal\Core\Authentication\AuthenticationManager $authentication_manager */
|
Chris@0
|
174 $authentication_manager = $this->getContainer()->get('authentication');
|
Chris@0
|
175 $account = $authentication_manager->authenticate($request) ?: new AnonymousUserSession();
|
Chris@0
|
176
|
Chris@0
|
177 /** @var \Drupal\Core\Session\AccountProxyInterface $current_user */
|
Chris@0
|
178 $current_user = $this->getContainer()->get('current_user');
|
Chris@0
|
179 $current_user->setAccount($account);
|
Chris@0
|
180
|
Chris@0
|
181 /** @var \Drupal\system\Access\DbUpdateAccessCheck $db_update_access */
|
Chris@0
|
182 $db_update_access = $this->getContainer()->get('access_check.db_update');
|
Chris@0
|
183
|
Chris@0
|
184 if (!Settings::get('update_free_access', FALSE) && !$db_update_access->access($account)->isAllowed()) {
|
Chris@0
|
185 throw new AccessDeniedHttpException('In order to run update.php you need to either be logged in as admin or have set $settings[\'update_free_access\'] in your settings.php.');
|
Chris@0
|
186 }
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 }
|