mirror of
https://github.com/doctrine/doctrine-website.git
synced 2026-03-23 22:32:11 +01:00
Remove sculpin and replace with something simpler.
This commit is contained in:
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,13 +1,12 @@
|
||||
vendor
|
||||
source/projects/doctrine-*
|
||||
source/api
|
||||
output_*
|
||||
app/config/local.yml
|
||||
tests/Doctrine/Website/Tests/Docs/resources/projects
|
||||
tests/Doctrine/Website/Tests/Docs/resources/docs
|
||||
tests/Doctrine/Website/Tests/Docs/resources/sculpin-source
|
||||
/config/local.yml
|
||||
/vendor
|
||||
/source/projects/doctrine-*
|
||||
/source/projects/doctrine1
|
||||
/source/api
|
||||
/tests/Doctrine/Website/Tests/Docs/resources/projects
|
||||
/tests/Doctrine/Website/Tests/Docs/resources/docs
|
||||
/tests/Doctrine/Website/Tests/Docs/resources/sculpin-source
|
||||
/docs
|
||||
projects
|
||||
build-*
|
||||
/.phpcs-cache
|
||||
|
||||
/build-*
|
||||
/projects
|
||||
|
||||
35
.travis.yml
35
.travis.yml
@@ -18,26 +18,37 @@ install:
|
||||
- rm composer.lock
|
||||
- travis_retry composer update -n --prefer-dist
|
||||
|
||||
script:
|
||||
- cp app/config/local.yml.dist app/config/local.yml
|
||||
- ./vendor/bin/sculpin build-docs --sync-git
|
||||
- ./vendor/bin/sculpin build-website
|
||||
- ./vendor/bin/phpunit --debug
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: Coverage
|
||||
- stage: Test
|
||||
env: DEPENDENCIES=low
|
||||
install:
|
||||
- rm composer.lock
|
||||
- travis_retry composer update --prefer-dist --prefer-lowest
|
||||
script:
|
||||
- cp config/local.yml.dist config/local.yml
|
||||
- ./vendor/bin/phpunit
|
||||
|
||||
- stage: Test
|
||||
env: COVERAGE
|
||||
before_script:
|
||||
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,}
|
||||
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
|
||||
script:
|
||||
- cp config/local.yml.dist config/local.yml
|
||||
- ./bin/console build-docs --sync-git
|
||||
- ./bin/console build-website
|
||||
- ./vendor/bin/phpunit --coverage-clover clover.xml
|
||||
after_script:
|
||||
- wget https://scrutinizer-ci.com/ocular.phar
|
||||
- php ocular.phar code-coverage:upload --format=php-clover clover.xml
|
||||
|
||||
- stage: Coding standard
|
||||
install:
|
||||
- travis_retry composer install -n --prefer-dist
|
||||
script:
|
||||
- ./vendor/bin/phpcs
|
||||
- stage: Code Quality
|
||||
env: CODING_STANDARDS
|
||||
install: travis_retry composer install --prefer-dist
|
||||
script: ./vendor/bin/phpcs
|
||||
|
||||
- stage: Code Quality
|
||||
env: STATIC_ANALYSIS
|
||||
install: travis_retry composer install --prefer-dist
|
||||
script: vendor/bin/phpstan analyse
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
|
||||
|
||||
class SculpinKernel extends AbstractKernel
|
||||
{
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getAdditionalSculpinBundles() : array
|
||||
{
|
||||
return ['Doctrine\Website\DoctrineSculpinBundle\DoctrineSculpinBundle'];
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
parameters:
|
||||
doctrine.search.algolia.admin_api_key: 'abcd'
|
||||
doctrine.projects_path: '%kernel.root_dir%/../projects'
|
||||
@@ -1,142 +0,0 @@
|
||||
imports:
|
||||
- { resource: local.yml }
|
||||
- { resource: projects.yml }
|
||||
- { resource: team_members.yml }
|
||||
|
||||
sculpin_content_types:
|
||||
posts:
|
||||
type: path
|
||||
path: _posts
|
||||
permalink: :year/:month/:day/:filename/
|
||||
taxonomies:
|
||||
- tags
|
||||
- categories
|
||||
|
||||
sculpin_twig:
|
||||
source_view_paths: ['_views', '_layouts', '_partials', '_includes']
|
||||
extensions: ['', 'twig', 'html', 'html.twig', 'twig.html', 'rst']
|
||||
|
||||
services:
|
||||
doctrine.twig.main.extension:
|
||||
class: Doctrine\Website\Twig\MainExtension
|
||||
public: false
|
||||
arguments:
|
||||
- '%doctrine.team_members%'
|
||||
tags:
|
||||
- { name: twig.extension }
|
||||
|
||||
doctrine.twig.project.extension:
|
||||
class: Doctrine\Website\Twig\ProjectExtension
|
||||
public: false
|
||||
arguments:
|
||||
- '@doctrine.project.repository'
|
||||
- '%doctrine.sculpin_source_path%'
|
||||
tags:
|
||||
- { name: twig.extension }
|
||||
|
||||
doctrine.project.factory:
|
||||
class: Doctrine\Website\Projects\ProjectFactory
|
||||
public: false
|
||||
|
||||
doctrine.process.factory:
|
||||
class: Doctrine\Website\ProcessFactory
|
||||
public: false
|
||||
|
||||
doctrine.project.repository:
|
||||
class: Doctrine\Website\Projects\ProjectRepository
|
||||
public: false
|
||||
arguments:
|
||||
- '%doctrine.projects%'
|
||||
- '@doctrine.project.factory'
|
||||
|
||||
doctrine.project.git_syncer:
|
||||
class: Doctrine\Website\Projects\ProjectGitSyncer
|
||||
public: false
|
||||
arguments:
|
||||
- '@doctrine.process.factory'
|
||||
- '%doctrine.projects_path%'
|
||||
|
||||
doctrine.search.algolia_client:
|
||||
class: AlgoliaSearch\Client
|
||||
public: false
|
||||
arguments:
|
||||
- '%doctrine.search.algolia.application_id%'
|
||||
- '%doctrine.search.algolia.admin_api_key%'
|
||||
|
||||
doctrine.search.indexer:
|
||||
class: Doctrine\Website\Docs\SearchIndexer
|
||||
public: false
|
||||
arguments:
|
||||
- '@doctrine.search.algolia_client'
|
||||
- '@doctrine.docs.rst_builder'
|
||||
|
||||
doctrine.rst.kernel.html:
|
||||
class: Doctrine\RST\HTML\Kernel
|
||||
public: false
|
||||
|
||||
doctrine.rst.kernel:
|
||||
class: Doctrine\Website\RST\Kernel
|
||||
public: false
|
||||
arguments:
|
||||
- @doctrine.rst.kernel.html
|
||||
- []
|
||||
|
||||
doctrine.rst.builder:
|
||||
class: Doctrine\RST\Builder
|
||||
public: false
|
||||
arguments:
|
||||
- '@doctrine.rst.kernel'
|
||||
|
||||
doctrine.docs.api_builder:
|
||||
class: Doctrine\Website\Docs\APIBuilder
|
||||
public: false
|
||||
arguments:
|
||||
- '@doctrine.process.factory'
|
||||
- '%doctrine.projects_path%'
|
||||
- '%doctrine.sculpin_source_path%'
|
||||
|
||||
doctrine.docs.rst_builder:
|
||||
class: Doctrine\Website\Docs\RSTBuilder
|
||||
arguments:
|
||||
- '%doctrine.sculpin_source_path%'
|
||||
- '@doctrine.rst.builder'
|
||||
- '%doctrine.projects_path%'
|
||||
|
||||
doctrine.docs.build_docs:
|
||||
class: Doctrine\Website\Docs\BuildDocs
|
||||
public: true
|
||||
arguments:
|
||||
- '@doctrine.project.repository'
|
||||
- '@doctrine.project.git_syncer'
|
||||
- '@doctrine.docs.api_builder'
|
||||
- '@doctrine.docs.rst_builder'
|
||||
- '@doctrine.search.indexer'
|
||||
|
||||
doctrine.website_builder:
|
||||
class: Doctrine\Website\WebsiteBuilder
|
||||
public: true
|
||||
arguments:
|
||||
- '@doctrine.process.factory'
|
||||
- '@sculpin.site_configuration'
|
||||
- '@doctrine.project.repository'
|
||||
- '%kernel.root_dir%'
|
||||
|
||||
doctrine.watcher:
|
||||
class: Doctrine\Website\Watcher
|
||||
public: true
|
||||
arguments:
|
||||
- '@doctrine.process.factory'
|
||||
- '%kernel.root_dir%'
|
||||
|
||||
doctrine.deployer:
|
||||
class: Doctrine\Website\Deployer
|
||||
public: true
|
||||
arguments:
|
||||
- '@doctrine.process.factory'
|
||||
- '%kernel.environment%'
|
||||
|
||||
parameters:
|
||||
doctrine.sculpin_source_path: '%kernel.root_dir%/../source'
|
||||
|
||||
doctrine.search.algolia.application_id: YVYTFT9XMW
|
||||
doctrine.search.algolia.index: pages
|
||||
@@ -1,12 +0,0 @@
|
||||
# The contents of this file are parsed and made available as
|
||||
# via `site.*`. So for example, {{ site.title }} can be used
|
||||
# in a template to get the contents of the `title` key.
|
||||
title: Doctrine
|
||||
subtitle: PHP Database Tools
|
||||
url: http://lcl.doctrine-project.org:8080
|
||||
keywords: [php, mysql, orm, dbal, database, mongodb, odm, annotations, migrations, cache, couchdb]
|
||||
description: >
|
||||
The Doctrine Project is the home to several PHP libraries primarily
|
||||
focused on database storage and object mapping. The core projects
|
||||
are the Object Relational Mapper (ORM) and the Database Abstraction
|
||||
Layer (DBAL) it is built upon.
|
||||
@@ -1,5 +0,0 @@
|
||||
imports:
|
||||
- sculpin_site.yml
|
||||
|
||||
url: https://www.doctrine-project.org
|
||||
google_analytics_tracking_id: UA-288343-7
|
||||
@@ -1,4 +0,0 @@
|
||||
imports:
|
||||
- sculpin_site.yml
|
||||
|
||||
url: https://staging.doctrine-project.org
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
|
||||
|
||||
use Sculpin\Core\Console\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DeployCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->setName('deploy')
|
||||
->setDescription('Deploy the Doctrine website.')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : void
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$deployer = $container->get('doctrine.deployer');
|
||||
|
||||
$deployer->deploy($output);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
|
||||
|
||||
use Sculpin\Core\Console\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use function sprintf;
|
||||
|
||||
class WatchCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->setName('watch')
|
||||
->setDescription('Watch for changes to the website source code and build.')
|
||||
->addArgument(
|
||||
'build-dir',
|
||||
InputArgument::OPTIONAL,
|
||||
'The directory where the website is built'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : void
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$rootDir = $container->getParameter('kernel.root_dir');
|
||||
$env = $container->getParameter('kernel.environment');
|
||||
|
||||
$buildDir = $input->getArgument('build-dir');
|
||||
|
||||
if (! $buildDir) {
|
||||
$buildDir = sprintf('%s/../build-%s', $rootDir, $env);
|
||||
}
|
||||
|
||||
$watcher = $this->getContainer()->get('doctrine.watcher');
|
||||
|
||||
$watcher->watch($buildDir, $output);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\DependencyInjection\CompilerPass;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
|
||||
class DirectivesCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container) : void
|
||||
{
|
||||
$kernel = $container->getDefinition('doctrine.rst.kernel');
|
||||
$kernel->replaceArgument(
|
||||
1,
|
||||
array_map(
|
||||
[$container, 'getDefinition'],
|
||||
array_keys($container->findTaggedServiceIds('doctrine.rst.directive'))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
|
||||
class DoctrineSculpinExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $config
|
||||
*/
|
||||
public function load(array $config, ContainerBuilder $container) : void
|
||||
{
|
||||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle;
|
||||
|
||||
use Doctrine\Website\DoctrineSculpinBundle\DependencyInjection\CompilerPass\DirectivesCompilerPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class DoctrineSculpinBundle extends Bundle
|
||||
{
|
||||
public function build(ContainerBuilder $container) : void
|
||||
{
|
||||
$container->addCompilerPass(new DirectivesCompilerPass());
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
services:
|
||||
doctrine.code_highlighter:
|
||||
public: false
|
||||
class: Highlight\Highlighter
|
||||
|
||||
doctrine.code_block.renderer:
|
||||
public: false
|
||||
class: Doctrine\Website\Docs\CodeBlockRenderer
|
||||
arguments:
|
||||
- '@doctrine.code_block.console.renderer'
|
||||
- '@doctrine.code_block.with_line_numbers.renderer'
|
||||
|
||||
doctrine.code_block.language_detector:
|
||||
public: false
|
||||
class: Doctrine\Website\Docs\CodeBlockLanguageDetector
|
||||
|
||||
doctrine.code_block.console.renderer:
|
||||
public: false
|
||||
class: Doctrine\Website\Docs\CodeBlockConsoleRenderer
|
||||
|
||||
doctrine.code_block.with_line_numbers.renderer:
|
||||
public: false
|
||||
class: Doctrine\Website\Docs\CodeBlockWithLineNumbersRenderer
|
||||
arguments:
|
||||
- '@doctrine.code_highlighter'
|
||||
|
||||
doctrine.website.directive.warning:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\WarningDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.caution:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\CautionDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.tip:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TipDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.configuration_block:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\ConfigurationBlockDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.section_author:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\SectionAuthorDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.version_added:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\VersionAddedDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.role:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\RoleDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.index:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\IndexDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.hint:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\HintDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.notice:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\NoticeDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.note:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\NoteDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.toc:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TocDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.toc_header:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TocHeaderDirective
|
||||
arguments: []
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
|
||||
doctrine.website.directive.code_block:
|
||||
public: false
|
||||
class: Doctrine\Website\DoctrineSculpinBundle\Directive\CodeBlockDirective
|
||||
arguments:
|
||||
- '@doctrine.code_block.renderer'
|
||||
- '@doctrine.code_block.language_detector'
|
||||
tags: [{ name: doctrine.rst.directive }]
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use function array_merge;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function glob;
|
||||
use function is_dir;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
use function time;
|
||||
|
||||
class Watcher
|
||||
{
|
||||
/** @var ProcessFactory */
|
||||
private $processFactory;
|
||||
|
||||
/** @var string */
|
||||
private $kernelRootDir;
|
||||
|
||||
public function __construct(ProcessFactory $processFactory, string $kernelRootDir)
|
||||
{
|
||||
$this->processFactory = $processFactory;
|
||||
$this->kernelRootDir = $kernelRootDir;
|
||||
}
|
||||
|
||||
public function watch(string $buildDir, OutputInterface $output) : void
|
||||
{
|
||||
$rootDir = realpath($this->kernelRootDir . '/..');
|
||||
|
||||
$buildScriptPath = sprintf(
|
||||
'%s/doctrine build-website %s --env=dev',
|
||||
$rootDir,
|
||||
$buildDir
|
||||
);
|
||||
|
||||
$startPaths = [
|
||||
$rootDir . '/app/*',
|
||||
$rootDir . '/source/*',
|
||||
];
|
||||
|
||||
$lastTime = time();
|
||||
|
||||
while (true) {
|
||||
$files = $this->recursiveGlob($startPaths);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$time = filemtime($file);
|
||||
|
||||
if ($time <= $lastTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lastTime = time();
|
||||
|
||||
$output->writeln(sprintf('%s was changed. Building...', $file));
|
||||
|
||||
$this->processFactory->run($buildScriptPath, function ($type, $buffer) use ($output) : void {
|
||||
$output->write($buffer);
|
||||
});
|
||||
|
||||
file_put_contents($buildDir . '/changed', time());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $paths
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function recursiveGlob(array $paths) : array
|
||||
{
|
||||
$allFiles = [];
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$files = glob($path);
|
||||
|
||||
$allFiles = array_merge($allFiles, $files);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (! is_dir($file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dirPath = $file . '/*';
|
||||
|
||||
$dirFiles = $this->recursiveGlob([$dirPath]);
|
||||
|
||||
$allFiles = array_merge($allFiles, $dirFiles);
|
||||
}
|
||||
}
|
||||
|
||||
return $allFiles;
|
||||
}
|
||||
}
|
||||
16
bin/console
Executable file
16
bin/console
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Doctrine\Website\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
$input = new ArgvInput();
|
||||
$env = $input->getParameterOption(['--env', '-e'], 'dev');
|
||||
|
||||
$container = Application::getContainer($env);
|
||||
|
||||
$application = $container->get(Application::class);
|
||||
|
||||
$application->run($input);
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace ComponentManager;
|
||||
|
||||
use Composer\Script\Event;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class ComponentManager
|
||||
{
|
||||
public static function postComposerInstall(Event $event)
|
||||
{
|
||||
$config = $event->getComposer()->getConfig();
|
||||
$componentDir = $config->get('component-dir');
|
||||
$components = $config->get('components');
|
||||
$vendorDir = $config->get('vendor-dir');
|
||||
|
||||
// if either configuration is empty it's a noop
|
||||
if (empty($componentDir) || empty($components)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$componentDir = __DIR__ .'/'. $componentDir;
|
||||
|
||||
if (!is_dir($componentDir)) {
|
||||
mkdir($componentDir);
|
||||
}
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
foreach ($components as $component) {
|
||||
$componentSource = $vendorDir .'/'. $component;
|
||||
|
||||
if (!is_dir($componentSource)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filesystem->mirror($componentSource, $componentDir .'/'. basename($component));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"name": "doctrine/doctrine-website",
|
||||
"description": "Source code for doctrine-project.org",
|
||||
"type": "jwage.com",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable" : true,
|
||||
"type": "project",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
@@ -13,36 +11,40 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"algolia/algoliasearch-client-php": "~1.25.0",
|
||||
"components/highlightjs": "^9.7",
|
||||
"dflydev/embedded-composer": "^1.0@dev",
|
||||
"algolia/algoliasearch-client-php": "^1.27",
|
||||
"doctrine/rst-parser": "dev-master",
|
||||
"kriswallsmith/assetic": "1.1.2",
|
||||
"scrivo/highlight.php": "9.12.0.2",
|
||||
"sculpin/sculpin": "^2.1@dev"
|
||||
"erusev/parsedown": "^1.7",
|
||||
"scrivo/highlight.php": "v9.12.0.4",
|
||||
"symfony/config": "^4.1",
|
||||
"symfony/console": "^4.1",
|
||||
"symfony/dependency-injection": "^4.1",
|
||||
"symfony/filesystem": "^4.1",
|
||||
"symfony/finder": "^4.1",
|
||||
"symfony/process": "^4.1",
|
||||
"symfony/yaml": "^4.1",
|
||||
"twig/twig": "^2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"doctrine/coding-standard": "^4.0",
|
||||
"phpstan/phpstan": "^0.10",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.10",
|
||||
"phpstan/phpstan-phpunit": "^0.10",
|
||||
"phpstan/phpstan-strict-rules": "^0.10",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"symfony/dom-crawler": "^4.0",
|
||||
"symfony/css-selector": "^4.0"
|
||||
},
|
||||
"config": {
|
||||
"component-dir": "source/components",
|
||||
"components": [
|
||||
"components/highlightjs"
|
||||
],
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
"ComponentManager\\ComponentManager::postComposerInstall"
|
||||
]
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["component-manager.php"],
|
||||
"psr-0": {
|
||||
"Doctrine": "app/src/"
|
||||
"psr-4": {
|
||||
"Doctrine\\Website\\": "lib/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Website\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3389
composer.lock
generated
3389
composer.lock
generated
File diff suppressed because it is too large
Load Diff
17
config/config.yml
Normal file
17
config/config.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
parameters:
|
||||
doctrine.website.algolia.app_id: 'YVYTFT9XMW'
|
||||
doctrine.website.algolia.admin_api_key: '1234'
|
||||
|
||||
doctrine.website.projects_path: '%doctrine.website.root_dir%/projects'
|
||||
doctrine.website.source_path: '%doctrine.website.root_dir%/source'
|
||||
doctrine.website.templates_path: '%doctrine.website.root_dir%/templates'
|
||||
|
||||
doctrine.website.title: Doctrine
|
||||
doctrine.website.subtitle: PHP Database Tools
|
||||
doctrine.website.url: http://lcl.doctrine-project.org:8080
|
||||
doctrine.website.keywords: [php, mysql, orm, dbal, database, mongodb, odm, annotations, migrations, cache, couchdb]
|
||||
doctrine.website.description: >
|
||||
The Doctrine Project is the home to several PHP libraries primarily
|
||||
focused on database storage and object mapping. The core projects
|
||||
are the Object Relational Mapper (ORM) and the Database Abstraction
|
||||
Layer (DBAL) it is built upon.
|
||||
4
config/config_dev.yml
Normal file
4
config/config_dev.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
imports:
|
||||
- config.yml
|
||||
|
||||
parameters: []
|
||||
5
config/config_prod.yml
Normal file
5
config/config_prod.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
imports:
|
||||
- config.yml
|
||||
|
||||
parameters:
|
||||
doctrine.website.url: 'https://www.doctrine-project.org'
|
||||
5
config/config_staging.yml
Normal file
5
config/config_staging.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
imports:
|
||||
- { resource: config.yml }
|
||||
|
||||
parameters:
|
||||
doctrine.website.url: 'https://staging.doctrine-project.org'
|
||||
3
config/local.yml.dist
Normal file
3
config/local.yml.dist
Normal file
@@ -0,0 +1,3 @@
|
||||
parameters:
|
||||
doctrine.website.algolia.admin_api_key: 'abcd'
|
||||
doctrine.website.projects_path: '%doctrine.website.root_dir%/projects'
|
||||
@@ -1,5 +1,5 @@
|
||||
parameters:
|
||||
doctrine.projects:
|
||||
doctrine.website.projects:
|
||||
orm:
|
||||
active: true
|
||||
name: Object Relational Mapper
|
||||
65
config/services.xml
Normal file
65
config/services.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<defaults autowire="true" autoconfigure="true" public="false">
|
||||
<bind key="$rootDir">%doctrine.website.root_dir%</bind>
|
||||
<bind key="$env">%doctrine.website.env%</bind>
|
||||
<bind key="$projectsPath">%doctrine.website.projects_path%</bind>
|
||||
<bind key="$sourcePath">%doctrine.website.source_path%</bind>
|
||||
<bind key="$projects">%doctrine.website.projects%</bind>
|
||||
<bind key="$teamMembers">%doctrine.website.team_members%</bind>
|
||||
<bind key="$templatesPath">%doctrine.website.templates_path%</bind>
|
||||
</defaults>
|
||||
|
||||
<prototype namespace="Doctrine\Website\" resource="../lib/*" />
|
||||
|
||||
<service id="Doctrine\Website\Application" autowire="true" public="true" />
|
||||
|
||||
<service id="Doctrine\RST\Builder">
|
||||
<argument type="service" id="Doctrine\Website\RST\Kernel" />
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\RST\HTML\Kernel" autowire="true" />
|
||||
<service id="Highlight\Highlighter" autowire="true" />
|
||||
<service id="Parsedown" class="Parsedown" autowire="true" />
|
||||
<service id="Symfony\Component\Console\Application" autowire="true" />
|
||||
<service id="Symfony\Component\Filesystem\Filesystem" autowire="true" />
|
||||
|
||||
<service id="AlgoliaSearch\Client">
|
||||
<argument>%doctrine.website.algolia.app_id%</argument>
|
||||
<argument>%doctrine.website.algolia.admin_api_key%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\Site">
|
||||
<argument>%doctrine.website.title%</argument>
|
||||
<argument>%doctrine.website.subtitle%</argument>
|
||||
<argument>%doctrine.website.url%</argument>
|
||||
<argument>%doctrine.website.keywords%</argument>
|
||||
<argument>%doctrine.website.description%</argument>
|
||||
<argument>%doctrine.website.env%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\RST\Kernel" autowire="true" public="true">
|
||||
<argument type="service" id="Doctrine\RST\HTML\Kernel" />
|
||||
<argument type="collection">
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\CautionDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\CodeBlockDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\ConfigurationBlockDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\HintDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\IndexDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\NoteDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\NoticeDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\RoleDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\SectionAuthorDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\TipDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\TocDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\TocHeaderDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\VersionAddedDirective" />
|
||||
<argument type="service" id="Doctrine\Website\RST\Directive\WarningDirective" />
|
||||
</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
@@ -1,5 +1,5 @@
|
||||
parameters:
|
||||
doctrine.team_members:
|
||||
doctrine.website.team_members:
|
||||
# active
|
||||
alcaeus:
|
||||
name: Andreas
|
||||
79
lib/Application.php
Normal file
79
lib/Application.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
use Doctrine\Website\Commands\BuildDocsCommand;
|
||||
use Doctrine\Website\Commands\BuildWebsiteCommand;
|
||||
use Doctrine\Website\Commands\DeployCommand;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Console\Application as BaseApplication;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
use function file_exists;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
|
||||
class Application
|
||||
{
|
||||
/** @var BaseApplication */
|
||||
private $application;
|
||||
|
||||
/** @var BuildDocsCommand */
|
||||
private $buildDocsCommand;
|
||||
|
||||
/** @var BuildWebsiteCommand */
|
||||
private $buildWebsiteCommand;
|
||||
|
||||
/** @var DeployCommand */
|
||||
private $deployCommand;
|
||||
|
||||
public function __construct(
|
||||
BaseApplication $application,
|
||||
BuildDocsCommand $buildDocsCommand,
|
||||
BuildWebsiteCommand $buildWebsiteCommand,
|
||||
DeployCommand $deployCommand
|
||||
) {
|
||||
$this->application = $application;
|
||||
$this->buildDocsCommand = $buildDocsCommand;
|
||||
$this->buildWebsiteCommand = $buildWebsiteCommand;
|
||||
$this->deployCommand = $deployCommand;
|
||||
}
|
||||
|
||||
public function run(InputInterface $input) : int
|
||||
{
|
||||
$this->application->add($this->buildDocsCommand);
|
||||
$this->application->add($this->buildWebsiteCommand);
|
||||
$this->application->add($this->deployCommand);
|
||||
|
||||
return $this->application->run($input);
|
||||
}
|
||||
|
||||
public static function getContainer(string $env) : ContainerBuilder
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('doctrine.website.env', $env);
|
||||
$container->setParameter('doctrine.website.root_dir', realpath(__DIR__ . '/..'));
|
||||
$container->setParameter('doctrine.website.config_dir', realpath(__DIR__ . '/../config'));
|
||||
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$loader->load('services.xml');
|
||||
|
||||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$loader->load('projects.yml');
|
||||
$loader->load('team_members.yml');
|
||||
|
||||
$loader->load(sprintf('config_%s.yml', $env));
|
||||
|
||||
if (file_exists($container->getParameter('doctrine.website.config_dir') . '/local.yml')) {
|
||||
$loader->load('local.yml');
|
||||
}
|
||||
|
||||
$container->compile();
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
122
lib/Builder/SourceFile.php
Normal file
122
lib/Builder/SourceFile.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Builder;
|
||||
|
||||
use DateTime;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function in_array;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use function strtotime;
|
||||
|
||||
class SourceFile
|
||||
{
|
||||
private const TWIG_EXTENSIONS = ['html', 'md', 'rst', 'xml', 'txt'];
|
||||
|
||||
private const NEEDS_LAYOUT_EXTENSIONS = ['html', 'md', 'rst'];
|
||||
|
||||
private const MARKDOWN_EXTENSION = 'md';
|
||||
|
||||
/** @var string */
|
||||
private $extension;
|
||||
|
||||
/** @var string */
|
||||
private $writePath;
|
||||
|
||||
/** @var string */
|
||||
private $contents;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $parameters = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
public function __construct(
|
||||
string $extension,
|
||||
string $writePath,
|
||||
string $contents,
|
||||
array $parameters
|
||||
) {
|
||||
$this->extension = $extension;
|
||||
$this->writePath = $writePath;
|
||||
$this->contents = $contents;
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
public function getWritePath() : string
|
||||
{
|
||||
return $this->writePath;
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
{
|
||||
return $this->parameters['url'];
|
||||
}
|
||||
|
||||
public function getDate() : DateTime
|
||||
{
|
||||
$e = explode('/', $this->getUrl());
|
||||
|
||||
if (count($e) < 4) {
|
||||
return new DateTime();
|
||||
}
|
||||
|
||||
$date = strtotime(sprintf('%s/%s/%s', $e[1], $e[2], $e[3]));
|
||||
|
||||
if ($date === false) {
|
||||
return new DateTime();
|
||||
}
|
||||
|
||||
return (new DateTime())->setTimestamp($date);
|
||||
}
|
||||
|
||||
public function getExtension() : string
|
||||
{
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
public function isMarkdown() : bool
|
||||
{
|
||||
return $this->getExtension() === self::MARKDOWN_EXTENSION;
|
||||
}
|
||||
|
||||
public function isTwig() : bool
|
||||
{
|
||||
return in_array($this->getExtension(), self::TWIG_EXTENSIONS, true) && $this->isApiDocs() === false;
|
||||
}
|
||||
|
||||
public function isLayoutNeeded() : bool
|
||||
{
|
||||
return in_array($this->getExtension(), self::NEEDS_LAYOUT_EXTENSIONS, true);
|
||||
}
|
||||
|
||||
public function isApiDocs() : bool
|
||||
{
|
||||
return strpos($this->getUrl(), '/api/') === 0;
|
||||
}
|
||||
|
||||
public function getContents() : string
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getParameters() : array
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameter(string $key)
|
||||
{
|
||||
return $this->parameters[$key] ?? '';
|
||||
}
|
||||
}
|
||||
48
lib/Builder/SourceFileBuilder.php
Normal file
48
lib/Builder/SourceFileBuilder.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Builder;
|
||||
|
||||
use Parsedown;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class SourceFileBuilder
|
||||
{
|
||||
/** @var SourceFileRenderer */
|
||||
private $sourceFileRenderer;
|
||||
|
||||
/** @var Filesystem */
|
||||
private $filesystem;
|
||||
|
||||
/** @var Parsedown */
|
||||
private $parsedown;
|
||||
|
||||
public function __construct(
|
||||
SourceFileRenderer $sourceFileRenderer,
|
||||
Filesystem $filesystem,
|
||||
Parsedown $parsedown
|
||||
) {
|
||||
$this->sourceFileRenderer = $sourceFileRenderer;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->parsedown = $parsedown;
|
||||
}
|
||||
|
||||
public function buildFile(SourceFile $sourceFile, string $buildDir) : void
|
||||
{
|
||||
$rendered = $sourceFile->getContents();
|
||||
|
||||
if ($sourceFile->isMarkdown()) {
|
||||
$rendered = $this->parsedown->text($rendered);
|
||||
}
|
||||
|
||||
if ($sourceFile->isTwig()) {
|
||||
$rendered = $this->sourceFileRenderer->render(
|
||||
$sourceFile,
|
||||
$rendered
|
||||
);
|
||||
}
|
||||
|
||||
$this->filesystem->dumpFile($sourceFile->getWritePath(), $rendered);
|
||||
}
|
||||
}
|
||||
60
lib/Builder/SourceFileRenderer.php
Normal file
60
lib/Builder/SourceFileRenderer.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Builder;
|
||||
|
||||
use Doctrine\Website\Site;
|
||||
use Doctrine\Website\Twig\TwigRenderer;
|
||||
use function array_merge;
|
||||
use function preg_match_all;
|
||||
|
||||
class SourceFileRenderer
|
||||
{
|
||||
/** @var TwigRenderer */
|
||||
private $twigRenderer;
|
||||
|
||||
/** @var Site */
|
||||
private $site;
|
||||
|
||||
public function __construct(TwigRenderer $twigRenderer, Site $site)
|
||||
{
|
||||
$this->twigRenderer = $twigRenderer;
|
||||
$this->site = $site;
|
||||
}
|
||||
|
||||
public function render(SourceFile $sourceFile, string $contents) : string
|
||||
{
|
||||
$template = $this->prepareTemplate($sourceFile, $contents);
|
||||
|
||||
$pageParameters = $this->preparePageParameters($sourceFile);
|
||||
|
||||
return $this->twigRenderer->render($template, [
|
||||
'page' => $pageParameters,
|
||||
'site' => $this->site,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function preparePageParameters(SourceFile $sourceFile) : array
|
||||
{
|
||||
return array_merge($sourceFile->getParameters(), [
|
||||
'date' => $sourceFile->getDate(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function prepareTemplate(SourceFile $sourceFile, string $contents) : string
|
||||
{
|
||||
if ($sourceFile->isLayoutNeeded()) {
|
||||
if (! preg_match_all('/{%\s+block\s+(\w+)\s+%}(.*?){%\s+endblock\s+%}/si', $contents, $matches)) {
|
||||
$contents = '{% block content %}' . $contents . '{% endblock %}';
|
||||
}
|
||||
|
||||
$contents = '{% extends "layouts/' . $sourceFile->getParameter('layout') . '.html.twig" %}' . $contents;
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
126
lib/Builder/SourceFileRepository.php
Normal file
126
lib/Builder/SourceFileRepository.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Builder;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use function end;
|
||||
use function explode;
|
||||
use function file_get_contents;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function str_replace;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
|
||||
class SourceFileRepository
|
||||
{
|
||||
/** @var string */
|
||||
private $rootDir;
|
||||
|
||||
public function __construct(string $rootDir)
|
||||
{
|
||||
$this->rootDir = $rootDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SourceFile[]
|
||||
*/
|
||||
public function getFiles(string $buildDir, string $inPath = 'source') : array
|
||||
{
|
||||
$finder = new Finder();
|
||||
|
||||
$finder
|
||||
->in($this->rootDir . '/' . $inPath)
|
||||
->files();
|
||||
|
||||
$files = [];
|
||||
|
||||
foreach ($finder as $splFileInfo) {
|
||||
$path = $splFileInfo->getRealPath();
|
||||
|
||||
$contents = file_get_contents($path);
|
||||
|
||||
$extension = $this->getExtension($path);
|
||||
|
||||
$writePath = $this->getWritePath($buildDir, $path, $extension);
|
||||
|
||||
$parameters = $this->getFileParameters($buildDir, $writePath, $contents);
|
||||
|
||||
$writePath = $buildDir . $parameters['url'];
|
||||
|
||||
$contents = $this->stripFileParameters($contents);
|
||||
|
||||
$files[] = new SourceFile(
|
||||
$extension,
|
||||
$writePath,
|
||||
$contents,
|
||||
$parameters
|
||||
);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
private function getWritePath(string $buildDir, string $path, string $extension) : string
|
||||
{
|
||||
$writePath = $buildDir . str_replace($this->rootDir . '/source', '', $path);
|
||||
|
||||
if (in_array($extension, ['md', 'rst'], true)) {
|
||||
$writePath = substr($writePath, 0, strrpos($writePath, '.')) . '.html';
|
||||
}
|
||||
|
||||
return $writePath;
|
||||
}
|
||||
|
||||
private function getExtension(string $path) : string
|
||||
{
|
||||
$e = explode('.', $path);
|
||||
|
||||
return end($e);
|
||||
}
|
||||
|
||||
private function stripFileParameters(string $contents) : string
|
||||
{
|
||||
return preg_replace('/^\s*(?:---[\s]*[\r\n]+)(.*?)(?:---[\s]*[\r\n]+)(.*?)$/s', '$2', $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function getFileParameters(string $buildDir, string $writePath, string $string) : array
|
||||
{
|
||||
$parameters = [];
|
||||
|
||||
if (preg_match('/^\s*(?:---[\s]*[\r\n]+)(.*?)(?:---[\s]*[\r\n]+)(.*?)$/s', $string, $matches)) {
|
||||
if (preg_match('/^(\s*[-]+\s*|\s*)$/', $matches[1]) === 0) {
|
||||
$parameters = Yaml::parse($matches[1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (! isset($parameters['layout'])) {
|
||||
$parameters['layout'] = 'default';
|
||||
}
|
||||
|
||||
$parameters['url'] = $this->getUrl($buildDir, $writePath, $parameters);
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
private function getUrl(string $buildDir, string $writePath, array $parameters) : string
|
||||
{
|
||||
$permalink = $parameters['permalink'] ?? '';
|
||||
|
||||
if ($permalink !== '' && $permalink !== 'none') {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
return str_replace($buildDir, '', $writePath);
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,26 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
|
||||
namespace Doctrine\Website\Commands;
|
||||
|
||||
use Sculpin\Core\Console\Command\ContainerAwareCommand;
|
||||
use Doctrine\Website\Docs\BuildDocs;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class BuildDocsCommand extends ContainerAwareCommand
|
||||
class BuildDocsCommand extends Command
|
||||
{
|
||||
/** @var BuildDocs */
|
||||
private $buildDocs;
|
||||
|
||||
public function __construct(BuildDocs $buildDocs)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->buildDocs = $buildDocs;
|
||||
}
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
@@ -46,6 +57,12 @@ class BuildDocsCommand extends ContainerAwareCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'Sync git repositories before building.'
|
||||
)
|
||||
->addOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The environment.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -57,9 +74,7 @@ class BuildDocsCommand extends ContainerAwareCommand
|
||||
$buildSearchIndexes = (bool) $input->getOption('search');
|
||||
$syncGit = (bool) $input->getOption('sync-git');
|
||||
|
||||
$buildDocs = $this->getContainer()->get('doctrine.docs.build_docs');
|
||||
|
||||
$buildDocs->build(
|
||||
$this->buildDocs->build(
|
||||
$output,
|
||||
$projectToBuild,
|
||||
$versionToBuild,
|
||||
@@ -2,23 +2,45 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
|
||||
namespace Doctrine\Website\Commands;
|
||||
|
||||
use Doctrine\Website\WebsiteBuilder;
|
||||
use InvalidArgumentException;
|
||||
use Sculpin\Core\Console\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use function in_array;
|
||||
use function ini_set;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
|
||||
class BuildWebsiteCommand extends ContainerAwareCommand
|
||||
class BuildWebsiteCommand extends Command
|
||||
{
|
||||
/** @var WebsiteBuilder */
|
||||
private $websiteBuilder;
|
||||
|
||||
/** @var string */
|
||||
private $rootDir;
|
||||
|
||||
/** @var string */
|
||||
private $env;
|
||||
|
||||
public function __construct(
|
||||
WebsiteBuilder $websiteBuilder,
|
||||
string $rootDir,
|
||||
string $env
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->websiteBuilder = $websiteBuilder;
|
||||
$this->rootDir = $rootDir;
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
@@ -35,26 +57,29 @@ class BuildWebsiteCommand extends ContainerAwareCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'Publish the build to GitHub Pages.'
|
||||
)
|
||||
->addOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The environment.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : void
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
ini_set('memory_limit', '1024M');
|
||||
|
||||
$rootDir = $container->getParameter('kernel.root_dir');
|
||||
$env = $container->getParameter('kernel.environment');
|
||||
$publish = (bool) $input->getOption('publish');
|
||||
|
||||
$publish = $input->getOption('publish');
|
||||
|
||||
if ($publish && ! in_array($env, WebsiteBuilder::PUBLISHABLE_ENVS)) {
|
||||
throw new InvalidArgumentException(sprintf('You cannot publish the "%s" environment.', $env));
|
||||
if ($publish && ! in_array($this->env, WebsiteBuilder::PUBLISHABLE_ENVS, true)) {
|
||||
throw new InvalidArgumentException(sprintf('You cannot publish the "%s" environment.', $this->env));
|
||||
}
|
||||
|
||||
$buildDir = $input->getArgument('build-dir');
|
||||
|
||||
if (! $buildDir) {
|
||||
$buildDir = sprintf('%s/../build-%s', $rootDir, $env);
|
||||
if ($buildDir === null) {
|
||||
$buildDir = sprintf('%s/build-%s', $this->rootDir, $this->env);
|
||||
}
|
||||
|
||||
if (! is_dir($buildDir)) {
|
||||
@@ -63,8 +88,6 @@ class BuildWebsiteCommand extends ContainerAwareCommand
|
||||
|
||||
$buildDir = realpath($buildDir);
|
||||
|
||||
$buildWebsite = $container->get('doctrine.website_builder');
|
||||
|
||||
$buildWebsite->build($output, $buildDir, $env, $publish);
|
||||
$this->websiteBuilder->build($output, $buildDir, $this->env, $publish);
|
||||
}
|
||||
}
|
||||
44
lib/Commands/DeployCommand.php
Normal file
44
lib/Commands/DeployCommand.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Commands;
|
||||
|
||||
use Doctrine\Website\Deployer;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DeployCommand extends Command
|
||||
{
|
||||
/** @var Deployer */
|
||||
private $deployer;
|
||||
|
||||
public function __construct(Deployer $deployer)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->deployer = $deployer;
|
||||
}
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->setName('deploy')
|
||||
->setDescription('Deploy the Doctrine website.')
|
||||
->addOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'The environment.'
|
||||
)
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : void
|
||||
{
|
||||
$this->deployer->deploy($output);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class Deployer
|
||||
|
||||
public function deploy(OutputInterface $output) : void
|
||||
{
|
||||
if (! in_array($this->env, self::ENVS)) {
|
||||
if (! in_array($this->env, self::ENVS, true)) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Cannot deploy the %s environment.', $this->env)
|
||||
);
|
||||
@@ -72,11 +72,7 @@ class Deployer
|
||||
|
||||
// build the docs, website and publish
|
||||
$deployCommand = sprintf(
|
||||
'cd /data/doctrine-website-%s && ./doctrine build-docs --api --sync-git && ./doctrine build-website /data/doctrine-website-build-%s --env=%s --publish',
|
||||
$this->env,
|
||||
$this->env,
|
||||
$this->env,
|
||||
$this->env,
|
||||
'cd /data/doctrine-website-%s && ./bin/console build-docs --api --sync-git && ./bin/console build-website /data/doctrine-website-build-%s --env=%s --publish',
|
||||
$this->env,
|
||||
$this->env,
|
||||
$this->env
|
||||
@@ -20,16 +20,16 @@ class APIBuilder
|
||||
private $projectsPath;
|
||||
|
||||
/** @var string */
|
||||
private $sculpinSourcePath;
|
||||
private $sourcePath;
|
||||
|
||||
public function __construct(
|
||||
ProcessFactory $processFactory,
|
||||
string $projectsPath,
|
||||
string $sculpinSourcePath
|
||||
string $sourcePath
|
||||
) {
|
||||
$this->processFactory = $processFactory;
|
||||
$this->projectsPath = $projectsPath;
|
||||
$this->sculpinSourcePath = $sculpinSourcePath;
|
||||
$this->processFactory = $processFactory;
|
||||
$this->projectsPath = $projectsPath;
|
||||
$this->sourcePath = $sourcePath;
|
||||
}
|
||||
|
||||
public function buildAPIDocs(
|
||||
@@ -50,7 +50,7 @@ return new Sami\Sami('%s', [
|
||||
CONFIG;
|
||||
|
||||
$codeDir = $this->projectsPath . '/' . $project->getRepositoryName() . $project->getCodePath();
|
||||
$buildDir = $this->sculpinSourcePath . '/api/' . $project->getSlug() . '/' . $version->getSlug();
|
||||
$buildDir = $this->sourcePath . '/api/' . $project->getSlug() . '/' . $version->getSlug();
|
||||
$cacheDir = $this->projectsPath . '/' . $project->getRepositoryName() . '/cache';
|
||||
|
||||
$renderedConfigContent = sprintf(
|
||||
@@ -64,7 +64,7 @@ CONFIG;
|
||||
);
|
||||
|
||||
$configPath = $this->projectsPath . '/' . $project->getRepositoryName() . '/sami.php';
|
||||
$samiPharPath = $this->sculpinSourcePath . '/../sami.phar';
|
||||
$samiPharPath = $this->sourcePath . '/../sami.phar';
|
||||
|
||||
$this->filePutContents($configPath, $renderedConfigContent);
|
||||
|
||||
@@ -29,7 +29,7 @@ class CodeBlockRenderer
|
||||
*/
|
||||
public function render(array $lines, string $language) : string
|
||||
{
|
||||
if (in_array($language, self::CONSOLE_LANGUAGES)) {
|
||||
if (in_array($language, self::CONSOLE_LANGUAGES, true)) {
|
||||
return $this->codeBlockConsoleRenderer->render(
|
||||
$lines
|
||||
);
|
||||
@@ -96,7 +96,7 @@ TEMPLATE;
|
||||
|
||||
private function shouldHighlight(string $language) : bool
|
||||
{
|
||||
return $language !== '' && ! in_array($language, self::LANGUAGES_NOT_TO_HIGHLIGHT);
|
||||
return $language !== '' && ! in_array($language, self::LANGUAGES_NOT_TO_HIGHLIGHT, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8,22 +8,26 @@ use Doctrine\RST\Builder;
|
||||
use Doctrine\RST\Document;
|
||||
use Doctrine\Website\Projects\Project;
|
||||
use Doctrine\Website\Projects\ProjectVersion;
|
||||
use function array_merge;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
use function dirname;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function glob;
|
||||
use function is_dir;
|
||||
use function iterator_to_array;
|
||||
use function mkdir;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function shell_exec;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function trim;
|
||||
use function unlink;
|
||||
|
||||
class RSTBuilder
|
||||
{
|
||||
@@ -51,7 +55,7 @@ class RSTBuilder
|
||||
|
||||
TEMPLATE;
|
||||
|
||||
public const SCULPIN_TEMPLATE = <<<TEMPLATE
|
||||
public const PARAMETERS_TEMPLATE = <<<TEMPLATE
|
||||
---
|
||||
layout: "documentation"
|
||||
indexed: true
|
||||
@@ -76,11 +80,14 @@ TEMPLATE;
|
||||
SIDEBAR;
|
||||
|
||||
/** @var string */
|
||||
private $sculpinSourcePath;
|
||||
private $sourcePath;
|
||||
|
||||
/** @var Builder */
|
||||
private $builder;
|
||||
|
||||
/** @var Filesystem */
|
||||
private $filesystem;
|
||||
|
||||
/** @var string */
|
||||
private $projectsPath;
|
||||
|
||||
@@ -88,14 +95,16 @@ SIDEBAR;
|
||||
private $tmpPath;
|
||||
|
||||
public function __construct(
|
||||
string $sculpinSourcePath,
|
||||
string $sourcePath,
|
||||
Builder $builder,
|
||||
Filesystem $filesystem,
|
||||
string $projectsPath
|
||||
) {
|
||||
$this->sculpinSourcePath = $sculpinSourcePath;
|
||||
$this->builder = $builder;
|
||||
$this->projectsPath = $projectsPath;
|
||||
$this->tmpPath = $this->sculpinSourcePath . '/../docs';
|
||||
$this->sourcePath = $sourcePath;
|
||||
$this->builder = $builder;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->projectsPath = $projectsPath;
|
||||
$this->tmpPath = $this->sourcePath . '/../docs';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +134,7 @@ SIDEBAR;
|
||||
$outputPath = $this->getProjectVersionTmpPath($project, $version);
|
||||
|
||||
// clear tmp directory first
|
||||
shell_exec(sprintf('rm -rf %s/*', $outputPath));
|
||||
$this->filesystem->remove($this->findFiles($outputPath));
|
||||
|
||||
$docsPath = $this->getProjectDocsPath($project) . '/en';
|
||||
|
||||
@@ -134,19 +143,9 @@ SIDEBAR;
|
||||
$sidebarPath = $docsPath . '/sidebar.rst';
|
||||
$sidebar = file_exists($sidebarPath) ? file_get_contents($sidebarPath) : self::DEFAULT_SIDEBAR;
|
||||
|
||||
$files = $this->recursiveGlob($docsPath);
|
||||
$files = $this->getSourceFiles($docsPath);
|
||||
|
||||
foreach ($files as $file) {
|
||||
// skip non .rst files
|
||||
if (strpos($file, '.rst') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip toc.rst
|
||||
if (strpos($file, 'toc.rst') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = str_replace($this->getProjectDocsPath($project) . '/en/', '', $file);
|
||||
|
||||
$newPath = $outputPath . '/' . $path;
|
||||
@@ -184,7 +183,7 @@ SIDEBAR;
|
||||
$content = str_replace('{{ sidebar }}', $sidebar, $content);
|
||||
|
||||
// append the source file name to the content so we can parse it back out
|
||||
// for use in the sculpin build process
|
||||
// for use in the build process
|
||||
$content .= sprintf('{{ SOURCE_FILE:/en/%s }}', $path);
|
||||
|
||||
file_put_contents($newPath, $content);
|
||||
@@ -195,8 +194,8 @@ SIDEBAR;
|
||||
{
|
||||
$outputPath = $this->getProjectVersionSourcePath($project, $version);
|
||||
|
||||
// clear projects docs source in the sculpin source folder before rebuilding
|
||||
shell_exec(sprintf('rm -rf %s/*', $outputPath));
|
||||
// clear projects docs source in the source folder before rebuilding
|
||||
$this->filesystem->remove($this->findFiles($outputPath));
|
||||
|
||||
// we have to get a fresh builder due to how the RST parser works
|
||||
$this->builder = $this->builder->recreate();
|
||||
@@ -212,23 +211,18 @@ SIDEBAR;
|
||||
{
|
||||
$projectDocsVersionPath = $this->getProjectVersionSourcePath($project, $version);
|
||||
|
||||
$files = $this->recursiveGlob($projectDocsVersionPath);
|
||||
$this->removeMetaFiles($projectDocsVersionPath);
|
||||
|
||||
$files = $this->getBuildFiles($projectDocsVersionPath);
|
||||
|
||||
foreach ($files as $file) {
|
||||
// we don't want the meta.php files in the end result
|
||||
if (strpos($file, 'meta.php')) {
|
||||
unlink($file);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = trim(file_get_contents($file));
|
||||
|
||||
// extract title from <h1>
|
||||
preg_match('/<h1>(.*)<\/h1>/', $content, $matches);
|
||||
|
||||
$title = '';
|
||||
if (! empty($matches)) {
|
||||
if ($matches !== []) {
|
||||
$title = $matches[1];
|
||||
}
|
||||
|
||||
@@ -240,7 +234,6 @@ SIDEBAR;
|
||||
);
|
||||
|
||||
// grab the html out of the <body> because that is all we need
|
||||
// sculpin will wrap it with the layout
|
||||
preg_match('/<body>(.*)<\/body>/s', $content, $matches);
|
||||
|
||||
$content = $matches[1] ?? $content;
|
||||
@@ -255,7 +248,7 @@ SIDEBAR;
|
||||
$content = str_replace($match[0], '', $content);
|
||||
|
||||
$newContent = sprintf(
|
||||
self::SCULPIN_TEMPLATE,
|
||||
self::PARAMETERS_TEMPLATE,
|
||||
$title,
|
||||
$project->getDocsSlug(),
|
||||
strpos($file, 'index.html') !== false ? 'true' : 'false',
|
||||
@@ -271,43 +264,103 @@ SIDEBAR;
|
||||
}
|
||||
}
|
||||
|
||||
private function removeMetaFiles(string $path) : void
|
||||
{
|
||||
$finder = new Finder();
|
||||
$finder->in($path)->name('meta.php')->files();
|
||||
|
||||
$files = $this->finderToArray($finder);
|
||||
|
||||
$this->filesystem->remove($files);
|
||||
}
|
||||
|
||||
private function getProjectDocsPath(Project $project) : string
|
||||
{
|
||||
return $project->getAbsoluteDocsPath($this->projectsPath);
|
||||
return realpath($project->getAbsoluteDocsPath($this->projectsPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function recursiveGlob(string $path) : array
|
||||
private function getSourceFiles(string $path) : array
|
||||
{
|
||||
$allFiles = [];
|
||||
|
||||
$files = glob($path . '/*');
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file)) {
|
||||
$allFiles = array_merge($allFiles, $this->recursiveGlob($file));
|
||||
} else {
|
||||
$allFiles[] = $file;
|
||||
}
|
||||
if (! is_dir($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $allFiles;
|
||||
$finder = $this->getFilesFinder($path);
|
||||
|
||||
$finder->name('*.rst');
|
||||
$finder->notName('toc.rst');
|
||||
|
||||
return $this->finderToArray($finder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getBuildFiles(string $path) : array
|
||||
{
|
||||
if (! is_dir($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$finder = $this->getFilesFinder($path);
|
||||
|
||||
$files = $this->finderToArray($finder);
|
||||
|
||||
return array_filter($files, function (string $file) {
|
||||
return strpos($file, 'meta.php') === false;
|
||||
});
|
||||
}
|
||||
|
||||
private function getFilesFinder(string $path) : Finder
|
||||
{
|
||||
$finder = new Finder();
|
||||
$finder->in($path)->files();
|
||||
|
||||
return $finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function findFiles(string $path) : array
|
||||
{
|
||||
if (! is_dir($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->finderToArray($this->getFilesFinder($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function finderToArray(Finder $finder) : array
|
||||
{
|
||||
return array_values(array_map(function (SplFileInfo $file) {
|
||||
return $file->getRealPath();
|
||||
}, iterator_to_array($finder)));
|
||||
}
|
||||
|
||||
private function ensureDirectoryExists(string $dir) : void
|
||||
{
|
||||
if (is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_exists($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Without the @ this fails on travis ci with error: "mkdir(): File exists"
|
||||
@mkdir($dir, 0777, true);
|
||||
}
|
||||
|
||||
private function getProjectVersionSourcePath(Project $project, ProjectVersion $version) : string
|
||||
{
|
||||
return $this->sculpinSourcePath . '/projects/' . $project->getDocsSlug() . '/en/' . $version->getSlug();
|
||||
return $this->sourcePath . '/projects/' . $project->getDocsSlug() . '/en/' . $version->getSlug();
|
||||
}
|
||||
|
||||
private function getProjectVersionTmpPath(Project $project, ProjectVersion $version) : string
|
||||
@@ -43,15 +43,6 @@ class SearchIndexer
|
||||
$index = $this->getSearchIndex();
|
||||
|
||||
$index->setSettings([
|
||||
'attributesToIndex' => [
|
||||
'unordered(projectName)',
|
||||
'unordered(h1)',
|
||||
'unordered(h2)',
|
||||
'unordered(h3)',
|
||||
'unordered(h4)',
|
||||
'unordered(h5)',
|
||||
'unordered(content)',
|
||||
],
|
||||
'attributesToIndex' => ['projectName', 'h1', 'h2', 'h3', 'h4', 'h5', 'content'],
|
||||
'customRanking' => ['asc(rank)'],
|
||||
'ranking' => ['words', 'typo', 'attribute', 'proximity', 'custom'],
|
||||
@@ -105,7 +96,7 @@ class SearchIndexer
|
||||
$nodeTypes = [TitleNode::class, ParagraphNode::class];
|
||||
|
||||
$nodes = $document->getNodes(function (Node $node) use ($nodeTypes) {
|
||||
return in_array(get_class($node), $nodeTypes);
|
||||
return in_array(get_class($node), $nodeTypes, true);
|
||||
});
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Directive;
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\CodeNode;
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\SubDirective;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\RawNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
|
||||
namespace Doctrine\Website\RST\Directive;
|
||||
|
||||
use Doctrine\RST\Nodes\Node;
|
||||
use Doctrine\RST\Nodes\WrapperNode;
|
||||
78
lib/Site.php
Normal file
78
lib/Site.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
class Site
|
||||
{
|
||||
/** @var string */
|
||||
private $title;
|
||||
|
||||
/** @var string */
|
||||
private $subtitle;
|
||||
|
||||
/** @var string */
|
||||
private $url;
|
||||
|
||||
/** @var string[] */
|
||||
private $keywords;
|
||||
|
||||
/** @var string */
|
||||
private $description;
|
||||
|
||||
/** @var string */
|
||||
private $env;
|
||||
|
||||
/**
|
||||
* @param string[] $keywords
|
||||
*/
|
||||
public function __construct(
|
||||
string $title,
|
||||
string $subtitle,
|
||||
string $url,
|
||||
array $keywords,
|
||||
string $description,
|
||||
string $env
|
||||
) {
|
||||
$this->title = $title;
|
||||
$this->subtitle = $subtitle;
|
||||
$this->url = $url;
|
||||
$this->keywords = $keywords;
|
||||
$this->description = $description;
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
public function getTitle() : string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getSubtitle() : string
|
||||
{
|
||||
return $this->subtitle;
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getKeywords() : array
|
||||
{
|
||||
return $this->keywords;
|
||||
}
|
||||
|
||||
public function getDescription() : string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getEnv() : string
|
||||
{
|
||||
return $this->env;
|
||||
}
|
||||
}
|
||||
47
lib/Twig/BlogExtension.php
Normal file
47
lib/Twig/BlogExtension.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Twig;
|
||||
|
||||
use Doctrine\Website\Builder\SourceFile;
|
||||
use Doctrine\Website\Builder\SourceFileRepository;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
use function array_reverse;
|
||||
use function usort;
|
||||
|
||||
class BlogExtension extends Twig_Extension
|
||||
{
|
||||
/** @var SourceFileRepository */
|
||||
private $sourceFileRepository;
|
||||
|
||||
public function __construct(SourceFileRepository $sourceFileRepository)
|
||||
{
|
||||
$this->sourceFileRepository = $sourceFileRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Twig_SimpleFunction[]
|
||||
*/
|
||||
public function getFunctions() : array
|
||||
{
|
||||
return [
|
||||
new Twig_SimpleFunction('get_blog_posts', [$this, 'getBlogPosts']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SourceFile[]
|
||||
*/
|
||||
public function getBlogPosts() : array
|
||||
{
|
||||
$blogPosts = $this->sourceFileRepository->getFiles('', 'source/blog');
|
||||
|
||||
usort($blogPosts, function (SourceFile $a, SourceFile $b) {
|
||||
return $a->getDate()->getTimestamp() - $b->getDate()->getTimestamp();
|
||||
});
|
||||
|
||||
return array_reverse($blogPosts);
|
||||
}
|
||||
}
|
||||
114
lib/Twig/MainExtension.php
Normal file
114
lib/Twig/MainExtension.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Twig;
|
||||
|
||||
use Parsedown;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function filemtime;
|
||||
use function md5;
|
||||
use function realpath;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
class MainExtension extends Twig_Extension
|
||||
{
|
||||
/** @var Parsedown */
|
||||
private $parsedown;
|
||||
|
||||
public function __construct(Parsedown $parsedown)
|
||||
{
|
||||
$this->parsedown = $parsedown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Twig_SimpleFunction[]
|
||||
*/
|
||||
public function getFunctions() : array
|
||||
{
|
||||
return [
|
||||
new Twig_SimpleFunction('get_asset_url', [$this, 'getAssetUrl']),
|
||||
new Twig_SimpleFunction('get_docs_urls', [$this, 'getDocsUrls']),
|
||||
new Twig_SimpleFunction('get_api_docs_urls', [$this, 'getApiDocsUrls']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Twig_SimpleFilter[]
|
||||
*/
|
||||
public function getFilters() : array
|
||||
{
|
||||
return [
|
||||
new Twig_SimpleFilter('markdown', [$this->parsedown, 'text']),
|
||||
];
|
||||
}
|
||||
|
||||
public function getAssetUrl(string $path, string $siteUrl) : string
|
||||
{
|
||||
return $siteUrl . $path . '?' . $this->getAssetCacheBuster($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getDocsUrls() : array
|
||||
{
|
||||
return $this->getUrlsFromFiles('projects');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getApiDocsUrls() : array
|
||||
{
|
||||
return $this->getUrlsFromFiles('api');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function getUrlsFromFiles(string $path, string $extension = 'html') : array
|
||||
{
|
||||
$root = realpath(__DIR__ . '/../../source');
|
||||
$path = $root . '/' . $path;
|
||||
|
||||
if (! file_exists($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$it = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
|
||||
$urls = [];
|
||||
foreach (new RecursiveIteratorIterator($it) as $file) {
|
||||
$path = (string) $file;
|
||||
|
||||
if (strpos($path, '.' . $extension) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = str_replace($root, '', $path);
|
||||
|
||||
$urls[] = [
|
||||
'url' => $url,
|
||||
'date' => filemtime($path),
|
||||
];
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
private function getAssetCacheBuster(string $path) : string
|
||||
{
|
||||
$assetPath = realpath(__DIR__ . '/../../source/' . $path);
|
||||
|
||||
return substr(md5(file_get_contents($assetPath)), 0, 6);
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ class ProjectExtension extends Twig_Extension
|
||||
private $projectRepository;
|
||||
|
||||
/** @var string */
|
||||
private $sculpinSourcePath;
|
||||
private $sourcePath;
|
||||
|
||||
public function __construct(ProjectRepository $projectRepository, string $sculpinSourcePath)
|
||||
public function __construct(ProjectRepository $projectRepository, string $sourcePath)
|
||||
{
|
||||
$this->projectRepository = $projectRepository;
|
||||
$this->sculpinSourcePath = $sculpinSourcePath;
|
||||
$this->sourcePath = $sourcePath;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ class ProjectExtension extends Twig_Extension
|
||||
$otherVersionUrl = str_replace($currentVersion, $projectVersion->getSlug(), $url);
|
||||
}
|
||||
|
||||
$otherVersionFile = $this->sculpinSourcePath . $otherVersionUrl;
|
||||
$otherVersionFile = $this->sourcePath . $otherVersionUrl;
|
||||
|
||||
if (! $this->fileExists($otherVersionFile)) {
|
||||
return null;
|
||||
@@ -6,22 +6,13 @@ namespace Doctrine\Website\Twig;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Website\Projects\Project;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
use function array_filter;
|
||||
use function file_get_contents;
|
||||
use function filemtime;
|
||||
use function in_array;
|
||||
use function ksort;
|
||||
use function md5;
|
||||
use function realpath;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
class MainExtension extends Twig_Extension
|
||||
class TeamExtension extends Twig_Extension
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private $teamMembers;
|
||||
@@ -40,23 +31,15 @@ class MainExtension extends Twig_Extension
|
||||
public function getFunctions() : array
|
||||
{
|
||||
return [
|
||||
new Twig_SimpleFunction('get_asset_url', [$this, 'getAssetUrl']),
|
||||
new Twig_SimpleFunction('get_active_core_team_members', [$this, 'getActiveCoreTeamMembers']),
|
||||
new Twig_SimpleFunction('get_active_documentation_team_members', [$this, 'getActiveDocumentationTeamMembers']),
|
||||
new Twig_SimpleFunction('get_inactive_team_members', [$this, 'getInactiveTeamMembers']),
|
||||
new Twig_SimpleFunction('get_active_project_team_members', [$this, 'getActiveProjectTeamMembers']),
|
||||
new Twig_SimpleFunction('get_inactive_project_team_members', [$this, 'getInactiveProjectTeamMembers']),
|
||||
new Twig_SimpleFunction('get_all_project_team_members', [$this, 'getAllProjectTeamMembers']),
|
||||
new Twig_SimpleFunction('get_docs_urls', [$this, 'getDocsUrls']),
|
||||
new Twig_SimpleFunction('get_api_docs_urls', [$this, 'getApiDocsUrls']),
|
||||
];
|
||||
}
|
||||
|
||||
public function getAssetUrl(string $path, string $siteUrl) : string
|
||||
{
|
||||
return $siteUrl . $path . '?' . $this->getAssetCacheBuster($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
@@ -123,7 +106,7 @@ class MainExtension extends Twig_Extension
|
||||
public function getAllProjectTeamMembers(Project $project) : array
|
||||
{
|
||||
return $this->getTeamMembers(function (array $teamMember) use ($project) {
|
||||
return in_array($project->getSlug(), $teamMember['projects'] ?? []);
|
||||
return in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -135,7 +118,7 @@ class MainExtension extends Twig_Extension
|
||||
return $this->getTeamMembers(function (array $teamMember) use ($project) {
|
||||
$active = $teamMember['active'] ?? false;
|
||||
|
||||
return $active && in_array($project->getSlug(), $teamMember['projects'] ?? []);
|
||||
return $active && in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,59 +130,7 @@ class MainExtension extends Twig_Extension
|
||||
return $this->getTeamMembers(function (array $teamMember) use ($project) {
|
||||
$active = $teamMember['active'] ?? false;
|
||||
|
||||
return ! $active && in_array($project->getSlug(), $teamMember['projects'] ?? []);
|
||||
return ! $active && in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getDocsUrls() : array
|
||||
{
|
||||
return $this->getUrlsFromFiles('projects');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getApiDocsUrls() : array
|
||||
{
|
||||
return $this->getUrlsFromFiles('api');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function getUrlsFromFiles(string $path) : array
|
||||
{
|
||||
$root = realpath(__DIR__ . '/../../../../../source');
|
||||
$path = $root . '/' . $path;
|
||||
|
||||
$it = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
|
||||
$urls = [];
|
||||
foreach (new RecursiveIteratorIterator($it) as $file) {
|
||||
$path = (string) $file;
|
||||
|
||||
if (strpos($path, '.html') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = str_replace($root, '', $path);
|
||||
|
||||
$urls[] = [
|
||||
'url' => $url,
|
||||
'date' => filemtime($path),
|
||||
];
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
private function getAssetCacheBuster(string $path) : string
|
||||
{
|
||||
$assetPath = realpath(__DIR__ . '/../../../../../source/' . $path);
|
||||
|
||||
return substr(md5(file_get_contents($assetPath)), 0, 6);
|
||||
}
|
||||
}
|
||||
66
lib/Twig/TwigRenderer.php
Normal file
66
lib/Twig/TwigRenderer.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Twig;
|
||||
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use function sha1;
|
||||
|
||||
class TwigRenderer
|
||||
{
|
||||
/** @var MainExtension */
|
||||
private $mainExtension;
|
||||
|
||||
/** @var ProjectExtension */
|
||||
private $projectExtension;
|
||||
|
||||
/** @var TeamExtension */
|
||||
private $teamExtension;
|
||||
|
||||
/** @var BlogExtension */
|
||||
private $blogExtension;
|
||||
|
||||
/** @var string */
|
||||
private $templatesPath;
|
||||
|
||||
public function __construct(
|
||||
MainExtension $mainExtension,
|
||||
ProjectExtension $projectExtension,
|
||||
TeamExtension $teamExtension,
|
||||
BlogExtension $blogExtension,
|
||||
string $templatesPath
|
||||
) {
|
||||
$this->mainExtension = $mainExtension;
|
||||
$this->projectExtension = $projectExtension;
|
||||
$this->teamExtension = $teamExtension;
|
||||
$this->blogExtension = $blogExtension;
|
||||
$this->templatesPath = $templatesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
public function render(string $twig, array $parameters) : string
|
||||
{
|
||||
$name = sha1($twig);
|
||||
|
||||
$loader = new ArrayLoader([$name => $twig]);
|
||||
|
||||
$chainLoader = new ChainLoader([
|
||||
$loader,
|
||||
new FilesystemLoader($this->templatesPath),
|
||||
]);
|
||||
|
||||
$twig = new Environment($chainLoader);
|
||||
$twig->addExtension($this->mainExtension);
|
||||
$twig->addExtension($this->projectExtension);
|
||||
$twig->addExtension($this->teamExtension);
|
||||
$twig->addExtension($this->blogExtension);
|
||||
|
||||
return $twig->render($name, $parameters);
|
||||
}
|
||||
}
|
||||
@@ -4,51 +4,62 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
use Dflydev\DotAccessConfiguration\Configuration;
|
||||
use Doctrine\Website\Builder\SourceFileBuilder;
|
||||
use Doctrine\Website\Builder\SourceFileRepository;
|
||||
use Doctrine\Website\Projects\Project;
|
||||
use Doctrine\Website\Projects\ProjectRepository;
|
||||
use Doctrine\Website\Projects\ProjectVersion;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use function chdir;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function glob;
|
||||
use function in_array;
|
||||
use function is_dir;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function symlink;
|
||||
use function unlink;
|
||||
|
||||
class WebsiteBuilder
|
||||
{
|
||||
public const URL_LOCAL = 'lcl.doctrine-project.org';
|
||||
public const URL_STAGING = 'staging.doctrine-project.org';
|
||||
public const URL_PRODUCTION = 'www.doctrine-project.org';
|
||||
public const PUBLISHABLE_ENVS = ['prod', 'staging'];
|
||||
|
||||
private const URL_PRODUCTION = 'www.doctrine-project.org';
|
||||
private const URL_STAGING = 'staging.doctrine-project.org';
|
||||
|
||||
private const PUBLISHABLE_ENV_URLS = [
|
||||
'prod' => self::URL_PRODUCTION,
|
||||
'staging' => self::URL_STAGING,
|
||||
];
|
||||
|
||||
/** @var ProcessFactory */
|
||||
private $processFactory;
|
||||
|
||||
/** @var Configuration */
|
||||
private $sculpinConfig;
|
||||
|
||||
/** @var ProjectRepository */
|
||||
private $projectRepository;
|
||||
|
||||
/** @var string */
|
||||
private $kernelRootDir;
|
||||
/** @var Filesystem */
|
||||
private $filesystem;
|
||||
|
||||
/** @var SourceFileRepository */
|
||||
private $sourceFileRepository;
|
||||
|
||||
/** @var SourceFileBuilder */
|
||||
private $sourceFileBuilder;
|
||||
|
||||
public function __construct(
|
||||
ProcessFactory $processFactory,
|
||||
Configuration $sculpinConfig,
|
||||
ProjectRepository $projectRepository,
|
||||
string $kernelRootDir
|
||||
Filesystem $filesystem,
|
||||
SourceFileRepository $sourceFileRepository,
|
||||
SourceFileBuilder $sourceFileBuilder
|
||||
) {
|
||||
$this->processFactory = $processFactory;
|
||||
$this->sculpinConfig = $sculpinConfig;
|
||||
$this->projectRepository = $projectRepository;
|
||||
$this->kernelRootDir = $kernelRootDir;
|
||||
$this->processFactory = $processFactory;
|
||||
$this->projectRepository = $projectRepository;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->sourceFileRepository = $sourceFileRepository;
|
||||
$this->sourceFileBuilder = $sourceFileBuilder;
|
||||
}
|
||||
|
||||
public function build(
|
||||
@@ -63,40 +74,19 @@ class WebsiteBuilder
|
||||
$buildDir
|
||||
));
|
||||
|
||||
$rootDir = realpath($this->kernelRootDir . '/..');
|
||||
|
||||
if ($publish) {
|
||||
$output->writeln(' - updating from git');
|
||||
|
||||
$this->processFactory->run(sprintf('cd %s && git pull origin master', $buildDir));
|
||||
}
|
||||
|
||||
$output->writeln(' - sculpin generate');
|
||||
$output->writeln(' - building website');
|
||||
|
||||
$command = sprintf(
|
||||
'php -d memory_limit=1024M %s/vendor/bin/sculpin generate --env=%s',
|
||||
$rootDir,
|
||||
$env
|
||||
);
|
||||
|
||||
$this->processFactory->run($command);
|
||||
|
||||
$output->writeln(' - preparing build');
|
||||
|
||||
$outputDir = sprintf('output_%s', $env);
|
||||
|
||||
// cleanup the build directory
|
||||
$this->processFactory->run(sprintf('rm -rf %s/*', $buildDir));
|
||||
|
||||
// copy the build to the build directory
|
||||
$this->processFactory->run(sprintf('mv %s/%s/* %s', $rootDir, $outputDir, $buildDir));
|
||||
$this->buildWebsite($buildDir);
|
||||
|
||||
// put the CNAME file back for publishable envs
|
||||
if (in_array($env, self::PUBLISHABLE_ENVS)) {
|
||||
$url = $this->sculpinConfig->get('url');
|
||||
$cname = str_replace(['https://', 'http://'], '', $url);
|
||||
|
||||
$this->filePutContents($buildDir . '/CNAME', $cname);
|
||||
if (in_array($env, self::PUBLISHABLE_ENVS, true)) {
|
||||
$this->filePutContents($buildDir . '/CNAME', self::PUBLISHABLE_ENV_URLS[$env]);
|
||||
}
|
||||
|
||||
$this->createProjectVersionAliases($buildDir);
|
||||
@@ -115,9 +105,14 @@ class WebsiteBuilder
|
||||
file_put_contents($path, $contents);
|
||||
}
|
||||
|
||||
protected function execute(string $command) : void
|
||||
private function buildWebsite(string $buildDir) : void
|
||||
{
|
||||
$this->processFactory->run($command);
|
||||
// cleanup the build directory
|
||||
$this->filesystem->remove(glob($buildDir . '/*'));
|
||||
|
||||
foreach ($this->sourceFileRepository->getFiles($buildDir) as $file) {
|
||||
$this->sourceFileBuilder->buildFile($file, $buildDir);
|
||||
}
|
||||
}
|
||||
|
||||
private function createProjectVersionAliases(string $buildDir) : void
|
||||
@@ -9,12 +9,8 @@
|
||||
<!-- Ignore warnings, show progress of the run and show sniff names -->
|
||||
<arg value="nps"/>
|
||||
|
||||
<file>app</file>
|
||||
<file>lib</file>
|
||||
<file>tests</file>
|
||||
|
||||
<rule ref="Doctrine"/>
|
||||
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
|
||||
<exclude-pattern>app/SculpinKernel.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
||||
9
phpstan.neon.dist
Normal file
9
phpstan.neon.dist
Normal file
@@ -0,0 +1,9 @@
|
||||
includes:
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
parameters:
|
||||
level: 1
|
||||
paths:
|
||||
- lib
|
||||
- tests
|
||||
@@ -1,15 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./vendor/autoload.php" colors="true">
|
||||
<filter>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./app/src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
verbose="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine Website Test Suite">
|
||||
<directory suffix="Test.php">./tests/Doctrine/Website/Tests/</directory>
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./lib</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
{% extends "default" %}
|
||||
|
||||
{% block head_meta %}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "NewsArticle",
|
||||
"mainEntityOfPage": {
|
||||
"@type": "WebPage",
|
||||
"@id": "{{ site.url }}{{ page.url }}"
|
||||
},
|
||||
"headline": "{{ page.title }}",
|
||||
"image": [
|
||||
"{{ site.url }}/images/og.png"
|
||||
],
|
||||
"datePublished": "{{ page.date|date('c') }}",
|
||||
"dateModified": "{{ page.date|date('c') }}",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "{{ page.authorName ?? 'Doctrine' }}"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "Doctrine",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "{{ site.url }}/images/og.png"
|
||||
}
|
||||
},
|
||||
"description": "{{ page.blocks.content|raw|striptags[:100] }}"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_wrapper %}
|
||||
<article>
|
||||
<header>
|
||||
<h2>{{ page.title }} <small>post</small></h2>
|
||||
</header>
|
||||
|
||||
<p class="lead">
|
||||
Posted on {{ page.date|date('Y-m-d') }}
|
||||
{% if page.authorName %}
|
||||
by
|
||||
{% if page.authorEmail %}
|
||||
<a href="mailto:{{ page.authorEmail }}">{{ page.authorName }}</a>
|
||||
{% else %}
|
||||
{{ page.authorName }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
{{ page.blocks.content|raw }}
|
||||
</div>
|
||||
|
||||
{% if page.previous_post or page.next_post %}
|
||||
<nav class="article">
|
||||
<ul class="pagination">
|
||||
{% if page.previous_post %}
|
||||
<li class="page-item"><a class="page-link previous" href="{{ site.url }}{{ page.previous_post.url }}" title="{{ page.previous_post.title }}"><span class="title">Previous: {{ page.previous_post.title }}</span></a></li>
|
||||
{% endif %}
|
||||
{% if page.next_post %}
|
||||
<li class="page-item"><a class="page-link next" href="{{ site.url }}{{ page.next_post.url }}" title="{{ page.next_post.title }}"><span class="title">Next: {{ page.next_post.title }}</span></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
|
||||
{% if site.disqus.shortname and site.disqus.shortname != '' %}
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||
var disqus_shortname = '{{site.disqus.shortname}}'; // required: replace example with your forum shortname
|
||||
|
||||
|
||||
{% if page.disqus.identifier %}var disqus_identifier = '{{page.disqus.identifier}}'; {% endif %}
|
||||
|
||||
{% if page.disqus.title %}var disqus_title = '{{page.disqus.title}}';{% endif %}
|
||||
|
||||
{% if page.disqus.url %}var disqus_url = '{{page.disqus.url}}';{% endif %}
|
||||
|
||||
{% if page.disqus.category_id %}var disqus_category_id = '{{page.disqus.category_id}}';{% endif %}
|
||||
|
||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||
(function () {
|
||||
var dsq = document.createElement('script');
|
||||
dsq.type = 'text/javascript';
|
||||
dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the
|
||||
<a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a>
|
||||
</noscript>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
title: Posts Archive
|
||||
generator: pagination
|
||||
use:
|
||||
- posts
|
||||
|
||||
---
|
||||
{% set year = '0' %}
|
||||
|
||||
<h1><i class="fa fa-archive"></i> Archive</h1>
|
||||
|
||||
{% for post in page.pagination.items %}
|
||||
{% set this_year %}{{ post.date | date("Y") }}{% endset %}
|
||||
|
||||
{% if year != this_year %}
|
||||
{% set month = '0' %}
|
||||
{% set year = this_year %}
|
||||
{% endif %}
|
||||
|
||||
{% set this_month %}{{ post.date | date("F") }}{% endset %}
|
||||
|
||||
{% if month != this_month %}
|
||||
{% set month = this_month %}
|
||||
<h3>{{ month }} {{ year }}</h3>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<a href="{{ site.url }}{{ post.url }}">{{ post.title }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if page.pagination.previous_page or page.pagination.next_page %}
|
||||
<nav class="mt-4">
|
||||
<ul class="pagination">
|
||||
{% if page.pagination.previous_page %}
|
||||
<li class="page-item"><a class="page-link previous" href="{{ site.url }}{{ page.pagination.previous_page.url }}" title="Previous Page"><span class="title">Previous Page</span></a></li>
|
||||
{% endif %}
|
||||
|
||||
{% if page.pagination.next_page %}
|
||||
<li class="page-item"><a class="page-link next" href="{{ site.url }}{{ page.pagination.next_page.url }}" title="Next Page"><span class="title">Next Page</span></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
use: ["posts"]
|
||||
permalink: atom.xml
|
||||
permalink: /atom.xml
|
||||
---
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
@@ -18,15 +17,13 @@ permalink: atom.xml
|
||||
</author>
|
||||
{% endif %}
|
||||
|
||||
<generator uri="http://sculpin.io/">Sculpin</generator>
|
||||
|
||||
{% for post in data.posts|slice(0, 10) %}
|
||||
{% for post in get_blog_posts()|slice(0, 10) %}
|
||||
<entry>
|
||||
<title type="html"><![CDATA[{{ post.title }}]]></title>
|
||||
<title type="html"><![CDATA[{{ post.parameters.title }}]]></title>
|
||||
<link href="{{ site.url }}{{ post.url }}"/>
|
||||
<updated>{{ post.date|date('c') }}</updated>
|
||||
<id>{{ site.url }}{{ post.url }}</id>
|
||||
<content type="html"><![CDATA[{{ post.blocks.content|raw }}]]></content>
|
||||
<content type="html"><![CDATA[{{ post.contents|markdown|raw }}]]></content>
|
||||
</entry>
|
||||
{% endfor %}
|
||||
</feed>
|
||||
|
||||
@@ -2,53 +2,23 @@
|
||||
layout: default
|
||||
title: Blog
|
||||
menuSlug: blog
|
||||
generator: pagination
|
||||
pagination:
|
||||
max_per_page: 3
|
||||
use:
|
||||
- posts
|
||||
permalink: /blog/index.html
|
||||
---
|
||||
|
||||
{% for post in page.pagination.items %}
|
||||
<article>
|
||||
<header>
|
||||
<h2><a href="{{ site.url }}{{ post.url }}">{{ post.title }}</a></h2>
|
||||
</header>
|
||||
<h1>Blog</h1>
|
||||
|
||||
<p class="lead">
|
||||
Posted on {{ post.date|date('Y-m-d') }}
|
||||
{% if post.authorName %}
|
||||
by
|
||||
{% if post.authorEmail %}
|
||||
<a href="mailto:{{ post.authorEmail }}">{{ post.authorName }}</a>
|
||||
{% else %}
|
||||
{{ post.authorName }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
{% for post in get_blog_posts() %}
|
||||
{{ post.date|date('Y-m-d') }} <a href="{{ post.url }}">{{ post.parameters.title }}</a>
|
||||
|
||||
<div>
|
||||
{{ post.blocks.content|raw }}
|
||||
</div>
|
||||
|
||||
{% if post.meta.tags %}
|
||||
<p class="tags">
|
||||
Tags:
|
||||
{% for tag in post.meta.tags %}
|
||||
<a href="{{ site.url }}/blog/tags/{{ tag|url_encode(true) }}">{{ tag }}</a>{% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% if post.parameters.authorName %}
|
||||
by
|
||||
{% if post.parameters.authorEmail %}
|
||||
<a href="mailto:{{ page.authorEmail }}">{{ post.parameters.authorName }}</a>
|
||||
{% else %}
|
||||
{{ post.parameters.authorName }}
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endif %}
|
||||
<br/>
|
||||
{% endfor %}
|
||||
|
||||
{% if page.pagination.previous_page or page.pagination.next_page %}
|
||||
<nav class="mt-4">
|
||||
<ul class="pagination">
|
||||
{% if page.pagination.previous_page %}<li class="page-item"><a class="page-link" href="{{ site.url }}{{ page.pagination.previous_page.url }}">Newer Posts</a></li>{% endif %}<br />
|
||||
{% if page.pagination.next_page %}<li class="page-item"><a class="page-link" href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts</a></li>{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: New Website
|
||||
title: "New Website"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2007/10/09/new-website.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: New Coverage Report
|
||||
title: "New Coverage Report"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2007/10/14/new-coverage-report.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Beta 2
|
||||
title: "Beta 2"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2007/11/02/beta-2.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Beta 2 Released
|
||||
title: "Beta 2 Released"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: [release]
|
||||
permalink: /2007/12/03/beta2_released.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: URL Changes
|
||||
title: "URL Changes"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2007/12/04/url_changes.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: New Design
|
||||
title: "New Design"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2007/12/08/new_design.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Project Status
|
||||
title: "Project Status"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/01/05/project_status.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Cleaning up the mess
|
||||
title: "Cleaning up the mess"
|
||||
menuSlug: blog
|
||||
authorName: guilhermeblanco
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: guilhermeblanco
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/01/16/cleaning_up_the_mess.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: A few updates for 2008
|
||||
title: "A few updates for 2008"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/01/25/a-few-updates-for-2008.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Using Doctrine with CodeIgniter
|
||||
title: "Using Doctrine with CodeIgniter"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/01/29/using-doctrine-with-codeigniter.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Doctrine all grown up
|
||||
title: "Doctrine all grown up"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/02/14/doctrine-all-grown-up.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Doctrine 0.9.1 / 0.10.1 Released
|
||||
title: "Doctrine 0.9.1 / 0.10.1 Released"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: [release]
|
||||
permalink: /2008/02/16/doctrine-0-9-1-0-10-1-released.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Doctrine ORM Sandbox
|
||||
title: "Doctrine ORM Sandbox"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/02/18/doctrine-orm-sandbox.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: 0.10.2 Released
|
||||
title: "0.10.2 Released"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: [release]
|
||||
permalink: /2008/03/01/0-10-2-released.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: My First Project Doctrine Tutorial
|
||||
title: "My First Project Doctrine Tutorial"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/03/02/my-first-project-doctrine-tutorial.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Doctrine Cheat Sheet
|
||||
title: "Doctrine Cheat Sheet"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/03/04/doctrine-cheat-sheet.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: 4,000th svn commit/revision
|
||||
title: "4,000th svn commit/revision"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/03/16/4-000th-svn-commit-revision.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: 0.10.3 Released
|
||||
title: "0.10.3 Released"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: [release]
|
||||
permalink: /2008/03/18/0-10-3-released.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: 0.10.4 Released - 46 Closed Tickets
|
||||
title: "0.10.4 Released - 46 Closed Tickets"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: [release]
|
||||
permalink: /2008/03/28/0-10-4-released-46-closed-tickets.html
|
||||
---
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Using Doctrine with Zend Framework
|
||||
title: "Using Doctrine with Zend Framework"
|
||||
menuSlug: blog
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
layout: blog-post
|
||||
authorName: jwage
|
||||
authorEmail:
|
||||
categories: []
|
||||
permalink: /2008/03/29/using-doctrine-zend-framework.html
|
||||
---
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user