├── Exception ├── Exception.php ├── OutOfBoundsException.php └── InvalidArgumentException.php ├── Sitemap ├── Provider.php ├── Storage │ ├── Storage.php │ ├── Memory.php │ └── Doctrine │ │ └── ODM │ │ └── MongoDB.php ├── Sitemap.php └── Url.php ├── Resources ├── config │ ├── routing.yml │ └── sitemap.xml └── views │ └── Sitemap │ ├── siteindex.xml.twig │ └── sitemap.xml.twig ├── Dumper ├── Dumper.php └── Doctrine │ └── ODM │ └── MongoDB.php ├── composer.json ├── DependencyInjection ├── Compiler │ └── SitemapProviderPass.php └── OpenSkySitemapExtension.php ├── OpenSkySitemapBundle.php ├── Tests ├── Sitemap │ ├── Storage │ │ ├── MemoryTest.php │ │ └── Doctrine │ │ │ └── ODM │ │ │ └── MongoDBTest.php │ ├── UrlTest.php │ └── SitemapTest.php ├── DependencyInjection │ └── SitemapExtensionTest.php └── Listener │ └── SitemapListenerTest.php ├── Command └── GenerateCommand.php ├── Listener └── SitemapListener.php ├── Controller └── SitemapController.php └── README.md /Exception/Exception.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2010 OpenSky Project Inc 10 | */ 11 | interface Exception 12 | { 13 | } -------------------------------------------------------------------------------- /Sitemap/Provider.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2010 OpenSky Project Inc 10 | */ 11 | interface Provider 12 | { 13 | public function populate(Sitemap $sitemap); 14 | } -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | sitemap: 2 | pattern: /sitemap.xml 3 | defaults: { _controller: OpenSkySitemapBundle:Sitemap:sitemap, _format: xml } 4 | requirements: { _method: GET } 5 | siteindex: 6 | pattern: /siteindex.xml 7 | defaults: { _controller: OpenSkySitemapBundle:Sitemap:siteindex, _format: xml } 8 | requirements: { _method: GET } -------------------------------------------------------------------------------- /Dumper/Dumper.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | interface Dumper 14 | { 15 | public function dump(Sitemap $sitemap); 16 | } -------------------------------------------------------------------------------- /Exception/OutOfBoundsException.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | class OutOfBoundsException extends BaseOutOfBoundsException implements Exception 14 | { 15 | } -------------------------------------------------------------------------------- /Resources/views/Sitemap/siteindex.xml.twig: -------------------------------------------------------------------------------- 1 | {% spaceless %} 2 | 3 | 4 | {% for page in range(1, max(1, totalPages)) %} 5 | 6 | {{ url('sitemap', {'page': page}) }} 7 | 8 | {% endfor %} 9 | 10 | {% endspaceless %} -------------------------------------------------------------------------------- /Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | class InvalidArgumentException extends BaseInvalidArgumentException implements Exception 14 | { 15 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opensky/sitemap-bundle", 3 | "description": "Adds a sitemap.xml file!", 4 | "keywords": [ "sitemap" ], 5 | "homepage": "https://github.com/opensky/SitemapBundle", 6 | "type": "symfony-bundle", 7 | "license": "MIT", 8 | "require": { 9 | "php": ">=5.3.0", 10 | "symfony/framework-bundle": ">=2.1.0,<2.3-dev" 11 | }, 12 | "autoload": { 13 | "psr-0": { "OpenSky\\Bundle\\SitemapBundle": "" } 14 | }, 15 | "target-dir": "OpenSky/Bundle/SitemapBundle" 16 | } 17 | -------------------------------------------------------------------------------- /Resources/views/Sitemap/sitemap.xml.twig: -------------------------------------------------------------------------------- 1 | {% spaceless %} 2 | 3 | 4 | {% for url in urls %} 5 | 6 | {% if url.loc %}{{ url.loc }}{% endif %} 7 | {% if url.lastmod %}{{ url.lastmod }}{% endif %} 8 | {% if url.changefreq %}{{ url.changefreq }}{% endif %} 9 | {% if url.priority %}{{ url.priority }}{% endif %} 10 | 11 | {% endfor %} 12 | 13 | {% endspaceless %} -------------------------------------------------------------------------------- /DependencyInjection/Compiler/SitemapProviderPass.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('opensky.sitemap.provider') as $id => $attributes) { 15 | $providers[] = $id; 16 | } 17 | 18 | if (count($providers)) { 19 | $container->setParameter('opensky.sitemap.providers', $providers); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /OpenSkySitemapBundle.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) 2010 OpenSky Project Inc 15 | */ 16 | class OpenSkySitemapBundle extends Bundle 17 | { 18 | public function __construct() 19 | { 20 | $this->extension = new OpenSkySitemapExtension(); 21 | } 22 | 23 | public function build(ContainerBuilder $container) 24 | { 25 | $container->addCompilerPass(new SitemapProviderPass()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sitemap/Storage/Storage.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | interface Storage 14 | { 15 | const PAGE_LIMIT = 50000; 16 | 17 | /** 18 | * @return int 19 | */ 20 | public function getTotalPages(); 21 | 22 | /** 23 | * @param string loc 24 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Url|null 25 | */ 26 | public function findOne($loc); 27 | 28 | /** 29 | * @param int page 30 | * @return \Traversable 31 | */ 32 | public function find($page); 33 | 34 | /** 35 | * @param OpenSky\Bundle\SitemapBundle\Sitemap\Url 36 | */ 37 | public function save(Url $url); 38 | } -------------------------------------------------------------------------------- /Sitemap/Storage/Memory.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | class Memory implements Storage 14 | { 15 | public $urls = array(); 16 | 17 | /** 18 | * @return int 19 | */ 20 | public function getTotalPages() 21 | { 22 | return ceil(count($this->urls) / self::PAGE_LIMIT); 23 | } 24 | 25 | /** 26 | * @param string loc 27 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Url|null 28 | */ 29 | public function findOne($loc) 30 | { 31 | return isset($this->urls[$loc]) ? $this->urls[$loc] : null; 32 | } 33 | 34 | /** 35 | * @param int page 36 | * @return \Traversable 37 | */ 38 | public function find($page) 39 | { 40 | return array_slice($this->urls, ($page - 1) * self::PAGE_LIMIT, self::PAGE_LIMIT); 41 | } 42 | 43 | /** 44 | * @param OpenSky\Bundle\SitemapBundle\Sitemap\Url 45 | */ 46 | public function save(Url $url) 47 | { 48 | $this->urls[$url->getLoc()] = $url; 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /Dumper/Doctrine/ODM/MongoDB.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright (c) 2010 OpenSky Project Inc 14 | */ 15 | class MongoDB implements Dumper 16 | { 17 | /** 18 | * ${@inheritDoc} 19 | */ 20 | public function dump(Sitemap $sitemap) 21 | { 22 | // remove the old ones first... 23 | $this->getDocumentCollection($sitemap)->remove(array()); 24 | 25 | // now flush the new ones 26 | $dm = $this->getDocumentManager($sitemap); 27 | $dm->flush(null, array('safe' => true)); 28 | } 29 | 30 | /** 31 | * @param Sitemap $sitemap 32 | * @return Doctrine\ODM\MongoDB\DocumentManager 33 | */ 34 | protected function getDocumentManager(Sitemap $sitemap) 35 | { 36 | return $sitemap->getStorage()->getDocumentManager(); 37 | } 38 | 39 | /** 40 | * @param Sitemap $sitemap 41 | * @return Doctrine\MongoDB\Collection 42 | */ 43 | protected function getDocumentCollection(Sitemap $sitemap) 44 | { 45 | return $this->getDocumentManager($sitemap)->getDocumentCollection($sitemap->getUrlClass()); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Tests/Sitemap/Storage/MemoryTest.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) 2010 OpenSky Project Inc 15 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 16 | */ 17 | class MemoryTest extends \PHPUnit_Framework_TestCase 18 | { 19 | protected $storage; 20 | 21 | public function setUp() 22 | { 23 | $this->storage = new Memory(); 24 | } 25 | 26 | public function tearDown() 27 | { 28 | unset($this->storage); 29 | } 30 | 31 | public function testFindReturnsEmptyResult() 32 | { 33 | $this->assertEquals(0, count($this->storage->find(1))); 34 | } 35 | 36 | public function testFindOneReturnsNullForNonExistentResult() 37 | { 38 | $this->assertNull($this->storage->findOne('http://google.com')); 39 | } 40 | 41 | public function testHasUrlAfterAdding() 42 | { 43 | $location = 'http://www.twitter.com'; 44 | $url = $this->getCreateUrl($location); 45 | $this->storage->save($url); 46 | $this->assertSame($url, $this->storage->findOne($location)); 47 | $this->assertEquals(1, count($this->storage->find(1))); 48 | } 49 | 50 | public function testGetTotalPages() 51 | { 52 | $this->storage->urls = array_pad(array(), Memory::PAGE_LIMIT + 1, 'http://www.google.com'); 53 | $this->assertEquals(2, $this->storage->getTotalPages()); 54 | } 55 | 56 | protected function getCreateUrl($location) 57 | { 58 | return new Url($location); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /Command/GenerateCommand.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright (c) 2010 OpenSky Project Inc 16 | */ 17 | class GenerateCommand extends ContainerAwareCommand 18 | { 19 | 20 | /** 21 | * {@inheritDoc} 22 | */ 23 | protected function configure() 24 | { 25 | $this 26 | ->setName('sitemap:generate') 27 | ->setDescription('Generate sitemap, using its data providers.'); 28 | } 29 | 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | public function execute(InputInterface $input, OutputInterface $output) 34 | { 35 | $sitemap = $this->getSitemap(); 36 | foreach ($this->getProviders() as $id) { 37 | $this->getContainer()->get($id)->populate($sitemap); 38 | } 39 | $this->getSitemapDumper()->dump($sitemap); 40 | } 41 | 42 | /** 43 | * @return Bundle\SitemapBundle\Sitemap\Sitemap 44 | */ 45 | protected function getSitemap() 46 | { 47 | return $this->getContainer()->get('opensky.sitemap'); 48 | } 49 | 50 | /** 51 | * @return Bundle\SitemapBundle\Dumper\Dumper 52 | */ 53 | protected function getSitemapDumper() 54 | { 55 | return $this->getContainer()->get('opensky.sitemap.dumper'); 56 | } 57 | 58 | /** 59 | * @return array Provider service ids 60 | */ 61 | protected function getProviders() 62 | { 63 | return $this->getContainer()->getParameter('opensky.sitemap.providers'); 64 | } 65 | } -------------------------------------------------------------------------------- /DependencyInjection/OpenSkySitemapExtension.php: -------------------------------------------------------------------------------- 1 | 16 | * @copyright (c) 2010 OpenSky Project Inc 17 | */ 18 | class OpenSkySitemapExtension extends Extension 19 | { 20 | 21 | /** 22 | * Loads OpenSky Sitemap configuration into the container: 23 | * 24 | * opensky_sitemap: 25 | * default_lastmod: 2010-06-01 26 | * default_changefreq: monthly 27 | * default_priority: 0.5 28 | * 29 | * @see Symfony\Component\DependencyInjection\Extension\ExtensionInterface::load() 30 | */ 31 | public function load(array $configs, ContainerBuilder $container) 32 | { 33 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 34 | $loader->load('sitemap.xml'); 35 | 36 | $defaults = $container->getParameter('opensky.sitemap.defaults'); 37 | foreach ($configs as $config) { 38 | foreach (array('changefreq', 'priority', 'lastmod') as $prop) { 39 | if (isset($config['default_' . $prop])) { 40 | $defaults[$prop] = $config['default_' . $prop]; 41 | } 42 | } 43 | } 44 | 45 | $container->setParameter('opensky.sitemap.defaults', $defaults); 46 | } 47 | 48 | /** 49 | * @see Symfony\Component\DependencyInjection\Extension\ExtensionInterface::getAlias() 50 | * @codeCoverageIgnore 51 | */ 52 | public function getAlias() 53 | { 54 | return 'opensky_sitemap'; 55 | } 56 | } -------------------------------------------------------------------------------- /Tests/Sitemap/UrlTest.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright (c) 2010 OpenSky Project Inc 14 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 15 | */ 16 | class UrlTest extends \PHPUnit_Framework_TestCase 17 | { 18 | 19 | /** 20 | * @expectedException Bundle\SitemapBundle\Exception\InvalidArgumentException 21 | */ 22 | public function testThrowsOnInvalidUrl() 23 | { 24 | new Url('somdasdasd'); 25 | } 26 | 27 | public function testGetLoc() 28 | { 29 | $url = new Url('http://www.example.org/'); 30 | $this->assertEquals('http://www.example.org/', $url->getLoc()); 31 | } 32 | 33 | public function testSetLastmod() 34 | { 35 | $url = new Url('http://www.example.org/'); 36 | $now = new \DateTime(); 37 | $url->setLastmod($now); 38 | $this->assertEquals(date(Url::LASTMOD_FORMAT, $now->getTimestamp()), $url->getLastmod()); 39 | } 40 | 41 | /** 42 | * @expectedException Bundle\SitemapBundle\Exception\InvalidArgumentException 43 | */ 44 | public function testThrowsOnInvalidChangefreq() 45 | { 46 | $url = new Url('http://www.example.org/'); 47 | $url->setChangefreq('somefreq'); 48 | } 49 | 50 | public function testGetChangefreq() 51 | { 52 | $url = new Url('http://www.example.org/'); 53 | $url->setChangefreq(Url::DAILY); 54 | $this->assertEquals(Url::DAILY, $url->getChangefreq()); 55 | } 56 | 57 | public function testGetPriority() 58 | { 59 | $url = new Url('http://www.example.org/'); 60 | $url->setPriority(1.0); 61 | $this->assertEquals(1.0, $url->getPriority()); 62 | } 63 | 64 | /** 65 | * @expectedException Bundle\SitemapBundle\Exception\InvalidArgumentException 66 | */ 67 | public function testThrowsOnInvalidPriority() 68 | { 69 | $url = new Url('http://www.example.org/'); 70 | $url->setPriority(2.0); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Tests/DependencyInjection/SitemapExtensionTest.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) 2010 OpenSky Project Inc 15 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 16 | */ 17 | class SitemapExtensionTest extends \PHPUnit_Framework_TestCase 18 | { 19 | 20 | public function testSitemapLoad() 21 | { 22 | $configuration = new ContainerBuilder(); 23 | $loader = new SitemapExtension('testkernel'); 24 | $configuration = $loader->configLoad(array('driver' => 'odm.mongodb'), $configuration); 25 | $this->assertEquals('Bundle\SitemapBundle\Sitemap\Sitemap', $configuration->getParameter('sitemap.class'), '->sitemapLoad() merges default configration parameters'); 26 | $this->assertHasDefinition('sitemap.sitemap', $configuration, '->sitemapLoad() defines sitemap service'); 27 | } 28 | 29 | public function testSitemapLoadWithDefaults() 30 | { 31 | $configuration = new ContainerBuilder(); 32 | $loader = new SitemapExtension('testkernel'); 33 | $configuration = $loader->configLoad(array( 34 | 'driver' => 'odm.mongodb', 35 | 'default_changefreq' => 'daily', 36 | 'default_lastmod' => strtotime('2006-01-01'), 37 | 'default_priority' => 0.3, 38 | ), $configuration); 39 | $this->assertEquals(array( 40 | 'changefreq' => 'daily', 41 | 'lastmod' => strtotime('2006-01-01'), 42 | 'priority' => 0.3, 43 | ), $configuration->getParameter('sitemap.defaults'), '->sitemapLoad() merges default configration parameters'); 44 | $this->assertHasDefinition('sitemap.dumper', $configuration, '->sitemapLoad() defines sitemap.dumper service'); 45 | } 46 | 47 | public function assertHasDefinition($id, ContainerBuilder $configuration, $message = '') 48 | { 49 | $this->assertTrue(($configuration->hasDefinition($id) ? : $configuration->hasAlias($id)), $message); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /Listener/SitemapListener.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright (c) 2010 OpenSky Project Inc 16 | */ 17 | class SitemapListener 18 | { 19 | const DEFAULT_PRIORITY = '0.2'; 20 | 21 | /** 22 | * @var OpenSky\Bundle\SitemapBundle\Sitemap\Sitemap 23 | */ 24 | protected $sitemap; 25 | /** 26 | * @var OpenSky\Bundle\SitemapBundle\Dumper\Dumper 27 | */ 28 | protected $dumper; 29 | 30 | /** 31 | * @param OpenSky\Bundle\SitemapBundle\Sitemap\Sitemap $sitemap 32 | */ 33 | public function __construct(Sitemap $sitemap, Dumper $dumper) 34 | { 35 | $this->sitemap = $sitemap; 36 | $this->dumper = $dumper; 37 | } 38 | 39 | public function update(Event $event) 40 | { 41 | $urlLoc = $event->get('loc'); 42 | 43 | if (!$this->sitemap->has($urlLoc)) { 44 | throw new Exception\OutOfBoundsException('Url ' . $urlLoc . ' could not be found.'); 45 | } 46 | 47 | $url = $this->sitemap->get($urlLoc); 48 | 49 | $time = new \DateTime(); 50 | $lastmod = $url->getLastmod(); 51 | 52 | $url->setLastmod($time); 53 | $url->setChangefreq($this->getChangefreq($time->diff(\DateTime::createFromFormat(Url::LASTMOD_FORMAT, $lastmod)))); 54 | 55 | $this->dump($this->sitemap); 56 | } 57 | 58 | public function create(Event $event) 59 | { 60 | $this->sitemap->add($event->get('loc'), array( 61 | 'changefreq' => ($event->has('changefreq') ? $event->get('changefreq') : Url::YEARLY), 62 | 'priority' => ($event->has('priority') ? $event->get('priority') : self::DEFAULT_PRIORITY), 63 | 'lastmod' => new \DateTime(), 64 | )); 65 | 66 | $this->dump($this->sitemap); 67 | } 68 | 69 | protected function getChangefreq(\DateInterval $interval) 70 | { 71 | return ($interval->y >= 1) ? Url::YEARLY : (($interval->m >= 1) ? Url::MONTHLY : (($interval->d >= 7) ? Url::WEEKLY : Url::DAILY)); 72 | } 73 | 74 | protected function dump(Sitemap $sitemap) 75 | { 76 | $this->dumper->dump($sitemap); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /Sitemap/Storage/Doctrine/ODM/MongoDB.php: -------------------------------------------------------------------------------- 1 | 16 | * @copyright (c) 2010 OpenSky Project Inc 17 | */ 18 | class MongoDB implements Storage 19 | { 20 | /** 21 | * @var Doctrine\ODM\MongoDB\DocumentManager 22 | */ 23 | protected $dm; 24 | 25 | /** 26 | * @var Doctrine\ODM\MongoDB\DocumentRepository 27 | */ 28 | protected $repository; 29 | 30 | /** 31 | * Constructor. 32 | * 33 | * @param Doctrine\ODM\MongoDB\DocumentManager $dm 34 | */ 35 | public function __construct(DocumentManager $dm, DocumentRepository $repository) 36 | { 37 | $this->dm = $dm; 38 | $this->repository = $repository; 39 | } 40 | 41 | /** 42 | * Finds one Url by location, returns null if not found 43 | * 44 | * @param string $loc 45 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Url|null 46 | */ 47 | public function findOne($loc) 48 | { 49 | return $this->repository->find($loc); 50 | } 51 | 52 | /** 53 | * Finds all urls on specific page 54 | * 55 | * @param int $page 56 | * @return \Traversable 57 | */ 58 | public function find($page) 59 | { 60 | return $this->repository->findAll() 61 | ->skip($this->getSkip($page)) 62 | ->limit(self::PAGE_LIMIT); 63 | } 64 | 65 | /** 66 | * Returns total number of pages in the sitemap 67 | * 68 | * @return int 69 | */ 70 | public function getTotalPages() 71 | { 72 | return ceil($this->repository->findAll()->count() / self::PAGE_LIMIT); 73 | } 74 | 75 | /** 76 | * Persists Url in DocumentManager, does not call flush 77 | * 78 | * @param OpenSky\Bundle\SitemapBundle\Sitemap\Url $url 79 | */ 80 | public function save(Url $url) 81 | { 82 | $this->dm->persist($url); 83 | } 84 | 85 | /** 86 | * @return Doctrine\ODM\MongoDB\DocumentManager 87 | */ 88 | public function getDocumentManager() 89 | { 90 | return $this->dm; 91 | } 92 | 93 | /** 94 | * @return Doctrine\ODM\MongoDB\DocumentRepository 95 | */ 96 | public function getDocumentRepository() 97 | { 98 | return $this->repository; 99 | } 100 | 101 | private function getSkip($page) 102 | { 103 | return ((int) $page - 1) * self::PAGE_LIMIT; 104 | } 105 | } -------------------------------------------------------------------------------- /Resources/config/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | OpenSky\Bundle\SitemapBundle\Listener\RequestParser 8 | OpenSky\Bundle\SitemapBundle\Listener\ResponseFilter 9 | OpenSky\Bundle\SitemapBundle\Document\Url 10 | OpenSky\Bundle\SitemapBundle\Sitemap\SitemapExporter 11 | OpenSky\Bundle\SitemapBundle\Dumper\Doctrine\ODM\MongoDB 12 | OpenSky\Bundle\SitemapBundle\Sitemap\Storage\Doctrine\ODM\MongoDB 13 | OpenSky\Bundle\SitemapBundle\Sitemap\Sitemap 14 | OpenSky\Bundle\SitemapBundle\Listener\SitemapListener 15 | twig 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | %opensky.sitemap.defaults% 25 | 26 | %opensky.sitemap.url.class% 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | %opensky.sitemap.url.class% 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Controller/SitemapController.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright (c) 2010 OpenSky Project Inc 16 | */ 17 | class SitemapController extends Controller 18 | { 19 | 20 | /** 21 | * @return Symfony\Component\HttpKernel\Response 22 | */ 23 | public function siteindexAction() 24 | { 25 | return $this->generateResponse('siteindex', array( 26 | 'totalPages' => $this->getTotalPages(), 27 | 'router' => $this->getRouter(), 28 | )); 29 | } 30 | 31 | /** 32 | * @return Symfony\Component\HttpKernel\Response 33 | */ 34 | public function sitemapAction() 35 | { 36 | $page = $this->getPage($this->get('request')->query); 37 | return $this->generateResponse('sitemap', array( 38 | 'urls' => $this->getUrls($page), 39 | 'page' => $page, 40 | )); 41 | } 42 | 43 | protected function generateResponse($view, array $args) 44 | { 45 | $template = sprintf( 46 | 'OpenSkySitemapBundle:Sitemap:%s.xml.%s', 47 | $view, 48 | $this->container->getParameter('opensky.sitemap.template.engine') 49 | ); 50 | 51 | return $this->getTemplating()->renderResponse($template, $args, new Response('', 200, array( 52 | 'Content-Type' => 'application/xml', 53 | ))); 54 | } 55 | 56 | /** 57 | * @return int 58 | */ 59 | protected function getTotalPages() 60 | { 61 | return $this->getSitemap()->getTotalPages(); 62 | } 63 | 64 | /** 65 | * @param int $page 66 | * @return Traversable 67 | */ 68 | protected function getUrls($page) 69 | { 70 | return $this->getSitemap()->getUrls($page); 71 | } 72 | 73 | /** 74 | * @return Symfony\Component\Templating\Engine 75 | */ 76 | protected function getTemplating() 77 | { 78 | return $this->get('templating'); 79 | } 80 | 81 | /** 82 | * 83 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Sitemap 84 | */ 85 | protected function getSitemap() 86 | { 87 | return $this->get('opensky.sitemap'); 88 | } 89 | 90 | /** 91 | * @return Symfony\Component\Routing\Router 92 | */ 93 | protected function getRouter() 94 | { 95 | return $this->get('router'); 96 | } 97 | 98 | /** 99 | * @return int 100 | */ 101 | protected function getPage($query) 102 | { 103 | return (int) max(array(1, $query->get('page', 1))); 104 | } 105 | 106 | /** 107 | * @return Symfony\Component\HttpKernel\Response 108 | */ 109 | protected function getResponse() 110 | { 111 | return $this->get('response'); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /Sitemap/Sitemap.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | class Sitemap 14 | { 15 | const DEFAULT_URL_CLASS = 'OpenSky\Bundle\SitemapBundle\Sitemap\Url'; 16 | 17 | /** 18 | * @var string 19 | */ 20 | protected $urlClass = self::DEFAULT_URL_CLASS; 21 | /** 22 | * @var array 23 | */ 24 | protected $defaults = array(); 25 | /** 26 | * @var OpenSky\Bundle\SitemapBundle\Sitemap\Storage\Storage 27 | */ 28 | protected $storage; 29 | 30 | /** 31 | * @param OpenSky\Bundle\SitemapBundle\Sitemap\Storage\Storage $storage 32 | * @param array $defaults 33 | */ 34 | public function __construct(Storage $storage, array $defaults = array()) 35 | { 36 | $this->storage = $storage; 37 | foreach (array('changefreq', 'priority', 'lastmod') as $prop) { 38 | if (isset($defaults[$prop])) { 39 | $this->defaults[$prop] = $defaults[$prop]; 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * @return int 46 | */ 47 | public function getTotalPages() 48 | { 49 | return $this->storage->getTotalPages(); 50 | } 51 | 52 | /** 53 | * @param int $page 54 | * @return \Traversable 55 | */ 56 | public function getUrls($page = 1) 57 | { 58 | return $this->storage->find($page); 59 | } 60 | 61 | /** 62 | * @param string $loc 63 | * @param array $info 64 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Url 65 | */ 66 | public function add($loc, array $info) 67 | { 68 | $info = array_merge($this->defaults, $info); 69 | $urlClass = $this->getUrlClass(); 70 | $url = new $urlClass($loc); 71 | foreach (array('changefreq', 'priority', 'lastmod') as $prop) { 72 | if (isset($info[$prop])) { 73 | $url->{'set' . ucfirst($prop)}($info[$prop]); 74 | } 75 | } 76 | $this->storage->save($url); 77 | return $url; 78 | } 79 | 80 | /** 81 | * @param string $loc 82 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Url|null 83 | */ 84 | public function get($loc) 85 | { 86 | return $this->storage->findOne($loc); 87 | } 88 | 89 | /** 90 | * @param string $loc 91 | * @return boolean 92 | */ 93 | public function has($loc) 94 | { 95 | return ($this->get($loc) !== null); 96 | } 97 | 98 | /** 99 | * @param string $class 100 | */ 101 | public function setUrlClass($class) 102 | { 103 | if ($class !== self::DEFAULT_URL_CLASS && (!class_exists($class) || !is_subclass_of($class, self::DEFAULT_URL_CLASS))) { 104 | throw new \InvalidArgumentException('Class ' . $class . ' doesn\'t exist or is not instance of ' . self::DEFAULT_URL_CLASS); 105 | } 106 | $this->urlClass = $class; 107 | } 108 | 109 | /** 110 | * @return string 111 | */ 112 | public function getUrlClass() 113 | { 114 | return $this->urlClass; 115 | } 116 | 117 | /** 118 | * @return OpenSky\Bundle\SitemapBundle\Sitemap\Storage\Storage 119 | */ 120 | public function getStorage() 121 | { 122 | return $this->storage; 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /Sitemap/Url.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2010 OpenSky Project Inc 12 | */ 13 | class Url 14 | { 15 | const PATTERN = '~^ 16 | (http|https):// # protocol 17 | ( 18 | ([a-z0-9-]+\.)+[a-z]{2,6} # a domain name 19 | | # or 20 | \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # a IP address 21 | ) 22 | (:[0-9]+)? # a port (optional) 23 | (/?|/\S+) # a /, nothing or a / with something 24 | $~ix'; 25 | const DAILY = 'daily'; 26 | const WEEKLY = 'weekly'; 27 | const MONTHLY = 'monthly'; 28 | const YEARLY = 'yearly'; 29 | const LASTMOD_FORMAT = 'Y-m-d'; 30 | 31 | /** 32 | * @var string 33 | */ 34 | protected $loc; 35 | /** 36 | * 37 | * @var string 38 | */ 39 | protected $lastmod; 40 | /** 41 | * 42 | * @var string 43 | */ 44 | protected $changefreq; 45 | /** 46 | * @var float 47 | */ 48 | protected $priority; 49 | 50 | /** 51 | * @param string $loc 52 | * @throws \InvalidArgumentException 53 | */ 54 | public function __construct($loc) 55 | { 56 | if (!preg_match(self::PATTERN, $loc)) { 57 | throw new Exception\InvalidArgumentException($loc . ' is not valid url location'); 58 | } 59 | $this->loc = $loc; 60 | } 61 | 62 | /** 63 | * @return string 64 | */ 65 | public function getLoc() 66 | { 67 | return $this->loc; 68 | } 69 | 70 | /** 71 | * @param string|\DateTime $lastmod 72 | */ 73 | public function setLastmod($lastmod) 74 | { 75 | if ($lastmod instanceof \DateTime) { 76 | $lastmod = $lastmod->getTimestamp(); 77 | } 78 | $this->lastmod = date(self::LASTMOD_FORMAT, $lastmod); 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function getLastmod() 85 | { 86 | if ($this->lastmod instanceof \DateTime) { 87 | $this->lastmod = $this->lastmod->format(self::LASTMOD_FORMAT); 88 | } 89 | return $this->lastmod; 90 | } 91 | 92 | /** 93 | * @param string $changefreq 94 | */ 95 | public function setChangefreq($changefreq) 96 | { 97 | if (!in_array($changefreq, array(self::DAILY, self::MONTHLY, self::WEEKLY, self::YEARLY))) { 98 | throw new Exception\InvalidArgumentException('Change frequency ' . $changefreq . ' is invalid'); 99 | } 100 | $this->changefreq = $changefreq; 101 | } 102 | 103 | /** 104 | * @return string 105 | */ 106 | public function getChangefreq() 107 | { 108 | return $this->changefreq; 109 | } 110 | 111 | /** 112 | * @param float $priority 113 | */ 114 | public function setPriority($priority) 115 | { 116 | if ($priority <= 0 || $priority > 1) { 117 | throw new Exception\InvalidArgumentException('Priority must be in between 0 and 1, ' . $priority . ' given'); 118 | } 119 | $this->priority = $priority; 120 | } 121 | 122 | /** 123 | * @return string 124 | */ 125 | public function getPriority() 126 | { 127 | return number_format($this->priority, 1); 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /Tests/Listener/SitemapListenerTest.php: -------------------------------------------------------------------------------- 1 | 17 | * @copyright (c) 2010 OpenSky Project Inc 18 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 19 | */ 20 | class SitemapListenerTest extends \PHPUnit_Framework_TestCase 21 | { 22 | /** 23 | * @var Bundle\SitemapBundle\Listener\SitemapListener 24 | */ 25 | protected $listener; 26 | /** 27 | * @var Bundle\SitemapBundle\Sitemap\Sitemap 28 | */ 29 | protected $sitemap; 30 | /** 31 | * @var Bundle\SitemapBundle\Dumper\Dumper 32 | */ 33 | protected $dumper; 34 | 35 | public function setUp() 36 | { 37 | $this->sitemap = $this->getSitemap(); 38 | $this->dumper = $this->getDumper(); 39 | $this->listener = new SitemapListener($this->sitemap, $this->dumper); 40 | } 41 | 42 | public function tearDown() 43 | { 44 | unset($this->sitemap, $this->dumper, $this->listener); 45 | } 46 | 47 | public function testRegister() 48 | { 49 | $connectedEvents = array(); 50 | 51 | $eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcher', array('connect'), array(), '', false, false); 52 | $eventDispatcher->expects($this->exactly(2)) 53 | ->method('connect') 54 | ->will($this->returnCallback(function ($eventName, $callback) use (&$connectedEvents) { 55 | $connectedEvents[$eventName] = $callback; 56 | })); 57 | 58 | $this->listener->register($eventDispatcher); 59 | 60 | foreach (array('update', 'create') as $name) { 61 | $eventName = 'sitemap.' . $name; 62 | $this->assertArrayHasKey($eventName, $connectedEvents); 63 | $this->assertEquals(array($this->listener, $name), $connectedEvents[$eventName]); 64 | } 65 | } 66 | 67 | public function testCreate() 68 | { 69 | $this->dumper->expects($this->once()) 70 | ->method('dump') 71 | ->with($this->sitemap); 72 | 73 | $urlData = array( 74 | 'loc' => 'http://google.com', 75 | 'changefreq' => 'monthly', 76 | 'priority' => '1', 77 | ); 78 | 79 | $this->listener->create(new Event($this, 'sitemap.create', $urlData)); 80 | 81 | $this->assertTrue($this->sitemap->has($urlData['loc'])); 82 | 83 | $url = $this->sitemap->get($urlData['loc']); 84 | 85 | $this->assertEquals($urlData, array( 86 | 'loc' => $url->getLoc(), 87 | 'changefreq' => $url->getChangefreq(), 88 | 'priority' => $url->getPriority(), 89 | )); 90 | $this->assertEquals(date(Url::LASTMOD_FORMAT), $url->getLastmod()); 91 | } 92 | 93 | public function testUpdate() 94 | { 95 | $url = 'http://google.com'; 96 | 97 | $entry = $this->sitemap->add($url, array( 98 | 'lastmod' => new \DateTime('-2 months'), 99 | 'changefreq' => Url::YEARLY, 100 | 'priority' => '0.8', 101 | )); 102 | 103 | $this->dumper->expects($this->once()) 104 | ->method('dump') 105 | ->with($this->sitemap); 106 | 107 | $this->listener->update(new Event($this, 'sitemap.update', array('loc' => $url))); 108 | 109 | $this->assertEquals(date(Url::LASTMOD_FORMAT), $entry->getLastmod()); 110 | $this->assertEquals(Url::MONTHLY, $entry->getChangefreq()); 111 | } 112 | 113 | /** 114 | * @expectedException Bundle\SitemapBundle\Exception\OutOfBoundsException 115 | */ 116 | public function testUpdateThrowsException() 117 | { 118 | $this->listener->update(new Event($this, 'sitemap.update', array('loc' => 'http://www.example.com'))); 119 | } 120 | 121 | /** 122 | * @return Bundle\SitemapBundle\Sitemap\Sitemap 123 | */ 124 | protected function getSitemap() 125 | { 126 | return new Sitemap(new Memory()); 127 | } 128 | 129 | /** 130 | * @return Bundle\SitemapBundle\Dumper\Dumper 131 | */ 132 | protected function getDumper() 133 | { 134 | return $this->getMock('Bundle\SitemapBundle\Dumper\Dumper', array('dump'), array(), '', false, false); 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /Tests/Sitemap/SitemapTest.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) 2010 OpenSky Project Inc 15 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 16 | */ 17 | class SitemapTest extends \PHPUnit_Framework_TestCase 18 | { 19 | 20 | public function testNoUrls() 21 | { 22 | $sitemap = $this->getSitemap(); 23 | $this->assertEquals(0, count($sitemap->getUrls())); 24 | } 25 | 26 | public function testAddUrl() 27 | { 28 | $sitemap = $this->getSitemap(); 29 | $sitemap->add('http://www.example.org/', array( 30 | 'lastmod' => new \DateTime(), 31 | 'changefreq' => Url::DAILY, 32 | 'priority' => 1.0, 33 | )); 34 | $this->assertEquals(1, count($sitemap->getUrls())); 35 | } 36 | 37 | public function testAddGetsUrl() 38 | { 39 | $sitemap = $this->getSitemap(); 40 | $lastMod = new \DateTime(); 41 | $url = $sitemap->add('http://www.example.org/', array( 42 | 'lastmod' => $lastMod, 43 | 'changefreq' => Url::DAILY, 44 | 'priority' => 1.0, 45 | )); 46 | $this->assertUrlProperties(array( 47 | 'loc' => 'http://www.example.org/', 48 | 'lastmod' => date(Url::LASTMOD_FORMAT, $lastMod->getTimestamp()), 49 | 'changefreq' => 'daily', 50 | 'priority' => 1.0, 51 | ), $url); 52 | } 53 | 54 | /** 55 | * @expectedException InvalidArgumentException 56 | */ 57 | public function testThrowsOnInvalidUrlClass() 58 | { 59 | $sitemap = $this->getSitemap(); 60 | $sitemap->setUrlClass(get_class($this)); 61 | } 62 | 63 | public function testGetUrlClass() 64 | { 65 | $sitemap = $this->getSitemap(); 66 | $sitemap->setUrlClass('Bundle\SitemapBundle\Sitemap\Url'); 67 | $this->assertEquals('Bundle\SitemapBundle\Sitemap\Url', $sitemap->getUrlClass()); 68 | } 69 | 70 | public function testAddsDefaultInfo() 71 | { 72 | $sitemap = $this->getSitemap(array( 73 | 'changefreq' => 'monthly', 74 | 'lastmod' => new \DateTime('2006-01-01'), 75 | 'priority' => 0.1, 76 | )); 77 | $url = $sitemap->add('http://www.google.com/', array()); 78 | $this->assertUrlProperties(array( 79 | 'loc' => 'http://www.google.com/', 80 | 'changefreq' => 'monthly', 81 | 'lastmod' => '2006-01-01', 82 | 'priority' => 0.1, 83 | ), $url); 84 | } 85 | 86 | public function testAppendsDefaultInfo() 87 | { 88 | $sitemap = $this->getSitemap(array( 89 | 'changefreq' => 'monthly', 90 | 'lastmod' => new \DateTime('2006-01-01'), 91 | 'priority' => 0.1, 92 | )); 93 | $url = $sitemap->add('http://www.google.com/', array( 94 | 'lastmod' => new \DateTime('2010-01-01'), 95 | 'priority' => 0.6, 96 | )); 97 | $this->assertUrlProperties(array( 98 | 'loc' => 'http://www.google.com/', 99 | 'changefreq' => 'monthly', 100 | 'lastmod' => '2010-01-01', 101 | 'priority' => 0.6, 102 | ), $url); 103 | } 104 | 105 | public function testGetUrl() 106 | { 107 | $now = new \DateTime(); 108 | $sitemap = $this->getSitemap(); 109 | $sitemap->add('http://www.example.org/', array( 110 | 'lastmod' => $now, 111 | 'changefreq' => Url::MONTHLY, 112 | 'priority' => 1.0, 113 | )); 114 | $sitemap->add('http://www.example.org/index', array( 115 | 'lastmod' => $now, 116 | 'changefreq' => Url::DAILY, 117 | 'priority' => 0.8, 118 | )); 119 | $this->assertUrlProperties(array( 120 | 'loc' => 'http://www.example.org/', 121 | 'lastmod' => date(Url::LASTMOD_FORMAT, $now->getTimestamp()), 122 | 'changefreq' => Url::MONTHLY, 123 | 'priority' => 1.0, 124 | ), $sitemap->get('http://www.example.org/')); 125 | } 126 | 127 | public function testGetUrlReturnsNullIfNoFound() 128 | { 129 | $sitemap = $this->getSitemap(); 130 | $this->assertNull($sitemap->get('http://www.example.org')); 131 | } 132 | 133 | public function testHasReturnsFalseOnNonExistentRoute() 134 | { 135 | $this->assertFalse($this->getSitemap()->has('http://www.google.com/')); 136 | } 137 | 138 | public function testReturnsTrueOnExistentUrl() 139 | { 140 | $sitemap = $this->getSitemap(); 141 | $sitemap->add('http://www.google.com/', array( 142 | 'lastmod' => new \DateTime('2010-01-01'), 143 | 'priority' => 0.6, 144 | )); 145 | $this->assertTrue($sitemap->has('http://www.google.com/')); 146 | } 147 | 148 | public function getSitemap(array $options = array()) 149 | { 150 | return new Sitemap(new \Bundle\SitemapBundle\Sitemap\Storage\Memory(), $options); 151 | } 152 | 153 | protected function assertUrlProperties(array $properties, Url $url, $message = 'Url properties didn\'t match specification') 154 | { 155 | foreach (array('loc', 'lastmod', 'changefreq', 'priority') as $prop) { 156 | if (isset($properties[$prop]) && $properties[$prop] != $url->{'get' . ucfirst($prop)} ()) { 157 | $this->fail($message . PHP_EOL . 'property: ' . $prop . PHP_EOL . 'expected: ' . print_r($properties[$prop], true) . PHP_EOL . 'actual: ' . print_r($url->{'get' . ucfirst($prop)} (), true)); 158 | } 159 | } 160 | } 161 | 162 | } -------------------------------------------------------------------------------- /Tests/Sitemap/Storage/Doctrine/ODM/MongoDBTest.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) 2010 OpenSky Project Inc 15 | * @license http://www.gnu.org/licenses/agpl.txt GNU Affero General Public License 16 | */ 17 | class MongoDBTest extends \PHPUnit_Framework_TestCase 18 | { 19 | protected $storage; 20 | protected $dm; 21 | protected $repository; 22 | 23 | public function setUp() 24 | { 25 | $this->dm = $this->getDocumentManagerMock(); 26 | $this->repository = $this->getDocumentRepositoryMock(); 27 | $this->storage = new MongoDB($this->dm); 28 | 29 | $this->storage->setRepository($this->repository); 30 | } 31 | 32 | public function tearDown() 33 | { 34 | unset($this->storage, $this->repository, $this->dm); 35 | } 36 | 37 | public function testRegister() 38 | { 39 | $classMetadata = $this->getClassMetadataMock(); 40 | $classMetadataFactory = $this->getClassMetadataFactoryMock(); 41 | 42 | $classMetadataFactory->expects($this->once()) 43 | ->method('setMetadataFor') 44 | ->with(MongoDB::URL_CLASS, $classMetadata); 45 | 46 | $this->storage->register($classMetadata, $classMetadataFactory); 47 | } 48 | 49 | /** 50 | * @dataProvider getUrls 51 | */ 52 | public function testFindOne($location, $result) 53 | { 54 | $this->repository->expects($this->once()) 55 | ->method('find') 56 | ->with($location) 57 | ->will($this->returnValue($result)); 58 | 59 | $this->assertSame($result, $this->storage->findOne($location)); 60 | } 61 | 62 | public function testFind() 63 | { 64 | $expectedNumberOfResults = 5; 65 | $page = 1; 66 | $cursor = $this->getMongoCursorMock(); 67 | 68 | $cursor->expects($this->once()) 69 | ->method('skip') 70 | ->with(($page - 1) * MongoDB::PAGE_LIMIT) 71 | ->will($this->returnValue($cursor)); 72 | $cursor->expects($this->once()) 73 | ->method('limit') 74 | ->with(MongoDB::PAGE_LIMIT) 75 | ->will($this->returnValue($cursor)); 76 | $cursor->expects($this->once()) 77 | ->method('count') 78 | ->will($this->returnValue($expectedNumberOfResults)); 79 | 80 | $this->repository->expects($this->once()) 81 | ->method('findAll') 82 | ->will($this->returnValue($cursor)); 83 | 84 | $this->assertEquals($expectedNumberOfResults, count($this->storage->find($page))); 85 | } 86 | 87 | public function testSave() 88 | { 89 | $url = new Url('http://www.example.com'); 90 | 91 | $this->dm->expects($this->once()) 92 | ->method('persist') 93 | ->with($url); 94 | 95 | $this->storage->save($url); 96 | } 97 | 98 | public function testGetTotalPages() 99 | { 100 | $cursor = $this->getMongoCursorMock(); 101 | 102 | $cursor->expects($this->once()) 103 | ->method('count') 104 | ->will($this->returnValue(MongoDB::PAGE_LIMIT + 1)); 105 | 106 | $this->repository->expects($this->once()) 107 | ->method('findAll') 108 | ->will($this->returnValue($cursor)); 109 | 110 | $this->assertEquals(2, $this->storage->getTotalPages()); 111 | } 112 | 113 | public function testGetDocumentManager() 114 | { 115 | $this->assertSame($this->dm, $this->storage->getDocumentManager()); 116 | } 117 | 118 | public function testGetDocumentRepository() 119 | { 120 | $this->assertSame($this->repository, $this->storage->getDocumentRepository()); 121 | } 122 | 123 | public function getUrls() 124 | { 125 | return array( 126 | array('http://example.com/', null), 127 | array('http://example.com/', new Url('http://example.com/')), 128 | ); 129 | } 130 | 131 | /** 132 | * @return Doctrine\ODM\MongoDB\Mapping\ClassMetadata 133 | */ 134 | protected function getClassMetadataMock() 135 | { 136 | return $this->getMockBuilder('Doctrine\ODM\MongoDB\Mapping\ClassMetadata') 137 | ->disableOriginalConstructor() 138 | ->disableOriginalClone() 139 | ->getMock(); 140 | } 141 | 142 | /** 143 | * @return Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory 144 | */ 145 | protected function getClassMetadataFactoryMock() 146 | { 147 | return $this->getMockBuilder('Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory') 148 | ->disableOriginalConstructor() 149 | ->disableOriginalClone() 150 | ->getMock(); 151 | } 152 | 153 | /** 154 | * @return Doctrine\ODM\MongoDB\DocumentManager 155 | */ 156 | protected function getDocumentManagerMock() 157 | { 158 | return $this->getMockBuilder('Doctrine\ODM\MongoDB\DocumentManager') 159 | ->disableOriginalConstructor() 160 | ->disableOriginalClone() 161 | ->getMock(); 162 | } 163 | 164 | /** 165 | * @return Doctrine\ODM\MongoDB\DocumentRepository 166 | */ 167 | protected function getDocumentRepositoryMock() 168 | { 169 | return $this->getMockBuilder('Doctrine\ODM\MongoDB\DocumentRepository') 170 | ->disableOriginalConstructor() 171 | ->disableOriginalClone() 172 | ->getMock(); 173 | } 174 | 175 | /** 176 | * @return Doctrine\ODM\MongoDB\Cursor 177 | */ 178 | protected function getMongoCursorMock() 179 | { 180 | return $this->getMockBuilder('Doctrine\ODM\MongoDB\Cursor') 181 | ->disableOriginalConstructor() 182 | ->disableOriginalClone() 183 | ->getMock(); 184 | } 185 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenSky SitemapBundle 2 | 3 | This bundle will help with sitemap generation in your Symfony2 based projects. 4 | 5 | ## Installation via Composer 6 | 7 | Add the following to the "repositories" section of composer.json: 8 | ``` 9 | { 10 | "type": "vcs", 11 | "url": "https://github.com/opensky/SitemapBundle" 12 | } 13 | ``` 14 | 15 | Add the following to the "require" section of composer.json: 16 | 17 | "opensky/sitemap-bundle": "dev-master" 18 | 19 | ## Adding the bundle to your kernel 20 | 21 | To enable the sitemap bundle, add it to your kernel registerBundles() method: 22 | 23 | use Symfony\Foundation\Kernel; 24 | 25 | class MyKernel extends Kernel { 26 | // ... 27 | public function registerBundles() { 28 | return array( 29 | // ... 30 | new OpenSky\Bundle\SitemapBundle\OpenSkySitemapBundle(), 31 | // ... 32 | ); 33 | } 34 | } 35 | 36 | 37 | ## Enabling the services 38 | 39 | The second step is to enable its DependencyInjection extension in your `config.yml`: 40 | 41 | opensky_sitemap: 42 | default_lastmod: 2010-06-01 43 | default_changefreq: monthly 44 | default_priority: 0.5 45 | 46 | You will need a Doctrine ODM MongoDB connection for your sitemap. This means that you have to add `DoctrineMongoDBBundle` to your Kernel and register its configuration like so: 47 | 48 | doctrine_odm.mongodb: 49 | auto_generate_proxy_classes: true 50 | default_document_manager: default 51 | default_connection: mongodb 52 | cache_driver: array 53 | metadata_cache_driver: array 54 | default_database: opensky 55 | proxy_namespace: Proxies 56 | document_managers: 57 | default: 58 | connection: mongodb 59 | connections: 60 | mongodb: 61 | server: localhost:27017 62 | 63 | 64 | ## Defining a Url class 65 | 66 | You will need to add a URL document to your model. Most likely, you will want to save a class that looks like this to your `Document` directory: 67 | 68 | topicRepository = $topicRepository; 119 | $this->router = $router; 120 | } 121 | 122 | public function populate(Sitemap $sitemap) 123 | { 124 | foreach ($this->topicRepository->find() as $topic) { 125 | $sitemap->add($this->router->generate('topic_view', array( 126 | 'id' => $topic->getId(), 127 | ), true), array( 128 | 'changefreq' => \OpenSky\Bundle\SitemapBundle\Sitemap\Url::MONTHLY, 129 | 'lastmod' => $seller->getUpdatedAt(), 130 | 'priority' => '0.8', 131 | ) 132 | ); 133 | } 134 | } 135 | } 136 | 137 | **NOTE:** in the above example, we use router to generate absolute urls. Since you don't have knowledge of your current domain in the CLI mode (the mode, where commands are run), router will still generate relative urls. You have to make the host a container parameter, that you will then use inside of your sitemap provider. 138 | 139 | And register your provider in DIC like this: 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | After providers are in place and registered, time to run the generation command: 148 | 149 | > php forum/console sitemap:generate 150 | 151 | or simply: 152 | 153 | > php forum/console sitemap:g 154 | 155 | 156 | ## Creating/Updating sitemap urls in the application 157 | 158 | After the three steps were completed, you can use Symfony2's native 'event_dispatcher' 159 | service to let the 'sitemap' know of new url: 160 | 161 | $eventDispatcher->notify(new Event($this, 'opensky.sitemap.create', array( 162 | 'loc' => $router->generate('user_view', array('id' => $user->getId())), 163 | 'changefreq' => 'daily', 164 | 'priority' => '0.8', 165 | ))); 166 | 167 | or existing url updates: 168 | 169 | $eventDispatcher->notify(new Event($this, 'opensky.sitemap.update', array( 170 | 'loc' => $router->generate('user_view', array('id' => $user->getId())), 171 | 'priority' => '0.6', 172 | ))); 173 | 174 | 175 | ## Enabling sitemap routes 176 | 177 | The last and most important step is to enable sitemap routing in your routing.yml: 178 | 179 | sitemap: 180 | resource: @OpenSkySitemapBundle/Resources/config/routing.yml 181 | 182 | After that is done, you can access your sitemap at /sitemap.xml and siteindex at /siteindex.xml 183 | 184 | Happy Coding 185 | --------------------------------------------------------------------------------