Commit 03f502a8 authored by Sean Madsen's avatar Sean Madsen

major refactor, phase 1

* classes for Library, Book, Language, and Version
* home page using these objects now and working well
* other things still broken in the midst of refactor
parent 37863755
......@@ -4,6 +4,9 @@ parameters:
# parameter_name: value
services:
library:
class: AppBundle\Model\Library
arguments: ['%kernel.root_dir%/config/books']
book.loader:
class: AppBundle\Utils\BookLoader
arguments: ['%kernel.root_dir%/config/books']
......
<?php
//
// namespace AppBundle\Controller;
//
// use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
// use Symfony\Bundle\FrameworkBundle\Controller\Controller;
// use Symfony\Component\HttpFoundation\Request;
//
// class DefaultController extends Controller
// {
// /**
// * @Route("/", name="homepage")
// */
// public function indexAction(Request $request)
// {
// // replace this example code with whatever you need
// return $this->render('default/index.html.twig', [
// 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
// ]);
// }
// }
......@@ -6,9 +6,6 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Parser;
/**
* @TODO Make the errors that will occur if the slugs don't pass the regexp
......@@ -50,8 +47,7 @@ class PublishController extends Controller {
$processor = $this->get('github.hook.processor');
$processor->process($event, $payload);
if (!$processor->published) {
return new Response('Something went wrong during publishing.', 200);
// @TODO Add more appropriate error code
return new Response('Something went wrong during publishing.', 200); // @TODO Add more appropriate error code
}
$messages = $processor->getMessages();
$subject = $processor->getSubject();
......@@ -62,15 +58,14 @@ class PublishController extends Controller {
->setFrom('no-reply@civicrm.org')
->setTo($recipients)
->setBody(
$this->renderView(
'Emails/notify.html.twig',
array(
'branch' => $processor->publisher->branch,
'book' => $processor->publisher->book,
'lang' => $processor->publisher->lang,
'messages' => $processor->publisher->getMessages(),
)
), 'text/html'
$this->renderView('Emails/notify.html.twig',
array(
'branch' => $processor->publisher->branch,
'book' => $processor->publisher->book,
'lang' => $processor->publisher->lang,
'messages' => $processor->publisher->getMessages(),
)
), 'text/html'
);
$this->get('mailer')->send($mail);
return new Response($subject, 200);
......
......@@ -4,64 +4,17 @@ namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Intl\ResourceBundle\RegionBundle;
class ReadController extends Controller {
/**
* @Route("/{path}")
*/
public function RedirectAction($path) {
//If path is the recognised name of a book, then redirect to the
//stable path of the book, else redirect to the home page.
$k = $this->get('kernel');
$fs = $this->get('filesystem');
$bookConfigFile = $k->getRootDir() . "/config/books/{$path}.yml";
if (!$fs->exists($bookConfigFile)) {
return $this->redirect("/");
}
return $this->redirect("{$path}/en/stable");
}
// $k = $this->get('kernel');
// if(substr( $path, -1)=='/'){
// return new Response(file_get_contents($k->getCacheDir()."/{$path}index.html"));
// }else{
// return new Response(file_get_contents($k->getCacheDir()."/$path"));
// }
// //return $this->render('AppBundle:Read:read.html.twig');
/**
* @Route("/")
*/
public function HomeAction() {
$k = $this->get('kernel');
// This seems like a kind of hacky way to find the locales, but not
// sure what a better way would be.
$locales = json_decode(file_get_contents(
$k->getRootDir()
. '/../vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales/en.json'
), TRUE);
$finder = new Finder();
$yaml = new Parser();
$books = $this->get('book.loader')->find();
return $this->render('AppBundle:Read:home.html.twig', array(
'books' => $books,
'locales' => $locales['Names'])
return $this->render(
'AppBundle:Read:home.html.twig',
array('library' => $this->get('library'))
);
}
// $k = $this->get('kernel');
// if(substr( $path, -1)=='/'){
// return new Response(file_get_contents($k->getCacheDir()."/{$path}index.html"));
// }else{
// return new Response(file_get_contents($k->getCacheDir()."/$path"));
// }
// //return $this->render('AppBundle:Read:read.html.twig');
}
<?php
namespace AppBundle\Model;
use Symfony\Component\Yaml\Parser;
class Book {
/**
* @var string $shortName The reference identifier for this book, taken from
* the name of the book's .yml file.
*/
public $slug;
/**
* @var string $fullName The title of the book, taken from the "name"
* attribute in the book's .yml file.
*/
public $name;
/**
* @var string $description Description of the book taken from the
* "description" attribute in the book's .yml file
* and displayed on the home page.
*/
public $description;
/**
* @var array $languages An array (without keys of Language objects to
* represent the available languages for the book.
*/
public $languages;
/**
*
* @var int $weight Used to sort books
*/
public $weight;
/**
* Creates a book based on a yaml conf file
*
* @param string $confFile The path to the yaml configuration file which
* defines the attributes of the book.
*/
public function __construct($confFile) {
$parser = new Parser();
$yaml = $parser->parse(file_get_contents($confFile));
$this->slug = basename($confFile, '.yml');
$this->name = $yaml['name'];
$this->weight = isset($yaml['weight']) ? $yaml['weight'] : 0;
$this->description = isset($yaml['description']) ? $yaml['description'] : "";
foreach ($yaml['langs'] as $code => $languageData) {
$this->languages[] = new Language($code, $languageData);
}
}
/**
* @return bool True when the book contains multiple languages.
*/
public function isMultiLanguage(){
return count($this->languages) > 1;
}
}
<?php
namespace AppBundle\Model;
class Language {
/**
* @var string $LOCALES_DIR the path to the symfony directory containing
* locale information in the form of json files.
* TODO: is there a better way to determine this
* path?
*/
const LOCALES_DIR = '../vendor/symfony/symfony/src/Symfony/Component/Intl/Resources/data/locales';
/**
*
* @var string $repo The URL to the git repository for this language
*/
public $repo;
/**
*
* @var array $versions An array (without keys) of Version objects
*/
public $versions;
/**
*
* @var string $code The two letter language code for this language as
* specified by https://en.wikipedia.org/wiki/ISO_639-1
*/
public $code;
/**
*
* @param string $code two letter language code
* @param array $yaml language data from a book's yaml file
*/
public function __construct($code, $yaml) {
$this->code = $code;
$this->repo = $yaml['repo'];
$latestBranch = isset($yaml['latest']) ? $yaml['latest'] : NULL;
$stableBranch = isset($yaml['stable']) ? $yaml['stable'] : NULL;
if ($latestBranch) {
$this->versions[] = new Version('latest', $latestBranch);
}
if ($stableBranch != $latestBranch) {
$this->versions[] = new Version('stable', $stableBranch);
}
$history = isset($yaml['history']) ? $yaml['history'] : array();
foreach ($history as $item) {
$this->versions[] = new Version($item);
}
}
/**
* Returns the name of a language, in another language. For example, if
* $languageCode = 'en' and $localeCode = 'es' this function would answer the
* question "what word do Spanish-speaking people use to refer to English?"
*
* @param type $languageCode The language we're asking about
* @param type $localeCode The language in which we want our answer
*
* @return string
*/
private static function getLaguageNameInLocale($languageCode, $localeCode) {
$localesFiles = self::LOCALES_DIR . "/$localeCode.json";
$locales = json_decode(file_get_contents($localesFiles), TRUE);
return $locales['Names'][$languageCode];
}
/**
* The name of the language, in English (e.g. "Spanish")
*
* @return string
*/
public function englishName() {
return $this::getLaguageNameInLocale($this->code, 'en');
}
/**
* The native name of the language, in the language (e.g. "Español")
*
* @return string
*/
public function nativeName() {
return $this::getLaguageNameInLocale($this->code, $this->code);
}
public function descriptiveName() {
if($this->code == 'en') {
return $this->englishName();
}
else {
return $this->nativeName() . " (" . $this->englishName() . ")";
}
}
/**
* True when this language contains multiple distinct versions.
*
* @return bool
*/
public function isMultiVersion() {
return count($this->versions) > 1;
}
}
<?php
namespace AppBundle\Model;
use Symfony\Component\Finder\Finder;
class Library {
/**
*
* @var array $books An array (without keys) of Book objects to represent all
* the books in the system.
*/
public $books;
/**
* Build a new Library based on a directory of book conf files.
*
* @param type $configDir
*/
public function __construct($configDir) {
$finder = new Finder();
$files = $finder->in($configDir)->name("*.yml");
foreach ($files as $file) {
$book = new Book($file);
$this->books[] = $book;
}
$this->sortBooks();
}
/**
* Compares 2 books, side by side, for the purpose of sorting an array of
* books with uasort()
*
* @param Book $a
* @param Book $b
* @return int - Negative when $a comes before $b.
* Zero when $a and $b have identical sort orders.
* Positive when $b comes before $a.
*/
public static function compareBooksBySortOrder($a, $b) {
$weightDiff = $a->weight - $b->weight;
return ($weightDiff != 0) ? $weightDiff : strnatcmp($a->name, $b->name);
}
/**
* Modifies $this->books by sorting the array of books correctly
*/
private function sortBooks() {
if (isset($this->books)) {
uasort($this->books, ['self', 'compareBooksBySortOrder']);
}
}
}
<?php
namespace AppBundle\Model;
/**
* Description of Version
*
*/
class Version {
/**
*
* @var string $name Version name (e.g. "4.6" or "latest"). This is what
* readers see. Sometimes it's the same as name of the
* branch, but not always.
*/
public $name;
/**
*
* @var string $branch The git branch that corresponds to this version
* (e.g. "master" or "4.6"). Sometimes it's the same as
* $name but not always.
*/
public $branch;
/**
*
* @var array $aliases An array (without keys) of strings which represent
* aliases to this version of the book. For each alias,
* we will create symbolic links so that a reader can also
* access this version of the book at a URL with that
* alias.
*/
public $aliases;
public function __construct($name, $branch = NULL, $aliases = array()) {
$this->name = $name;
$this->branch = $branch ?: $name;
$this->aliases = $aliases;
}
}
<ul class="books">
{% for short_name, book in books %}
{% for book in library.books %}
<li class="book">
<span class="name">
{% if book.is_multi_stable_lang or
book.stable_langs|first.is_multi_version %}
{% if book.isMultiLanguage or book.languages|first.isMultiVersion %}
{{ book.name }}
{% else %}
{% set lang = book.langs|keys|first %}
{% set url = "/" ~ short_name ~ "/" ~ lang ~ "/latest" %}
{% set language = book.languages|first %}
{% set url = "/" ~ book.slug ~ "/" ~ language.code ~ "/latest" %}
<a href="{{ url }}">{{ book.name }}</a>
{% endif %}
</span>
<span class="separator">&ndash;</span>
<span class="description">{{ book.description }}</span>
{% if book.is_multi_stable_lang %}
{% if book.isMultiLanguage %}
{% include 'AppBundle:Read:language_list.html.twig' %}
{% elseif book.stable_langs|first.is_multi_version %}
{% elseif book.languages|first.isMultiVersion %}
{% include 'AppBundle:Read:version_list.html.twig'
with {
language: book.stable_langs|first,
lang_code: book.stable_langs|keys|first
} %}
with {language: book.languages|first} %}
{% endif %}
</li>
{% endfor %}
......
<ul class="languages">
{% for lang_code, language in book.stable_langs %}
<li class="language {{ lang_code }}">
{% set language_name = attribute(locales, lang_code) %}
{% for language in book.languages %}
<li class="language {{ language.code }}">
{% spaceless %}
<span class="language-name">
{% if language.is_multi_version %}
{{- language_name -}}
{% if language.isMultiVersion %}
{{- language.descriptiveName -}}
<span class="separator">:</span>
{% else %}
{% set url = "/" ~ short_name ~ "/" ~ lang_code ~ "/latest" %}
{% set url = "/" ~ book.slug ~ "/" ~ language.code ~ "/latest" %}
<a href="{{ url }}">
{{- language_name -}}
{{- language.descriptiveName -}}
</a>
{% endif %}
</span>
{% endspaceless %}
{% if language.is_multi_version %}
{% if language.isMultiVersion %}
{% include 'AppBundle:Read:version_list.html.twig' %}
{% endif %}
</li>
......
{% for version_key, version_branch in language.distinct_versions %}
{% for version in language.versions %}
<ul class="versions">
<li class="version">
{% set url = "/" ~ short_name ~ "/" ~ lang_code ~ "/" ~ version_key %}
<a href="{{ url }}">{{ version_key }} version</a>
{% set url = "/" ~ book.slug ~ "/" ~ language.code ~ "/" ~ version.name %}
<a href="{{ url }}">{{ version.name }} version</a>
</li>
</ul>
{% endfor %}
\ No newline at end of file
......@@ -32,23 +32,23 @@ class BookLoader {
* @param array $bookB
* @return int
*/
private function compareBooksBySortOrder($bookA, $bookB) {
$aWeight = isset($bookA['weight']) ? $bookA['weight'] : 0;
$bWeight = isset($bookB['weight']) ? $bookB['weight'] : 0;
if ($aWeight == $bWeight) {
return strnatcmp($bookA['name'], $bookB['name']);
}
return $aWeight - $bWeight;
}
// private function compareBooksBySortOrder($bookA, $bookB) {
// $aWeight = isset($bookA['weight']) ? $bookA['weight'] : 0;
// $bWeight = isset($bookB['weight']) ? $bookB['weight'] : 0;
// if ($aWeight == $bWeight) {
// return strnatcmp($bookA['name'], $bookB['name']);
// }
// return $aWeight - $bWeight;
// }
/**
* Modifies the internal book cache by sorting the array of books correctly
*/
private function cacheSort() {
if (isset($this->cache)) {
uasort($this->cache, [$this, 'compareBooksBySortOrder']);
}
}
// private function cacheSort() {
// if (isset($this->cache)) {
// uasort($this->cache, [$this, 'compareBooksBySortOrder']);
// }
// }
/**
* Modifies the book passed in by inserting new elements into the book's
......@@ -57,13 +57,13 @@ class BookLoader {
*
* @param array &$book an array of properties which represent a book
*/
private function addStatsToBook(&$book) {
$this->addToBookDistinctVersions($book);
$this->addToBookIsMultiVersion($book);
$this->addToBookIsMultiLang($book);
$this->addToBookStableLangs($book);
$this->addtoBookIsMultiStableLang($book);
}
// private function addStatsToBook(&$book) {
// $this->addToBookDistinctVersions($book);
// $this->addToBookIsMultiVersion($book);
// $this->addToBookIsMultiLang($book);
// $this->addToBookStableLangs($book);
// $this->addtoBookIsMultiStableLang($book);
// }
/**
* Adds 'distinct_versions' element to a book which lists all the distinct
......@@ -73,20 +73,20 @@ class BookLoader {
* @param array &$book an array of properties which represent a book
*
*/
private function addToBookDistinctVersions(&$book) {
foreach ($book['langs'] as &$lang) {
$lang['distinct_versions']['latest'] = $lang['latest'];
if (isset($lang['stable']) && $lang['stable'] != $lang['latest']) {
$lang['distinct_versions']['stable'] = $lang['stable'];
}
if (isset($lang['history'])) {
foreach ($lang['history'] as $version) {
$key = (string) $version;
$lang['distinct_versions'][$key] = $version;
}
}
}
}
// private function addToBookDistinctVersions(&$book) {
// foreach ($book['langs'] as &$lang) {
// $lang['distinct_versions']['latest'] = $lang['latest'];
// if (isset($lang['stable']) && $lang['stable'] != $lang['latest']) {
// $lang['distinct_versions']['stable'] = $lang['stable'];
// }
// if (isset($lang['history'])) {
// foreach ($lang['history'] as $version) {
// $key = (string) $version;
// $lang['distinct_versions'][$key] = $version;
// }
// }
// }
// }
/**
* Adds 'is_multi_version' to all language elements of a book to say
......@@ -95,11 +95,11 @@ class BookLoader {
*
* @param array &$book an array of properties which represent a book
*/
private function addToBookIsMultiVersion(&$book) {
foreach ($book['langs'] as &$lang) {
$lang['is_multi_version'] = count($lang['distinct_versions']) > 1 ? 1 : 0;
}
}
// private function addToBookIsMultiVersion(&$book) {
// foreach ($book['langs'] as &$lang) {
// $lang['is_multi_version'] = count($lang['distinct_versions']) > 1 ? 1 : 0;
// }
// }
/**
* Adds 'is_multi_lang' element to a book to say whether the book has
......@@ -107,9 +107,9 @@ class BookLoader {
*
* @param array &$book an array of properties which represent a book
*/
private function addToBookIsMultiLang(&$book) {
$book['is_multi_lang'] = count($book['langs']) > 1 ? 1 : 0;
}
// private function addToBookIsMultiLang(&$book) {
// $book['is_multi_lang'] = count($book['langs']) > 1 ? 1 : 0;
// }
/**
* Adds 'stable_langs' element to a book -- an array of all the languages
......@@ -117,13 +117,13 @@ class BookLoader {
*
* @param array &$book an array of properties which represent a book
*/
private function addToBookStableLangs(&$book) {
foreach ($book['langs'] as $lang => $language) {
if (isset($language['stable'])) {
$book['stable_langs'][$lang] = $language;
}
}
}
// private function addToBookStableLangs(&$book) {
// foreach ($book['langs'] as $lang => $language) {
// if (isset($language['stable'])) {
// $book['stable_langs'][$lang] = $language;
// }
// }
// }
/**
* Adds 'is_multi_stable_lang' element to a book to say whether the book has
......@@ -131,12 +131,12 @@ class BookLoader {
*
* @param array &$book an array of properties which represent a book
*/
private function addToBookIsMultiStableLang(&$book) {
if (!isset($book['stable_langs'])) {
$this->addToBookStableLangs($book);
}
$book['is_multi_stable_lang'] = count($book['stable_langs']) > 1 ? 1 : 0;
}
// private function addToBookIsMultiStableLang(&$book) {
// if (!isset($book['stable_langs'])) {
// $this->addToBookStableLangs($book);
// }
// $book['is_multi_stable_lang'] = count($book['stable_langs']) > 1 ? 1 : 0;
// }
/**
* Find all the books
......@@ -145,23 +145,23 @@ class BookLoader {
*
* @return array all books
*/
public function find() {
if ($this->cache === NULL) {
$finder = new Finder();
$yaml = new Parser();
$books = array();
foreach ($finder->in($this->configDir)
->name("*.yml") as $file) {
$books[basename($file, '.yml')] = $yaml->parse(file_get_contents("$file"));
}
foreach ($books as &$book) {
$this->addStatsToBook($book);
}
$this->cache = $books;
$this->cacheSort();
}
return $this->cache;
}
// public function find() {
// if ($this->cache === NULL) {
// $finder = new Finder();
// $yaml = new Parser();
// $books = array();
// foreach ($finder->in($this->configDir)
// ->name("*.yml") as $file) {