Skip to content

Commit

Permalink
Init 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
tg666 committed Sep 30, 2019
0 parents commit c65ce2c
Show file tree
Hide file tree
Showing 37 changed files with 1,875 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.gitattributes export-ignore
.gitignore export-ignore
.php_cs.dist export-ignore
.travis.yml export-ignore
tests export-ignore
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
composer.lock
/vendor
/.idea
36 changes: 36 additions & 0 deletions .php_cs.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
;

return PhpCsFixer\Config::create()
->setUsingCache(FALSE)
->setIndent("\t")
->setRules([
'@PSR2' => TRUE,
'array_syntax' => ['syntax' => 'short'],
'trailing_comma_in_multiline_array' => true,
'lowercase_constants' => FALSE,
'declare_strict_types' => TRUE,
'phpdoc_align' => TRUE,
'blank_line_after_opening_tag' => TRUE,
'blank_line_before_statement' => [
'statements' => ['break', 'continue', 'declare', 'return'],
],
'blank_line_after_namespace' => TRUE,
'single_blank_line_before_namespace' => TRUE,
'return_type_declaration' => [
'space_before' => 'none',
],
'ordered_imports' => [
'sort_algorithm' => 'length',
],
'no_unused_imports' => TRUE,
'single_line_after_imports' => TRUE,
'no_leading_import_slash' => TRUE,
])
->setRiskyAllowed(TRUE)
->setFinder($finder)
;
36 changes: 36 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
language: php

php:
- 7.1

env:
- TESTER_PHP_BIN="php-cgi"

before_install:
- composer self-update

install:
- composer install --no-interaction --prefer-source

before_script:
- travis_retry composer update
- travis_retry composer create-project nette/code-checker temp/code-checker ~2.5 --no-interaction

script:
# check coding standard for our code
- vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run
- vendor/bin/tester -p $TESTER_PHP_BIN -s ./tests # -c ./tests/php.ini
- vendor/bin/tester ./tests --coverage coverage.xml --coverage-src ./src -d zend_extension=xdebug.so

after_failure:
# print content of output files *.actual
- for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done

after_script:
# get scrutinizer for coverage upload
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.xml

cache:
directories:
- $HOME/.composer/cache
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# MIT License

Copyright (c) 2019 '68 Publishers

> 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.
115 changes: 115 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Doctrine Sluggable

:abc: Doctrine Sluggable extension!

Simple usage and integration into [Nette Framework](https://github.com/nette).

## Installation

The best way to install `68publishers/doctrine-sluggable` is using Composer:

```bash
$ composer require 68publishers/doctrine-sluggable
```

then register `SluggableEventSubscriber` into `EventManager` like this:

```php
<?php

/** @var Doctrine\ORM\EntityManager $em */
/** @var Doctrine\Common\Annotations\Reader $reader */

$subscriber = new SixtyEightPublishers\DoctrineSluggable\SluggableEventSubscriber(
new SixtyEightPublishers\DoctrineSluggable\SluggableDefinitionStorage($reader)
);

$em->getEventManager()->addEventSubscriber($subscriber);
```

but you'd better use compiler extension if you are using `Nette` Framework:

```yaml
extensions:
sluggable: SixtyEightPublishers\DoctrineSluggable\Bridge\Nette\SluggableExtension
```
## Usage
Example entity:
```php
<?php

use Doctrine\ORM\Mapping as ORM;
use SixtyEightPublishers\DoctrineSluggable\Annotation as Sluggable;

/**
* @ORM\Entity
*/
class Product {
/**
* @ORM\Column(type="string", length=255)
*
* @var string
*/
private $name;

/**
* @ORM\ManyToOne(targetEntity="Category")
*
* @var Category
*/
private $category;

/**
* @Sluggable\Slug(
* strategy="SixtyEightPublishers\DoctrineSluggable\Strategy\GenerateOnInsertStrategy",
* strategyOptions={
* @Sluggable\Option(name="fields", value={"name"}),
* @Sluggable\Option(name="checkOnUpdate", value=true)
* },
* finder="SixtyEightPublishers\DoctrineSluggable\Finder\NegativeFieldBasedSimilarSlugFinder",
* finderOptions={
* @Sluggable\Option(name="field", value="category")
* },
* transliterate="SixtyEightPublishers\DoctrineSluggable\Transliterate\CamelCaseSlugTransliterate"
* )
* @ORM\Column(type="string", length=255)
*
* @var string
*/
private $slug;

/**
* @return string
*/
public function getSlug() : string
{
# slug is generated on EntityManager's onFlush event
if (NULL === $this->slug) {
throw new RuntimeException('Slug is not set.');
}

return $this->slug;
}
}
```

## Options

@todo

## Contributing

Before committing any changes, don't forget to run

```bash
$ vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run
```

and

```bash
$ vendor/bin/tester ./tests
```
34 changes: 34 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "68publishers/doctrine-sluggable",
"description": "Doctrine Sluggable extension",
"keywords": ["68publishers", "remote-access"],
"license": "MIT",
"authors": [
{
"name": "Tomáš Glawaty",
"email": "[email protected]"
}
],
"require": {
"php": "^7.1",
"doctrine/orm": "^2.5",
"behat/transliterator": "^1.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.0",
"nette/tester": "^1.7",
"mockery/mockery": "^1.2",
"nette/di": "^2.4"
},
"suggest": {
"nette/di": "For integration into Nette Framework"
},
"autoload": {
"classmap": ["src/"],
"files": []
},
"autoload-dev": {
"classmap": ["tests/"],
"files": []
}
}
31 changes: 31 additions & 0 deletions src/AbstractAdjustableObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace SixtyEightPublishers\DoctrineSluggable;

use Doctrine;

abstract class AbstractAdjustableObject implements IAdjustable
{
/**
* {@inheritdoc}
*/
public static function getOption(array $options, string $name, $default = NULL)
{
foreach ($options as $option) {
if ($option instanceof Annotation\Option && $option->name === $name) {
return $option->value;
}
}

return $default;
}

/**
* {@inheritdoc}
*/
public static function assertOptions(array $options, Doctrine\ORM\Mapping\ClassMetadata $metadata): void
{
}
}
17 changes: 17 additions & 0 deletions src/Annotation/Option.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace SixtyEightPublishers\DoctrineSluggable\Annotation;

/**
* @Annotation
*/
final class Option
{
/** @var string */
public $name;

/** @var mixed */
public $value;
}
84 changes: 84 additions & 0 deletions src/Annotation/Slug.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace SixtyEightPublishers\DoctrineSluggable\Annotation;

use Doctrine;
use SixtyEightPublishers;

/**
* @Annotation
* @Target("PROPERTY")
*/
final class Slug extends Doctrine\Common\Annotations\Annotation
{
/** @var string */
public $strategy = SixtyEightPublishers\DoctrineSluggable\Strategy\GenerateAlwaysStrategy::class;

/** @var array<SixtyEightPublishers\DoctrineSluggable\Annotation\Option> */
public $strategyOptions = [];

/** @var string */
public $finder = SixtyEightPublishers\DoctrineSluggable\Finder\DefaultSimilarSlugFinder::class;

/** @var array<SixtyEightPublishers\DoctrineSluggable\Annotation\Option> */
public $finderOptions = [];

/** @var string */
public $transliterate = SixtyEightPublishers\DoctrineSluggable\Transliterate\DefaultSlugTransliterate::class;

/** @var array<SixtyEightPublishers\DoctrineSluggable\Annotation\Option> */
public $transliterateOptions = [];

/** @var string */
public $uniquer = SixtyEightPublishers\DoctrineSluggable\Uniquer\DefaultUniquer::class;

/** @var array<SixtyEightPublishers\DoctrineSluggable\Annotation\Option> */
public $uniquerOptions = [];

/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata
*
* @return void
*/
public function validateFor(Doctrine\ORM\Mapping\ClassMetadata $metadata): void
{
$this->assertSubclass($this->strategy, SixtyEightPublishers\DoctrineSluggable\Strategy\ISluggableStrategy::class);
$this->assertSubclass($this->finder, SixtyEightPublishers\DoctrineSluggable\Finder\ISimilarSlugFinder::class);
$this->assertSubclass($this->transliterate, SixtyEightPublishers\DoctrineSluggable\Transliterate\ISlugTransliterate::class);
$this->assertSubclass($this->uniquer, SixtyEightPublishers\DoctrineSluggable\Uniquer\ISlugUniquer::class);

($this->strategy . '::assertOptions')($this->strategyOptions, $metadata);
($this->finder . '::assertOptions')($this->finderOptions, $metadata);
($this->transliterate . '::assertOptions')($this->transliterateOptions, $metadata);
($this->uniquer . '::assertOptions')($this->finderOptions, $metadata);
}

/**
* @param string $class
* @param string $parentClass
*
* @return void
* @throws \SixtyEightPublishers\DoctrineSluggable\Exception\AssertionException
*/
private function assertSubclass(string $class, string $parentClass): void
{
if (!class_exists($class)) {
throw new SixtyEightPublishers\DoctrineSluggable\Exception\AssertionException(sprintf(
'Class %s doesn\'t exists.',
$class
));
}
if (!is_subclass_of($class, $parentClass, TRUE)) {
$isInterface = interface_exists($parentClass);

throw new SixtyEightPublishers\DoctrineSluggable\Exception\AssertionException(sprintf(
'Class %s must be %s %s.',
$class,
$isInterface ? 'implementor of interface' : 'inheritor of class',
$parentClass
));
}
}
}
Loading

0 comments on commit c65ce2c

Please sign in to comment.