Page 1 sur 1

MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 11:53
par caema
Bonjour à tous,

J'ai conçu un MVC en suivant le tuto du site http://www.grafikart.fr/tutoriels/index/php?page=3.
Tout fonctionne bien, j'ai réalisé le tuto jusqu'au bout.
La question que je me pose concerne la page d'accueil de mon site.
Actuellement elle est gérée comme toutes les autres pages, pourtant c'est une page un peu "spéciale": je souhaite en effet qu'elle contienne un div reprenant les dernières news.
Ces news, je les gère déjà via un controller PostsController, et une vue index.php.
En gros, j'ai donc cette arborescence:
/controller
* PagesController.php
* PostsController.php
/view
/pages
* view.php
/posts
* index.php
Mon idée de départ, c'était de mettre ceci dans view.php:
<?php 
	if ($page->id == 1){
		include_once('posts/index.php');
	}
?>
et donc d'inclure une vue, dans une autre vue.
Mais ce semble pas fonctionner puisque j'ai 2 erreurs:
Warning: include_once(posts/index.php): failed to open stream: No such file or directory in ....
Warning: include_once(): Failed opening 'posts/index.php' for inclusion (include_path='.;C:\wamp\bin\php\php5.4.16\pear;') in ...
Ma question est donc, en MVC, est-il possible d'inclure une vue dans une autre vue?
Et si non, comment raisonner pour résoudre mon problème?

D'avance merci!

Re: MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 15:36
par yann18
bonjour,

php ne peut pas trouver le fichier posts/index.php car le chemin indiqué n'est pas bon. En effet quand tu es dans le dossier pages pour inclure le fichier situé dans posts il faut sortir de posts.


dans view.php :
//pages/view.php
  if ($page->id == 1){
                include_once('../posts/index.php');
        }

ou encore dans view.php:
//pages/view.php
 if ($page->id == 1){
                include_once(dirname(__DIR__) .'/posts/index.php');
        }

Re: MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 17:38
par caema
Effectivement, en faisant ceci, ça "fonctionne" avec le dirname.
Sauf que j'ai des erreurs une fois le fichier inclus...

Le fichier que j'inclus, /posts/index.php contient ceci:
<div>
	<div class="row">
		<div class="span13">
			<div class="page-header">
				<h1><?php echo isset($title)?$title:'Le blog'; ?></h1>
			</div>
			<?php foreach ($posts as $k => $v): ?>
				<div class="clearfix">
					<h3><?php echo $v->name; ?><small>,<a href="<?php echo Router::url('posts/category/slug:'.$v->catslug); ?>"><?php echo $v->catname; ?></a></small></h3>
					<?php echo substr(strip_tags($v->content),0,300); ?>...
				</div>
				<p style="text-align:right"><a href="<?php echo Router::url("posts/view/id:{$v->id}/slug:$v->slug"); ?>">Lire la suite &rarr;</a></p>
				<p>&nbsp;</p>
			<?php endforeach ?>

			<div class="pagination">
			  <ul>
				  <?php for($i=1; $i <= $page; $i++): ?>
				    <li <?php if($i==$this->request->page) echo 'class="active"'; ?>><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
				  <?php endfor; ?>
			  </ul>
			</div>
		</div>
		<?php require('sidebar.php'); ?>
	</div>
</div>
Et j'ai les erreurs suivantes:
Undefined variable: posts et Invalid argument supplied for foreach() in... pour la ligne
<?php foreach ($posts as $k => $v): ?>
et 2 erreurs Object of class stdClass could not be converted to int in... pour cette ligne:
<?php for($i=1; $i <= $page; $i++): ?>
Voilà où j'en suis actuellement.

Je précise que si j'essaye d’accéder à ce même fichier /posts/index.php, je n'ai aucune de ces erreurs.

J'ai pas capté un truc dans la logique là je crois mais il faut que je comprenne lol, pas le choix mon projet est lancé

Re: MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 18:49
par orenx22
Bonjour,

Une bonne gestion du MVC ne se fait pas par l’intermédiaire d'include à la volé !

En gros tu devrais avoir plusieurs dossiers :

