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