link_orcid-1.0.0-rc1/src/Controller/OrcidController.php
src/Controller/OrcidController.php
<?php
declare(strict_types=1);
namespace Drupal\link_orcid\Controller;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Url;
use Drupal\link_orcid\OrcidClient;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Symfony\Component\HttpFoundation\Request;
/**
* Controller for ORCID OAuth flow.
*/
final class OrcidController implements ContainerInjectionInterface {
use StringTranslationTrait;
public function __construct(
private readonly OrcidClient $client,
private readonly MessengerInterface $messenger,
private readonly AccountProxyInterface $currentUser,
private readonly EntityTypeManagerInterface $entityTypeManager,
private readonly ConfigFactoryInterface $configFactory,
) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): static {
return new static(
$container->get('link_orcid.client'),
$container->get('messenger'),
$container->get('current_user'),
$container->get('entity_type.manager'),
$container->get('config.factory'),
);
}
/**
* Redirect to ORCID authorize endpoint.
*/
public function start(Request $request): TrustedRedirectResponse {
$state = bin2hex(random_bytes(16));
$request->getSession()->set('link_orcid_state', $state);
$redirect_uri = Url::fromRoute('link_orcid.oauth_callback', [], ['absolute' => TRUE])->toString();
$auth_url = $this->client->getAuthorizeRedirect($state, $redirect_uri);
return new TrustedRedirectResponse($auth_url);
}
/**
* OAuth callback handler.
*/
public function callback(Request $request): RedirectResponse {
$code = $request->query->get('code');
$state = $request->query->get('state');
$saved_state = $request->getSession()->get('link_orcid_state');
if (!$code || !$state || !$saved_state || !hash_equals((string) $saved_state, (string) $state)) {
$this->messenger->addError($this->t('Missing or invalid parameters from ORCID.'));
return $this->redirectToProfile();
}
try {
$redirect_uri = Url::fromRoute('link_orcid.oauth_callback', [], ['absolute' => TRUE])->toString();
$result = $this->client->exchangeCodeForToken((string) $code, (string) $state, $redirect_uri);
if (!$result || empty($result['orcid'])) {
$this->messenger->addError($this->t('Failed to link your ORCID.'));
return $this->redirectToProfile();
}
$this->client->saveCurrentUserOrcid($result['orcid']);
$this->messenger->addStatus($this->t('Your ORCID has been linked: @orcid', ['@orcid' => $result['orcid']]));
}
catch (\Throwable $e) {
$this->messenger->addError($this->t('ORCID linking failed: @msg', ['@msg' => $e->getMessage()]));
}
return $this->redirectToProfile();
}
/**
* Redirect to current user's profile edit page.
*/
private function redirectToProfile(): RedirectResponse {
$user_id = $this->currentUser->id();
$url = Url::fromRoute('entity.user.edit_form', ['user' => $user_id])->toString();
return new RedirectResponse($url);
}
/**
* Unlink ORCID from current user.
*/
public function unlink(): RedirectResponse {
$user_id = $this->currentUser->id();
$config = $this->configFactory->get('link_orcid.settings');
$field = (string) $config->get('user_field');
$user = $this->entityTypeManager->getStorage('user')->load($user_id);
if ($user && $field && $user->hasField($field)) {
$user->set($field, NULL);
$user->save();
$this->messenger->addStatus($this->t('Your ORCID has been unlinked.'));
}
else {
$this->messenger->addError($this->t('Could not unlink ORCID.'));
}
return $this->redirectToProfile();
}
}
