This repository has been archived by the owner on Sep 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is the start of supporting annotations and mapping files instead of PHP extractor methods and lots of interfaces.
- Loading branch information
Showing
14 changed files
with
518 additions
and
356 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
<?php | ||
|
||
namespace Symfony\Cmf\Bundle\SeoBundle\Loader; | ||
|
||
use Symfony\Cmf\Bundle\SeoBundle\Cache\CacheInterface; | ||
use Symfony\Cmf\Bundle\SeoBundle\Extractor\ExtractorInterface; | ||
use Symfony\Component\Config\Loader\Loader; | ||
|
||
/** | ||
* @author Wouter de Jong <[email protected]> | ||
*/ | ||
class ExtractorLoader extends Loader | ||
{ | ||
/** | ||
* @var null|CacheInterface | ||
*/ | ||
private $cache; | ||
|
||
/** | ||
* @var ExtractorInterface[][] | ||
*/ | ||
private $extractors = array(); | ||
|
||
/** | ||
* @param CacheInterface $cache | ||
*/ | ||
public function __construct(CacheInterface $cache = null) | ||
{ | ||
$this->cache = $cache; | ||
} | ||
|
||
/** | ||
* Add an extractor for SEO metadata. | ||
* | ||
* @param ExtractorInterface $extractor | ||
* @param int $priority | ||
*/ | ||
public function addExtractor(ExtractorInterface $extractor, $priority = 0) | ||
{ | ||
if (!isset($this->extractors[$priority])) { | ||
$this->extractors[$priority] = array(); | ||
} | ||
$this->extractors[$priority][] = $extractor; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function supports($resource, $type = null) | ||
{ | ||
return is_object($resource) && ((!$type && $this->containsExtractors($resource)) || 'extractors' === $type); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
* | ||
* @param object $content | ||
*/ | ||
public function load($content, $type = null) | ||
{ | ||
$seoMetadata = SeoMetadataFactory::initializeSeoMetadata($content); | ||
|
||
$extractors = $this->getExtractorsForContent($content); | ||
|
||
foreach ($extractors as $extractor) { | ||
$extractor->updateMetadata($content, $seoMetadata); | ||
} | ||
|
||
return $seoMetadata; | ||
} | ||
|
||
/** | ||
* Returns and caches the extractors for content. | ||
* | ||
* @param object $content | ||
* | ||
* @return ExtractorInterface[] | ||
*/ | ||
private function getExtractorsForContent($content) | ||
{ | ||
$cachingAvailable = (bool) $this->cache; | ||
|
||
if (!$cachingAvailable) { | ||
return $this->findExtractorsForContent($content); | ||
} | ||
|
||
$extractors = $this->cache->loadExtractorsFromCache(get_class($content)); | ||
|
||
if (null === $extractors || !$extractors->isFresh()) { | ||
$extractors = $this->findExtractorsForContent($content); | ||
$this->cache->putExtractorsInCache(get_class($content), $extractors); | ||
} | ||
|
||
return $extractors; | ||
} | ||
|
||
/** | ||
* Returns the extractors that support the content. | ||
* | ||
* @param object $content | ||
* | ||
* @return ExtractorInterface[] | ||
*/ | ||
private function findExtractorsForContent($content) | ||
{ | ||
$extractors = array(); | ||
ksort($this->extractors); | ||
foreach ($this->extractors as $priority) { | ||
$supportedExtractors = array_filter($priority, function (ExtractorInterface $extractor) use ($content) { | ||
return $extractor->supports($content); | ||
}); | ||
|
||
$extractors = array_merge($extractors, $supportedExtractors); | ||
} | ||
|
||
return $extractors; | ||
} | ||
|
||
/** | ||
* Whether there are extractors supporting the content. | ||
* | ||
* @param object $content | ||
* | ||
* @return bool | ||
*/ | ||
private function containsExtractors($content) | ||
{ | ||
$cacheAvailable = (bool) $this->cache; | ||
if ($cacheAvailable) { | ||
$extractors = $this->cache->loadExtractorsFromCache(get_class($content)); | ||
|
||
if (null !== $extractors) { | ||
return count($extractors) > 0; | ||
} | ||
} | ||
|
||
ksort($this->extractors); | ||
foreach (array_map('array_merge', $this->extractors) as $extractor) { | ||
if ($extractor->supports($content)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
|
||
namespace Symfony\Cmf\Bundle\SeoBundle\Loader; | ||
|
||
use Symfony\Cmf\Bundle\SeoBundle\Exception\InvalidArgumentException; | ||
use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata; | ||
use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadataInterface; | ||
use Symfony\Cmf\Bundle\SeoBundle\SeoAwareInterface; | ||
|
||
/** | ||
* Creates a SeoMetadata object based on the content. | ||
* | ||
* This returns either an empty SeoMetadata instance or the | ||
* SeoMetadata instance return by getSeoMetadata() of the | ||
* content object. | ||
* | ||
* @author Wouter de Jong <[email protected]> | ||
*/ | ||
class SeoMetadataFactory | ||
{ | ||
/** | ||
* @param object $content | ||
* | ||
* @return SeoMetadataInterface | ||
* | ||
* @throws InvalidArgumentException | ||
*/ | ||
public static function initializeSeoMetadata($content) | ||
{ | ||
if (!$content instanceof SeoAwareInterface) { | ||
return new SeoMetadata(); | ||
} | ||
|
||
$contentSeoMetadata = $content->getSeoMetadata(); | ||
|
||
if ($contentSeoMetadata instanceof SeoMetadataInterface) { | ||
return self::copyMetadata($contentSeoMetadata); | ||
} | ||
|
||
if (null === $contentSeoMetadata) { | ||
$seoMetadata = new SeoMetadata(); | ||
$content->setSeoMetadata($seoMetadata); // make sure it has metadata the next time | ||
|
||
return $seoMetadata; | ||
} | ||
|
||
throw new InvalidArgumentException(sprintf( | ||
'getSeoMetadata must return either an instance of SeoMetadataInterface or null, "%s" given', | ||
is_object($contentSeoMetadata) ? get_class($contentSeoMetadata) : gettype($contentSeoMetadata) | ||
)); | ||
} | ||
|
||
/** | ||
* Copy the metadata object to sanitize it and remove doctrine traces. | ||
* | ||
* @param SeoMetadataInterface $contentSeoMetadata | ||
* | ||
* @return SeoMetadata | ||
*/ | ||
private static function copyMetadata(SeoMetadataInterface $contentSeoMetadata) | ||
{ | ||
$metadata = new SeoMetadata(); | ||
|
||
return $metadata | ||
->setTitle($contentSeoMetadata->getTitle()) | ||
->setMetaKeywords($contentSeoMetadata->getMetaKeywords()) | ||
->setMetaDescription($contentSeoMetadata->getMetaDescription()) | ||
->setOriginalUrl($contentSeoMetadata->getOriginalUrl()) | ||
->setExtraProperties($contentSeoMetadata->getExtraProperties() ?: array()) | ||
->setExtraNames($contentSeoMetadata->getExtraNames() ?: array()) | ||
->setExtraHttp($contentSeoMetadata->getExtraHttp() ?: array()) | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" ?> | ||
|
||
<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> | ||
<service id="cmf_seo.loader_resolver" class="Symfony\Component\Config\Loader\LoaderResolver" public="false"> | ||
<argument type="collection"> | ||
<argument type="service" id="cmf_seo.loader.extractor"/> | ||
</argument> | ||
</service> | ||
|
||
<service id="cmf_seo.loader" class="Symfony\Component\Config\Loader\DelegatingLoader" public="false"> | ||
<argument type="service" id="cmf_seo.loader_resolver"/> | ||
</service> | ||
|
||
<service id="cmf_seo.loader.extractor" class="Symfony\Cmf\Bundle\SeoBundle\Loader\ExtractorLoader" public="false"> | ||
<argument type="service" id="file_locator"/> | ||
<argument type="service" id="cmf_seo.cache"/> | ||
</service> | ||
</services> | ||
</container> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.