.app (pour stocker les contrôleurs et les vues)
..controller (objet avec des actions / methodes)
..view (fichier phtml)
.conf (fichier de configurations)
.lib (pour stocker les objets fonctionnels)
.data (pour stocker les éléments css, js, img, fichier relatif au design)
index.php (qui fait office de dispatcher)
.htaccess (pour géré ta réécriture d'url)

Je t'invite à te renseigner sur le VHOSTING, ce qui va te permettre de travailler en condition similaire à cette du web.

Uns fois chose fait, cela va te permettre d’utiliser un nom de domaine en local pour une bonne exploitation du module_rewrite (réécriture d'url).

Pour moi l'url dois s’écrire de cette manière :

http://www.monsite.lan/controller/action/param1/param2

Le première élément après le nom de domaine étant le contrôleur à lancer, le deuxième étant l'action (la méthode) de se même contrôleur à lancer et du reste de la requête (ici param1 & param2) doivent être transmis à l'action lancé.
Je t'invite aussi à te renseigner sur l'autoload, quasi indispensable pour les applications utilisant de nombres objets.

Pour les vues, je te fourni un objet, qui doit être configuré dans tes action d'un contrôleur lancé.

<?php

class view
{
    private $filename ;
    
    private $vars ;
    
    public function __construct( $vars = array() )
    {
        $this-> vars = $vars ;
    }
    
    public function __set( $name, $value )
    {
        $this-> vars[$name] = $value ;
    }
    
    public function __get( $name )
    {
        $result = null ;
        
        if( array_key_exists( $name, $this-> vars ) )
        {
            $result = $this-> vars[$name];
        }
        
        return $result ;
    }
    
    public function __isset( $name )
    {
        return isset( $this-> vars[$name] );
    }
    
    public function __unset( $name )
    {
        if( array_key_exists( $name, $this-> vars ) )
        {
            unset( $this-> vars[$name] );
        }
    }
    
    public function __toString()
    {
        $result = '' ;
        
        if( !is_null( $this-> filename ) )
        {
            ob_start();
            
            require $this-> filename ;
            
            $result = ob_get_contents();
            
            ob_end_clean();
        }
        
        return $result ;
    }
    
    public function load( $filename )
    {
        if( file_exists( $filename ) )
        {
            $this-> filename = $filename ;
        }
        else trigger_error( "La vue \"$filename\" est introuvable." );
    }
}
Exploitation (à faire d'une méthode / action d'un contrôleur lancé) :

<?php

define( 'PATH_ROOT', dirname( __FILE__ ) );
include_once 'view.php' ;

$pagePrincipale = new view();
$pagePrincipale-> load( PATH_ROOT.'/view/principale.phtml' );
$pagePrincipale-> title = "Accueil" ;

$pageContenu = new view();
$pageContenu-> load( PATH_ROOT.'/view/contenu.phtml' );
$pageContenu-> message = "Ceci est un message" ;

$pagePrincipale-> pageContenu = $pageContenu ;
echo $pagePrincipale ;
exit ;
ps : la constante et l'inclusion de l'objet de vue doit être fait sur l'index.php

Page principale :

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo $this-> title ?></title>
</head>
<body>
<div id="principale">
<?php echo $this-> pageContenu ?>
</div>
</body>
</html>
Page contenu :

<div id="contenu">
<span><?php echo $this-> message ?></span>
</div>
résultat :

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Accueil</title>
</head>
<body>
<div id="principale">
<div id="contenu">
<span>Ceci est un message</span>
</div>
</div>
</body>
</html>
Je connais très bien le site de graphikart, pour le tuto que tu as consulté, il faut le voir comme une ébauche d'un MVC, non pas comme tel. Il reste bcp de chose à mettre en place pour avoir quelque chose de performant et d'exploitable. Si tu souhaites construire ton propre MVC dis le moi et j'essayerai de faire un tuto vidéo de quelques heures pour pouvoir évoluer dans ce sens.

Ciao et bon courage.

Re: MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 19:12
par caema
Ouf, donc en gros, cet affichage des news en page d'accueil est la dernière chose qu'il reste à faire pour mon site, et là... je dois "tout" recommencer. Ca va être hyper chaud pour moi j'avoue, j'ai un timing serré.
Non pas que je vous en veuille lol, je suis juste dépitée là... 8-|

Je vais lire calmement votre post, voir comment je peux adapter ce que j'ai déjà à la structure que vous proposez, mais bien entendu je ne dirais pas non à un tuto.
Très dur à trouver par ailleurs un bon tuto MVC complet, tout ce que je trouve, anglais compris, c'est du MVC et ASP, mais point de php et POO... raison pour laquelle celui de grafikart est une bénédiction lol

Merci de vous donner la peine de m'aider en tout cas, c'est très aimable à vous

Re: MVC - inclure une vue dans une autre?

Posté : 14 déc. 2013, 21:05
par yann18
Je précise que si j'essaye d’accéder à ce même fichier /posts/index.php, je n'ai aucune de ces erreurs.

visiblement la variable $posts(de /posts/index.php) est construite depuis le contrôleur posts et est transmise à la vue index.php, d'où l’impossibilité de récupérer la variable $posts dans une vue autre que celle de son contrôleur/action.

De la même manière que la variable $posts a été construite dans le contrôleur $posts essaies de la construire aussi dans le contrôleur pages.Puis dans pages/view.php tu pourras aisément faire l'inclusion de posts/index.php'.

Tu peux tout autant décider la construction de la variable $posts au sein d'une méthode dans une super classe dont héritera les contrôleurs posts et pages.

Re: MVC - inclure une vue dans une autre?

Posté : 15 déc. 2013, 11:12
par caema
J'avais bien capté qu'il était impossible d’accéder à cette variable pour les raisons que vous mentionnez, mais je n'étais pas certaine de la méthode à utiliser pour résoudre le problème, c'est mon premier MVC...
Ok, et bien je vais tenter de mettre en place cette "super class" pour $posts, ça sera le plus facile pour moi je pense.

Bon, alors que ce soit pour PostsController ou PagesController, les 2 extends de Controller
Je peux donc envisager de déclarer $posts dans ce fichier Controller.php ?

Pour info, voici ce que contient mon fichier PostsController:
<?php 
class PostsController extends Controller{
	function index(){
		$perPage = 10; 
		$this->loadModel('Post');
		$condition = array('online' => 1,'type'=>'post'); 
		$d['posts'] = $this->Post->find(array(
			'conditions' => $condition,
			'fields'     => 'Post.id,Post.name,Post.slug,Post.created,Category.name as catname,Post.content,Category.slug as catslug',
			'order'      => 'created DESC',
			'limit'      => ($perPage*($this->request->page-1)).','.$perPage,
			'join'       => array('categories as Category'=>'Category.id=Post.category_id')
		));
		$d['total'] = $this->Post->findCount($condition); 
		$d['page'] = ceil($d['total'] / $perPage);
		$this->set($d);
	}

	function category($slug){
		$this->loadModel('Category'); 
		$category = $this->Category->findFirst(array(
			'conditions' => array('slug' => $slug),
			'fields'     => 'id,name'
		));
		if(empty($category)){
			$this->e404();
		}
		$perPage = 10; 
		$this->loadModel('Post');
		$condition = array('online' => 1,'type'=>'post','category_id' => $category->id); 
		$d['posts'] = $this->Post->find(array(
			'conditions' => $condition,
			'fields'     => 'Post.id,Post.name,Post.slug,Post.created,Category.name as catname,Post.content,Category.slug as catslug',
			'order'      => 'created DESC',
			'limit'      => ($perPage*($this->request->page-1)).','.$perPage,
			'join'       => array('categories as Category'=>'Category.id=Post.category_id')
		));
		$d['total'] = $this->Post->findCount($condition); 
		$d['page'] = ceil($d['total'] / $perPage);
		$d['title'] = 'Tous les articles "'.$category->name.'"'; 
		$this->set($d);
		// Le système est le même que la page index alors on rend la vue Index
		$this->render('index'); 
	}

	function view($id,$slug){
		$this->loadModel('Post');
		$d['post']  = $this->Post->findFirst(array(
			'fields'	 => 'Post.id,Post.content,Post.name,Post.slug,Category.name as catname,Category.slug as catslug',
			'conditions' => array('Post.online' => 1,'Post.id'=>$id,'Post.type'=>'post'),
			'join'		 => array('categories as Category'=>'Category.id=Post.category_id')
		)); 
		if(empty($d['post'])){
			$this->e404('Page introuvable'); 
		}
		if($slug != $d['post']->slug){
			$this->redirect("posts/view/id:$id/slug:".$d['post']->slug,301);
		}
		$this->set($d);
	}
	
	function admin_index(){
		$perPage = 10; 
		$this->loadModel('Post');
		$condition = array('type'=>'post'); 
		$d['posts'] = $this->Post->find(array(
			'fields'     => 'Post.id,Post.name,Post.online,Category.name as catname,Category.slug as catslug',
			'order' 	 => 'created DESC',
			'conditions' => $condition,
			'limit'      => ($perPage*($this->request->page-1)).','.$perPage,
			'join'		 => array('categories as Category'=>'Category.id=Post.category_id')
		));
		$d['total'] = $this->Post->findCount($condition); 
		$d['page'] = ceil($d['total'] / $perPage);
		$this->set($d);
	}

	function admin_edit($id = null){
		$this->loadModel('Post'); 
		if($id === null){
			$post = $this->Post->findFirst(array(
				'conditions' => array('online' => -1),
			));
			if(!empty($post)){
				$id = $post->id;
			}else{
				$this->Post->save(array(
					'online' => -1,
					'created' 	 => date('Y-m-d')
				));
				$id = $this->Post->id;
			} 
		}
		$d['id'] = $id; 
		if($this->request->data){
			if($this->Post->validates($this->request->data)){
				$this->request->data->type = 'post';

				$this->Post->save($this->request->data);
				$this->Session->setFlash('Le contenu a bien été modifié'); 
				$this->redirect('admin/posts/index'); 
			}else{
				$this->Session->setFlash('Merci de corriger vos informations','error'); 
			}
			
		}else{
			$this->request->data = $this->Post->findFirst(array(
				'conditions' => array('id'=>$id)
			));
		}
		$this->loadModel('Category');
		$d['categories'] = $this->Category->findList(); 
		$this->set($d);
	}

	function admin_delete($id){
		$this->loadModel('Post');
		$this->Post->delete($id);
		$this->Session->setFlash('Le contenu a bien été supprimé'); 
		$this->redirect('admin/posts/index'); 
	}

	function admin_tinymce(){
		$this->loadModel('Post');
		$this->layout = 'modal'; 
		$d['posts'] = $this->Post->find();
		$this->set($d);
	}
}
Merci de votre aide