IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MVC PHP Discussion :

Models de 0.6 vers 1.8 [ZF 1.8]


Sujet :

MVC PHP

  1. #1
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut Models de 0.6 vers 1.8
    Bonjour, j'essaie d'avoir accès à mes données, mais en changeant de version je n'y arrive pas.

    Voici ce que je fais dans le Bootstrap

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    <?php
    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {
     
        protected function _initLibraryNamespaces()
        {
            $autoloader = Zend_Loader_Autoloader::getInstance();
            $autoloader->registerNamespace(array('My_','OLE_','Spreadsheet_','Ssh_'));
     
            // Les modèles !!
            $application = new Zend_Loader_Autoloader_Resource(array(
                    'basePath'      => APPLICATION_PATH . '/models',
                    'namespace'     => '',
                ));
        }
     
     
        public function _initLang(){
            Zend_Session::start();
            $session = new Zend_Session_Namespace('default');
            if (! isset($session->lan))
            {
                $session->lan = 'fr';
            }
     
        }
     
     
    }

    et dans dans un controller je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    $db = new Models_Spaces();
    J'obtiens l'erreur suivante :

    Fatal error: Class 'Models_Spaces' not found in /var/www/RdcMonGG1_8/app/controllers/SpacesController.php

    Comment déclarer le répertoire models dans l'application ?

    Merci de votre aide.

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 13
    Par défaut
    Dans la 1.8 tu as le namespace Model:

    - Dans le dossiers models tu as tes models (Jusque là la logique est implacable....)
    - Tu as ton model Maclasse.php
    - Ta classe devrais se nommer comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class Model_Maclasse extends Zend_db_Table_Abstract {
            // J'ai bien écrit "Model" sans "s".... 
    }
    de plus ça ne sert à rien de mettre ça dans ton bootstap

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $application = new Zend_Loader_Autoloader_Resource(array(
                    'basePath'      => APPLICATION_PATH . '/models',
                    'namespace'     => '',
                ));

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    http://www.developpez.net/forums/d76...rouvable-zend/

    Le nom de la classe doit effectivement contenir le namespace.

  4. #4
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut
    cela ne fonctionne pas , avant la 1.8, je faisais ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    set_include_path(
    '../library/'								.PATH_SEPARATOR.
    '../app/models'								.PATH_SEPARATOR.
    '../app/controller'							.PATH_SEPARATOR.
    get_include_path()
    );
    cela me suffisais à récupérer mes classes de données, or maintanant cela ne fonctionne plus.

    Sauf si je déplace toutes mes classes dans un sous répertoire /library/Models

    et que je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     $autoloader->registerNamespace(array('My_','OLE_','Spreadsheet_','Ssh_','Models_'));
    Alors c'est Nikel, sauf que je dois renomer dans mes controller !

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 13
    Par défaut
    Et tu a essayer en appellant ton model comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //en retirant le s...
    $db = new Model_Spaces();

  6. #6
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut
    oui

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    En enregistrant les modèles, il n'y a pas de récursivité !
    Donc tu dois charger tous tes répertoires qui contiennent modèles, comme dans le lien que je t'ai donné.

    Si ça ne marche pas, présente les tests que tu fais.

  8. #8
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    En enregistrant les modèles, il n'y a pas de récursivité !
    Donc tu dois charger tous tes répertoires qui contiennent modèles, comme dans le lien que je t'ai donné.

    Si ça ne marche pas, présente les tests que tu fais.
    J'hésite sur la démarche à suivre

    en sachant que ma classe modèle se trouves donc dans /app/models/Spaces.php par exemple

    Que mettrais tu dans le 'ressourcesType'?, afin que je puisse instancier cette classe!

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Et bien de quoi s'agit-il ? Ce modèle est un formulaire, un modèle de table, que sais-je ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $application = new Zend_Loader_Autoloader_Resource(array(
     'basePath'      => APPLICATION_PATH . '/models',
     'namespace'     => '',
     'resourceTypes' => array('tables'=>array('path'=>'Tables','namespace'=>'Table'),
                              'forms'=>array('path'=>'Forms', 'namespace'=>'Form'),
                              'itemForms'=>array('path'=>'Forms/Item', 'namespace'=>'Form_Item'),
                              'adminForms'=>array('path'=>'Forms/Admin', 'namespace'=>'Form_Admin'),
                              'membreForms'=>array('path'=>'Forms/Membre', 'namespace'=>'Form_Membre'),
                              'wallForms'=>array('path'=>'Forms/Wall', 'namespace'=>'Form_Wall'),
                              'contactForms'=>array('path'=>'Forms/Contact', 'namespace'=>'Form_Contact')
    )));
    Vois dans cet exemple !

  10. #10
    Membre Expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    Et bien de quoi s'agit-il ? Ce modèle est un formulaire, un modèle de table, que sais-je ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $application = new Zend_Loader_Autoloader_Resource(array(
     'basePath'      => APPLICATION_PATH . '/models',
     'namespace'     => '',
     'resourceTypes' => array('tables'=>array('path'=>'Tables','namespace'=>'Table'),
                              'forms'=>array('path'=>'Forms', 'namespace'=>'Form'),
                              'itemForms'=>array('path'=>'Forms/Item', 'namespace'=>'Form_Item'),
                              'adminForms'=>array('path'=>'Forms/Admin', 'namespace'=>'Form_Admin'),
                              'membreForms'=>array('path'=>'Forms/Membre', 'namespace'=>'Form_Membre'),
                              'wallForms'=>array('path'=>'Forms/Wall', 'namespace'=>'Form_Wall'),
                              'contactForms'=>array('path'=>'Forms/Contact', 'namespace'=>'Form_Contact')
    )));
    Vois dans cet exemple !
    Je ne comprend pas bien dans l'exemple donné l'intérêt de lister ainsi toutes les ressources. D'autant que tes namespaces ne sont pas suffisamment spécifiques :
    - tout d'abord il ne faut pas oublier le _ terminal
    - Form_Item, Form_Admin, ... sont compris dans le namespace Form...

    Citation Envoyé par MaitrePylos Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     $autoloader->registerNamespace(array('My_','OLE_','Spreadsheet_','Ssh_','Models_'));
    Alors c'est Nikel, sauf que je dois renomer dans mes controller !
    Ce n'est pas ce que tu as déjà fait ?
    Citation Envoyé par MaitrePylos
    et dans dans un controller je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $db = new Models_Spaces();
    Je commence à être perdu

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Bah Eusebe, j'peux juste te dire que ce que tu dis contredit les faits, car chez moi ça fonctionne, sans "_" final, et la déclaration de la ressource "form" n'est pas récursive, donc "form_admin" & cie ne sont pas déclaré avec la ressource "form".

  12. #12
    Membre Expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    Bah Eusebe, j'peux juste te dire que ce que tu dis contredit les faits, car chez moi ça fonctionne, sans "_" final, et la déclaration de la ressource "form" n'est pas récursive, donc "form_admin" & cie ne sont pas déclaré avec la ressource "form".
    Que ça fonctionne sans l'underscore, oui, le seul risque c'est d'empiéter sur un autre namespace. Par contre, que Form_Admin & Co ne soient pas chargés automatiquement alors que tu as un namespace Form, là je trouve ça bizarre...

    Mais j'avoue ne jamais avoir utilisé cette fonctionnalité avancée de l'autoloader, puisque mes classes respectent les règles de nommage du framework (donc Form_ par exemple dans un répertoire 'Form/').

    Mais par curiosité, j'aimerais bien comprendre pourquoi ça ne fonctionne pas en ne déclarant que le namespace Form_.

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Mes classes aussi respectent les conventions de nomage du Framework !

  14. #14
    Membre Expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    Mes classes aussi respectent les conventions de nomage du Framework !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    'path'=>'Forms', 'namespace'=>'Form'
    il y a un "s" en plus dans le chemin, non ?

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Ah, oui, pas faux, c'est MA convention particulière, tous les noms (variable, fonction, etc..) sont au singulier et au masculin, ça m'évite de me poser des questions ensuite.

    Effectivement pour les dossiers, c'est l'architecture que j'avais quand j'ai débuté avec Zend et je l'ai gardé ^^

  16. #16
    Membre Expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    Ah, oui, pas faux, c'est MA convention particulière, tous les noms (variable, fonction, etc..) sont au singulier et au masculin, ça m'évite de me poser des questions ensuite.

    Effectivement pour les dossiers, c'est l'architecture que j'avais quand j'ai débuté avec Zend et je l'ai gardé ^^
    Et sauf erreur de ma part (ce qui est loin d'être impossible, surtout avec ce nouveau composant), c'est pour cela que tu es obligé d'utiliser une ressource. Sinon, tu aurais pu te contenter de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $autoloader->registerNamespace('Form_');
    avec le répertoire parant dans l'include_path de PHP...

    Personnellement, au passage en 1.8, c'est ce que j'ai fait : j'ai préfixé mes modèles, et j'ai simpelment utilisé registerNamespace('Prefixe_')...

  17. #17
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut
    Bon j'essaye de recadrer mon soucis.

    Avant la 1.8, j'avais dans mes modèles un accès aux données via un simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $db = new Spaces();
    Or depuis que je suis passé à la 1.8, il ne me reconnais plus mes classes se trouvant dans mon répertoire /app/models

    J'ai beau renommer, ajouter dans les namespaces et tout le toutim je n'arrive pas à instancier une classe de mes modèles.

    La seule façon où j'obtiens un résultat c'est de déplacer les classes dans une répertoire /library/Models et de le mettre dans le namespace et ça roule, mais bon c'est pas l'idéale.


    de plus, je ne sais pas si cela à de l'importance, mais mes méthodes dans mes classes modèles sont toutes faite d'une requêtes SQL lancer par fetchAll comme par exemple celle-ci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
       public function bigTablespace()
    	{
    		$sql = "
    WITH
    TABLESPACES (INSTANCE,DATABASE,TABLESPACE,TABLESPACE_TYPE,CONTENT_TYPE,PAGESIZE,USED_SPACE) AS
    ( SELECT
            DAT.T_INSTANCE_NAME AS INSTANCE,
            DAT.T_NAME AS DATABASE,
            TBLS.T_NAME AS TABLESPACE ,
            TBLS.T_I_TBSPACETYPE as TABLESPACE_TYPE,
            case TBLS.T_I_CONTENT_TYPE WHEN 'ANY' THEN 'REGULAR' ELSE TBLS.T_I_CONTENT_TYPE END as CONTENT_TYPE,
            TBLS.N_I_PAGESIZE AS PAGESIZE,
            TBLSU.N_I_MAX_USED_SIZE_GBYTES AS USED_SPACE
                    FROM RDC.DATABASE AS DAT
                            INNER JOIN RDC.TABLESPACE AS TBLS
                                    ON DAT.O_ID = TBLS.O_DATABASE_ID
                            INNER JOIN RDC.TABLESPACE_USAGE AS TBLSU
                                    ON TBLS.O_ID = TBLSU.O_TABLESPACE_ID
            WHERE TBLSU.S_I_INSERT_TIMESTAMP =      (
                                                      SELECT MAX(S_I_INSERT_TIMESTAMP)
                                                      FROM RDC.TABLE_USAGE
                                                    )
            AND TBLSU.N_I_MAX_USED_SIZE_GBYTES <> 0
            AND TBLS.T_I_TBSPACETYPE = 'DMS' )
    ,
    LIMITS (TABLESPACE_TYPE,PAGESIZE,CONTENT_TYPE,MAX_SPACE) AS
    (  VALUES ('DMS',4096,'REGULAR',64),
              ('DMS',8192,'REGULAR',128),
              ('DMS',16384,'REGULAR',256),
              ('DMS',32768,'REGULAR',512),
              ('DMS',4096,'LARGE',2048),
              ('DMS',8192,'LARGE',4096),
              ('DMS',16384,'LARGE',8192),
              ('DMS',32768,'LARGE',16384) )
     
    SELECT A.INSTANCE,
           A.DATABASE,
           A.TABLESPACE,
           A.TABLESPACE_TYPE,
           A.CONTENT_TYPE,
           A.PAGESIZE,
           A.USED_SPACE,
           B.MAX_SPACE,
           (A.USED_SPACE*100)/B.MAX_SPACE as PCT_USED
      FROM TABLESPACES A,
           LIMITS B
     WHERE A.TABLESPACE_TYPE = B.TABLESPACE_TYPE
       AND A.PAGESIZE = B.PAGESIZE
       AND A.CONTENT_TYPE = B.CONTENT_TYPE
       AND A.USED_SPACE > 0.5*B.MAX_SPACE
     ORDER BY PCT_USED DESC, A.PAGESIZE
     
    		";
     
    		return $this->_db->fetchAll($sql);
    	}
    Merci de votre aide pour la démarche .

  18. #18
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Montre-nous tes essais !!
    Donne un exemple de classe (en fait c'est le nom qui est important), le chemin de cette classe dans ton répertoire models, et ta déclaration dans le bootstrap.

    Si tu ne donne pas ton cas concret on peut pas t'aider plus que ça :/

  19. #19
    Modérateur

    Avatar de MaitrePylos
    Homme Profil pro
    DBA
    Inscrit en
    Juin 2005
    Messages
    5 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : DBA
    Secteur : Service public

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 506
    Par défaut
    Ma classe /app/models/Spaces.php

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    class Spaces extends GeneralDb {
     
        public function  __construct($fileMng=null,$envi=null) {
            parent::__construct($fileMng,$envi);
        }
     
        public function getServeur()
        {
            $sql = "
            SELECT DISTINCT (T_NAME)
              FROM RDC.SERVER
              WHERE T_I_DELETED = 'N'";
            return $this->_db->fetchAll($sql);
        }
    ma classe controller

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
     */
    class SpacesController extends Zend_Controller_Action {
     
     
        public function filesystemSpaceAction(){
            $db = new Spaces(My_Session::getData('database'));
            if(($serveur = $this->_cache->load('space_serveur'))==false){
                $serveur = $db->getServeur();
                $this->_cache->save($serveur, 'space_serveur');
     
            }
            $this->view->display = 1;
            $this->view->serveur = $serveur;
        }
    Avant en faisant comme ceci c'étais nickel, maintenant plus rien ne fonctionne.

    Comment faire ?

  20. #20
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $autoloader->registerNamespace('My_');
    // La classe se nomme : My_Spaces
    // Le fichier est /app/models/Spaces.php
     
    // Appel de la classe
    $foo = new My_Spaces();

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Passage du Model relationnel(Entité-Relation) Vers un model dimensionnel (DW)
    Par Koko7a dans le forum Conception/Modélisation
    Réponses: 9
    Dernier message: 01/07/2016, 23h00
  2. récupérer une variable de 'Model' vers 'Controller'
    Par salmoucha dans le forum Zend Framework
    Réponses: 4
    Dernier message: 08/04/2008, 15h56
  3. [ORM] Objet Role Modeling vers modèle relationnel.
    Par Asuki dans le forum Schéma
    Réponses: 3
    Dernier message: 21/03/2008, 00h27
  4. [Entité-Association] passage du modéle entité association vers le modele relationnel
    Par hunter99 dans le forum Schéma
    Réponses: 1
    Dernier message: 24/11/2007, 13h10
  5. access export etat vers un modele de document word
    Par dougzacker dans le forum Access
    Réponses: 6
    Dernier message: 07/03/2006, 02h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo