Recreate Docker setup for contributors to be more up to date and robust (#401)

Recreate Docker setup for contributors to be more up to date and robust
This commit is contained in:
Yuri Sizov
2022-07-10 00:55:41 +03:00
committed by GitHub
parent 2d17aaa7a0
commit 6931563dd2
411 changed files with 520 additions and 24018 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
plugins/* linguist-vendored

View File

@@ -5,7 +5,7 @@ on:
jobs:
test:
name: Test
name: Validate formatting and setup
runs-on: ubuntu-20.04
steps:
- name: Checkout
@@ -20,35 +20,44 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: "7.3"
tools: composer:v1
tools: composer:v2
extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_mysql, xml, zip
# Disable Xdebug to improve performance.
coverage: none
- name: Install October and set up MySQL database
- name: Set up MySQL and install OctoberCMS
run: |
sudo systemctl start mysql
echo -e '[client]\nuser="root"\npassword="root"' > "$HOME/.my.cnf"
mysql -e 'CREATE DATABASE IF NOT EXISTS `database`;'
mysql -e "CREATE DATABASE IF NOT EXISTS october;"
# https://stackoverflow.com/questions/52364415/php-with-mysql-8-0-error-the-server-requested-authentication-method-unknown-to
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';"
mkdir -p october
pushd october
php -r "eval('?>'.file_get_contents('https://octobercms.com/api/installer'));"
php artisan key:generate
# Set up the database.
sed -i "s/'password' => ''/'password' => 'root'/g" config/database.php
sed -i "s/'activeTheme' => 'demo'/'activeTheme' => 'godotengine'/g" config/cms.php
php artisan october:up
# Explicitly allow all plugins to run scripts during installation.
composer config -g allow-plugins true
cp -r ../plugins/* plugins
mkdir -p october
composer create-project october/october ./october "v1.0.474" --no-dev
pushd october
php artisan key:generate
# Copy project files.
cp -r ../themes/* themes
php artisan plugin:refresh paulvonzimmerman.patreon
env -C plugins/paulvonzimmerman/patreon composer install
php artisan plugin:refresh pikanji.agent
php artisan plugin:refresh rainlab.blog
php artisan plugin:refresh sobored.rss
cp -r ../docker/php/config/* config
# Fix up the config for CI.
sed -i "s/'host' => 'mariadb'/'host' => 'localhost'/g" config/database.php
sed -i "s/'username' => 'godot'/'username' => 'root'/g" config/database.php
sed -i "s/'password' => 'godot'/'password' => 'root'/g" config/database.php
php artisan october:up
php artisan october:fresh
php artisan plugin:install paulvonzimmerman.patreon
php artisan plugin:install pikanji.agent
php artisan plugin:install rainlab.blog
php artisan plugin:install sobored.rss
- name: Run Lighthouse CI
run: |

8
.gitignore vendored
View File

@@ -13,16 +13,12 @@
!.gitmodules
!.gitignore
# October CMS
# Local development tools
node_modules
# Plugins
!/plugins
/plugins/october/demo
# Winter CMS files
# Themes
!/themes
/themes/demo
# Docker
!/docker

105
README.md
View File

@@ -1,9 +1,19 @@
# Godot Website
This repository contains the theme and plugins used in Godot Engine's
October instance.
This repository contains the theme used by the Godot Engine's OctoberCMS/WinterCMS
instance. The theme describes both the styling of the website and the components
of its layouts, as well as some of its content.
## Development
- [OctoberCMS](https://github.com/octobercms/october) is the original CMS platform of choice.
- [WinterCMS](https://github.com/wintercms/winter) is the current CMS platform, a fork of October with more active development.
_WinterCMS_ is compatible with _OctoberCMS_, and uses the same plugin system. This is
at least true for the version of the project that we use.
This repository also contains a Docker setup to be used by contributors. It
is not used for production.
## Contributing
### Browser support
@@ -20,49 +30,71 @@ Internet Explorer isn't supported.
### Dependencies
- [Docker](https://docker.com)
- It's also possible to install PHP 7.2+, MySQL and October manually,
but this isn't covered in this README.
This project requires the following stack:
### Running the site
- PHP 7.2+ & Composer 2
- MySQL/MariaDB
- OctoberCMS/WinterCMS v1.0.xxx
There are also some linting tools that can be run locally that require Node.js.
This project comes with a [Docker](https://docker.com) setup that can be used to quickly
create a network of compatible containers. Using this setup, you can have a local copy of
the project, without the production database. For development purposes, you don't need
that database, as the only thing that is specific to production is blog posts, which can
be easily recreated if required.
### Local setup
While it is possible to configure a local environment manually,
we recommend using the provided Docker setup.
- Clone this repository.
- Put a database dump (if you have one) into the `/docker/mariadb/init` folder.
- If you have a database dump, put it into the `./docker/mariadb/init` folder.
- Make sure that your script starts with the line `USE october;` and that the file extension is `.sql`.
- Run the `./docker/restart.sh` script (this will take a while the first time).
- You might need to reinstall some plugins `/docker/php/install-plugin.sh author.name`.
- Replace `author.name` with the names in the `/plugins/[author]/[name]` folders.
- See the website at [http://localhost:8080](http://localhost:8080).
- Every `.sql` and `.sh` file from that directory will be automatically executed when building the container.
- Using a terminal, or another command-line environment, go to the `./docker` folder and execute the following command.
- You can replace `"godot-website"` with anything else to help you identify this project in your Docker manager.
- In the future, you can use the `./docker/restart.sh` script to rebuild containers.
### Restoring a database
```sh
mv /your/dump/backup-file.sql docker/mariadb/init
docker/mariadb/bash.sh
cd /docker-entrypoint-initdb.d/
mysql < 000-setup.sql
mysql < backup-file.sql
```
docker-compose -p "godot-website" up --build -d --force-recreate
```
### Interfacing with the Docker containers
The script will take a couple of minutes to run the first time. After the
build is done, the containers will automatically start and perform their
first time setup. Check the logs of the `godotengine-org--php` container,
as it takes more time to finish. You will see the following line in the
logs when it's done:
You can use the standard `docker exec -it godotengine-org--[php|mariadb] [command]` syntax or the following scripts:
> Godot Website is READY to use!
- `./docker/php/bash.sh`
- `./docker/php/install-plugin.sh`
- `./docker/php/log.sh`
- `./docker/mariadb/bash.sh`
- `./docker/mariadb/log.sh`
- `./docker/mariadb/mysql.sh`
See the website at [http://localhost:8080](http://localhost:8080). The control
panel is located at [http://localhost:8080/backend](http://localhost:8080/backend).
The default admin account is `admin/admin`.
### Setting up the theme
### Interfacing with Docker containers
- Log into the October backend (located at `/backend`) and change the frontend theme from the Settings tab.
- Alternatively, you can edit `config/cms.php` and change the theme to `godotengine` there.
- Change directory into `plugins/paulvonzimmerman/patreon` then run `composer install`.
- You should now have approximately what's in production. The only missing
pieces are everything that's stored in the production database
(blog entries).
You can use the standard syntax to either execute a shell script or connect
to the running container:
```
# Execute shell command.
docker exec -it godotengine-org--[php|mariadb] [command]
# Connect to a remote shell.
docker exec -it godotengine-org--[php|mariadb] /bin/bash
```
There are several shell scripts that come with the project, that may be useful
when developing (assuming you're running Linux or macOS):
- `./docker/php/bash.sh` starts a bash session with the PHP container.
- `./docker/php/install-plugin.sh` is used to install additional CMS plugins with `artisan`.
- `./docker/php/log.sh` is used to access logs of the PHP container.
- `./docker/mariadb/bash.sh` starts a bash session with the MariaDB container.
- `./docker/mariadb/log.sh` is used to access logs of the MariaDB container.
- `./docker/mariadb/mysql.sh` starts a MySQL shell session in the MariaDB container.
### Syntax highlighting
@@ -72,6 +104,7 @@ extension to benefit from syntax highlighting in `.htm` templates.
## Resources
- Discuss on Godot Contributors Chat [#website](https://chat.godotengine.org/channel/website) channel.
- Join the discussion on Godot Contributors Chat in the
[#website](https://chat.godotengine.org/channel/website) channel.
- When working on the theme, please take note of the
[website stats](https://stats.tuxfamily.org/godotengine.org).

View File

@@ -4,26 +4,8 @@ networks:
godotengine-org--network: ~
services:
php:
build:
context: ./php
args:
# Fallback version is the one we deploy on the website.
october_version: "${OCTOBER_VERSION:-v1.0.469}"
container_name: "godotengine-org--php"
depends_on:
- mariadb
networks:
- godotengine-org--network
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ../plugins:/var/www/html/plugins
- ../themes/godotengine:/var/www/html/themes/godotengine
mariadb:
image: mariadb
image: mariadb:10.8
container_name: "godotengine-org--mariadb"
networks:
- godotengine-org--network
@@ -35,3 +17,20 @@ services:
volumes:
- ./mariadb/storage:/var/lib/mysql
- ./mariadb/init:/docker-entrypoint-initdb.d
php:
build:
context: ./php
args:
# Fallback version is the one we deploy on the website.
october_version: "${OCTOBER_VERSION:-v1.0.474}"
container_name: "godotengine-org--php"
depends_on:
- mariadb
networks:
- godotengine-org--network
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ../themes/godotengine:/var/www/html/themes/godotengine

View File

@@ -1,39 +1,52 @@
FROM php:apache
# Pin Debian 11 (Bullseye) and PHP 7.4.x.
FROM php:7.4-apache-bullseye
# Settings
# Configure working environment.
WORKDIR /var/www/html
ENV COMPOSER_ALLOW_SUPERUSER=1
# Install server dependencies
# Install additional server dependencies.
RUN apt-get update &&\
apt-get install -y git unzip vim zlib1g-dev libzip-dev libpng-dev
apt-get install -y git unzip vim nano mc zlib1g-dev libzip-dev libpng-dev netcat
# Install PHP extensions
# Configure PHP installation.
# Install additional PHP extensions.
RUN docker-php-ext-install mysqli pdo pdo_mysql zip gd
# Enable PHP modules
# Enable required PHP modules.
RUN a2enmod rewrite
# Install composer
RUN curl -sS https://getcomposer.org/installer -o composer-setup.php &&\
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
# Install OctoberCMS
# Install Composer 2.
# Disables warnings when working as superuser.
ENV COMPOSER_ALLOW_SUPERUSER=1
RUN cd /opt &&\
# Download the installer and check for its integrity.
curl -sSL https://getcomposer.org/installer > composer-setup.php &&\
curl -sSL https://composer.github.io/installer.sha384sum > composer-setup.sha384sum &&\
sha384sum --check composer-setup.sha384sum &&\
# Then run it, aliasing it as just `composer`.
php composer-setup.php --install-dir=/usr/local/bin --filename=composer &&\
# Remove temporary files.
rm /opt/composer-setup.php /opt/composer-setup.sha384sum
# Install OctoberCMS and update configuration.
ARG october_version
RUN echo "Installing OctoberCMS version: ${october_version}" &&\
git init . &&\
git remote add origin https://github.com/octobercms/october.git &&\
git fetch origin &&\
git checkout ${october_version} -b october-${october_version} &&\
composer install -v
# Explicitly allow all plugins to run scripts during installation.
RUN composer config -g allow-plugins true
RUN cd /var/www/html &&\
composer create-project october/october . "${october_version}" --no-dev
# Override default configuration (with backup).
RUN mv ./config/cms.php ./config/cms.php.orig &&\
mv ./config/database.php ./config/database.php.orig
COPY config/cms.php config/database.php /var/www/html/config/
# Config
RUN sed -i "s/'host' => 'localhost'/'host' => 'mariadb'/g" config/database.php
RUN sed -i "s/'database' => 'database'/'database' => 'october'/g" config/database.php
RUN sed -i "s/'username' => 'root'/'username' => 'godot'/g" config/database.php
RUN sed -i "s/'password' => ''/'password' => 'godot'/g" config/database.php
# Copy startup and setup scripts.
COPY init/* /usr/local/bin/
RUN chmod -R +x /usr/local/bin
RUN sed -i "s/'activeTheme' => 'demo'/'activeTheme' => 'godotengine'/g" config/cms.php
# Set permissions
RUN chown www-data:www-data -R .
# Override container's entrypoint to inject first-time setup.
ENTRYPOINT docker-entrypoint.sh

72
docker/php/config/cms.php Normal file
View File

@@ -0,0 +1,72 @@
<?php
// See https://github.com/octobercms/october/blob/v1.0.474/config/cms.php
return [
// Overridden.
'activeTheme' => 'godotengine',
'edgeUpdates' => false,
'backendUri' => 'backend',
'backendForceSecure' => false,
'backendForceRemember' => true,
'backendTimezone' => 'UTC',
'backendSkin' => 'Backend\Skins\Standard',
'runMigrationsOnLogin' => null,
'loadModules' => ['System', 'Backend', 'Cms'],
// Overridden, use composer for updates.
'disableCoreUpdates' => true,
'disablePlugins' => [],
'enableRoutesCache' => false,
'urlCacheTtl' => 10,
'parsedPageCacheTTL' => 10,
'enableAssetCache' => false,
'enableAssetMinify' => null,
'enableAssetDeepHashing' => null,
'databaseTemplates' => false,
'pluginsPath' => '/plugins',
'themesPath' => '/themes',
'storage' => [
'uploads' => [
'disk' => 'local',
'folder' => 'uploads',
'path' => '/storage/app/uploads',
'temporaryUrlTTL' => 3600,
],
'media' => [
'disk' => 'local',
'folder' => 'media',
'path' => '/storage/app/media',
],
],
'convertLineEndings' => false,
'linkPolicy' => 'detect',
'defaultMask' => ['file' => null, 'folder' => null],
'enableSafeMode' => null,
'enableCsrfProtection' => true,
'forceBytecodeInvalidation' => true,
'enableTwigStrictVariables' => false,
'restrictBaseDir' => true,
'enableBackendServiceWorkers' => false,
];

View File

@@ -0,0 +1,51 @@
<?php
// See https://github.com/octobercms/october/blob/v1.0.474/config/database.php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => 'mysql',
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => 'storage/database.sqlite',
'prefix' => '',
],
// Overridden.
'mysql' => [
'driver' => 'mysql',
'engine' => 'InnoDB',
'host' => 'mariadb',
'port' => 3306,
'database' => 'october',
'username' => 'godot',
'password' => 'godot',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'varcharmax' => 191,
],
],
'migrations' => 'migrations',
'redis' => [
'cluster' => false,
'default' => [
'host' => '127.0.0.1',
'password' => null,
'port' => 6379,
'database' => 0,
],
],
'useConfigForTesting' => false,
];

View File

@@ -0,0 +1,4 @@
#!/bin/bash
echo "Checking if MariaDB is reachable..."
exec wait-for-it.sh mariadb:3306 -s -t 30 -- init.sh

33
docker/php/init/init.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Only do this once.
CONTAINER_ALREADY_STARTED="/tmp/CONTAINER_ALREADY_STARTED"
if [ ! -e $CONTAINER_ALREADY_STARTED ]; then
touch $CONTAINER_ALREADY_STARTED
echo "Performing initial OctoberCMS setup..."
# Migrate OctoberCMS to the actual database and reset it.
echo "Migrating OctoberCMS to the actual database..."
php artisan october:up
echo "Resetting OctoberCMS and removing demo assets..."
php artisan october:fresh
echo "Resetting OctoberCMS admin account..."
php artisan october:passwd admin admin
# Install plugins.
echo "Installing required October plugins..."
# TODO: Pin plugin versions.
php artisan plugin:install "paulvonzimmerman.patreon"
php artisan plugin:install "pikanji.agent"
php artisan plugin:install "rainlab.blog"
php artisan plugin:install "sobored.rss"
echo "Updating file permissions for newly created files..."
chown www-data:www-data -R .
echo "Godot Website is READY to use!"
else
echo "Skipped initial OctoberCMS setup."
fi
exec docker-php-entrypoint apache2-foreground

View File

@@ -0,0 +1,204 @@
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
# The MIT License (MIT)
# Copyright (c) 2016 Giles Hall
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi

View File

@@ -1,5 +0,0 @@
vendor
bower_components
*.swo
*.swp
composer.phar

View File

@@ -1,28 +0,0 @@
<?php namespace PaulVonZimmerman\Patreon;
use System\Classes\PluginBase;
class Plugin extends PluginBase
{
public function registerComponents()
{
return [
'PaulVonZimmerman\Patreon\Components\Goal' => 'Goal'
];
}
public function registerSettings()
{
return [
'settings' => [
'label' => 'Patreon Settings',
'description' => 'Set your patreon client_id and client_secret',
'icon' => 'icon-money',
'class' => 'PaulVonZimmerman\Patreon\Models\Settings',
'order' => 0,
'keywords' => 'security location',
'permissions' => ['paulvonzimmerman.patreon.access_settings']
]
];
}
}

View File

@@ -1,29 +0,0 @@
# October patreon
![Screenshot](./screenshot.png)
## Setup
### Logging in to Patreon
Once the plugin is installed a new tab will appear in the backend menu. This tab contains the instructions on how to connect your patreon account. Here is the general gist of those instructions:
- Register a Patreon application [here](https://www.patreon.com/platform/documentation/clients)
- Go to the settings page of your October website and set your client_secret and client_id. The settings page also includes options to set the refresh time (how often the plugin will refresh the data from patreon, very important to set that) and the link to your patreon.
- Set the "redirect_url" of your patreon application, the plugin will provide the link in the patreon tab, set it in your patreon application settings.
- Finally, click the connect application button to connect your patreon to your website.
### Adding the goal component to a page
### Regular page (not a partial)
- Navigate to the CMS section of the october backend
- Click the page you want to add the component to
- Click components in the left sidebar
- Click the patreon drop down
- Click "Goal Component"
- add: {% component 'Goal' %} wherver you want the component to show up.
### Partial (usually your header, footer, etc.)
- The steps are the same as adding it to a regular page, except you need to add the {% scripts %} tag and {% styles %} tag to the top of the page.
### Adding to a partial:
If you add this component to a partial, be sure to include the `{% scripts %}` and `{% styles %}` tags.

View File

@@ -1,3 +0,0 @@
div.patreon-row:nth-child(2) {
display: none;
}

View File

@@ -1,80 +0,0 @@
#goal a {
display: flex;
justify-content: flex-start;
}
.goalContainer {
width: 100%;
background-color: #052D49;
height: 16.5px;
border-top: 2px solid #052D49;
border-bottom: 2px solid #052D49;
}
.percentageBar {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.goalContainer div div {
font-weight: bold;
color: #F96854;
font-size: 12px;
}
.patreon {
width: 180px;
display: flex;
flex-direction: column;
align-items: center;
background-color: #F96854;
box-sizing: border-box;
padding: 6px 6px 2px 6px;
transition: border .2s;
border-bottom: 4px solid #F96854;
height: 50px;
}
a:hover > .patreon {
border-bottom: 4px solid #052D49;
}
.patreon-row {
height: 50%;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
}
.patreon-brand {
background-image: url('../images/become_a_patron_button.png');
background-size: 130px;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
.patreon-uppercase {
font-weight: bold;
color: white;
text-transform: uppercase;
font-size: 10px;
margin: 0;
padding: 10px;
}
#goal {
width: 100%;
}
a.patreonLink {
display: inline-block;
padding: 0;
height: auto;
margin-left: 30px;
}
a.patreonLink:hover {
text-decoration: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,19 +0,0 @@
window.onload = function () {
var pBar = document.querySelector(".goalContainer .percentageBar");
var pBarP = document.querySelector(".goalContainer > .percentageBar > div");
var goal = document.getElementById('goal').dataset.percentage;
function animate (time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
var start = {x: 0};
var tween = new TWEEN.Tween(start)
.to({x: goal}, 500)
.onUpdate( function () {
pBarP.innerHTML = Math.round(start.x) + "%";
pBar.style.backgroundImage = 'linear-gradient(90deg, white '+start.x+'%, #052D49 '+start.x+'%)';
})
.start();
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,20 +0,0 @@
{
"name": "patreon",
"homepage": "https://github.com/pcvonz/october_patreon_goal_status",
"authors": [
"PaulVonZimmerman Von Zimmerman <pcvonz@gmail.com>"
],
"description": "",
"main": "",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"tween.js": "tweenjs#^16.6.0"
}
}

View File

@@ -1,83 +0,0 @@
<?php namespace PaulVonZimmerman\Patreon\Components;
use Cms\Classes\ComponentBase;
use PaulVonZimmerman\Patreon\Models\Settings;
class Goal extends ComponentBase
{
public function componentDetails()
{
return [
'name' => 'Goal Component',
'description' => "Adds a small widget that displays the percentage complete of a patreon campaign."
];
}
private function patreonRequest()
{
$register_client = new \Patreon\API(Settings::get('access_token'));
$campaign_response = $register_client->fetch_campaign();
// Handle access_token expiring:
if (isset($campaign_response['errors'])) {
$oauth_client = new \Patreon\OAuth(Settings::get('client_id'), Settings::get('client_secret'));
// Get a fresher access token
$tokens = $oauth_client->refresh_token(Settings::get('refresh_token'), null);
// echo Settings::get('refresh_token').'</br>';
if (isset($tokens['access_token'])) {
// Set new token
$access_token = $tokens['access_token'];
Settings::set('refresh_token', $tokens['refresh_token']);
Settings::set('access_token', $access_token);
} else {
// print_r($tokens);
$this->addCss('/plugins/paulvonzimmerman/patreon/assets/css/error.css');
return false;
}
}
$included = $campaign_response['included'];
if ($included != null) {
foreach ($included as $obj) {
if ($obj["type"] == "goal") {
$goal = $obj;
// Grab the first goal that is less than 100%
// If none are less than 100%, it'll pull latest entry from settings
if($goal['attributes']['completed_percentage'] < 100) {
// Set new goal amount (in case of update)
$this->update_goal_amount($goal['attributes']['amount_cents']);
Settings::set('completed_percentage', $goal['attributes']['completed_percentage']);
break;
}
}
}
}
}
public function update_goal_amount($cents)
{
Settings::set('amount_cents', '$'.number_format($cents / 100, 2, '.', ','));
}
public function init()
{
$this->page['patreon_url'] = Settings::get('patreon_url');
$refresh_time = Settings::get('refresh_time');
// Make sure refresh time is never 0
if ( $refresh_time == '' || $refresh_time < 5) {
$refresh_time = 5;
}
if ((Settings::get('time_since_last_update') + $refresh_time * 60) < time()) {
$this->patreonRequest();
Settings::set('time_since_last_update', time());
}
$this->page['amount_cents'] = Settings::get('amount_cents');
$this->page['goalPercentage'] = Settings::get('completed_percentage');
}
public function onRun()
{
$this->addCss('/plugins/paulvonzimmerman/patreon/assets/css/goal.css');
$this->addJs('/plugins/paulvonzimmerman/patreon/assets/js/goal.js');
}
public function defineProperties()
{
return [];
}
}

View File

@@ -1,21 +0,0 @@
<a class="patreonLink" href="{{ patreon_url }}">
<div class="patreon">
<div class="patreon-row">
<div class="patreon-brand">
</div>
</div>
<div class="patreon-row">
<div data-percentage="{{ goalPercentage }}" id="goal">
<div class="goalContainer">
<div class="percentageBar">
<div> {{ goalPercentage }}% </div>
</div>
</div
</div>
</div>
<p class="patreon-uppercase">{{ amount_cents }}</p>
</div>
</div>
</a>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/16.3.5/Tween.min.js"></script>

View File

@@ -1 +0,0 @@
{% partial 'Goal::_goal' %}

View File

@@ -1,5 +0,0 @@
{
"require": {
"patreon/patreon": "^0.1.0"
}
}

View File

@@ -1,54 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "3b481eedd85a1ad734a913541f0da1c7",
"packages": [
{
"name": "patreon/patreon",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://github.com/Patreon/patreon-php.git",
"reference": "2283c1295cafd49d509da7ac878db9489d2fe913"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Patreon/patreon-php/zipball/2283c1295cafd49d509da7ac878db9489d2fe913",
"reference": "2283c1295cafd49d509da7ac878db9489d2fe913",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Patreon": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "David Kettler",
"email": "david@patreon.com"
}
],
"description": "Interact with the Patreon API via OAuth",
"time": "2015-12-16T19:34:11+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}

View File

@@ -1,130 +0,0 @@
<?php namespace PaulVonZimmerman\Patreon\Controllers;
use Backend\Classes\Controller;
use BackendMenu;
use \Patreon\API;
use \Patreon\OAuth;
use PaulVonZimmerman\Patreon\Models\Settings;
class Register extends Controller
{
public $client_id;
public $client_secret;
public $redirect_uri;
public $creator_id;
public $actual_link;
public function __construct()
{
parent::__construct();
BackendMenu::setContext('PaulVonZimmerman.Patreon', 'Patreon');
$this->pageTitle = 'Patreon';
$this->client_id = Settings::get('client_id');
$this->client_secret = Settings::get('client_secret');
$this->redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$this->creator_id = 'test';
$this->actual_link = $actual_link = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]".'/backend/PaulVonZimmerman/patreon/register';
$this->vars['redirect_uri'] = $this->actual_link;
$this->vars['url'] = 'http://www.patreon.com/oauth2/authorize?response_type=code&client_id='.$this->client_id.'&redirect_uri='.$this->actual_link;
$this->vars['status'] = 'Retrieving status... ';
$this->vars['short_description'] = 'waiting..';
$this->vars['detail'] = 'Shouldnt take but a moment.';
$this->vars['class'] = 'info';
$this->vars['icon'] = 'info';
}
public function index()
{
}
public function onLoad()
{
if (isset($_GET['code'])) {
$oauth_client = new \Patreon\OAuth($this->client_id, $this->client_secret);
$tokens = $oauth_client->get_tokens($_GET['code'], $this->actual_link);
// Unset access_token could happen if they refresh right after
// getting an access token (?code is still set);
if (isset($tokens['access_token'])) {
$access_token = $tokens['access_token'];
$refresh_token = $tokens['refresh_token'];
Settings::set('refresh_token', $refresh_token);
Settings::set('access_token', $access_token);
$register_client = new \Patreon\API(Settings::get('access_token'));
$patron_response = $register_client->fetch_campaign();
$patron = $patron_response['data'];
$string = json_encode($patron);
$included = $patron_response['included'];
$goal = null;
if ($included != null) {
foreach ($included as $obj) {
if ($obj["type"] == "goal") {
$pledge = $obj;
$amount_cents = $pledge['attributes']['amount_cents'];
$amount_dollars = $amount_cents / 100;
$amount_cents = $amount_cents % 100;
if ($amount_cents < 9) {
$amount_cents = '0'.$amount_cents;
}
Settings::set('amount_cents', '$'.$amount_dollars.'.'.$amount_cents);
break;
}
}
}
}
}
if(Settings::get('access_token') != null) {
$register_client = new \Patreon\API(Settings::get('access_token'));
$campaign_response = $register_client->fetch_campaign();
// Handle access_token expiring:
if (isset($campaign_response['errors'])) {
$oauth_client = new \Patreon\OAuth(Settings::get('client_id'), Settings::get('client_secret'));
// Get a fresher access token
$tokens = $oauth_client->refresh_token(Settings::get('refresh_token'), null);
if (isset($tokens['access_token'])) {
// Set new token
$access_token = $tokens['access_token'];
Settings::set('refresh_token', $tokens['refresh_token']);
Settings::set('access_token', $access_token);
} else {
$this->vars['status'] = 'Error';
$this->vars['short_description'] = $campaign_response['errors'][0]['code_name'];
$this->vars['detail'] = $campaign_response['errors'][0]['detail'];
$this->vars['class'] = 'danger';
$this->vars['icon'] = 'warning';
}
}
if (isset($campaign_response['errors'])) {
$this->vars['status'] = 'Error';
$this->vars['short_description'] = $campaign_response['errors'][0]['code_name'];
$this->vars['detail'] = $campaign_response['errors'][0]['detail'];
$this->vars['class'] = 'danger';
$this->vars['icon'] = 'warning';
}
elseif (isset($campaign_response['data'])) {
$this->vars['status'] = 'Connection Successful';
$this->vars['short_description'] = 'Successful response from Patreon!';
$this->vars['detail'] = 'Now connected to: '.$campaign_response['data'][0]['attributes']['creation_name'].'<p>Goals:</p><ul>';
$this->vars['class'] = 'success';
$this->vars['icon'] = 'check';
$included = $campaign_response['included'];
$goal = null;
if ($included != null) {
foreach ($included as $obj) {
if ($obj["type"] == "goal") {
$pledge = $obj;
$this->vars['detail'] = $this->vars['detail'].'<li>'.$pledge['attributes']['description'];
}
}
}
$this->vars['detail'] = $this->vars['detail'].'</ul>';
}
}
else {
$this->vars['status'] = 'Access token not set.';
$this->vars['short_description'] = 'Did you complete step four?';
$this->vars['detail'] = 'October Patreon couldnt find an access token.';
$this->vars['class'] = 'danger';
$this->vars['icon'] = 'warning';
}
}
}

View File

@@ -1,11 +0,0 @@
<div id="patreonStatus" class="callout fade in callout-<?= $class ?>">
<div class="header">
<i class="icon-<?= $icon ?>"></i>
<h3><?= $status ?></h3>
<p><?= $short_description ?> </p>
</div>
<div class="content">
<p> <?= $detail ?></p>
</div>
</div>

View File

@@ -1,25 +0,0 @@
<h3> Patreon </h3>
<ol>
<li>Register a Patreon application <a class="btn btn-default" role="button" href="https://www.patreon.com/platform/documentation/clients"> here </a>.</li>
<li>Go to the settings page and set your <b> client_secret </b> and <b> client_id </b>.</li>
<li>
<p>copy this url:</p>
<code> <?= $redirect_uri ?> </code>
</p>And set it as the <b> redirect_uri </b> of your Patreon application.</p>
</li>
<li><a class="btn btn-default" role="button"href="<?= $url ?>"> Click here to connect your patreon </a></li>
</ol>
<hr />
<?= $this->makePartial('patreonstatus')?>
<script>
$(document).ready(function () {
$(this).request('onLoad', {update: {patreonstatus: '#patreonStatus'
}
});
});
</script>

View File

@@ -1,6 +0,0 @@
<?php return [
'plugin' => [
'name' => 'patreon',
'description' => 'Provides a component that displays the percentage complete of a patreon campaign',
]
];

View File

@@ -1,16 +0,0 @@
<?php namespace PaulVonZimmerman\Patreon\Models;
use Model;
/**
* Model
*/
class Settings extends Model
{
// Settings
public $implement = ['System.Behaviors.SettingsModel'];
// Settings field & Code
public $settingsFields = 'fields.yaml';
public $settingsCode = 'paulvonzimmerman_patreon_system_settings';
}

View File

@@ -1,20 +0,0 @@
fields:
client_id:
label: 'Client ID'
span: auto
oc.commentPosition: ''
type: password
client_secret:
label: 'Client Secret'
oc.commentPosition: ''
span: auto
type: password
patreon_url:
label: 'Patreon URL'
span: auto
oc.commentPosition: ''
type: text
refresh_time:
label: 'Time (in minutes) to refresh patreon data'
span: auto
type: number

View File

@@ -1,17 +0,0 @@
plugin:
name: Patreon
description: 'paulvonzimmerman.patreon::lang.plugin.description'
author: PaulVonZimmerman
icon: icon-money
homepage: ''
navigation:
Patreon:
label: Patreon
url: paulvonzimmerman/patreon/register
icon: icon-money
permissions:
- paulvonzimmerman.patreon.manage_register
permissions:
paulvonzimmerman.patreon.manage_register:
tab: 'paulvonzimmerman.patreon::lang.plugin.name'
label: Manage

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1,28 +0,0 @@
<?php namespace PaulVonZimmerman\Patreon\Updates;
use Schema;
use October\Rain\Database\Updates\Migration;
class BuilderTableCreatePaulVonZimmermanPatreonSystemSettings extends Migration
{
public function up()
{
Schema::create('paulvonzimmerman_patreon_system_settings', function($table)
{
$table->engine = 'InnoDB';
$table->string('access_token')->nullable();
$table->string('refresh_token')->nullable();
$table->integer('completed_percentage')->nullable();
$table->string('client_secret')->nullable();
$table->integer('refresh_time')->nullable()->default(30);
$table->integer('time_since_last_update')->nullable();
$table->string('client_id')->nullable();
$table->integer('amount_cents')->nullable();
});
}
public function down()
{
Schema::dropIfExists('paulvonzimmerman_patreon_system_settings');
}
}

View File

@@ -1,7 +0,0 @@
1.0.1: 'First version of Demo'
1.0.2:
- 'Created table paulvonzimmerman_patreon_system_settings'
- builder_table_create_paulvonzimmerman_patreon_system_settings.php
1.0.3:
- 'Add supuport for multiple goals'
- 'Added commas to the amount displayed in the component'

View File

@@ -1,30 +0,0 @@
<?php namespace Pikanji\Agent;
use System\Classes\PluginBase;
use Illuminate\Foundation\AliasLoader;
use App;
/**
* Agent Plugin Information File
*/
class Plugin extends PluginBase
{
public function boot()
{
// Enable jessengers/agent package and register Agent facade.
App::register('Jenssegers\Agent\AgentServiceProvider');
AliasLoader::getInstance()->alias('Agent', 'Jenssegers\Agent\Facades\Agent');
}
/**
* Registers any front-end components implemented in this plugin.
*
* @return array
*/
public function registerComponents()
{
return [
'Pikanji\Agent\Components\Agent' => 'Agent',
];
}
}

View File

@@ -1,78 +0,0 @@
# OctoberCMS Agent Plugin
[日本語版はこちら](./README_ja.md)
[OctoberCMS](http://octobercms.com/) plugin to detect user's browser, OS, and device.
This is available not only from PHP but also from Twig templates.
This is a wrapper plugin of [jenssegers/agent](https://github.com/jenssegers/agent).
Thanks to jenssegers, and also serbanghita created it's base [serbanghita/Mobile-Detect](https://github.com/serbanghita/Mobile-Detect).
## API
Please refer [jenssegers/agent](https://github.com/jenssegers/agent) for available APIs.
## Usage
### Installation
You can install this plugin either via composer or from the backend UI.
#### With Composer
Execute below at the root of your project.
```
composer require pikanji/agent-plugin
```
#### With OctoberCMS UI
* Login to OctoberCMS backend
* Go to Settings > Update & Plugins.
* Click "Install plugins" button.
* Search for "Agent", and select it to start installation.
### Using in Twig Templates
Agent object will be available after Agent component is added to pages or layouts.
I recommend to add the component to your layout, so that you don't have to add every page.
Preparation is to add `[Agent]` to the configuration section of page or layout files. There is no parameter needed for Agent component.
```
description = "Default layout"
[Agent]
==
<!DOCTYPE html>
...
```
Then you can use this Agent object to call [jenssegers/agent](https://github.com/jenssegers/agent) APIs.
```
...
{% if Agent.isFireFox() %}
...
```
### Using in PHP Code
Add `use Agent;`, and call methods from `Agent` facade.
```php
use Agent;
...
if (Agent::isFireFox()) {
...
```
If you don't want to use facade, you can use it like this.
```php
use Jenssegers\Agent\Agent;
...
$agent = new Agent();
if ($agent->isFireFox()) {
...
```
It is just using [jenssegers/agent](https://github.com/jenssegers/agent) directly. Please refer to its documentation.
You don't need to install it since it is installed as the dependency of this plugin.

View File

@@ -1,79 +0,0 @@
# OctoberCMS Agent Plugin
PHP側でユーザのブラウザ、OS、デバイスを判定するための [OctoberCMS](http://octobercms.com/) 用プラグインです。
PHPだけでなくTwigテンプレートからも利用できます。
このプラグインは [jenssegers/agent](https://github.com/jenssegers/agent) のタダのラッパーです。
jenssegers さんと更にその[ベース](https://github.com/serbanghita/Mobile-Detect) を作った serbanghita さんに感謝です。
## API
利用可能なAPIはこちら[jenssegers/agent](https://github.com/jenssegers/agent)を参考にしてください。
## 使い方
### インストール
comopserと管理画面バックエンドUIのどちらからでもインストールが可能です。
#### composerの場合
プロジェクトルートから下記を実行します。
```
composer require pikanji/agent-plugin
```
#### UIからの場合
* 管理画面にログインします。
* Settings > Updates & Plugins と開きます。
* "Install plugins"ボタンをクリックします。
* 検索ボックスに"Agent"と入力すると候補にこのプラグインが表示されます。
* 候補からAgentを選択するとインストールが始まります。
### Twigテンプレートからの利用
ページやレイアウトにコンポーネントを追加するだけで利用できます。
レイアウトに追加すれば、ページごとに追加する必要が無いのでおすすめです。
まず、準備はレイアウトの設定セクションに `[Agent]` を記述するだけです。Agentプラグイン自体の設定は何もありません。
```
description = "Default layout"
[Agent]
==
<!DOCTYPE html>
...
```
そして、テンプレートから下記のように利用できます。
```
...
{% if Agent.isFireFox() %}
...
```
### PHPからの利用
`use Agent;` 入れて `Agent` ファサードからメソッドを呼び出せます。
```php
use Agent;
...
if (Agent::isFireFox()) {
...
```
ちなみに、ファサードを使わない場合は、基本的にはこのようになります。
```php
use Jenssegers\Agent\Agent;
...
$agent = new Agent();
if ($agent->isFireFox()) {
...
```
[jenssegers/agent](https://github.com/jenssegers/agent) を直接使うだけなので、そちらの README を参考にしてください。
依存関係としてすでにインストールされているので別途インストールする必要はありません。

View File

@@ -1,32 +0,0 @@
<?php namespace Pikanji\Agent\Components;
use Cms\Classes\ComponentBase;
use Jenssegers\Agent\Agent as JenssegersAgent;
class Agent extends ComponentBase
{
private $agent;
public function componentDetails()
{
return [
'name' => 'Agent Component',
'description' => 'A simple wrapper plugin for jenssegers/agent which provides browser/platform information.'
];
}
public function init()
{
$this->agent = new JenssegersAgent();
}
public function __call($name, $arguments)
{
if (method_exists($this->agent, $name)) {
$refMethod = new \ReflectionMethod('Jenssegers\Agent\Agent', $name);
return $refMethod->invokeArgs($this->agent, $arguments);
} else {
return $this->agent->__call($name, $arguments);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,5 +0,0 @@
<?php return [
'name' => 'Agent',
'description' => "Detect user's browser, OS, and device from UserAgent. This is a wrapper plugin of jenssegers/agent. Thanks to jenssegers.",
'author' => 'Kanji Furuhashi',
];

View File

@@ -1,5 +0,0 @@
<?php return [
'name' => 'Agent',
'description' => 'UserAgentからブラウザ、OSやデバイスの判定を行います。これは jenssegers/agent のラッパープラグインです。jenssegersさんありがとうございます。',
'author' => '古橋 寛士',
];

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="../../../tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="Plugin Unit Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
</php>
</phpunit>

View File

@@ -1,6 +0,0 @@
plugin:
name: 'pikanji.agent::plugin.name'
description: 'pikanji.agent::plugin.description'
author: 'pikanji.agent::plugin.author'
homepage: 'https://coderwall.com/pikanji'

View File

@@ -1,31 +0,0 @@
<?php namespace Pikanji\Agent\Tests\Unit;
use Agent;
use PluginTestCase;
/**
* Class PluginTest
*
* Test for Plugin class. This test requires to add 2 line below after
* `$plugin = $manager->loadPlugin($namespace, $path);` in PluginTestCase class.
* ```
* $manager->registerPlugin($plugin);
* $manager->bootPlugin($plugin);
* ```
*
* @see https://github.com/octobercms/october/issues/1833#issuecomment-193202296
*
* @package Pikanji\Agent\Tests\Unit
*/
class PluginTest extends PluginTestCase
{
/**
* Checks if Agent facade is available.
*/
public function testAgentFacade()
{
Agent::setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36');
$this->assertSame('Chrome', Agent::browser());
}
}

View File

@@ -1,2 +0,0 @@
1.0.1: First version of Agent
1.0.2: Add service provider and facade automatically

View File

@@ -1,7 +0,0 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInitcb2fa31c7f07a0d043ec554823540b89::getLoader();

View File

@@ -1,413 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View File

@@ -1,21 +0,0 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,10 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
);

View File

@@ -1,10 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Detection' => array($vendorDir . '/mobiledetect/mobiledetectlib/namespaced'),
);

View File

@@ -1,12 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Jenssegers\\Agent\\' => array($vendorDir . '/jenssegers/agent/src'),
'Jaybizzle\\CrawlerDetect\\' => array($vendorDir . '/jaybizzle/crawler-detect/src'),
'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src/Composer/Installers'),
);

View File

@@ -1,45 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitcb2fa31c7f07a0d043ec554823540b89
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitcb2fa31c7f07a0d043ec554823540b89', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitcb2fa31c7f07a0d043ec554823540b89', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
return $loader;
}
}

View File

@@ -1,294 +0,0 @@
[
{
"name": "composer/installers",
"version": "v1.4.0",
"version_normalized": "1.4.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/installers.git",
"reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/installers/zipball/9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b",
"reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0"
},
"replace": {
"roundcube/plugin-installer": "*",
"shama/baton": "*"
},
"require-dev": {
"composer/composer": "1.0.*@dev",
"phpunit/phpunit": "4.1.*"
},
"time": "2017-08-09 07:53:48",
"type": "composer-plugin",
"extra": {
"class": "Composer\\Installers\\Plugin",
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Composer\\Installers\\": "src/Composer/Installers"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kyle Robinson Young",
"email": "kyle@dontkry.com",
"homepage": "https://github.com/shama"
}
],
"description": "A multi-framework Composer library installer",
"homepage": "https://composer.github.io/installers/",
"keywords": [
"Craft",
"Dolibarr",
"Eliasis",
"Hurad",
"ImageCMS",
"Kanboard",
"Lan Management System",
"MODX Evo",
"Mautic",
"Maya",
"OXID",
"Plentymarkets",
"Porto",
"RadPHP",
"SMF",
"Thelia",
"WolfCMS",
"agl",
"aimeos",
"annotatecms",
"attogram",
"bitrix",
"cakephp",
"chef",
"cockpit",
"codeigniter",
"concrete5",
"croogo",
"dokuwiki",
"drupal",
"eZ Platform",
"elgg",
"expressionengine",
"fuelphp",
"grav",
"installer",
"itop",
"joomla",
"kohana",
"laravel",
"lavalite",
"lithium",
"magento",
"mako",
"mediawiki",
"modulework",
"moodle",
"osclass",
"phpbb",
"piwik",
"ppi",
"puppet",
"reindex",
"roundcube",
"shopware",
"silverstripe",
"sydes",
"symfony",
"typo3",
"wordpress",
"yawik",
"zend",
"zikula"
]
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.28",
"version_normalized": "2.8.28.0",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "65cd802dad5e85cb8f0ab1ba54ae5fdca765062b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/65cd802dad5e85cb8f0ab1ba54ae5fdca765062b",
"reference": "65cd802dad5e85cb8f0ab1ba54ae5fdca765062b",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|5.7"
},
"time": "2017-12-09 09:59:47",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"Mobile_Detect.php"
],
"psr-0": {
"Detection": "namespaced/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
]
},
{
"name": "jaybizzle/crawler-detect",
"version": "v1.2.54",
"version_normalized": "1.2.54.0",
"source": {
"type": "git",
"url": "https://github.com/JayBizzle/Crawler-Detect.git",
"reference": "9af25770d9382917b680009a88497162405bbe48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/9af25770d9382917b680009a88497162405bbe48",
"reference": "9af25770d9382917b680009a88497162405bbe48",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.8.*",
"satooshi/php-coveralls": "1.*"
},
"time": "2017-10-28 13:05:55",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Jaybizzle\\CrawlerDetect\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Beech",
"email": "m@rkbee.ch",
"role": "Developer"
}
],
"description": "CrawlerDetect is a PHP class for detecting bots/crawlers/spiders via the user agent",
"homepage": "https://github.com/JayBizzle/Crawler-Detect/",
"keywords": [
"crawler",
"crawler detect",
"crawler detector",
"crawlerdetect",
"php crawler detect"
]
},
{
"name": "jenssegers/agent",
"version": "v2.6.0",
"version_normalized": "2.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/jenssegers/agent.git",
"reference": "df71082ed2a95fc8a82ba30832ccf72df939f02a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jenssegers/agent/zipball/df71082ed2a95fc8a82ba30832ccf72df939f02a",
"reference": "df71082ed2a95fc8a82ba30832ccf72df939f02a",
"shasum": ""
},
"require": {
"jaybizzle/crawler-detect": "^1.2",
"mobiledetect/mobiledetectlib": "^2.7.6",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0|^6.0",
"satooshi/php-coveralls": "^1.0"
},
"time": "2017-11-10 10:35:35",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
},
"laravel": {
"providers": [
"Jenssegers\\Agent\\AgentServiceProvider"
],
"aliases": {
"Agent": "Jenssegers\\Agent\\Facades\\Agent"
}
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Jenssegers\\Agent\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jens Segers",
"homepage": "https://jenssegers.com"
}
],
"description": "Desktop/mobile user agent parser with support for Laravel, based on Mobiledetect",
"homepage": "https://github.com/jenssegers/agent",
"keywords": [
"Agent",
"browser",
"desktop",
"laravel",
"mobile",
"platform",
"user agent",
"useragent"
]
}
]

View File

@@ -1,69 +0,0 @@
# Change Log
## [Unreleased]
## v1.4.0 - 2017-08-09
### Added
* Installer for eZ Platform.
* Installer for UserFrosting.
* Installer for Osclass.
* Installer for Lan Management System.
### Changed
* Added vendor name to package path for Lavalite.
## v1.3.0 - 2017-04-24
### Added
* Kanboard plugins installer.
* Porto-SAP installer.
* Add `core` to concrete5 installer.
* Support Moodle "search" plugin type.
* SyDES installer.
* iTop installer.
* Lavalite installer.
* Module type for Eliasis.
* Vgmcp installer.
* OntoWiki installer.
* The requirements for contributing (CONTRIBUTING.md).
## v1.2.0 - 2016-08-13
### Added
* Installer for Attogram.
* Installer for Cockpit.
* Installer for Plentymarkets.
* Installer for ReIndex.
* Installer for Vanilla.
* Installer for YAWIK.
* Added missing environments for new Shopware (5.2) Plugin System.
## v1.1.0 - 2016-07-05
### Added
* Installer for ReIndex.
* Installer for RadPHP.
* Installer for Decibel.
* Installer for Phifty.
* Installer for ExpressionEngine.
### Changed
* New paths for new Bitrix CMS. Old paths is deprecated.
### Deprecated
* Old paths in Bitrix CMS Installer is deprecated.
## v1.0.25 - 2016-04-13
### Removed
* Revert TYPO3 installer deletion.
## v1.0.24 - 2016-04-05
### Added
* Installer for ImageCMS.
* Installer for Mautic.
* New types in the Kirby installer: `kirby-plugin` and `kirby-field`.
* New types in the Drupal installer: `custom-theme` and `custom-module`.
### Changed
* Switch to PSR-4.
* Update Bitrix Installer: configuration for setting custom path to directory with kernel.
### Removed
* Remove TYPO3 Extension installers.

