Merge pull request #87 from acelaya/feature/1.3.1

Feature/1.3.1
This commit is contained in:
Alejandro Celaya 2017-01-22 11:36:04 +01:00 committed by GitHub
commit 2e10ee66b7
26 changed files with 323 additions and 99 deletions

View file

@ -1,20 +1,35 @@
## CHANGELOG
### 1.3.1
**Tasks**
* [82: Enable FastRoute routes cache](https://github.com/shlinkio/shlink/issues/82)
* [85: Update year in license file](https://github.com/shlinkio/shlink/issues/85)
* [81: Add docker containers config](https://github.com/shlinkio/shlink/issues/81)
**Bugs**
* [83: Short codes list: search in tags when filtering by query string](https://github.com/shlinkio/shlink/issues/83)
* [79: Increase the number of followed redirects](https://github.com/shlinkio/shlink/issues/79)
* [75: Apply PathVersionMiddleware only to rest routes defining it by configuration instead of code](https://github.com/shlinkio/shlink/issues/75)
* [77: Allow defining database server hostname and port](https://github.com/shlinkio/shlink/issues/77)
### 1.3.0
**Enhancements:**
* [67: Allow to order the short codes list](https://github.com/acelaya/url-shortener/issues/67)
* [60: Accept JSON requests in REST and use a body parser middleware to set the parsedBody](https://github.com/acelaya/url-shortener/issues/60)
* [72: When listing API keys from CLI, display in yellow color enabled keys that have expired](https://github.com/acelaya/url-shortener/issues/72)
* [58: Allow to filter short URLs by tag](https://github.com/acelaya/url-shortener/issues/58)
* [69: Allow to filter short codes by text query](https://github.com/acelaya/url-shortener/issues/69)
* [67: Allow to order the short codes list](https://github.com/shlinkio/shlink/issues/67)
* [60: Accept JSON requests in REST and use a body parser middleware to set the parsedBody](https://github.com/shlinkio/shlink/issues/60)
* [72: When listing API keys from CLI, display in yellow color enabled keys that have expired](https://github.com/shlinkio/shlink/issues/72)
* [58: Allow to filter short URLs by tag](https://github.com/shlinkio/shlink/issues/58)
* [69: Allow to filter short codes by text query](https://github.com/shlinkio/shlink/issues/69)
**Tasks**
* [73: Tag endpoints in swagger file](https://github.com/acelaya/url-shortener/issues/73)
* [71: Separate swagger docs into multiple files](https://github.com/acelaya/url-shortener/issues/71)
* [63: Add path versioning to REST API routes](https://github.com/acelaya/url-shortener/issues/63)
* [73: Tag endpoints in swagger file](https://github.com/shlinkio/shlink/issues/73)
* [71: Separate swagger docs into multiple files](https://github.com/shlinkio/shlink/issues/71)
* [63: Add path versioning to REST API routes](https://github.com/shlinkio/shlink/issues/63)
### 1.2.2
@ -26,91 +41,91 @@
**Bugs**
* [62: Fix cross-domain requests in REST API](https://github.com/acelaya/url-shortener/issues/62)
* [62: Fix cross-domain requests in REST API](https://github.com/shlinkio/shlink/issues/62)
### 1.2.0
**Features**
* [45: Allow to define tags on short codes, to improve filtering and classification](https://github.com/acelaya/url-shortener/issues/45)
* [7: Add website previews while listing available URLs](https://github.com/acelaya/url-shortener/issues/7)
* [45: Allow to define tags on short codes, to improve filtering and classification](https://github.com/shlinkio/shlink/issues/45)
* [7: Add website previews while listing available URLs](https://github.com/shlinkio/shlink/issues/7)
**Enhancements:**
* [57: Add database migrations system to improve updating between versions](https://github.com/acelaya/url-shortener/issues/57)
* [31: Add support for other database management systems by improving the EntityManager factory](https://github.com/acelaya/url-shortener/issues/31)
* [51: Generate build process to paquetize the app and ease distribution](https://github.com/acelaya/url-shortener/issues/51)
* [38: Define installation script. It will request dynamic data on the fly so that there is no need to define env vars](https://github.com/acelaya/url-shortener/issues/38)
* [57: Add database migrations system to improve updating between versions](https://github.com/shlinkio/shlink/issues/57)
* [31: Add support for other database management systems by improving the EntityManager factory](https://github.com/shlinkio/shlink/issues/31)
* [51: Generate build process to paquetize the app and ease distribution](https://github.com/shlinkio/shlink/issues/51)
* [38: Define installation script. It will request dynamic data on the fly so that there is no need to define env vars](https://github.com/shlinkio/shlink/issues/38)
**Tasks**
* [55: Create update script which does not try to create a new database](https://github.com/acelaya/url-shortener/issues/55)
* [54: Add cache namespace to prevent name collisions with other apps in the same environment](https://github.com/acelaya/url-shortener/issues/54)
* [29: Use the acelaya/ze-content-based-error-handler package instead of custom error handler implementation](https://github.com/acelaya/url-shortener/issues/29)
* [55: Create update script which does not try to create a new database](https://github.com/shlinkio/shlink/issues/55)
* [54: Add cache namespace to prevent name collisions with other apps in the same environment](https://github.com/shlinkio/shlink/issues/54)
* [29: Use the acelaya/ze-content-based-error-handler package instead of custom error handler implementation](https://github.com/shlinkio/shlink/issues/29)
**Bugs**
* [53: Fix entities database interoperability](https://github.com/acelaya/url-shortener/issues/53)
* [52: Add missing htaccess file for apache environments](https://github.com/acelaya/url-shortener/issues/52)
* [53: Fix entities database interoperability](https://github.com/shlinkio/shlink/issues/53)
* [52: Add missing htaccess file for apache environments](https://github.com/shlinkio/shlink/issues/52)
### 1.1.0
**Features**
* [46: Define a route that returns a QR code representing the shortened URL](https://github.com/acelaya/url-shortener/issues/46)
* [46: Define a route that returns a QR code representing the shortened URL](https://github.com/shlinkio/shlink/issues/46)
**Enhancements:**
* [32: Add support for other cache adapters by improving the Cache factory](https://github.com/acelaya/url-shortener/issues/32)
* [14: https://github.com/shlinkio/shlink/issues/14](https://github.com/acelaya/url-shortener/issues/14)
* [41: Cache the "short code" => "URL" map to prevent extra DB hits](https://github.com/acelaya/url-shortener/issues/41)
* [13: Improve REST authentication](https://github.com/acelaya/url-shortener/issues/13)
* [32: Add support for other cache adapters by improving the Cache factory](https://github.com/shlinkio/shlink/issues/32)
* [14: https://github.com/shlinkio/shlink/issues/14](https://github.com/shlinkio/shlink/issues/14)
* [41: Cache the "short code" => "URL" map to prevent extra DB hits](https://github.com/shlinkio/shlink/issues/41)
* [13: Improve REST authentication](https://github.com/shlinkio/shlink/issues/13)
**Tasks**
* [39: Change copyright from "Alejandro Celaya" to "Shlink" in error pages](https://github.com/acelaya/url-shortener/issues/39)
* [42: Make REST endpoints that need to find something return a 404 when "something" is not found](https://github.com/acelaya/url-shortener/issues/42)
* [35: Make CLI commands to use the same PHP namespace as the one used for the command name](https://github.com/acelaya/url-shortener/issues/35)
* [39: Change copyright from "Alejandro Celaya" to "Shlink" in error pages](https://github.com/shlinkio/shlink/issues/39)
* [42: Make REST endpoints that need to find something return a 404 when "something" is not found](https://github.com/shlinkio/shlink/issues/42)
* [35: Make CLI commands to use the same PHP namespace as the one used for the command name](https://github.com/shlinkio/shlink/issues/35)
**Bugs**
* [40: Take into account the X-Forwarded-For header in order to get the visitor information, in case the server is behind a load balancer or proxy](https://github.com/acelaya/url-shortener/issues/40)
* [40: Take into account the X-Forwarded-For header in order to get the visitor information, in case the server is behind a load balancer or proxy](https://github.com/shlinkio/shlink/issues/40)
### 1.0.0
**Enhancements:**
* [33: Create a command to generate a short code charset by randomizing the default one](https://github.com/acelaya/url-shortener/issues/33)
* [15: Return JSON/HTML responses for errors (4xx and 5xx) based on accept header (content negotiation)](https://github.com/acelaya/url-shortener/issues/15)
* [23: Translate application literals](https://github.com/acelaya/url-shortener/issues/23)
* [21: Allow to filter visits by date range](https://github.com/acelaya/url-shortener/issues/21)
* [22: Save visits locations data on a visit_locations table](https://github.com/acelaya/url-shortener/issues/22)
* [20: Inject cross domain headers in response only if the Origin header is present in the request](https://github.com/acelaya/url-shortener/issues/20)
* [11: Separate code into multiple modules](https://github.com/acelaya/url-shortener/issues/11)
* [18: Group routable middleware in an Action namespace](https://github.com/acelaya/url-shortener/issues/18)
* [33: Create a command to generate a short code charset by randomizing the default one](https://github.com/shlinkio/shlink/issues/33)
* [15: Return JSON/HTML responses for errors (4xx and 5xx) based on accept header (content negotiation)](https://github.com/shlinkio/shlink/issues/15)
* [23: Translate application literals](https://github.com/shlinkio/shlink/issues/23)
* [21: Allow to filter visits by date range](https://github.com/shlinkio/shlink/issues/21)
* [22: Save visits locations data on a visit_locations table](https://github.com/shlinkio/shlink/issues/22)
* [20: Inject cross domain headers in response only if the Origin header is present in the request](https://github.com/shlinkio/shlink/issues/20)
* [11: Separate code into multiple modules](https://github.com/shlinkio/shlink/issues/11)
* [18: Group routable middleware in an Action namespace](https://github.com/shlinkio/shlink/issues/18)
**Tasks**
* [36: Remove hhvm from the CI matrix since it doesn't support array constants and will fail](https://github.com/acelaya/url-shortener/issues/36)
* [4: Installation steps](https://github.com/acelaya/url-shortener/issues/4)
* [6: Remove dependency on expressive helpers package](https://github.com/acelaya/url-shortener/issues/6)
* [30: Replace the "services" first level config entry by "dependencies", in order to fulfill default Expressive name](https://github.com/acelaya/url-shortener/issues/30)
* [12: Improve code coverage](https://github.com/acelaya/url-shortener/issues/12)
* [25: Replace "Middleware" suffix on routable middlewares by "Action"](https://github.com/acelaya/url-shortener/issues/25)
* [19: Update the vendor and app namespace from Acelaya\UrlShortener to Shlinkio\Shlink](https://github.com/acelaya/url-shortener/issues/19)
* [36: Remove hhvm from the CI matrix since it doesn't support array constants and will fail](https://github.com/shlinkio/shlink/issues/36)
* [4: Installation steps](https://github.com/shlinkio/shlink/issues/4)
* [6: Remove dependency on expressive helpers package](https://github.com/shlinkio/shlink/issues/6)
* [30: Replace the "services" first level config entry by "dependencies", in order to fulfill default Expressive name](https://github.com/shlinkio/shlink/issues/30)
* [12: Improve code coverage](https://github.com/shlinkio/shlink/issues/12)
* [25: Replace "Middleware" suffix on routable middlewares by "Action"](https://github.com/shlinkio/shlink/issues/25)
* [19: Update the vendor and app namespace from Acelaya\UrlShortener to Shlinkio\Shlink](https://github.com/shlinkio/shlink/issues/19)
**Bugs**
* [24: Prevent duplicated shortcodes errors because of the case insensitive behavior on MySQL](https://github.com/acelaya/url-shortener/issues/24)
* [24: Prevent duplicated shortcodes errors because of the case insensitive behavior on MySQL](https://github.com/shlinkio/shlink/issues/24)
### 0.2.0
**Enhancements:**
* [9: Use symfony/console to dispatch console requests, instead of trying to integrate the process with expressive](https://github.com/acelaya/url-shortener/issues/9)
* [8: Create a REST API](https://github.com/acelaya/url-shortener/issues/8)
* [10: Add more CLI functionality](https://github.com/acelaya/url-shortener/issues/10)
* [9: Use symfony/console to dispatch console requests, instead of trying to integrate the process with expressive](https://github.com/shlinkio/shlink/issues/9)
* [8: Create a REST API](https://github.com/shlinkio/shlink/issues/8)
* [10: Add more CLI functionality](https://github.com/shlinkio/shlink/issues/10)
**Tasks**
* [5: Create CHANGELOG file](https://github.com/acelaya/url-shortener/issues/5)
* [5: Create CHANGELOG file](https://github.com/shlinkio/shlink/issues/5)

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 Alejandro Celaya
Copyright (c) 2017 Alejandro Celaya
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -15,6 +15,7 @@ projectdir=$(pwd)
echo 'Copying project files...'
rm -rf "${builtcontent}"
mkdir "${builtcontent}"
sudo chmod -R 777 "${projectdir}"/data/infra/{database,nginx}
cp -R "${projectdir}"/* "${builtcontent}"
cd "${builtcontent}"
@ -22,7 +23,7 @@ cd "${builtcontent}"
rm -r vendor
rm composer.lock
composer self-update
composer install --no-dev --optimize-autoloader
composer install --no-dev --optimize-autoloader --no-progress --no-interaction
# Delete development files
echo 'Deleting dev files...'
@ -34,6 +35,7 @@ rm php*
rm README.md
rm -r build
rm -f data/database.sqlite
rm -rf data/infra
rm -rf data/{cache,log,proxies}/{*,.gitignore}
rm -rf config/params/{*,.gitignore}
rm -rf config/autoload/{{,*.}local.php{,.dist},.gitignore}

View file

@ -14,7 +14,7 @@
"require": {
"php": "^5.6 || ^7.0",
"zendframework/zend-expressive": "^1.0",
"zendframework/zend-expressive-fastroute": "^1.1",
"zendframework/zend-expressive-fastroute": "^1.3",
"zendframework/zend-expressive-twigrenderer": "^1.0",
"zendframework/zend-stdlib": "^2.7",
"zendframework/zend-servicemanager": "^3.0",

View file

@ -4,18 +4,15 @@ use Zend\Expressive\Container;
use Zend\Expressive\Router;
use Zend\Expressive\Template;
use Zend\Expressive\Twig;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'dependencies' => [
'factories' => [
Expressive\Application::class => Container\ApplicationFactory::class,
Router\FastRouteRouter::class => InvokableFactory::class,
Template\TemplateRendererInterface::class => Twig\TwigRendererFactory::class,
],
'aliases' => [
Router\RouterInterface::class => Router\FastRouteRouter::class,
\Twig_Environment::class => Twig\TwigEnvironmentFactory::class,
Router\RouterInterface::class => Router\FastRouteRouterFactory::class,
],
],

View file

@ -6,14 +6,10 @@ return [
'proxies_dir' => 'data/proxies',
],
'connection' => [
'driver' => 'pdo_mysql',
'user' => env('DB_USER'),
'password' => env('DB_PASSWORD'),
'dbname' => env('DB_NAME', 'shlink'),
'charset' => 'utf8',
'driverOptions' => [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
],
],
],

View file

@ -0,0 +1,14 @@
<?php
return [
'entity_manager' => [
'connection' => [
'driver' => 'pdo_mysql',
'host' => 'shlink_db',
'driverOptions' => [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
],
],
],
];

View file

@ -0,0 +1,13 @@
<?php
use Zend\Expressive\Router\FastRouteRouter;
return [
'router' => [
'fastroute' => [
FastRouteRouter::CONFIG_CACHE_ENABLED => true,
FastRouteRouter::CONFIG_CACHE_FILE => 'data/cache/fastroute_cached_routes.php',
],
],
];

View file

@ -0,0 +1,12 @@
<?php
use Zend\Expressive\Router\FastRouteRouter;
return [
'router' => [
'fastroute' => [
FastRouteRouter::CONFIG_CACHE_ENABLED => false,
],
],
];

2
data/infra/database/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

6
data/infra/db.Dockerfile Normal file
View file

@ -0,0 +1,6 @@
FROM mysql:5.7
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
# Enable remote access (default is localhost only, we change this
# otherwise our database would not be reachable from outside the container)
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf

View file

@ -0,0 +1,5 @@
FROM nginx:1.11.6-alpine
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
# Delete default nginx vhost
RUN rm /etc/nginx/conf.d/default.conf

2
data/infra/nginx/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

87
data/infra/php.Dockerfile Normal file
View file

@ -0,0 +1,87 @@
FROM php:7.1-fpm-alpine
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
RUN apk update
# Install common php extensions
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install iconv
RUN docker-php-ext-install mbstring
RUN docker-php-ext-install calendar
RUN apk add --no-cache --virtual sqlite-libs
RUN apk add --no-cache --virtual sqlite-dev
RUN docker-php-ext-install pdo_sqlite
RUN apk add --no-cache --virtual icu-dev
RUN docker-php-ext-install intl
RUN apk add --no-cache --virtual zlib-dev
RUN docker-php-ext-install zip
RUN apk add --no-cache --virtual libmcrypt-dev
RUN docker-php-ext-install mcrypt
RUN apk add --no-cache --virtual libpng-dev
RUN docker-php-ext-install gd
# Install redis extension
ADD https://github.com/phpredis/phpredis/archive/php7.tar.gz /tmp/phpredis.tar.gz
RUN mkdir -p /usr/src/php/ext/redis\
&& tar xf /tmp/phpredis.tar.gz -C /usr/src/php/ext/redis --strip-components=1
# configure and install
RUN docker-php-ext-configure redis\
&& docker-php-ext-install redis
# cleanup
RUN rm /tmp/phpredis.tar.gz
# Install memcached extension
RUN apk add --no-cache --virtual cyrus-sasl-dev
RUN apk add --no-cache --virtual libmemcached-dev
ADD https://github.com/php-memcached-dev/php-memcached/archive/php7.tar.gz /tmp/memcached.tar.gz
RUN mkdir -p /usr/src/php/ext/memcached\
&& tar xf /tmp/memcached.tar.gz -C /usr/src/php/ext/memcached --strip-components=1
# configure and install
RUN docker-php-ext-configure memcached\
&& docker-php-ext-install memcached
# cleanup
RUN rm /tmp/memcached.tar.gz
# Install APCu extension
ADD https://pecl.php.net/get/apcu-5.1.3.tgz /tmp/apcu.tar.gz
RUN mkdir -p /usr/src/php/ext/apcu\
&& tar xf /tmp/apcu.tar.gz -C /usr/src/php/ext/apcu --strip-components=1
# configure and install
RUN docker-php-ext-configure apcu\
&& docker-php-ext-install apcu
# cleanup
RUN rm /tmp/apcu.tar.gz
# Install APCu-BC extension
ADD https://pecl.php.net/get/apcu_bc-1.0.3.tgz /tmp/apcu_bc.tar.gz
RUN mkdir -p /usr/src/php/ext/apcu-bc\
&& tar xf /tmp/apcu_bc.tar.gz -C /usr/src/php/ext/apcu-bc --strip-components=1
# configure and install
RUN docker-php-ext-configure apcu-bc\
&& docker-php-ext-install apcu-bc
# cleanup
RUN rm /tmp/apcu_bc.tar.gz
# Load APCU.ini before APC.ini
RUN rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini
RUN echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini
# Install xdebug
ADD https://pecl.php.net/get/xdebug-2.5.0 /tmp/xdebug.tar.gz
RUN mkdir -p /usr/src/php/ext/xdebug\
&& tar xf /tmp/xdebug.tar.gz -C /usr/src/php/ext/xdebug --strip-components=1
# configure and install
RUN docker-php-ext-configure xdebug\
&& docker-php-ext-install xdebug
# cleanup
RUN rm /tmp/xdebug.tar.gz
# Install composer
RUN php -r "readfile('https://getcomposer.org/installer');" | php
RUN chmod +x composer.phar
RUN mv composer.phar /usr/local/bin/composer

1
data/infra/php.ini Normal file
View file

@ -0,0 +1 @@
date.timezone = Europe/Madrid

21
data/infra/vhost.conf Normal file
View file

@ -0,0 +1,21 @@
server {
listen 80 default_server;
server_name shlink.local;
root /home/shlink/www/public;
index index.php;
charset utf-8;
error_log /home/shlink/www/data/infra/nginx/shlink.error.log;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
root /home/shlink/www/public;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass shlink_php:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}

41
docker-compose.yml Normal file
View file

@ -0,0 +1,41 @@
version: '2'
services:
shlink_nginx:
container_name: shlink_nginx
build:
context: .
dockerfile: ./data/infra/nginx.Dockerfile
ports:
- "8000:80"
volumes:
- ./:/home/shlink/www
- ./docs:/home/shlink/www/public/docs
- ./data/infra/vhost.conf:/etc/nginx/conf.d/shlink-vhost.conf
links:
- shlink_php
shlink_php:
container_name: shlink_php
build:
context: .
dockerfile: ./data/infra/php.Dockerfile
volumes:
- ./:/home/shlink/www
- ./data/infra/php.ini:/usr/local/etc/php/php.ini
links:
- shlink_db
shlink_db:
container_name: shlink_db
build:
context: .
dockerfile: ./data/infra/db.Dockerfile
ports:
- "3307:3306"
volumes:
- ./:/home/shlink/www
- ./data/infra/database:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: shlink

View file

@ -26,10 +26,8 @@
"description": "A list of tags used to filter the resultset. Only short URLs tagged with at least one of the provided tags will be returned. (Since v1.3.0)",
"required": false,
"type": "array",
"schema": {
"items": {
"type": "string"
}
"items": {
"type": "string"
}
},
{

2
indocker Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
docker exec -it shlink_php /bin/sh -c "cd /home/shlink/www && $*"

View file

@ -135,11 +135,18 @@ class InstallCommand extends Command
$params['NAME'] = $this->ask('Database name', 'shlink');
$params['USER'] = $this->ask('Database username');
$params['PASSWORD'] = $this->ask('Database password');
$params['HOST'] = $this->ask('Database host', 'localhost');
$params['PORT'] = $this->ask('Database port', $this->getDefaultDbPort($params['DRIVER']));
}
return $params;
}
protected function getDefaultDbPort($driver)
{
return $driver === 'pdo_mysql' ? '3306' : '5432';
}
protected function askUrlShortener()
{
$this->printTitle('URL SHORTENER');
@ -272,6 +279,14 @@ class InstallCommand extends Command
$config['entity_manager']['connection']['user'] = $params['DATABASE']['USER'];
$config['entity_manager']['connection']['password'] = $params['DATABASE']['PASSWORD'];
$config['entity_manager']['connection']['dbname'] = $params['DATABASE']['NAME'];
$config['entity_manager']['connection']['host'] = $params['DATABASE']['HOST'];
$config['entity_manager']['connection']['port'] = $params['DATABASE']['PORT'];
if ($params['DATABASE']['DRIVER'] === 'pdo_mysql') {
$config['entity_manager']['connection']['driverOptions'] = [
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
];
}
}
return $config;

View file

@ -47,12 +47,14 @@ class InstallCommandTest extends TestCase
protected function createInputStream()
{
$stream = fopen('php://memory', 'r+', false);
fputs($stream, <<<CLI_INPUT
$stream = fopen('php://memory', 'rb+', false);
fwrite($stream, <<<CLI_INPUT
shlink_db
alejandro
1234
0
doma.in
abc123BCA
@ -69,7 +71,7 @@ CLI_INPUT
/**
* @test
*/
public function testInputIsProperlyParsed()
public function inputIsProperlyParsed()
{
$this->configWriter->toFile(Argument::any(), [
'app_options' => [
@ -81,6 +83,11 @@ CLI_INPUT
'dbname' => 'shlink_db',
'user' => 'alejandro',
'password' => '1234',
'host' => 'localhost',
'port' => '3306',
'driverOptions' => [
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
]
],
],
'translator' => [

View file

@ -21,15 +21,15 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
$qb->select('s');
// Set limit and offset
if (isset($limit)) {
if ($limit !== null) {
$qb->setMaxResults($limit);
}
if (isset($offset)) {
if ($offset !== null) {
$qb->setFirstResult($offset);
}
// In case the ordering has been specified, the query could be more complex. Process it
if (isset($orderBy)) {
if ($orderBy !== null) {
return $this->processOrderByForList($qb, $orderBy);
}
@ -47,7 +47,7 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
'visits',
'visitsCount',
'visitCount',
])) {
], true)) {
$qb->addSelect('COUNT(v) AS totalVisits')
->leftJoin('s.visits', 'v')
->groupBy('s')
@ -58,7 +58,7 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
'originalUrl',
'shortCode',
'dateCreated',
])) {
], true)) {
$qb->orderBy('s.' . $fieldName, $order);
}
@ -93,9 +93,12 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
// Apply search term to every searchable field if not empty
if (! empty($searchTerm)) {
$qb->join('s.tags', 't');
$conditions = [
$qb->expr()->like('s.originalUrl', ':searchPattern'),
$qb->expr()->like('s.shortCode', ':searchPattern'),
$qb->expr()->like('t.name', ':searchPattern'),
];
// Unpack and apply search conditions

View file

@ -117,7 +117,9 @@ class UrlShortener implements UrlShortenerInterface
protected function checkUrlExists(UriInterface $url)
{
try {
$this->httpClient->request('GET', $url);
$this->httpClient->request('GET', $url, ['allow_redirects' => [
'max' => 15,
]]);
} catch (GuzzleException $e) {
throw InvalidUrlException::fromUrl($url, $e);
}

View file

@ -5,6 +5,7 @@ return [
'middleware_pipeline' => [
'pre-routing' => [
'path' => '/rest',
'middleware' => [
Middleware\PathVersionMiddleware::class,
],

View file

@ -37,19 +37,13 @@ class PathVersionMiddleware implements MiddlewareInterface
$uri = $request->getUri();
$path = $uri->getPath();
// Exclude non-rest route
if (strpos($path, '/rest') !== 0) {
return $out($request, $response);
}
// If the path does not begin with the version number, prepend v1 by default for retrocompatibility purposes
if (strpos($path, '/rest/v') !== 0) {
if (strpos($path, '/v') !== 0) {
$parts = explode('/', $path);
// Remove the first empty part and the "/rest" prefix
// Remove the first empty part and the
array_shift($parts);
array_shift($parts);
// Prepend the prefix with version
array_unshift($parts, '/rest/v1');
// Prepend the version prefix
array_unshift($parts, '/v1');
$request = $request->withUri($uri->withPath(implode('/', $parts)));
}

View file

@ -25,7 +25,7 @@ class PathVersionMiddlewareTest extends TestCase
*/
public function whenVersionIsProvidedRequestRemainsUnchanged()
{
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/rest/v2/foo'));
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/v2/foo'));
$test = $this;
$this->middleware->__invoke($request, new Response(), function ($req) use ($request, $test) {
$test->assertSame($request, $req);
@ -37,23 +37,11 @@ class PathVersionMiddlewareTest extends TestCase
*/
public function versionOneIsPrependedWhenNoVersionIsDefined()
{
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/rest/bar/baz'));
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/bar/baz'));
$test = $this;
$this->middleware->__invoke($request, new Response(), function (Request $req) use ($request, $test) {
$test->assertNotSame($request, $req);
$this->assertEquals('/rest/v1/bar/baz', $req->getUri()->getPath());
});
}
/**
* @test
*/
public function nonRestPathsAreNotProcessed()
{
$request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/non-rest'));
$test = $this;
$this->middleware->__invoke($request, new Response(), function ($req) use ($request, $test) {
$test->assertSame($request, $req);
$this->assertEquals('/v1/bar/baz', $req->getUri()->getPath());
});
}
}