Ok, je vais les consulter et vous revenir après. Merci !
En visitant les liens, on m'a fait savoir que c'est le composant "symfony/doctrine-bridge" qui manquait. Je l'ai donc ajouter à composer et mis à jour celui-ci. Ainsi, le message d'erreur a changé pour devenir ceci :
Cela fait déjà quelques jours que je peine à réaliser mon premier dévoir.
En effet, je suis sur la partie modélisation. Après modifications nécessaires, j'ai ce message lorsque je lance l'application "la connexion à la bdd a été réinitialisé".
Voici mon POPO:
<?php
namespace OC_MyBooks\Domain;
class Book
{
/**
* Book id.
* @var integer
*/
private $_id;
/**
* Book title.
* @var string
*/
private $_title;
/**
* Book isbn.
* @var string
*/
private $_isbn;
/**
* Book summary.
* @var string
*/
private $_summary;
/**
* Associated author.
* @var \OC-MyBooks\Domain\Author.php
*/
private $_author;
public function id ()
{
return $this->id;
}
public function setId ($id)
{
$id = (int) $id;
if ($id > 0)
{
$this->_id = $id;
}
}
public function title ()
{
return $this->title;
}
public function setTitle ($title)
{
$this->_title = $title;
}
public function isbn ()
{
return $this->isbn;
}
public function setIsbn ($isbn)
{
$this->_isbn = $isbn;
}
public function summary ()
{
return $this->summary;
}
public function setSummary ($summary)
{
$this->_summary = $summary;
}
public function author ()
{
return $this->author;
}
public function setAuthor (Author $author)
{
$this->_author = $author;
}
}
Et la classe d'accès à la bdd (hérité de DAO.php)
<?php
namespace OC_MyBooks\DAO;
use Doctrine\DBAL\Connection;
use OC_MyBooks\Domain\Book;
class BookDAO extends DAO
{
/**
* @var \OC-MyBooks\DAO\AuthorDAO
*
private $authorDAO;
public function (AuthorDAO $authorDAO)
{
$this->authorDAO = $authorDAO;
}
/**
* Return a list of all books for an author, sorted by book_title.
*
* @param integer $authorId The author id.
*
* @return array A list of all books for the author.
*/
/**
* Retrun a list of all books, sorted by book_title.
* @return array A list of all books
*/
public function findAll ()
{
$sql = "SELECT * FROM book ORDER BY book_title ASC";
$result = $this->db()->fetchAll($sql);
// Convert query result to array of domain ojects
$books = array();
foreach ($result as $row)
{
$bookId = $row['book_id'];
$books['$bookId'] = $this->buildObjectDomain($row);
}
return $books;
}
/**
/* Return a book matching the supplied id
* @param integer $id
* @return \OC-MyBooks\Domain\Book|throws an exception if no matching author is found
*/
public function find($id)
{
$sql = "SELECT * FROM book WHERE book_id = ?";
$row = $this->db()->fetchAssoc($sql, array($id));
if ($row)
return $this->buildDomainObject($row);
else
throw new \Exception("No book matching id " . $id);
}
/**
* Creates an Author object based on a DB row.
*
* @param array $row The DB row containing Author data.
* @return \OC-MyBooks\Domain\Author
*/
protected function buildDomainObject(array $row) {
$book = new Book();
$book->setId($row['book_id']);
$book->setTitle($row['book_title']);
$book->setIsbn($row['book_isbn']);
$book->setSummary($row['book_summary']);
// $book->setAuthor($row['auth_id']);
return $book;
}
}
Composer est bien à jour. Le fichier de paramétrage contient le code suivant:
<?php
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
// Register global error and exception handlers
ErrorHandler::register();
ExceptionHandler::register();
// Register service providers.
$app->register(new Silex\Provider\DoctrineServiceProvider());
// Register services.
$app['dao.book'] = function ($app) {
return new OC_MyBooks\DAO\BookDAO($app['db']);
};
Le fichier de production est bien correct. Le contrôleur est le suivant
<?php
// Home page
$app->get('/', function () use ($app) {
$books = $app['dao.book']->findAll();
ob_start(); // start buffering HTML output
require '../views/view.php';
$view = ob_get_clean(); // assign HTML output to $view
return $view;
});
La vue générée est la suivante
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="book.css">
<title>Mybooks</title>
</head>
<body>
<header><h1>Mybooks</h1></header>
<?php foreach ($books as $book): ?>
<article class="container">
<h2>
<?php echo $book->title() ?>
</h2>
<p><?php echo $book->summary() ?></p>
</article>
<?php endforeach ?>
<footer class="footer">Mybooks est construit avec PHP, Silex, Twig et Boostrap</footer>
</body>
</html>
J'avais déjà résolu cette étape. Le seul souci que j'ai actuellement c'est que l'appli n'affiche qu'un article et pas dans l'ordre que je veux. Ca me parait étrange. Je m'explique: dans ma classe BookDAO j'ai une méthode findAll() dont voici le contenu:
public function findAll ()
{
$sql = "SELECT * FROM book ORDER BY book_title DESC";
$result = $this->db()->fetchAll($sql);
// Convert query result to array of domain ojects
$books = array();
foreach ($result as $row)
{
$bookId = $row['book_id'];
$books['$bookId'] = $this->buildDomainObject($row);
}
return $books;
}
En faisant une boucle dans ma vue (avec Twig) je n'ai qu'un livre d'afficher.
{% for book in books %}
<article class="container">
<h2>
{{book.title}}
</h2>
<p>{{book.summary}}</p>
<p>L'id de cet book est: {{book.id}}</p>
</article>
{% endfor %}
Ici c'est le 1er livre qui s'affiche. Si dans la requette SQL je mets ASC c'est le 3è livre qui s'affiche. Je ne comprends pas pourquoi ça ne boucle pas comme je le souhaite.
ps: est-il possible d'importer un dossier vendor sur un autre projet. Quand on a p.ex coupure d'internet?
En réalisant le premier devoir; je me rends vite compte qu'il y a un point que je n'avait pas bien maitrisé quand je lisais le cours. D'où ma présence encore sur ce forum.
A l'itération 7: comment retrouve-t-on la valeur de $articleId?
public function findAllByArticle($articleId) {
// The associated article is retrieved only once
$article = $this->articleDAO->find($articleId);
//...
}
Et pourquoi n'est pas le sélectionné directement en bdd?
Je joue avec silex, à partir de la solution donnée dans ce cours. En restant strictement scotché au cours et en glissant mon appli dans celle qui est proposée : article -> compte, commentaire -> ecriture, ça fonctionne à merveille, je me familiarise avec l'objet, avec mvc et avec silex-twig, mais j'ai du mal à aller plus loin. Un exemple : J'ai un formulaire 'ecriture' ('commentaire' dans le cours) qui fonctionne parfaitement. (il est plus indépendant que le 'commentaire' du cours comme si on peut choisir l'article auquel rattacher le commentaire) il contient un champ de saisie idcompte (identifiant du 'compte' à laquelle appartient l'écriture, c'est un champ de la table 'ecriture') je voudrais remplacer ce champ 'input' par une liste déroulante dont les valeurs sont issues de la table compte (champs : id, denomination) pour obtenir le code HTML <option value="id">denomination</option> J'ai ajouté le code d'extration des données dans le controleur public function addEcritureAction($id, Request $request, Application $app) {
$comptes = $app['dao.compte']->findAll(); //extraction liste des comptes
$ecriture = new Ecriture(); $ecritureForm = $app['form.factory']->create(EcritureType::class, $ecriture); $ecritureForm->handleRequest($request); ... return $app['twig']->render('ecriture_form.html.twig', array( 'title' => 'Nouvelle ecriture', 'ecritureForm' => $ecritureForm->createView())); } mais comment transmettre $comptes à la form ? si je remplace le 'create' par : $ecritureForm = $app['form.factory']->create(new EcritureType('$comptes'), $ecriture); * ca génère une erreur Expected argument of type \"string\" dans ...vendor\\symfony\\form\\FormFactory.php:64
quelqu'un peut me mettre sur la bonne piste ?
Merci !
* l'idée est prise dans https://gist.github.com/bpesquet/a27232767712c72406c1, mais je n'ai pas tout compris dans ce code.
create-project Create new project from a package into given directory.
depends Shows which packages cause the given package to be installed.
diagnose Diagnoses the system to identify common errors.
dump-autoload Dumps the autoloader.
dumpautoload Dumps the autoloader.
exec Execute a vendored binary/script.
global Allows running commands in the global composer dir ($COMPOSER_HOME).
help Displays help for a command
home Opens the package's repository URL or homepage in your browser.
info Show information about packages.
init Creates a basic composer.json file in current directory.
install Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
licenses Show information about licenses of dependencies.
list Lists commands
outdated Shows a list of installed packages that have updates available, including their latest version.
prohibits Shows which packages prevent the given package from being installed.
remove Removes a package from the require or require-dev.
require Adds required packages to your composer.json and installs them.
run-script Run the scripts defined in composer.json.
search Search for packages.
self-update Updates composer.phar to the latest version.
selfupdate Updates composer.phar to the latest version.
show Show information about packages.
status Show a list of locally modified packages.
suggests Show package suggestions.
update Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.
validate Validates a composer.json and composer.lock.
why Shows which packages cause the given package to be installed.
why-not Shows which packages prevent the given package from being installed.
C'est ensuite que je suis bloqué, impossible de récupérer Silex via composer. "composer install" ne fonctionne pas j'ai un message d'erreur "-bash: composer: command not found".
create-project Create new project from a package into given directory.
depends Shows which packages cause the given package to be installed.
diagnose Diagnoses the system to identify common errors.
dump-autoload Dumps the autoloader.
dumpautoload Dumps the autoloader.
exec Execute a vendored binary/script.
global Allows running commands in the global composer dir ($COMPOSER_HOME).
help Displays help for a command
home Opens the package's repository URL or homepage in your browser.
info Show information about packages.
init Creates a basic composer.json file in current directory.
install Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
licenses Show information about licenses of dependencies.
list Lists commands
outdated Shows a list of installed packages that have updates available, including their latest version.
prohibits Shows which packages prevent the given package from being installed.
remove Removes a package from the require or require-dev.
require Adds required packages to your composer.json and installs them.
run-script Run the scripts defined in composer.json.
search Search for packages.
self-update Updates composer.phar to the latest version.
selfupdate Updates composer.phar to the latest version.
show Show information about packages.
status Show a list of locally modified packages.
suggests Show package suggestions.
update Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.
validate Validates a composer.json and composer.lock.
why Shows which packages cause the given package to be installed.
why-not Shows which packages prevent the given package from being installed.
C'est ensuite que je suis bloqué, impossible de récupérer Silex via composer. "composer install" ne fonctionne pas j'ai un message d'erreur "-bash: composer: command not found".
[2017-04-06 11:58:46] MicroCMS.CRITICAL: Symfony\Component\Form\Exception\UnexpectedTypeException: Expected argument of type "string", "MicroCMS\Form\Type\CommentType" given
Dans la doc de PHP (http://php.net/manual/fr/language.oop5.basic.php) on peut lire :
Depuis PHP 5.5, le mot clé class est également utilisé pour la résolution des noms de classes. Vous pouvez récupérer une chaîne contenant le nom qualifié complet de la classe ClassName en utilisant ClassName::class. C'est particulièrement pratique avec les classes utilisant desespaces de noms.
La valeur retournée est de type string. Et c'est ce que demande la méthode create comme premier paramètre.
Dans ton deuxième code, c'est un objet de cette classe qui est passé en paramètre, et ce n'est pas le bon type.
en fait la fonction demande à ce qu'on lui indique la structure de la classe, il faut donc lui envoyer la définition.
Si tu envoies un "new Classname()", tu crées une nouvelle instance et tu passes la référence de cette instance, un pointeur vers l'endroit où se trouve l'objet créé en mémoire, ce qui n'est pas ce dont a besoin la fonction.
C'est une erreur très commune chez les aspirants développeurs objet de confondre classe et instance de classe. La classe doit être vue comme un plan permettant de fabriquer des objets. L'instance est l'objet créé à partir du plan. Donc la classe c'est juste un ensemble de définitions et l'instance c'est l'objet manipulable, transformable. Comme chez Ike@, t'as la notice et puis t'as le meuble
Admettons que je préfère extraire les données d'une table au lieu de les coder "en dur" Comment faire passer ces données du controller à l'objet UserType.php ?
J'ai pensé qu'il fallait intervenir dans le controleur AdminController et au niveau de l'appel de UserType $userForm = $app['form.factory']->create(UserType::class, $user); Or puisque la méthode create n'accepte qu'une chaine (et qui en l'occurrence vaut "MicroCMS\Form\Type\UserType", j'ai vérifié, mais merci pour ta réponse dblbass)
C'est pour ça que j'essayais de lui passer un objet par exemple $roles = $app['dao.user']->findAll();
Bonjour, juste pour signaler que le lien vers l'application en ligne sur la correction de l'exercice itération 13 pointe en fait sur le site de l'exercice 1... juste pour info. D'autre part, ne fallait-il pas rajouter un "custom encoder" dans le dernier exercice ? Sinon les mots de passe ne passent pas le login (ils sont encodés par Digest apparemment). Merci
- Edité par CorinnePoullette 10 avril 2017 à 21:54:16
Merci pour votre réponse que j'ai consultée, en effet, il s'agit d'un problème de version, ce dont je me suis doutée. J'ai personnellement déclaré l'encodeur Digest dans app.php, ce qui m'a permit de régler le problème d'authentification.
En tout cas, un grand merci pour ce cours qui a été très enrichissant et qui m'a permit de découvrir Silex.
Excellent Mooc !
- Edité par CorinnePoullette 11 avril 2017 à 16:55:18
Bonjour, j'ai une erreur apres avoir suivi le cours https://openclassrooms.com/…/iteration-9-ajout-de-commentai…, l'erreur arrive des qu'il y a connection et des qu'on se dirige sur la page article. Quand il n'y a pas de connection, aucune erreur en naviguant.
l'erreur => Twig_Error_Runtime in form_div_layout.html.twig line 321: Variable "read_only" does not exist.
Eventuellement 15 Ko, mais les 10 premières lignes suffiront.
Selon ton message, il s'est planté dans form_div_layout.html.twig à la ligne 321.
Ce script se trouve dans .../vendor/symphony/twig-bridge/Resources/views.
A la ligne 321, on traite les attributs des widgets.
Logiquement, dans la liste des fichiers / pile d'appel apparaissant dans le message d'erreur, recherche le premier qui correspond à ton fichier (au hasard article.html.twig)
Je prends le pari que cela correspond à un appel de form_widget, dans lequel tu (quelqu'un) as placé l'attribut read_only sans le mettre en 'apostrophe'. Du coup twig considère que c'est une variable, qu'il ne trouve pas.
Admettons que je préfère extraire les données d'une table au lieu de les coder "en dur" Comment faire passer ces données du controller à l'objet UserType.php ?
J'ai pensé qu'il fallait intervenir dans le controleur AdminController et au niveau de l'appel de UserType $userForm = $app['form.factory']->create(UserType::class, $user); Or puisque la méthode create n'accepte qu'une chaine (et qui en l'occurrence vaut "MicroCMS\Form\Type\UserType", j'ai vérifié, mais merci pour ta réponse dblbass)
C'est pour ça que j'essayais de lui passer un objet par exemple $roles = $app['dao.user']->findAll();
mais alors, comment passer cet objet à UserType ?
Bon week end
Eric
Bonjour Eric,
Pour faire appelle à des roles qui sont placé dans une table, il faut utiliser les sous formulaires.
donc un formulaire RoleType inclue dans le formulaire UserType.
{% extends "layout.html.twig" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<p>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<h3>Commentaires</h3>
{% for comment in comments %}
<strong>{{ comment.pseudo.username }}</strong> dit : {{ comment.content }}<br>
{% else %}
Toujours pas de commentaires.
{% endfor %}
<h3>Ajoute un commentaire</h3>
{% if commentForm %}
{{ form_start(commentForm) }}
<div class="form-group">
{{ form_errors(commentForm.content) }}
{{ form_widget(commentForm.content, { 'attr': {
'rows': '4',
'class': 'form-control',
'placeholder': 'Ajouter votre commentaire'
}}) }}
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Publier commentaire" />
</div>
{{ form_end(commentForm) }}
{% for flashMessage in app.session.flashbag.get('success') %}
<div class="alert alert-success">
{{ flashMessage }}
</div>
{% endfor %}
{% else %}
<a href="{{ path('login') }} ">Connectez vous</a> pour ajouter un commentaire.
{% endif %}
</p>
{% endblock %}
je crois savoir pourquoi je ne peux pas ecrire, le moteur twig me cree le textarea avec readonly="readonly", faut que je trouve comment l enlever. => j'ai delete la ligne 321 et je peux ecrire dans le formulaire.
J'ai débuté le cours il y a quelques jours et je suis arrivé à l'itération 7.
Lorsque je veux accéder au commentaire de l'article, j'obtiens le message suivant dans mon navigateur :
"Not Found
The requested URL /MicroCMS/article/3 was not found on this server."
Je ne vois pas où est l'erreur alors que j'ai copié le code du cours. J'ai vu que certaines personnes ont eu le même souci mais je n'ai pas vu de réponse correspondante dans le fil des conversations.
Dans ma version de twig-bridge (v3.0.9), celle utilisée dans le tuto MicroCMS, la ligne correspondante (321, ici 5) est différente.
{%- block widget_attributes -%}
id="{{ id }}" name="{{ full_name }}"
{%- if disabled %} disabled="disabled"{% endif -%}
{%- if required %} required="required"{% endif -%}
{%- for attrname, attrvalue in attr -%}
{{- " " -}}
{%- if attrname in ['placeholder', 'title'] -%}
{{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}"
{%- elseif attrvalue is same as(true) -%}
{{- attrname }}="{{ attrname }}"
{%- elseif attrvalue is not same as(false) -%}
{{- attrname }}="{{ attrvalue }}"
{%- endif -%}
{%- endfor -%}
{%- endblock widget_attributes -%}
A part cela, ce n'est à mon avis pas une bonne idée de modifier le code d'une librairie installée avec composer. A la prochaine mise à jour, les modifs que tu as faites seront perdues.
Quelle version utilises-tu ?
Autre piste : qu'est-ce que tu as dans la méthode buildForm de ta classe .../src/Form/Type/XxxType.php ?
Cours Architecture PHP professionnelle / Questions
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Novioritum
Novioritum