View File

@@ -1,24 +0,0 @@
# Contributing
If you would like to help, please take a look at the list of
[issues](https://github.com/composer/installers/issues).
## Pull requests
* [Fork and clone](https://help.github.com/articles/fork-a-repo).
* Run the command `php composer.phar install` to install the dependencies.
This will also install the dev dependencies. See [Composer](https://getcomposer.org/doc/03-cli.md#install).
* Use the command `phpunit` to run the tests. See [PHPUnit](http://phpunit.de).
* Create a branch, commit, push and send us a
[pull request](https://help.github.com/articles/using-pull-requests).
To ensure a consistent code base, you should make sure the code follows the
coding standards [PSR-1](http://www.php-fig.org/psr/psr-1/) and
[PSR-2](http://www.php-fig.org/psr/psr-2/).
### Create a new Installer
* Create class extends `Composer\Installers\BaseInstaller` with your Installer.
* Create unit tests as a separate class or as part of a `Composer\Installers\Test\InstallerTest`.
* Add information about your Installer in `README.md` in section "Current Supported Package Types".
* Run the tests.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2012 Kyle Robinson Young
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,218 +0,0 @@
# A Multi-Framework [Composer](http://getcomposer.org) Library Installer
[![Build Status](http://img.shields.io/travis/composer/installers.svg)](http://travis-ci.org/composer/installers)
This is for PHP package authors to require in their `composer.json`. It will
install their package to the correct location based on the specified package
type.
The goal of Installers is to be a simple package type to install path map.
Users can also customize the install path per package and package authors can
modify the package name upon installing.
Installers isn't intended on replacing all custom installers. If your
package requires special installation handling then by all means, create a
custom installer to handle it.
**Natively Supported Frameworks**:
The following frameworks natively work with Composer and will be
installed to the default `vendor` directory. `composer/installers`
is not needed to install packages with these frameworks:
* Aura
* Symfony2
* Yii
* Yii2
## Current Supported Package Types
> Stable types are marked as **bold**, this means that installation paths
> for those type will not be changed. Any adjustment for those types would
> require creation of brand new type that will cover required changes.
| Framework | Types
| --------- | -----
| Aimeos | `aimeos-extension`
| Asgard | `asgard-module`<br>`asgard-theme`
| Attogram | `attogram-module`
| AGL | `agl-module`
| Bonefish | `bonefish-package`
| AnnotateCms | `annotatecms-module`<br>`annotatecms-component`<br>`annotatecms-service`
| Bitrix | `bitrix-module` (deprecated) <br>`bitrix-component` (deprecated) <br>`bitrix-theme` (deprecated) <br><br> `bitrix-d7-module` <br> `bitrix-d7-component` <br> `bitrix-d7-template`
| CakePHP 2+ | **`cakephp-plugin`**
| Chef | `chef-cookbook`<br>`chef-role`
| CCFramework | `ccframework-ship`<br>`ccframework-theme`
| Cockpit | `cockpit-module`
| CodeIgniter | `codeigniter-library`<br>`codeigniter-third-party`<br>`codeigniter-module`
| concrete5 | `concrete5-core`<br>`concrete5-package`<br>`concrete5-theme`<br>`concrete5-block`<br>`concrete5-update`
| Craft | `craft-plugin`
| Croogo | `croogo-plugin`<br>`croogo-theme`
| Decibel | `decibel-app`
| DokuWiki | `dokuwiki-plugin`<br>`dokuwiki-template`
| Dolibarr | `dolibarr-module`
| Drupal | <b>`drupal-core`<br>`drupal-module`<br>`drupal-theme`</b><br>`drupal-library`<br>`drupal-profile`<br>`drupal-drush`
| Elgg | `elgg-plugin`
| Eliasis | `eliasis-module`
| ExpressionEngine 3 | `ee3-addon`<br>`ee3-theme`
| eZ Platform | `ezplatform-assets`<br>`ezplatform-meta-assets`
| FuelPHP v1.x | `fuel-module`<br>`fuel-package`<br/>`fuel-theme`
| FuelPHP v2.x | `fuelphp-component`
| Grav | `grav-plugin`<br>`grav-theme`
| Hurad | `hurad-plugin`<br>`hurad-theme`
| ImageCMS | `imagecms-template`<br>`imagecms-module`<br>`imagecms-library`
| iTop | `itop-extension`
| Joomla | `joomla-component`<br>`joomla-module`<br>`joomla-template`<br>`joomla-plugin`<br>`joomla-library`
| Kanboard | `kanboard-plugin`
| Kirby | **`kirby-plugin`**<br>`kirby-field`<br>`kirby-tag`
| KodiCMS | `kodicms-plugin`<br>`kodicms-media`
| Kohana | **`kohana-module`**
| Lan Management System | `lms-plugin`<br>`lms-template`<br>`lms-document-template`<br>`lms-userpanel-module`
| Laravel | `laravel-library`
| Lavalite | `lavalite-theme`<br>`lavalite-package`
| Lithium | **`lithium-library`<br>`lithium-source`**
| Magento | `magento-library`<br>`magento-skin`<br>`magento-theme`
| Mako | `mako-package`
| Mautic | `mautic-plugin`<br>`mautic-theme`
| Maya | `maya-module`
| MODX Evo | `modxevo-snippet`<br>`modxevo-plugin`<br>`modxevo-module`<br>`modxevo-template`<br>`modxevo-lib`
| MediaWiki | `mediawiki-extension`
| October | **`october-module`<br>`october-plugin`<br>`october-theme`**
| OntoWiki | `ontowiki-extension`<br>`ontowiki-theme`<br>`ontowiki-translation`
| OXID | `oxid-module`<br>`oxid-theme`<br>`oxid-out`
| Osclass | `osclass-plugin`<br>`osclass-theme`<br>`osclass-language`
| MODULEWork | `modulework-module`
| Moodle | `moodle-*` (Please [check source](https://raw.githubusercontent.com/composer/installers/master/src/Composer/Installers/MoodleInstaller.php) for all supported types)
| Piwik | `piwik-plugin`
| phpBB | `phpbb-extension`<br>`phpbb-style`<br>`phpbb-language`
| Pimcore | `pimcore-plugin`
| Plentymarkets | `plentymarkets-plugin`
| PPI | **`ppi-module`**
| Puppet | `puppet-module`
| Porto | `porto-container`
| RadPHP | `radphp-bundle`
| REDAXO | `redaxo-addon`
| ReIndex | **`reindex-plugin`** <br> **`reindex-theme`**
| Roundcube | `roundcube-plugin`
| shopware | `shopware-backend-plugin`<br/>`shopware-core-plugin`<br/>`shopware-frontend-plugin`<br/>`shopware-theme`<br/>`shopware-plugin`<br/>`shopware-frontend-theme`
| SilverStripe | `silverstripe-module`<br>`silverstripe-theme`
| SMF | `smf-module`<br>`smf-theme`
| SyDES | `sydes-module`<br>`sydes-theme`
| symfony1 | **`symfony1-plugin`**
| Tusk | `tusk-task`<br>`tusk-command`<br>`tusk-asset`
| TYPO3 Flow | `typo3-flow-package`<br>`typo3-flow-framework`<br>`typo3-flow-plugin`<br>`typo3-flow-site`<br>`typo3-flow-boilerplate`<br>`typo3-flow-build`
| TYPO3 CMS | `typo3-cms-extension` (Deprecated in this package, use the [TYPO3 CMS Installers](https://packagist.org/packages/typo3/cms-composer-installers) instead)
| UserFrosting | `userfrosting-sprinkle`
| Vanilla | `vanilla-plugin`<br>`vanilla-theme`
| Vgmcp | `vgmcp-bundle`<br>`vgmcp-theme`
| Wolf CMS | `wolfcms-plugin`
| WordPress | <b>`wordpress-plugin`<br>`wordpress-theme`</b><br>`wordpress-muplugin`
| YAWIK | `yawik-module`
| Zend | `zend-library`<br>`zend-extra`<br>`zend-module`
| Zikula | `zikula-module`<br>`zikula-theme`
| Prestashop | `prestashop-module`<br>`prestashop-theme`
| Phifty | `phifty-bundle`<br>`phifty-framework`<br>`phifty-library`
## Example `composer.json` File
This is an example for a CakePHP plugin. The only important parts to set in your
composer.json file are `"type": "cakephp-plugin"` which describes what your
package is and `"require": { "composer/installers": "~1.0" }` which tells composer
to load the custom installers.
```json
{
"name": "you/ftp",
"type": "cakephp-plugin",
"require": {
"composer/installers": "~1.0"
}
}
```
This would install your package to the `Plugin/Ftp/` folder of a CakePHP app
when a user runs `php composer.phar install`.
So submit your packages to [packagist.org](http://packagist.org)!
## Custom Install Paths
If you are consuming a package that uses the `composer/installers` you can
override the install path with the following extra in your `composer.json`:
```json
{
"extra": {
"installer-paths": {
"your/custom/path/{$name}/": ["shama/ftp", "vendor/package"]
}
}
}
```
A package type can have a custom installation path with a `type:` prefix.
``` json
{
"extra": {
"installer-paths": {
"your/custom/path/{$name}/": ["type:wordpress-plugin"]
}
}
}
```
You can also have the same vendor packages with a custom installation path by
using the `vendor:` prefix.
``` json
{
"extra": {
"installer-paths": {
"your/custom/path/{$name}/": ["vendor:my_organization"]
}
}
}
```
These would use your custom path for each of the listed packages. The available
variables to use in your paths are: `{$name}`, `{$vendor}`, `{$type}`.
## Custom Install Names
If you're a package author and need your package to be named differently when
installed consider using the `installer-name` extra.
For example you have a package named `shama/cakephp-ftp` with the type
`cakephp-plugin`. Installing with `composer/installers` would install to the
path `Plugin/CakephpFtp`. Due to the strict naming conventions, you as a
package author actually need the package to be named and installed to
`Plugin/Ftp`. Using the following config within your **package** `composer.json`
will allow this:
```json
{
"name": "shama/cakephp-ftp",
"type": "cakephp-plugin",
"extra": {
"installer-name": "Ftp"
}
}
```
Please note the name entered into `installer-name` will be the final and will
not be inflected.
## Should we allow dynamic package types or paths? No.
What are they? The ability for a package author to determine where a package
will be installed either through setting the path directly in their
`composer.json` or through a dynamic package type: `"type":
"framework-install-here"`.
It has been proposed many times. Even implemented once early on and then
removed. Installers won't do this because it would allow a single package
author to wipe out entire folders without the user's consent. That user would
then come here to yell at us.
Anyone still wanting this capability should consider requiring https://github.com/oomphinc/composer-installers-extender.

View File

@@ -1 +0,0 @@
theme: jekyll-theme-cayman

View File

@@ -1,102 +0,0 @@
{
"name": "composer/installers",
"type": "composer-plugin",
"license": "MIT",
"description": "A multi-framework Composer library installer",
"keywords": [
"installer",
"Aimeos",
"AGL",
"AnnotateCms",
"Attogram",
"Bitrix",
"CakePHP",
"Chef",
"Cockpit",
"CodeIgniter",
"concrete5",
"Craft",
"Croogo",
"DokuWiki",
"Dolibarr",
"Drupal",
"Elgg",
"Eliasis",
"ExpressionEngine",
"eZ Platform",
"FuelPHP",
"Grav",
"Hurad",
"ImageCMS",
"iTop",
"Joomla",
"Kanboard",
"Kohana",
"Lan Management System",
"Laravel",
"Lavalite",
"Lithium",
"Magento",
"Mako",
"Mautic",
"Maya",
"MODX Evo",
"MediaWiki",
"OXID",
"osclass",
"MODULEWork",
"Moodle",
"Piwik",
"phpBB",
"Plentymarkets",
"PPI",
"Puppet",
"Porto",
"RadPHP",
"ReIndex",
"Roundcube",
"shopware",
"SilverStripe",
"SMF",
"SyDES",
"symfony",
"Thelia",
"TYPO3",
"WolfCMS",
"WordPress",
"YAWIK",
"Zend",
"Zikula"
],
"homepage": "https://composer.github.io/installers/",
"authors": [
{
"name": "Kyle Robinson Young",
"email": "kyle@dontkry.com",
"homepage": "https://github.com/shama"
}
],
"autoload": {
"psr-4": { "Composer\\Installers\\": "src/Composer/Installers" }
},
"extra": {
"class": "Composer\\Installers\\Plugin",
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"replace": {
"shama/baton": "*",
"roundcube/plugin-installer": "*"
},
"require": {
"composer-plugin-api": "^1.0"
},
"require-dev": {
"composer/composer": "1.0.*@dev",
"phpunit/phpunit": "4.1.*"
},
"scripts": {
"test": "phpunit"
}
}

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Installers Test Suite">
<directory>tests/Composer/Installers</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src/Composer/Installers</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -1,21 +0,0 @@
<?php
namespace Composer\Installers;
class AglInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'More/{$name}/',
);
/**
* Format package name to CamelCase
*/
public function inflectPackageVars($vars)
{
$vars['name'] = preg_replace_callback('/(?:^|_|-)(.?)/', function ($matches) {
return strtoupper($matches[1]);
}, $vars['name']);
return $vars;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class AimeosInstaller extends BaseInstaller
{
protected $locations = array(
'extension' => 'ext/{$name}/',
);
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class AnnotateCmsInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'addons/modules/{$name}/',
'component' => 'addons/components/{$name}/',
'service' => 'addons/services/{$name}/',
);
}

View File

@@ -1,49 +0,0 @@
<?php
namespace Composer\Installers;
class AsgardInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'Modules/{$name}/',
'theme' => 'Themes/{$name}/'
);
/**
* Format package name.
*
* For package type asgard-module, cut off a trailing '-plugin' if present.
*
* For package type asgard-theme, cut off a trailing '-theme' if present.
*
*/
public function inflectPackageVars($vars)
{
if ($vars['type'] === 'asgard-module') {
return $this->inflectPluginVars($vars);
}
if ($vars['type'] === 'asgard-theme') {
return $this->inflectThemeVars($vars);
}
return $vars;
}
protected function inflectPluginVars($vars)
{
$vars['name'] = preg_replace('/-module$/', '', $vars['name']);
$vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']);
$vars['name'] = str_replace(' ', '', ucwords($vars['name']));
return $vars;
}
protected function inflectThemeVars($vars)
{
$vars['name'] = preg_replace('/-theme$/', '', $vars['name']);
$vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']);
$vars['name'] = str_replace(' ', '', ucwords($vars['name']));
return $vars;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class AttogramInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'modules/{$name}/',
);
}

View File

@@ -1,136 +0,0 @@
<?php
namespace Composer\Installers;
use Composer\IO\IOInterface;
use Composer\Composer;
use Composer\Package\PackageInterface;
abstract class BaseInstaller
{
protected $locations = array();
protected $composer;
protected $package;
protected $io;
/**
* Initializes base installer.
*
* @param PackageInterface $package
* @param Composer $composer
* @param IOInterface $io
*/
public function __construct(PackageInterface $package = null, Composer $composer = null, IOInterface $io = null)
{
$this->composer = $composer;
$this->package = $package;
$this->io = $io;
}
/**
* Return the install path based on package type.
*
* @param PackageInterface $package
* @param string $frameworkType
* @return string
*/
public function getInstallPath(PackageInterface $package, $frameworkType = '')
{
$type = $this->package->getType();
$prettyName = $this->package->getPrettyName();
if (strpos($prettyName, '/') !== false) {
list($vendor, $name) = explode('/', $prettyName);
} else {
$vendor = '';
$name = $prettyName;
}
$availableVars = $this->inflectPackageVars(compact('name', 'vendor', 'type'));
$extra = $package->getExtra();
if (!empty($extra['installer-name'])) {
$availableVars['name'] = $extra['installer-name'];
}
if ($this->composer->getPackage()) {
$extra = $this->composer->getPackage()->getExtra();
if (!empty($extra['installer-paths'])) {
$customPath = $this->mapCustomInstallPaths($extra['installer-paths'], $prettyName, $type, $vendor);
if ($customPath !== false) {
return $this->templatePath($customPath, $availableVars);
}
}
}
$packageType = substr($type, strlen($frameworkType) + 1);
$locations = $this->getLocations();
if (!isset($locations[$packageType])) {
throw new \InvalidArgumentException(sprintf('Package type "%s" is not supported', $type));
}
return $this->templatePath($locations[$packageType], $availableVars);
}
/**
* For an installer to override to modify the vars per installer.
*
* @param array $vars
* @return array
*/
public function inflectPackageVars($vars)
{
return $vars;
}
/**
* Gets the installer's locations
*
* @return array
*/
public function getLocations()
{
return $this->locations;
}
/**
* Replace vars in a path
*
* @param string $path
* @param array $vars
* @return string
*/
protected function templatePath($path, array $vars = array())
{
if (strpos($path, '{') !== false) {
extract($vars);
preg_match_all('@\{\$([A-Za-z0-9_]*)\}@i', $path, $matches);
if (!empty($matches[1])) {
foreach ($matches[1] as $var) {
$path = str_replace('{$' . $var . '}', $$var, $path);
}
}
}
return $path;
}
/**
* Search through a passed paths array for a custom install path.
*
* @param array $paths
* @param string $name
* @param string $type
* @param string $vendor = NULL
* @return string
*/
protected function mapCustomInstallPaths(array $paths, $name, $type, $vendor = NULL)
{
foreach ($paths as $path => $names) {
if (in_array($name, $names) || in_array('type:' . $type, $names) || in_array('vendor:' . $vendor, $names)) {
return $path;
}
}
return false;
}
}

View File

@@ -1,126 +0,0 @@
<?php
namespace Composer\Installers;
use Composer\Util\Filesystem;
/**
* Installer for Bitrix Framework. Supported types of extensions:
* - `bitrix-d7-module` — copy the module to directory `bitrix/modules/<vendor>.<name>`.
* - `bitrix-d7-component` — copy the component to directory `bitrix/components/<vendor>/<name>`.
* - `bitrix-d7-template` — copy the template to directory `bitrix/templates/<vendor>_<name>`.
*
* You can set custom path to directory with Bitrix kernel in `composer.json`:
*
* ```json
* {
* "extra": {
* "bitrix-dir": "s1/bitrix"
* }
* }
* ```
*
* @author Nik Samokhvalov <nik@samokhvalov.info>
* @author Denis Kulichkin <onexhovia@gmail.com>
*/
class BitrixInstaller extends BaseInstaller
{
protected $locations = array(
'module' => '{$bitrix_dir}/modules/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
'component' => '{$bitrix_dir}/components/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
'theme' => '{$bitrix_dir}/templates/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
'd7-module' => '{$bitrix_dir}/modules/{$vendor}.{$name}/',
'd7-component' => '{$bitrix_dir}/components/{$vendor}/{$name}/',
'd7-template' => '{$bitrix_dir}/templates/{$vendor}_{$name}/',
);
/**
* @var array Storage for informations about duplicates at all the time of installation packages.
*/
private static $checkedDuplicates = array();
/**
* {@inheritdoc}
*/
public function inflectPackageVars($vars)
{
if ($this->composer->getPackage()) {
$extra = $this->composer->getPackage()->getExtra();
if (isset($extra['bitrix-dir'])) {
$vars['bitrix_dir'] = $extra['bitrix-dir'];
}
}
if (!isset($vars['bitrix_dir'])) {
$vars['bitrix_dir'] = 'bitrix';
}
return parent::inflectPackageVars($vars);
}
/**
* {@inheritdoc}
*/
protected function templatePath($path, array $vars = array())
{
$templatePath = parent::templatePath($path, $vars);
$this->checkDuplicates($templatePath, $vars);
return $templatePath;
}
/**
* Duplicates search packages.
*
* @param string $path
* @param array $vars
*/
protected function checkDuplicates($path, array $vars = array())
{
$packageType = substr($vars['type'], strlen('bitrix') + 1);
$localDir = explode('/', $vars['bitrix_dir']);
array_pop($localDir);
$localDir[] = 'local';
$localDir = implode('/', $localDir);
$oldPath = str_replace(
array('{$bitrix_dir}', '{$name}'),
array($localDir, $vars['name']),
$this->locations[$packageType]
);
if (in_array($oldPath, static::$checkedDuplicates)) {
return;
}
if ($oldPath !== $path && file_exists($oldPath) && $this->io && $this->io->isInteractive()) {
$this->io->writeError(' <error>Duplication of packages:</error>');
$this->io->writeError(' <info>Package ' . $oldPath . ' will be called instead package ' . $path . '</info>');
while (true) {
switch ($this->io->ask(' <info>Delete ' . $oldPath . ' [y,n,?]?</info> ', '?')) {
case 'y':
$fs = new Filesystem();
$fs->removeDirectory($oldPath);
break 2;
case 'n':
break 2;
case '?':
default:
$this->io->writeError(array(
' y - delete package ' . $oldPath . ' and to continue with the installation',
' n - don\'t delete and to continue with the installation',
));
$this->io->writeError(' ? - print help');
break;
}
}
}
static::$checkedDuplicates[] = $oldPath;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class BonefishInstaller extends BaseInstaller
{
protected $locations = array(
'package' => 'Packages/{$vendor}/{$name}/'
);
}

View File

@@ -1,83 +0,0 @@
<?php
namespace Composer\Installers;
use Composer\DependencyResolver\Pool;
use Composer\Package\PackageInterface;
class CakePHPInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'Plugin/{$name}/',
);
/**
* Format package name to CamelCase
*/
public function inflectPackageVars($vars)
{
if ($this->matchesCakeVersion('>=', '3.0.0')) {
return $vars;
}
$nameParts = explode('/', $vars['name']);
foreach ($nameParts as &$value) {
$value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value));
$value = str_replace(array('-', '_'), ' ', $value);
$value = str_replace(' ', '', ucwords($value));
}
$vars['name'] = implode('/', $nameParts);
return $vars;
}
/**
* Change the default plugin location when cakephp >= 3.0
*/
public function getLocations()
{
if ($this->matchesCakeVersion('>=', '3.0.0')) {
$this->locations['plugin'] = $this->composer->getConfig()->get('vendor-dir') . '/{$vendor}/{$name}/';
}
return $this->locations;
}
/**
* Check if CakePHP version matches against a version
*
* @param string $matcher
* @param string $version
* @return bool
*/
protected function matchesCakeVersion($matcher, $version)
{
if (class_exists('Composer\Semver\Constraint\MultiConstraint')) {
$multiClass = 'Composer\Semver\Constraint\MultiConstraint';
$constraintClass = 'Composer\Semver\Constraint\Constraint';
} else {
$multiClass = 'Composer\Package\LinkConstraint\MultiConstraint';
$constraintClass = 'Composer\Package\LinkConstraint\VersionConstraint';
}
$repositoryManager = $this->composer->getRepositoryManager();
if ($repositoryManager) {
$repos = $repositoryManager->getLocalRepository();
if (!$repos) {
return false;
}
$cake3 = new $multiClass(array(
new $constraintClass($matcher, $version),
new $constraintClass('!=', '9999999-dev'),
));
$pool = new Pool('dev');
$pool->addRepository($repos);
$packages = $pool->whatProvides('cakephp/cakephp');
foreach ($packages as $package) {
$installed = new $constraintClass('=', $package->getVersion());
if ($cake3->matches($installed)) {
return true;
}
}
}
return false;
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class ChefInstaller extends BaseInstaller
{
protected $locations = array(
'cookbook' => 'Chef/{$vendor}/{$name}/',
'role' => 'Chef/roles/{$name}/',
);
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Composer\Installers;
class ClanCatsFrameworkInstaller extends BaseInstaller
{
protected $locations = array(
'ship' => 'CCF/orbit/{$name}/',
'theme' => 'CCF/app/themes/{$name}/',
);
}

View File

@@ -1,34 +0,0 @@
<?php
namespace Composer\Installers;
class CockpitInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'cockpit/modules/addons/{$name}/',
);
/**
* Format module name.
*
* Strip `module-` prefix from package name.
*
* @param array @vars
*
* @return array
*/
public function inflectPackageVars($vars)
{
if ($vars['type'] == 'cockpit-module') {
return $this->inflectModuleVars($vars);
}
return $vars;
}
public function inflectModuleVars($vars)
{
$vars['name'] = ucfirst(preg_replace('/cockpit-/i', '', $vars['name']));
return $vars;
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class CodeIgniterInstaller extends BaseInstaller
{
protected $locations = array(
'library' => 'application/libraries/{$name}/',
'third-party' => 'application/third_party/{$name}/',
'module' => 'application/modules/{$name}/',
);
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Composer\Installers;
class Concrete5Installer extends BaseInstaller
{
protected $locations = array(
'core' => 'concrete/',
'block' => 'application/blocks/{$name}/',
'package' => 'packages/{$name}/',
'theme' => 'application/themes/{$name}/',
'update' => 'updates/{$name}/',
);
}

View File

@@ -1,35 +0,0 @@
<?php
namespace Composer\Installers;
/**
* Installer for Craft Plugins
*/
class CraftInstaller extends BaseInstaller
{
const NAME_PREFIX = 'craft';
const NAME_SUFFIX = 'plugin';
protected $locations = array(
'plugin' => 'craft/plugins/{$name}/',
);
/**
* Strip `craft-` prefix and/or `-plugin` suffix from package names
*
* @param array $vars
*
* @return array
*/
final public function inflectPackageVars($vars)
{
return $this->inflectPluginVars($vars);
}
private function inflectPluginVars($vars)
{
$vars['name'] = preg_replace('/-' . self::NAME_SUFFIX . '$/i', '', $vars['name']);
$vars['name'] = preg_replace('/^' . self::NAME_PREFIX . '-/i', '', $vars['name']);
return $vars;
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace Composer\Installers;
class CroogoInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'Plugin/{$name}/',
'theme' => 'View/Themed/{$name}/',
);
/**
* Format package name to CamelCase
*/
public function inflectPackageVars($vars)
{
$vars['name'] = strtolower(str_replace(array('-', '_'), ' ', $vars['name']));
$vars['name'] = str_replace(' ', '', ucwords($vars['name']));
return $vars;
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Composer\Installers;
class DecibelInstaller extends BaseInstaller
{
/** @var array */
protected $locations = array(
'app' => 'app/{$name}/',
);
}

View File

@@ -1,50 +0,0 @@
<?php
namespace Composer\Installers;
class DokuWikiInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'lib/plugins/{$name}/',
'template' => 'lib/tpl/{$name}/',
);
/**
* Format package name.
*
* For package type dokuwiki-plugin, cut off a trailing '-plugin',
* or leading dokuwiki_ if present.
*
* For package type dokuwiki-template, cut off a trailing '-template' if present.
*
*/
public function inflectPackageVars($vars)
{
if ($vars['type'] === 'dokuwiki-plugin') {
return $this->inflectPluginVars($vars);
}
if ($vars['type'] === 'dokuwiki-template') {
return $this->inflectTemplateVars($vars);
}
return $vars;
}
protected function inflectPluginVars($vars)
{
$vars['name'] = preg_replace('/-plugin$/', '', $vars['name']);
$vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']);
return $vars;
}
protected function inflectTemplateVars($vars)
{
$vars['name'] = preg_replace('/-template$/', '', $vars['name']);
$vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']);
return $vars;
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Composer\Installers;
/**
* Class DolibarrInstaller
*
* @package Composer\Installers
* @author Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
*/
class DolibarrInstaller extends BaseInstaller
{
//TODO: Add support for scripts and themes
protected $locations = array(
'module' => 'htdocs/custom/{$name}/',
);
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Composer\Installers;
class DrupalInstaller extends BaseInstaller
{
protected $locations = array(
'core' => 'core/',
'module' => 'modules/{$name}/',
'theme' => 'themes/{$name}/',
'library' => 'libraries/{$name}/',
'profile' => 'profiles/{$name}/',
'drush' => 'drush/{$name}/',
'custom-theme' => 'themes/custom/{$name}/',
'custom-module' => 'modules/custom/{$name}',
);
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class ElggInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'mod/{$name}/',
);
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class EliasisInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'modules/{$name}/'
);
}

View File

@@ -1,29 +0,0 @@
<?php
namespace Composer\Installers;
use Composer\Package\PackageInterface;
class ExpressionEngineInstaller extends BaseInstaller
{
protected $locations = array();
private $ee2Locations = array(
'addon' => 'system/expressionengine/third_party/{$name}/',
'theme' => 'themes/third_party/{$name}/',
);
private $ee3Locations = array(
'addon' => 'system/user/addons/{$name}/',
'theme' => 'themes/user/{$name}/',
);
public function getInstallPath(PackageInterface $package, $frameworkType = '')
{
$version = "{$frameworkType}Locations";
$this->locations = $this->$version;
return parent::getInstallPath($package, $frameworkType);
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Composer\Installers;
class EzPlatformInstaller extends BaseInstaller
{
protected $locations = array(
'meta-assets' => 'web/assets/ezplatform/',
'assets' => 'web/assets/ezplatform/{$name}/',
);
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class FuelInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'fuel/app/modules/{$name}/',
'package' => 'fuel/packages/{$name}/',
'theme' => 'fuel/app/themes/{$name}/',
);
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class FuelphpInstaller extends BaseInstaller
{
protected $locations = array(
'component' => 'components/{$name}/',
);
}

View File

@@ -1,30 +0,0 @@
<?php
namespace Composer\Installers;
class GravInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'user/plugins/{$name}/',
'theme' => 'user/themes/{$name}/',
);
/**
* Format package name
*
* @param array $vars
*
* @return array
*/
public function inflectPackageVars($vars)
{
$restrictedWords = implode('|', array_keys($this->locations));
$vars['name'] = strtolower($vars['name']);
$vars['name'] = preg_replace('/^(?:grav-)?(?:(?:'.$restrictedWords.')-)?(.*?)(?:-(?:'.$restrictedWords.'))?$/ui',
'$1',
$vars['name']
);
return $vars;
}
}

View File

@@ -1,25 +0,0 @@
<?php
namespace Composer\Installers;
class HuradInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'plugins/{$name}/',
'theme' => 'plugins/{$name}/',
);
/**
* Format package name to CamelCase
*/
public function inflectPackageVars($vars)
{
$nameParts = explode('/', $vars['name']);
foreach ($nameParts as &$value) {
$value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value));
$value = str_replace(array('-', '_'), ' ', $value);
$value = str_replace(' ', '', ucwords($value));
}
$vars['name'] = implode('/', $nameParts);
return $vars;
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class ImageCMSInstaller extends BaseInstaller
{
protected $locations = array(
'template' => 'templates/{$name}/',
'module' => 'application/modules/{$name}/',
'library' => 'application/libraries/{$name}/',
);
}

View File

@@ -1,201 +0,0 @@
<?php
namespace Composer\Installers;
use Composer\IO\IOInterface;
use Composer\Installer\LibraryInstaller;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
class Installer extends LibraryInstaller
{
/**
* Package types to installer class map
*
* @var array
*/
private $supportedTypes = array(
'aimeos' => 'AimeosInstaller',
'asgard' => 'AsgardInstaller',
'attogram' => 'AttogramInstaller',
'agl' => 'AglInstaller',
'annotatecms' => 'AnnotateCmsInstaller',
'bitrix' => 'BitrixInstaller',
'bonefish' => 'BonefishInstaller',
'cakephp' => 'CakePHPInstaller',
'chef' => 'ChefInstaller',
'ccframework' => 'ClanCatsFrameworkInstaller',
'cockpit' => 'CockpitInstaller',
'codeigniter' => 'CodeIgniterInstaller',
'concrete5' => 'Concrete5Installer',
'craft' => 'CraftInstaller',
'croogo' => 'CroogoInstaller',
'dokuwiki' => 'DokuWikiInstaller',
'dolibarr' => 'DolibarrInstaller',
'decibel' => 'DecibelInstaller',
'drupal' => 'DrupalInstaller',
'elgg' => 'ElggInstaller',
'eliasis' => 'EliasisInstaller',
'ee3' => 'ExpressionEngineInstaller',
'ee2' => 'ExpressionEngineInstaller',
'ezplatform' => 'EzPlatformInstaller',
'fuel' => 'FuelInstaller',
'fuelphp' => 'FuelphpInstaller',
'grav' => 'GravInstaller',
'hurad' => 'HuradInstaller',
'imagecms' => 'ImageCMSInstaller',
'itop' => 'ItopInstaller',
'joomla' => 'JoomlaInstaller',
'kanboard' => 'KanboardInstaller',
'kirby' => 'KirbyInstaller',
'kodicms' => 'KodiCMSInstaller',
'kohana' => 'KohanaInstaller',
'lms' => 'LanManagementSystemInstaller',
'laravel' => 'LaravelInstaller',
'lavalite' => 'LavaLiteInstaller',
'lithium' => 'LithiumInstaller',
'magento' => 'MagentoInstaller',
'mako' => 'MakoInstaller',
'maya' => 'MayaInstaller',
'mautic' => 'MauticInstaller',
'mediawiki' => 'MediaWikiInstaller',
'microweber' => 'MicroweberInstaller',
'modulework' => 'MODULEWorkInstaller',
'modxevo' => 'MODXEvoInstaller',
'moodle' => 'MoodleInstaller',
'october' => 'OctoberInstaller',
'ontowiki' => 'OntoWikiInstaller',
'oxid' => 'OxidInstaller',
'osclass' => 'OsclassInstaller',
'phpbb' => 'PhpBBInstaller',
'pimcore' => 'PimcoreInstaller',
'piwik' => 'PiwikInstaller',
'plentymarkets'=> 'PlentymarketsInstaller',
'ppi' => 'PPIInstaller',
'puppet' => 'PuppetInstaller',
'radphp' => 'RadPHPInstaller',
'phifty' => 'PhiftyInstaller',
'porto' => 'PortoInstaller',
'redaxo' => 'RedaxoInstaller',
'reindex' => 'ReIndexInstaller',
'roundcube' => 'RoundcubeInstaller',
'shopware' => 'ShopwareInstaller',
'silverstripe' => 'SilverStripeInstaller',
'smf' => 'SMFInstaller',
'sydes' => 'SyDESInstaller',
'symfony1' => 'Symfony1Installer',
'thelia' => 'TheliaInstaller',
'tusk' => 'TuskInstaller',
'typo3-cms' => 'TYPO3CmsInstaller',
'typo3-flow' => 'TYPO3FlowInstaller',
'userfrosting' => 'UserFrostingInstaller',
'vanilla' => 'VanillaInstaller',
'whmcs' => 'WHMCSInstaller',
'wolfcms' => 'WolfCMSInstaller',
'wordpress' => 'WordPressInstaller',
'yawik' => 'YawikInstaller',
'zend' => 'ZendInstaller',
'zikula' => 'ZikulaInstaller',
'prestashop' => 'PrestashopInstaller'
);
/**
* {@inheritDoc}
*/
public function getInstallPath(PackageInterface $package)
{
$type = $package->getType();
$frameworkType = $this->findFrameworkType($type);
if ($frameworkType === false) {
throw new \InvalidArgumentException(
'Sorry the package type of this package is not yet supported.'
);
}
$class = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType];
$installer = new $class($package, $this->composer, $this->getIO());
return $installer->getInstallPath($package, $frameworkType);
}
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
if (!$repo->hasPackage($package)) {
throw new \InvalidArgumentException('Package is not installed: '.$package);
}
$repo->removePackage($package);
$installPath = $this->getInstallPath($package);
$this->io->write(sprintf('Deleting %s - %s', $installPath, $this->filesystem->removeDirectory($installPath) ? '<comment>deleted</comment>' : '<error>not deleted</error>'));
}
/**
* {@inheritDoc}
*/
public function supports($packageType)
{
$frameworkType = $this->findFrameworkType($packageType);
if ($frameworkType === false) {
return false;
}
$locationPattern = $this->getLocationPattern($frameworkType);
return preg_match('#' . $frameworkType . '-' . $locationPattern . '#', $packageType, $matches) === 1;
}
/**
* Finds a supported framework type if it exists and returns it
*
* @param string $type
* @return string
*/
protected function findFrameworkType($type)
{
$frameworkType = false;
krsort($this->supportedTypes);
foreach ($this->supportedTypes as $key => $val) {
if ($key === substr($type, 0, strlen($key))) {
$frameworkType = substr($type, 0, strlen($key));
break;
}
}
return $frameworkType;
}
/**
* Get the second part of the regular expression to check for support of a
* package type
*
* @param string $frameworkType
* @return string
*/
protected function getLocationPattern($frameworkType)
{
$pattern = false;
if (!empty($this->supportedTypes[$frameworkType])) {
$frameworkClass = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType];
/** @var BaseInstaller $framework */
$framework = new $frameworkClass(null, $this->composer, $this->getIO());
$locations = array_keys($framework->getLocations());
$pattern = $locations ? '(' . implode('|', $locations) . ')' : false;
}
return $pattern ? : '(\w+)';
}
/**
* Get I/O object
*
* @return IOInterface
*/
private function getIO()
{
return $this->io;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class ItopInstaller extends BaseInstaller
{
protected $locations = array(
'extension' => 'extensions/{$name}/',
);
}

View File

@@ -1,15 +0,0 @@
<?php
namespace Composer\Installers;
class JoomlaInstaller extends BaseInstaller
{
protected $locations = array(
'component' => 'components/{$name}/',
'module' => 'modules/{$name}/',
'template' => 'templates/{$name}/',
'plugin' => 'plugins/{$name}/',
'library' => 'libraries/{$name}/',
);
// TODO: Add inflector for mod_ and com_ names
}

View File

@@ -1,18 +0,0 @@
<?php
namespace Composer\Installers;
/**
*
* Installer for kanboard plugins
*
* kanboard.net
*
* Class KanboardInstaller
* @package Composer\Installers
*/
class KanboardInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'plugins/{$name}/',
);
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Composer\Installers;
class KirbyInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'site/plugins/{$name}/',
'field' => 'site/fields/{$name}/',
'tag' => 'site/tags/{$name}/'
);
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Composer\Installers;
class KodiCMSInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'cms/plugins/{$name}/',
'media' => 'cms/media/vendor/{$name}/'
);
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Composer\Installers;
class KohanaInstaller extends BaseInstaller
{
protected $locations = array(
'module' => 'modules/{$name}/',
);
}

View File

@@ -1,27 +0,0 @@
<?php
namespace Composer\Installers;
class LanManagementSystemInstaller extends BaseInstaller
{
protected $locations = array(
'plugin' => 'plugins/{$name}/',
'template' => 'templates/{$name}/',
'document-template' => 'documents/templates/{$name}/',
'userpanel-module' => 'userpanel/modules/{$name}/',
);
/**
* Format package name to CamelCase
*/
public function inflectPackageVars($vars)
{
$vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name']));
$vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']);
$vars['name'] = str_replace(' ', '', ucwords($vars['name']));
return $vars;
}
}

Some files were not shown because too many files have changed in this diff Show More