web-dev-qa-db-fra.com

Extension de la classe WP_User et utilisation de cette sous-classe pendant tout le cycle de vie

Ce que j’essaie d’obtenir est le suivant: pour chaque utilisateur de notre site Web, je souhaite envoyer une demande d’API à un service (une API locale REST interagissant avec une autre base de données), puis mettre en cache le résultat dans la mémoire. WP_User (sous) classe jusqu'à ce que l'utilisateur se déconnecte et se reconnecte (car cette valeur est utilisée une fois sur chaque page de l'application, sinon elle devrait être extraite une fois pour chaque chargement de page, ce qui est très peu performant au niveau des performances).

La manière la plus élégante en termes de séparation des problèmes que j'ai trouvée jusqu'à présent consiste à étendre (sous-classer) la classe WP_User selon l'exemple présenté dans le livre O'Reilly Création d'applications Web avec WordPress Par Brian Messenlehner & Jason Coleman .

L'exemple de code peut être vu ici: voir ce fichier sur le GitHub de l'auteur .

Cependant, le problème est que nous n'avons toujours pas cet étudiant (étend WP_User, donc la sous-classe) disponible dans notre code. Nous devons encore l'instancier de la manière suivante pour obtenir une instance d'étudiant pour l'utilisateur actuel:

$student = new Student($current_user->ID);

Si nous faisons cela sur une page, l'instance sera toujours créée à nouveau (d'où mon renvoi au cycle de vie dans le titre) et l'appel à $student->assignments semble ne jamais être mis en cache dans la sous-classe WP_User elle-même après avoir navigué vers une nouvelle page et/ou recharger la page, donc pour chaque chargement de page, nous atteignons l'API et la base de données qui ne fonctionneront probablement jamais dans notre environnement de production à fort trafic.

Cependant, la variable globale $current_user au sein de WordPress lui-même (qui est une instance de WP_User) semble être créée directement après la connexion et est ensuite disponible dans toute l'application, pour autant que je sache. Ce que je veux vraiment, c’est la même disponibilité dans l’application, mais pour ma sous-classe (Étudiant) au lieu de la classe WP_User, mais plus important encore, je veux être sûr que pour chaque utilisateur connecté, la frappe d’API n’est effectuée qu’une seule fois ( comme pour $current_user->user_login qui est dans WP_User par exemple).

J'ai également envisagé d'ajouter user_meta à WP_User et de vérifier cette question qui semblait en partie utile: WordPress met-il en cache les résultats get_user_meta ()?

Cependant, ceci est récupéré via wp_cache_get qui est un cache d'objets WordPress qui indique clairement:

  1. Le cache non persistant est disponible uniquement pendant le chargement de la page en cours. une fois la page suivante chargée, il sera à nouveau vide.
  2. La taille de stockage est limitée par la mémoire totale disponible pour PHP sur le serveur. Ne stockez pas de grands ensembles de données, car vous pourriez vous retrouver avec un message "Mémoire insuffisante".
  3. L'utilisation de ce type de cache n'a de sens que pour les opérations répétées plusieurs fois lors de la création d'une page.

Nous n'utilisons pas les valeurs de la sous-classe Student plus d'une fois dans la création de la page. Cependant, la valeur est utilisée une fois sur chaque page de l'application. Elle doit donc être récupérée une fois pour chaque chargement de page.

Suis-je simplement en train de penser dans la mauvaise direction, ou comment cela serait-il possible dans WordPress? J'ai vraiment besoin d'une bonne solution à long terme ici, qui devrait fonctionner dans un environnement de production à fort trafic. Merci pour tous vos commentaires et votre aide!

4
Daniel

Si j'ai bien compris, nous devons mettre en cache une valeur extraite d'un autre service REST, de la connexion à la déconnexion de l'utilisateur sur l'installation de wordpress. Nous allons donc nous connecter à ce wp_login pour obtenir la valeur et le cache. en utilisant API transitoire , Options API ou un cache persistant plugin.

add_action('wp_login', 'my_get_and_cache_rest_value');
function my_get_and_cache_rest_value ($user_login, $user) {
    // do your rest call
    // cache it using Transient API, Options API or a persistent caching plugin
}

Nous pouvons ensuite étendre l'objet WP_User et définir nos appels magiques pour extraire les données souhaitées du cache.

class MY_User extends WP_User {
    // no constructor so WP_User's constructor is used

    // method to get cached data
    function getMyCachedData() {
        // get data via my cache solution
        if ( ! isset( $this->data->myData ) )
            $this->data->myData = my_get_cached_data( $this->ID );

        return $this->data->myData;
    }

    // magic method to detect $user->my_data
    function __get( $key ) {
        if ( $key == 'my_data' )
        {
            return $this->getMyCachedData();
        }
        else
        {
            // fallback to default WP_User magic method
            return parent::__get( $key );
        }
    }    
}

J'espère que cela aiderait quelqu'un et bravo à @Daniel.

1
JBoulhous

Ce qui suit ne répond pas à toute la question, mais aborde cette partie:

@ Daniel: La variable globale $current_user ... est alors disponible dans toute l'application pour autant que je sache. Ce que je veux vraiment, c'est la même disponibilité dans l'application ...

J'avais un besoin similaire, et c'est ce que j'ai proposé.

Il y a un hook set_current_user (dans la fonction wp_set_current_user () _) et, comme la variable globale $current_user est définie sur une instance de WP_User au moment où l'action est déclenchée, vous pouvez utiliser ce hook pour "effectuer des tâches "à cela.

Les appels à wp_get_current_user () _ retournent essentiellement la valeur du $current_user global, mais peuvent éventuellement appeler wp_set_current_user() dans certaines conditions, ce qui entraînera le déclenchement de votre action personnalisée.

Donc, dans un plugin personnalisé (je ne pense pas que cela fonctionnerait dans un fichier theme.php), vous pouvez définir une action:

add_action( 'set_current_user', 'extend_current_user', PHP_INT_MAX );

Et alors votre action peut écraser le $current_user global:

public function extend_current_user()
{
    global $current_user;

    if( $current_user->ID == 0 )
        return;

    $current_user = new Student( $current_user->ID );
}

Votre classe d’étudiant peut ensuite implémenter la API transitoire pour mettre en cache les données RESTful et proposer des méthodes ou des propriétés qui exposeront ces données. Et comme le $current_user global restera en tant qu'instance de Student, ces méthodes/propriétés seront toujours disponibles à partir de wp_get_current_user() chaque fois que vous en aurez besoin.

Bien entendu, en faisant cela, un programmeur défensif voudra vérifier que tout appel à wp_get_current_user() renvoie une instance de Student avant d'appeler des méthodes.

0
Matthew Clark

Votre question est un peu large, mais le problème principal semble être que pour chaque nouvel étudiant, vous souhaitez contacter une API externe, une seule fois .

Pour ce faire, vous devez vous connecter à wp_insert_user , qui est la fonction principale qui enregistre un nouvel utilisateur. Par définition, cette fonction n'est appelée qu'une fois pour chaque nouvel utilisateur. À la fin de cette fonction, vous voyez un crochet user_register , qui permet d’approcher l’API.

add_action ('user_register','wpse185731_approach_api');
function wpse185731_approach_api ($user_id) {
  $userdata = get_userdata( $user_id );
  if ( some condition based on $userdata) {
    ... approach API with $userdata, then store with:
    add_user_meta( $user_id, $meta_key, $meta_value, $unique );
    }
  }

Vous voudrez probablement faire cela dans un plugin, pas dans votre thème.

0
cjbj