Skip to content

Instantly share code, notes, and snippets.

@beberlei
Last active January 4, 2016 08:19
Show Gist options
  • Save beberlei/1fc7df1d9febeb3bac6e to your computer and use it in GitHub Desktop.
Save beberlei/1fc7df1d9febeb3bac6e to your computer and use it in GitHub Desktop.
PHPBenelux: Refactoring with Patterns
<?php
class ApplicationFactory
{
private $solarium;
public function createSolariumClient()
{
if ($this->solarium === null) {
$this->solarium = new SolariumClient(Config::getSolariumHost());
}
return $this->solarium;
}
public function setSolariumClient($client)
{
$this->solarium = $client;
}
public function createProductSearch()
{
return new SolariumProductSearch(
$this->createSolariumClient()
);
}
}
class Config
{
static public function getSolariumHost()
{
return 'localhost:8080';
}
}
class SolariumProductSearch
{
private $solarium;
public function __construct($client)
{
$this->solarium = $client;
}
public function queryForResults($req, $typeFilter, $tagsFilter)
{
$solarium = $this->solarium;
$select = $solarium->createSelect();
// filter by type
if ($typeFilter) {
$filterQueryTerm = sprintf('type:%s', $select->getHelper()->escapeTerm($typeFilter));
$filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm);
$select->addFilterQuery($filterQuery);
}
// filter by tags
if ($tagsFilter) {
$tags = array();
foreach ((array) $tagsFilter as $tag) {
$tags[] = $select->getHelper()->escapeTerm($tag);
}
$filterQueryTerm = sprintf('tags:(%s)', implode(' AND ', $tags));
$filterQuery = $select->createFilterQuery('tags')->setQuery($filterQueryTerm);
$select->addFilterQuery($filterQuery);
}
if ($req->has('q')) {
$escapedQuery = $select->getHelper()->escapeTerm($req->get('q'));
$select->setQuery($escapedQuery);
}
$result = $solarium->query($select);
return $result;
}
}
class SearchController extends Controller
{
private $solarium;
public function __construct($client, $productSearchService)
{
$this->solarium = $client;
$this->productSearchService = $productSearchService;
}
/**
* @param Request $request
*
* @return Response
*/
public function searchAction(Request $req)
{
$typeFilter = $req->get('type');
$tagsFilter = $req->get('tags');
if ($req->has('q') || $typeFilter || $tagsFilter) {
$result = $this->productSearchService->queryForResults($req, $typeFilter, $tagsFilter);
if ($req->isXmlHttpRequest()) {
try {
return $this->render('ProductBundle:Search:list.html.twig', array(
'products' => $result,
'noLayout' => true,
));
} catch (\Twig_Error_Runtime $e) {
if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) {
throw $e;
}
return new JsonResponse(array(
'status' => 'error',
'message' => 'Could not connect to the search server',
), 500);
}
} else {
return $this->render('ProductBundle:Search:search.html.twig', array(
'products' => $result,
));
}
}
return $this->render('ProductBundle:Search:search.html.twig', array(
'noLayout' => $req->isXmlHttpRequest(),
));
}
}
abstract class Controller
{
public function render($template, $variables)
{
return new Response($template . json_encode($variables));
}
public function generateUrl($route, $variables)
{
if ($route == 'search') {
return '/search';
}
return '/product/' . $variables['name'];
}
}
class Request
{
private $variables = array();
private $requestFormat = 'html';
public function has($name)
{
return isset($this->variables[$name]);
}
public function get($name)
{
if (!$this->has($name)) {
return null;
}
return $this->variables[$name];
}
public function set($name, $value)
{
$this->variables[$name] = $value;
}
public function getRequestFormat()
{
return $this->requestFormat;
}
public function setRequestFormat($format)
{
$this->requestFormat = $format;
}
public function isXmlHttpRequest()
{
return ($this->requestFormat === 'XmlHttpRequest');
}
}
class Response
{
public function __construct($content)
{
$this->content = $content;
}
public function getContent()
{
return $this->content;
}
}
class JsonResponse extends Response
{
}
class SolariumClient
{
public function createSelect()
{
return new SolariumSelect();
}
public function query($select)
{
return new ArrayIterator(array(
new Product('foo', 'A foo product', 42),
new Product('bar', 'A bar product', 23),
));
}
}
class SolariumSelect
{
public function __call($method, $args)
{
return $this;
}
}
class Product
{
public $name;
public $description;
public $price;
public function __construct($name, $description, $price)
{
$this->name = $name;
$this->description = $description;
$this->price = $price;
}
}
<?php
require_once __DIR__ . '/Refactoring.php';
class SearchControllerTest extends \PHPUnit_Framework_TestCase
{
public function testController()
{
$ctrl = $this->createSearchController();
$response = $ctrl->searchAction(new Request());
$this->assertEquals(
"ProductBundle:Search:search.html.twig{\"noLayout\":false}",
$response->getContent()
);
}
public function testControllerWithSearch()
{
$request = new Request();
$request->set('q', 'Hello');
$ctrl = $this->createSearchController();
$response = $ctrl->searchAction($request);
$this->assertEquals(
'ProductBundle:Search:search.html.twig{"products":{"0":{"name":"foo","description":"A foo product","price":42},"1":{"name":"bar","description":"A bar product","price":23}}}',
$response->getContent()
);
}
public function testControllerWithXmlHttpRequest()
{
$request = new Request();
$request->set('q', 'Hello');
$request->setRequestFormat('XmlHttpRequest');
$ctrl = $this->createSearchController();
$response = $ctrl->searchAction($request);
$this->assertEquals(
'ProductBundle:Search:list.html.twig{"products":{"0":{"name":"foo","description":"A foo product","price":42},"1":{"name":"bar","description":"A bar product","price":23}},"noLayout":true}',
$response->getContent()
);
}
private function createSearchController()
{
$factory = new ApplicationFactory();
$client = $factory->createSolariumClient();
$ctrl = new SearchController($client, $factory->createProductSearch());
return $ctrl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment