diff --git a/README.md b/README.md
index 58a3fc3..487264b 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,8 @@
-[](https://travis-ci.org/DevFactoryCH/taxonomy)
-[](https://packagist.org/packages/devfactory/taxonomy)
-[](https://packagist.org/packages/devfactory/taxonomy)
[](https://packagist.org/packages/devfactory/taxonomy)
#Taxonomy
-This package allows you to create vocabularies with terms in Laravel 4 and 5
+This package allows you to create vocabularies with terms in Laravel 5
## Installation
@@ -13,9 +10,16 @@ This package allows you to create vocabularies with terms in Laravel 4 and 5
In your `composer.json` add:
- "require": {
- "devfactory/taxonomy": "3.0.*"
- }
+ "require": {
+ "tonjoo/taxonomy": "master"
+ }
+
+ "repositories": [
+ {
+ "url": "https://github.com/todiadiyatmo/taxonomy.git",
+ "type": "git"
+ }
+ ]
From the terminal run
@@ -31,11 +35,11 @@ Then register the service provider and Facade by opening `app/config/app.php`
Then run the following artisant command to publish the config and migrations:
- php artisan vendor:publish
+ php artisan vendor:publish
Then run the migrations:
- php artisan migrate
+ php artisan migrate
And finally in any of the Models where you want to use the Taxonomy functionality, add the following trait:
@@ -51,9 +55,9 @@ class Car extends \Eloquent {
In your `composer.json` add:
- "require": {
- "devfactory/taxonomy": "2.0.*"
- }
+ "require": {
+ "devfactory/taxonomy": "2.0.*"
+ }
From the terminal run
@@ -87,67 +91,228 @@ class Car extends \Eloquent {
## Usage
-Creating a vocabulary:
+Use Taxonomy base class
+```
+use Devfactory\Taxonomy\Models\Term;
+use Devfactory\Taxonomy\Models\TermRelation;
+use Devfactory\Taxonomy\Models\Vocabulary;
+```
+
+### Taxonomy
+`Taxonomy` is the grouping mechanism between model/object. Each group is of `taxonomy` is called `vocabulary` .The name of different group between one `vocabulary` is called `term`. The `term` can have also have parrent-child relationship.
+
+This goal of this package is to make create and organizing multiple taxonomy as easy as possible
+
+Sample :
+
+**Region Vocabulary**
+
+List of term :
+
+- Asia
+ - Indonesia
+ - Singapore
+- Europe
+ - France
+ - Germany
+- North America
+ - Canada
+ - United States of America
+- Australia
+ - Australia
+ - New Zealand
+- Africa
+ - Egypt
+ - Marocco
+
+#### Vocabulary
+
+**Create vocabulary**
```php
-Taxonomy::createVocabulary('Cars');
+Taxonomy::createVocabulary('Region');
```
-Retrieving a Vocabulary:
-
+**Retrieve vocabulary**
```php
$vocabulary = Taxonomy::getVocabulary(1); // Using ID
-$vocabulary = Taxonomy::getVocabularyByName('Cars'); // Using Name
+$vocabulary = Taxonomy::getVocabularyByName('Region'); // Using Name
+```
+
+**Delete a vocabulary**
+```php
+$vocabulary->delete(); // Using Eloquent delete
+Taxonomy::deleteVocabulary('Region'); // Using Name
+```
+
+#### Term
+
+**Adding a term to a vocabulary**
+```php
+$vocabulary = Taxonomy::getVocabularyByName('Region');
+
+$termAsia = Taxonomy::createTerm($vocabulary->id, [
+ 'name' => 'Asia',
+ 'description'=>'Some description ',
+ 'parent_id'=>0 , // optional param, set 0 if it has not parrent
+ 'weight'=>0, // optional param, the term can be retrieved later and sort by its weight
+
+ ]);
+
+$termIndonesia = Taxonomy::createTerm($vocabulary->id, [
+ 'name' => 'Indonesia',
+ 'description'=>'Some description',
+ 'parent_id'=>$termAsia->id,
+
+ ]);
+```
+
+**Retrive single term**
+```php
+// Retrive term `Asia` from Vocabulary `Region`
+$term = Taxonomy::getTerm('Region', 'Asia')
+
+// Other method
+$vocabularyRegion = Taxonomy::getVocabularyByName('Region');
+$term = Taxonomy::getTerm($vocabularyRegion , 'Asia')
+```
+
+**Retrive all terms from vocabulary**
+```php
+/* Using Taxonomy Helper*/
+
+// Get term with child
+$terms = Taxonomy::getTerms('Region');
+
+// Get all first level terms ( parent_id = 0 )
+$terms = Taxonomy::getTerms('Region', false);
+
+// Get terms from Region Vocabulary , child of Asia term
+$terms = Taxonomy::getTerms('Region', 'Asia');
+
+/*From vocabulary model itself*/
+$vocabularyRegion = Taxonomy::getVocabularyByName('Region');
+
+// Get term with child
+$terms = $vocabularyRegion->terms();
+
+// Get term without child
+$terms = $vocabularyRegion->terms()->where('parent_id',0)->get()
```
-Deleting a Vocabulary:
+#### Working with Model
+
+Make sure your model is already using `\Devfactory\Taxonomy\TaxonomyTrait`
+**Assign one to many relationship**
```php
-Taxonomy::deleteVocabulary(1); // Using ID
-Taxonomy::deleteVocabularyByName('Cars'); // Using Name
+$car = \Car::findOrFail(1);
+
+$term = Taxonomy::getTerm('Region', 'Asia');
+
+// term object
+$car->setTerm($term)
+
+// term id
+$car->setTerm(1)
+
```
-Adding a Term to a vocabulary:
+**Assign many to many relationship**
+```php
+$car = \Car::findOrFail(1);
+
+$car->addTerm(Taxonomy::getTerm('Region', 'Asia'));
+$car->addTerm(Taxonomy::getTerm('Region', 'Europe'));
+// by term id
+$car->addTerm(1);
+```
+
+**Check if a model has a term**
```php
-Taxonomy::createTerm($vocabulary->id, 'Audi');
+$car = \Car::findOrFail(1);
+
+$term = Taxonomy::getTerm('Region', 'Asia');
+
+// by term object
+$car->hasTerm($term);
+
+// by term id
+$car->hasTerm(1);
```
-You can also optionally specify a parent term and a weight for each, so you can group them together and keep them sorted:
+**Get term(s) from model**
+
+`getTerm` and `getTerms` will return `TermRelation` Model
```php
-$german_cars = Taxonomy::createTerm($vocabulary->id, 'German Cars');
-$italian_cars = Taxonomy::createTerm($vocabulary->id, 'Italian Cars');
+$car = \Car::findOrFail(1);
+
+// using Vocabulary id
+$termRelation = $car->getTerm(1);
+$termRelations = $car->getTerms(1);
+
+// using Vocabulary Name
+$termRelation = $car->getTerm('Region');
+$termRelations = $car->getTerms('Region');
+
+$term = $termRelation->term;
+$terms = $termRelations->term;
-$term_audi = Taxonomy::CreateTerm($vocabulary->id, 'Audi', $german_cars->id, 0);
-$term_bmw = Taxonomy::CreateTerm($vocabulary->id, 'BMW', $german_cars->id, 1);
-$term_benz = Taxonomy::CreateTerm($vocabulary->id, 'Mercedes-Benz', $german_cars->id, 2);
-$term_ferrari = Taxonomy::CreateTerm($vocabulary->id, 'Ferrari', $italian_cars->id, 0);
```
-With the Car Model, I can create a new instance and assign it a term for the make it belongs to:
+**Remove term from model**
+```php
+$car = \Car::findOrFail(1);
+
+$term = Taxonomy::getTerm('Region', 'Asia');
+
+// Remove using term object
+$car->removeTerm($term);
+// Remove using term id
+$car->removeTerm(1);
+
+$car->removeTerms();
+```
+
+**Remove all terms from model**
```php
-$car = Car::create([
- 'model' => 'A3',
-]);
+$car = \Car::findOrFail(1);
+
+// REMOVE ALL TERMS FROM ALL VOCABULARY
+$car->removeTerms();
+```
-$car->addTerm($term_bmw->id);
-$car->addTerm($term_benz->id);
-$car->removeAllTerms(); // Remove all terms linked to this car
+**Remove all terms from specific vocabulary from model**
+```php
+$car = \Car::findOrFail(1);
-$car->addTerm($term_ferrari->id);
-$car->removeTerm($term_ferrari-id); // Remove a specific term
+// Remove all term with vocabulary id = 1
+$car->removeTerms(1);
-$car->addTerm($term_audi->id);
+$vocabularyRegion = Taxonomy::getVocabularyByName('Region');
-// Get all the terms from the vocabulary 'Cars' That
-// are attached to this Car.
-$terms = $car->getTermsByVocabularyName('Cars');
+$car->removeTerms($vocabularyRegion);
```
-To retrieve all the cars that match a given term:
+#### Running Query against Model
+
+**Get all model which belong to certain vocabulary**
+```php
+$vocabularyRegion = Taxonomy::getVocabulary('Region');
+
+$cars = Car::whereHasVocabulary($vocabularyRegion->id)->get();
+```
+**Get all model which belong to certain term(s)**
```php
-$audis = Car::getAllByTermId($term_audi->id)->get();
+$terms = Taxonomy::getTerms('Region')->pluck('id');
+
+$cars = Car::whereHasTerm($terms)->get();
+
+// Only Child of Asia
+$terms = Taxonomy::getTerms('Region','Asia')->pluck('id');
+$cars = Car::whereHasTerm($terms)->get();
```
diff --git a/composer.json b/composer.json
index c97103f..201cfa9 100644
--- a/composer.json
+++ b/composer.json
@@ -1,9 +1,13 @@
{
- "name": "devfactory/taxonomy",
+ "name": "tonjoo/taxonomy",
"description": "Create and manage a heirarchical taxonomy of terms within different vocabularies",
"license": "MIT",
"keywords": ["taxonomy"],
"authors": [
+ {
+ "name": "Todi Adiyatmo Wijoyo",
+ "email": "t@tonjoo.com"
+ },
{
"name": "Mark Cameron",
"email": "mark.cameron@devfactory.ch"
@@ -21,10 +25,5 @@
"psr-4": {
"Devfactory\\Taxonomy\\": "src/"
}
- },
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
}
}
diff --git a/sample.php b/sample.php
new file mode 100644
index 0000000..c5cf9e1
--- /dev/null
+++ b/sample.php
@@ -0,0 +1,178 @@
+truncate();
+ DB::table('terms')->truncate();
+ DB::table('vocabularies')->truncate();
+ DB::table('term_relations')->truncate();
+ DB::statement("SET foreign_key_checks=1");
+
+ Taxonomy::createVocabulary('Region');
+
+ $vocabulary = Taxonomy::getVocabulary(1);
+
+ if( $vocabulary->name === "Region")
+ echo "true 1
";
+
+ // Using ID
+ $vocabulary2 = Taxonomy::getVocabulary('Region'); // Using Name
+
+ if( $vocabulary2 == $vocabulary )
+ echo "true 2
";
+
+ $termAsia = Taxonomy::createTerm('Region', [
+ 'name' => 'Asia',
+ 'description'=>'description',
+ ]);
+
+ $termEurope = Taxonomy::createTerm('Region', [
+ 'name' => 'Europe',
+ 'description'=>'description',
+ ]);
+
+ $termIndonesia = Taxonomy::createTerm('Region', [
+ 'name' => 'Indonesia',
+ 'description'=>'description',
+ 'parent_id'=>$termAsia->id
+ ]);
+
+ $termSingapore = Taxonomy::createTerm('Region', [
+ 'name' => 'Singapore',
+ 'description'=>'description',
+ 'parent_id'=>$termAsia->id
+ ]);
+
+
+ $termFrance = Taxonomy::createTerm('Region', [
+ 'name' => 'France',
+ 'description'=>'description',
+ 'parent_id'=>$termEurope->id
+ ]);
+
+ $termGermany = Taxonomy::createTerm('Region', [
+ 'name' => 'Germany',
+ 'description'=>'description',
+ 'parent_id'=>$termEurope->id
+ ]);
+
+ if( $termAsia->name === 'Asia' && $termAsia->vocabulary_id === $vocabulary->id )
+ echo "true 3
";
+
+ if( $termEurope->name === 'Europe' && $termEurope->vocabulary_id === $vocabulary->id )
+ echo "true 4
";
+
+ if( $termIndonesia->name === 'Indonesia' && $termIndonesia->vocabulary_id === $vocabulary->id )
+ echo "true 5
";
+
+ if( $termSingapore->name === 'Singapore' && $termSingapore->vocabulary_id === $vocabulary->id )
+ echo "true 6
";
+
+ if( $termFrance->name === 'France' && $termFrance->vocabulary_id === $vocabulary->id )
+ echo "true 7
";
+
+ if( $termGermany->name === 'Germany' && $termGermany->vocabulary_id === $vocabulary->id )
+ echo "true 8
";
+
+ $terms = Vocabulary::where('name','Region')->first()->terms; // Using Name
+
+ if( count($terms) === 6 )
+ echo "true 9
";
+
+ $termGetAsia = Taxonomy::getTerm('Region', 'Asia');
+
+ if( $termGetAsia->name == $termAsia->name )
+ echo "true 10
";
+
+ $termsGet = Taxonomy::getTerms('Region');
+
+ if( count($termsGet) == count($terms) )
+ echo "true 11
";
+
+ $listTermId = Taxonomy::getTerms('Region')->pluck('id')->toArray();
+
+ if( in_array($termAsia->id, $listTermId) && in_array($termEurope->id, $listTermId) && in_array($termIndonesia->id, $listTermId) )
+ echo "true 12
";
+
+ $listTermIdAsia = Taxonomy::getTerms('Region','Asia')->pluck('id')->toArray();
+
+ if( in_array($termIndonesia->id, $listTermIdAsia) && in_array($termSingapore->id, $listTermIdAsia) )
+ echo "true 13
";
+
+
+ $productOne = Product::create([
+ 'name'=>'Lalala',
+ 'price'=>1
+ ]);
+
+ $productTwo = Product::create([
+ 'name'=>'Tototo',
+ 'price'=>2
+ ]);
+
+
+ $productThree = Product::create([
+ 'name'=>'Rururu',
+ 'price'=>2
+ ]);
+
+
+ $productOne->setTerm($termIndonesia);
+
+ // reset term
+ $productOne->setTerm($termAsia);
+
+ if( @$productOne->hasTerm($termAsia) == true )
+ echo "true 14
";
+
+ if( @$productOne->hasTerm($termIndonesia) == false )
+ echo "true 15
";
+
+ if( @$productOne->getTerm('Region')->term->id == $termAsia->id )
+ echo "true 16
";
+
+ // reset term
+ $productOne->removeTerm($termAsia);
+
+ if( @$productOne->hasTerm($termAsia) == false )
+ echo "true 17
";
+
+ $productOne->addTerm($termAsia);
+ $productOne->addTerm($termIndonesia);
+ $productOne->addTerm($termSingapore);
+
+ $productTwo->addTerm($termAsia);
+ $productTwo->addTerm($termIndonesia);
+ $productTwo->addTerm($termSingapore);
+
+ $productThree->addTerm($termAsia);
+ $productThree->addTerm($termIndonesia);
+ $productThree->addTerm($termSingapore);
+
+ if( count($productOne->getTerms('Region')) == 3 )
+ echo "true 18
";
+
+
+ $childOfAsia = Taxonomy::getTerms('Region','Asia')->pluck('id');
+
+ if( count($childOfAsia) == 2 )
+ echo "true 19
";
+
+ $productsFromTerm = Product::whereHasTerm($childOfAsia)->get();
+
+ if( count($productsFromTerm) == 3 )
+ echo "true 20
";
+
+ $vocabularyRegion = Taxonomy::getVocabulary('Region');
+
+ $productsFromVocabulary = Product::whereHasVocabulary($vocabularyRegion->id)->get();
+
+ if( count($productsFromVocabulary) == 3 )
+ echo "true 21
";
+
+});
\ No newline at end of file
diff --git a/src/Controllers/TaxonomyController.php b/src/Controllers/TaxonomyController.php
index 8726da1..a056550 100644
--- a/src/Controllers/TaxonomyController.php
+++ b/src/Controllers/TaxonomyController.php
@@ -118,18 +118,18 @@ public function getEdit($id) {
return Redirect::route($this->route_prefix . 'taxonomy.index');
}
- $terms = $vocabulary->terms()->orderBy('parent', 'ASC')->orderBy('weight', 'ASC')->get();
+ $terms = $vocabulary->terms()->orderBy('parent_id', 'ASC')->orderBy('weight', 'ASC')->get();
$ordered_terms = [];
foreach ($terms as $term) {
- if (!$term->parent) {
+ if (!$term->parent_id) {
$ordered_terms[$term->id] = [
'term' => $term,
'children' => [],
];
}
else {
- $ordered_terms[$term->parent]['children'][] = $term;
+ $ordered_terms[$term->parent_id]['children'][] = $term;
}
}
@@ -147,7 +147,7 @@ public function postOrderTerms($id) {
foreach ($content as $parent_key => $parent){
$parent_term = Term::find($parent->id);
- $parent_term->parent = 0;
+ $parent_term->parent_id = 0;
$parent_term->weight = $parent_key;
$parent_term->save();
@@ -158,7 +158,7 @@ public function postOrderTerms($id) {
foreach ($parent->children as $child_key => $child){
$child_term = Term::find($child->id);
- $child_term->parent = $parent_term->id;
+ $child_term->parent_id = $parent_term->id;
$child_term->weight = $child_key;
$child_term->save();
diff --git a/src/Controllers/TermsController.php b/src/Controllers/TermsController.php
index dc9bbd2..a1bb994 100644
--- a/src/Controllers/TermsController.php
+++ b/src/Controllers/TermsController.php
@@ -89,18 +89,18 @@ public function getEdit($id) {
public function getIndex() {
$vocabulary = Vocabulary::findOrFail(Input::get('id'));
- $terms = $vocabulary->terms()->orderBy('parent', 'ASC')->orderBy('weight', 'ASC')->get();
+ $terms = $vocabulary->terms()->orderBy('parent_id', 'ASC')->orderBy('weight', 'ASC')->get();
$ordered_terms = [];
foreach ($terms as $term) {
- if (!$term->parent) {
+ if (!$term->parent_id) {
$ordered_terms[$term->id] = [
'term' => $term,
'children' => [],
];
}
else {
- $ordered_terms[$term->parent]['children'][] = $term;
+ $ordered_terms[$term->parent_id]['children'][] = $term;
}
}
diff --git a/src/Exceptions/TermExistsException.php b/src/Exceptions/TermExistsException.php
new file mode 100644
index 0000000..f168497
--- /dev/null
+++ b/src/Exceptions/TermExistsException.php
@@ -0,0 +1,3 @@
+ 0,
+ 'parent_id' => 0,
+ ];
+
protected $fillable = [
'name',
'vocabulary_id',
- 'parent',
+ 'parent_id',
'weight',
+ 'description'
];
- public static $rules = [
- 'name' => 'required'
+ public static $rules = [
+ 'name' => 'required'
];
+
+
public function termRelation() {
- return $this->morphMany('Devfactory\Taxonomy\Models\TermRelation', 'relationable');
+ return $this->morphMany('TermRelation', 'relationable');
}
- public function vocabulary() {
- return $this->belongsTo('Devfactory\Taxonomy\Models\Vocabulary');
- }
+ public function vocabulary() {
+ return $this->belongsTo('Devfactory\Taxonomy\Models\Vocabulary');
+ }
public function childrens() {
- return $this->hasMany('Devfactory\Taxonomy\Models\Term', 'parent', 'id')
- ->orderBy('weight', 'ASC');
+ return $this->hasMany('Devfactory\Taxonomy\Models\Term', 'parent_id', 'id');
+ }
+
+ public function parent() {
+ return $this->hasOne('Devfactory\Taxonomy\Models\Term', 'id', 'parent_id');
}
- public function parentTerm() {
- return $this->hasOne('Devfactory\Taxonomy\Models\Term', 'id', 'parent');
+ public function root()
+ {
+ return \Devfactory\Taxonomy\Facades\TaxonomyFacade::recurseRoot($this);
}
+
+
}
diff --git a/src/Models/TermRelation.php b/src/Models/TermRelation.php
index d42df2a..44b0a95 100644
--- a/src/Models/TermRelation.php
+++ b/src/Models/TermRelation.php
@@ -1,20 +1,27 @@
morphTo();
}
- public function term() {
- return $this->belongsTo('Devfactory\Taxonomy\Models\Term');
- }
+ public function vocabulary() {
+ return $this->belongsTo('Devfactory\Taxonomy\Models\Vocabulary');
+ }
+
+
+ public function term() {
+ return $this->belongsTo('Devfactory\Taxonomy\Models\Term');
+ }
}
diff --git a/src/Models/Vocabulary.php b/src/Models/Vocabulary.php
index 196e6a6..1e2a297 100644
--- a/src/Models/Vocabulary.php
+++ b/src/Models/Vocabulary.php
@@ -1,7 +1,7 @@
vocabulary = $vocabulary;
$this->term = $term;
@@ -25,13 +27,15 @@ public function __construct(Vocabulary $vocabulary, Term $term) {
* The Vocabulary object if created, FALSE if error creating,
* Exception if the vocabulary name already exists.
*/
- public function createVocabulary($name) {
- if ($this->vocabulary->where('name', $name)->count()) {
+ public function createVocabulary($name)
+ {
+ if ($this->vocabulary->where('name', $name)->count())
+ {
throw new Exceptions\VocabularyExistsException();
}
- return $this->vocabulary->create(['name' => $name]);
- }
+ return $this->vocabulary->create(['name' => $name]);
+ }
/**
* Get a Vocabulary by ID
@@ -42,12 +46,37 @@ public function createVocabulary($name) {
* @return
* The Vocabulary Model object, otherwise NULL
*/
- public function getVocabulary($id) {
- return $this->vocabulary->find($id);
+ public function getVocabulary($vocabulary)
+ {
+ if($vocabulary instanceof Vocabulary)
+ return $vocabulary;
+ elseif(is_string($vocabulary))
+ return $this->vocabulary->where('name', $vocabulary)->first();
+ elseif(is_numeric($vocabulary))
+ return $this->vocabulary->where('id', $vocabulary)->first();
+
+ return false;
}
/**
- * Get a Vocabulary by name
+ * Get single term by name
+ *
+ * @param string $name
+ * The name of the Vocabulary to fetch
+ *
+ * @return
+ * The Vocabulary Model object, otherwise NULL
+ */
+ public function getTerm( $vocabulary, $name )
+ {
+
+ $vocabulary = $this->getVocabulary($vocabulary);
+
+ return $this->term->where( 'vocabulary_id', $vocabulary->id )->where( 'name', $name )->first();
+ }
+
+ /**
+ * Get a terms
*
* @param string $name
* The name of the Vocabulary to fetch
@@ -55,8 +84,30 @@ public function getVocabulary($id) {
* @return
* The Vocabulary Model object, otherwise NULL
*/
- public function getVocabularyByName($name) {
- return $this->vocabulary->where('name', $name)->first();
+ public function getTerms($vocabulary, $parentName = true, $withParent = false)
+ {
+ $vocabulary = $this->getVocabulary($vocabulary);
+
+ if(!$vocabulary)
+ return collect([]);
+
+ if( $parentName === true )
+ return $vocabulary->terms;
+
+
+ if( $parentName )
+ {
+ $term = $this->getTerm($vocabulary, $parentName);
+
+ $terms = $vocabulary->terms()->where($this->term->getTable().'.parent_id','=', $term->id)->get();
+
+ if( $withParent )
+ return $terms->push($term);
+
+ return $terms;
+ }
+
+ return collect([]);
}
/**
@@ -68,8 +119,9 @@ public function getVocabularyByName($name) {
* @return
* The Vocabulary Model object, otherwise NULL
*/
- public function getVocabularyByNameAsArray($name) {
- $vocabulary = $this->vocabulary->where('name', $name)->first();
+ public function getTermsByNameAsArray( $vocabulary , $field='name' )
+ {
+ $vocabulary = $this->getVocabulary($vocabulary);
if (!is_null($vocabulary)) {
return $vocabulary->terms->lists('name', 'id')->toArray();
@@ -78,6 +130,8 @@ public function getVocabularyByNameAsArray($name) {
return [];
}
+
+
/**
* Get a Vocabulary by name as an options array for dropdowns
*
@@ -87,11 +141,12 @@ public function getVocabularyByNameAsArray($name) {
* @return
* The Vocabulary Model object, otherwise NULL
*/
- public function getVocabularyByNameOptionsArray($name) {
+ public function getVocabularyByNameOptionsArray($name)
+ {
$vocabulary = $this->vocabulary->where('name', $name)->first();
if (is_null($vocabulary)) {
- return [];
+ return collect([]);
}
$parents = $this->term->whereParent(0)
@@ -117,7 +172,8 @@ public function getVocabularyByNameOptionsArray($name) {
*
* @return array
*/
- private function recurse_children($parent, &$options, $depth = 1) {
+ private function recurse_children($parent, &$options, $depth = 1)
+ {
$parent->childrens->map(function($child) use (&$options, $depth) {
$options[$child->id] = str_repeat('-', $depth) .' '. $child->name;
@@ -127,23 +183,22 @@ private function recurse_children($parent, &$options, $depth = 1) {
});
}
- /**
- * Delete a Vocabulary by ID
- *
- * @param int $id
- * The ID of the Vocabulary to delete
- *
- * @return bool
- * TRUE if Vocabulary is deletes, otherwise FALSE
- *
- * @thrown Illuminate\Database\Eloquent\ModelNotFoundException
- */
- public function deleteVocabulary($id) {
- $vocabulary = $this->vocabulary->findOrFail($id);
- return $vocabulary->delete();
+ public function recurseRoot( $term )
+ {
+
+ if($term->parent_id == 0 )
+ return $term;
+
+ if($term->parent)
+ {
+ return $this->recurseRoot($term->parent);
+ }
+
}
+
+
/**
* Delete a Vocabulary by ID
*
@@ -155,16 +210,23 @@ public function deleteVocabulary($id) {
*
* @thrown Illuminate\Database\Eloquent\ModelNotFoundException
*/
- public function deleteVocabularyByName($name) {
- $vocabulary = $this->vocabulary->where('name', $name)->first();
+ public function deleteVocabulary($vocabulary) {
- if (!is_null($vocabulary)) {
+ if( is_string( $vocabulary ) )
+ {
+
+ $vocabulary = $this->getVocabulary( $vocabulary );
+
+ if( !$vocabulary )
+ return false;
+
return $vocabulary->delete();
}
- return FALSE;
+ return false;
}
+
/**
* Create a new term in a specific vocabulary
*
@@ -185,15 +247,29 @@ public function deleteVocabularyByName($name) {
*
* @thrown Illuminate\Database\Eloquent\ModelNotFoundException
*/
- public function createTerm($vid, $name, $parent = 0, $weight = 0) {
- $vocabulary = $this->vocabulary->findOrFail($vid);
-
- $term = [
- 'name' => $name,
- 'vocabulary_id' => $vid,
- 'parent' => $parent,
- 'weight' => $weight,
- ];
+ public function createTerm($vocabulary, $term = array() )
+ {
+ $vocabulary = $this->getVocabulary($vocabulary);
+
+ if(!$vocabulary)
+ {
+ throw new Exceptions\VocabularyNotExistsException();
+ }
+
+
+ // if($this->vocabulary->terms)
+
+ $term['vocabulary_id'] = $vocabulary->id;
+ $term['parent_id'] = isset($term['parent_id']) ? $term['parent_id'] : 0 ;
+ $term['weight'] = isset($term['weight']) ? $term['weight'] : 0 ;
+
+ if($vocabulary->terms()
+ ->where($this->term->getTable().'.parent_id', $term['parent_id'])
+ ->where($this->term->getTable().'.name', $term['name'])
+ ->first())
+ {
+ throw new Exceptions\TermExistsException();
+ }
return $this->term->create($term);
}
diff --git a/src/TaxonomyTrait.php b/src/TaxonomyTrait.php
index 3faa802..313cc2d 100644
--- a/src/TaxonomyTrait.php
+++ b/src/TaxonomyTrait.php
@@ -2,20 +2,105 @@
use Devfactory\Taxonomy\Models\TermRelation;
use Devfactory\Taxonomy\Models\Term;
+use Devfactory\Taxonomy\Models\Vocabulary;
trait TaxonomyTrait {
/**
- * Return collection of tags related to the tagged model
- *
- * @return Illuminate\Database\Eloquent\Collection
- */
- public function related() {
- return $this->morphMany('Devfactory\Taxonomy\Models\TermRelation', 'relationable');
- }
+ * Get related vocabulary
+ */
+
+ public function getTaxonomiesAttribute()
+ {
+ $relatedGrouped = $this->related()->get()->groupBy('vocabulary_id');
+
+ $groupedTaxonomy = [];
+
+ foreach ($relatedGrouped as $key => $relateds) {
+
+ $vocabulary = Vocabulary::find($key);
+
+ $slug = str_slug($vocabulary->name,'_');
+
+ $groupedTaxonomy[$slug] = [];
+ // $groupedTaxonomy[$key]['name'] = $vocabulary->name;
+ // $groupedTaxonomy[$key]['id'] = $vocabulary->id;
+
+ // $groupedTaxonomy[$key]['terms'] = [];
+
+ foreach ($relateds as $related) {
+
+ $term = $related->term;
+
+ $termData = [
+ 'id' => $term->id,
+ 'name' => $term->name,
+ 'description' => $term->description,
+ 'root_term_id' => false,
+ 'root_term_name' => false,
+ 'root_term_description' => false
+ ];
+
+ $root = $term->root();
+
+ if( $root->id != $term->id )
+ {
+ $termData['root_term_id'] = $root->id;
+ $termData['root_term_name'] = $root->name;
+ $termData['root_term_description'] = $root->description;
+ }
+
+ array_push( $groupedTaxonomy[$slug], $termData );
+ }
+
+ }
+
+ return $this->attributes['taxonomies'] = $groupedTaxonomy;
+ }
+ /**
+ * Return collection of tags related to the tagged model
+ *
+ * @return Illuminate\Database\Eloquent\Collection
+ */
+ public function related() {
+ return $this->morphMany('Devfactory\Taxonomy\Models\TermRelation', 'relationable');
+ }
+
+ /**
+ * Set term to the inheriting model ( One to many )
+ *
+ * @param $term_id int
+ * The ID of the term or an instance of the Term object
+ *
+ * @return object
+ * The TermRelation object
+ */
+ public function setTerm($term, $description="") {
+
+ $term = ($term instanceof Term) ? $term : Term::findOrFail($term);
+
+ if(!$term)
+ return;
+
+ if( $this->hasTerm($term) )
+ return $this->updateTerm($term,$description);
+
+ // Check if the new term is already there
+ // $related = $this->related()->first();
+
+ // if( $related && $related->term->id == $term->id )
+ // {
+ // return $this->updateTerm($term, $description);
+ // }
+
+ // Remove all term from same vocabulary
+ $this->related()->where('relationable_id', $this->id)->where('vocabulary_id',$term->vocabulary->id)->delete();
+
+ return $this->addTerm($term,$description);
+ }
/**
- * Add an existing term to the inheriting model
+ * Add an existing term to the inheriting model (Many to Many )
*
* @param $term_id int
* The ID of the term or an instance of the Term object
@@ -23,17 +108,50 @@ public function related() {
* @return object
* The TermRelation object
*/
- public function addTerm($term_id) {
- $term = ($term_id instanceof Term) ? $term_id : Term::findOrFail($term_id);
+ public function addTerm($term, $description="") {
+
+ $term = ($term instanceof Term) ? $term : Term::findOrFail($term);
+
+ if(!$term)
+ return;
+
+ if( $this->hasTerm($term) )
+ return $this->updateTerm($term,$description);
$term_relation = [
- 'term_id' => $term->id,
- 'vocabulary_id' => $term->vocabulary_id,
+ 'term_id' => $term->id,
+ 'vocabulary_id' => $term->vocabulary_id,
+ 'description' => $description,
];
- $this->related()->save(new TermRelation($term_relation));
+ return $this->related()->save(new TermRelation($term_relation));
}
+
+
+ /**
+ * Update an existing term to the inheriting model
+ *
+ * @param $term_id int
+ * The ID of the term or an instance of the Term object
+ *
+ * @return object
+ * The TermRelation object
+ */
+ public function updateTerm($term,$description="") {
+ $term = ($term instanceof Term) ? $term : Term::findOrFail($term);
+
+ if(!$term)
+ return;
+
+ if( !$this->related() )
+ return;
+
+ $this->related()->where('term_id',$term->id)->update(['description' => $description]);
+ }
+
+
+
/**
* Check if the Model instance has the passed term as an existing relation
*
@@ -43,19 +161,42 @@ public function addTerm($term_id) {
* @return object
* The TermRelation object
*/
- public function hasTerm($term_id) {
- $term = ($term_id instanceof Term) ? $term_id : Term::findOrFail($term_id);
+ public function hasTerm($term) {
+ $term = ($term instanceof Term) ? $term : Term::findOrFail($term);
+ if(!$term)
+ return false;
+ return ($this->related()->where('term_id', $term->id )->count()) ? TRUE : FALSE;
+ }
- $term_relation = [
- 'term_id' => $term->id,
- 'vocabulary_id' => $term->vocabulary_id,
- ];
+ /**
+ * Check if the Model instance has the passed term as an existing relation
+ *
+ * @param mixed $term_id
+ * The ID of the term or an instance of the Term object
+ *
+ * @return object
+ * The TermRelation object
+ */
+ public function hasVocabulary($vocabulary, $name=false) {
+
+ $vocabulary = \Devfactory\Taxonomy\Facades\TaxonomyFacade::getVocabulary($vocabulary);
+
+ if(!$vocabulary)
+ return false;
+
+ if(!$name)
+ return $this->related()->where('term_relations.vocabulary_id', $vocabulary->id)->first();
- return ($this->related()->where('term_id', $term_id)->count()) ? TRUE : FALSE;
+ return $this ->related()
+ ->where('term_relations.vocabulary_id', $vocabulary->id)
+ ->whereHas('term', function($q) use($name) {
+ $q->where('term.name', '=', $name );
+ })
+ ->first();
}
/**
- * Get all the terms for a given vocabulary that are linked to the current
+ * Get all the term relations for a given vocabulary that are linked to the current
* Model.
*
* @param $name string
@@ -64,34 +205,63 @@ public function hasTerm($term_id) {
* @return object
* A collection of TermRelation objects
*/
- public function getTermsByVocabularyName($name) {
- $vocabulary = \Taxonomy::getVocabularyByName($name);
+ public function getRelated($term,$name=false) {
+
+ $term = ($term instanceof Term) ? $term : Term::findOrFail($term);
+ if(!$term)
+ return false;
- return $this->related()->where('vocabulary_id', $vocabulary->id)->get();
+ return $this->related()->where('term_id', $term->id )->first();
}
/**
- * Get all the terms for a given vocabulary that are linked to the current
- * Model as a key value pair array.
+ * Get all the term relations for a given vocabulary that are linked to the current
+ * Model.
*
* @param $name string
* The name of the vocabulary
*
- * @return array
- * A key value pair array of the type 'id' => 'name'
+ * @return object
+ * A collection of TermRelation objects
*/
- public function getTermsByVocabularyNameAsArray($name) {
- $vocabulary = \Taxonomy::getVocabularyByName($name);
+ public function getTerm($vocabulary,$name=false) {
- $term_relations = $this->related()->where('vocabulary_id', $vocabulary->id)->get();
+ $vocabulary = \Devfactory\Taxonomy\Facades\TaxonomyFacade::getVocabulary($vocabulary);
- $data = [];
- foreach ($term_relations as $term_relation) {
- $data[$term_relation->term->id] = $term_relation->term->name;
- }
+ if(!$vocabulary)
+ return false;
+
+ if(!$name)
+ return $this->related()->where('term_relations.vocabulary_id', $vocabulary->id)->first();
- return $data;
+ return $this ->related()
+ ->where('term_relations.vocabulary_id', $vocabulary->id)
+ ->whereHas('term', function($q) use($name) {
+ $q->where('term.name', '=', $name );
+ })
+ ->first();
}
+ /**
+ * Get all the terms for a given vocabulary that are linked to the current
+ * Model.
+ *
+ * @param $name string
+ * The name of the vocabulary
+ *
+ * @return object
+ * A collection of TermRelation objects
+ */
+ public function getTerms($vocabulary) {
+
+ $vocabulary = \Devfactory\Taxonomy\Facades\TaxonomyFacade::getVocabulary($vocabulary);
+
+ if(!$vocabulary)
+ return;
+
+ return $this->related()->where('term_relations.vocabulary_id', $vocabulary->id)->get();
+ }
+
+
/**
* Unlink the given term with the current model object
@@ -102,8 +272,9 @@ public function getTermsByVocabularyNameAsArray($name) {
* @return bool
* TRUE if the term relation has been deleted, otherwise FALSE
*/
- public function removeTerm($term_id) {
- $term_id = ($term_id instanceof Term) ? $term_id->id : $term_id;
+ public function removeTerm($term) {
+ $term_id = ($term instanceof Term) ? $term->id : $term;
+
return $this->related()->where('term_id', $term_id)->delete();
}
@@ -113,8 +284,15 @@ public function removeTerm($term_id) {
* @return bool
* TRUE if the term relation has been deleted, otherwise FALSE
*/
- public function removeAllTerms() {
- return $this->related()->delete();
+ public function removeTerms($vocabulary=false) {
+
+ $vocabulary = \Devfactory\Taxonomy\Facades\TaxonomyFacade::getVocabulary($vocabulary);
+
+ if(!$vocabulary)
+ return false;
+
+ return $this->related()->where('vocabulary_id', $vocabulary->id )->delete();
+
}
/**
@@ -125,14 +303,61 @@ public function removeAllTerms() {
*
* @return void
*/
- public function scopeGetAllByTermId($query, $term_id) {
- return $query->whereHas('related', function($q) use($term_id) {
- if (is_array($term_id)) {
- $q->whereIn('term_id', $term_id);
- }
- else {
- $q->where('term_id', '=', $term_id);
- }
- });
+ public function scopeWhereHasTerm($query, $term_id)
+ {
+
+
+ if( !is_array($term_id) )
+ {
+ return $query->whereHas('related', function($q) use($term_id)
+ {
+ $q->where('term_id', '=', $term_id );
+ });
+ }
+
+ if( method_exists($term_id,'toArray') )
+ $term_id = $term_id->toArray();
+
+ foreach ($term_id as $single_term_id)
+ {
+ $query = $query->whereHas('related', function($q) use($single_term_id)
+ {
+ $q->where('term_id', '=', $single_term_id );
+ });
+ }
+
+ return $query;
+ }
+
+ /**
+ * Filter the model to return a subset of entries matching the term ID
+ *
+ * @param object $query
+ * @param int $term_id
+ *
+ * @return void
+ */
+ public function scopeWhereHasVocabulary($query, $vocabulary_id)
+ {
+ if( !is_array($vocabulary_id) )
+ {
+ return $query->whereHas('related', function($q) use($vocabulary_id)
+ {
+ $q->where('vocabulary_id', '=', $vocabulary_id );
+ });
+ }
+
+ if( method_exists($vocabulary_id,'toArray') )
+ $vocabulary_id = $vocabulary_id->toArray();
+
+ foreach ($vocabulary_id as $single_vocabulary_id)
+ {
+ $query = $query->whereHas('related', function($q) use($single_vocabulary_id)
+ {
+ $q->where('vocabulary_id', '=', $single_vocabulary_id );
+ });
+ }
+
+ return $query;
}
}
diff --git a/src/migrations/2014_10_29_164925_create_terms_table.php b/src/migrations/2014_10_29_164925_create_terms_table.php
index 9d0d995..fe3078d 100644
--- a/src/migrations/2014_10_29_164925_create_terms_table.php
+++ b/src/migrations/2014_10_29_164925_create_terms_table.php
@@ -16,8 +16,9 @@ public function up()
$table->integer('vocabulary_id')->unsigned();
$table->foreign('vocabulary_id')->references('id')->on('vocabularies')->onDelete('cascade');
$table->string('name');
- $table->integer('parent')->unsigned();
- $table->integer('weight');
+ $table->integer('parent_id')->unsigned();
+ $table->unique(['parent_id','name']);
+ $table->integer('weight');
$table->timestamps();
});
}
diff --git a/src/migrations/2015_03_21_164940_add_description_column.php b/src/migrations/2015_03_21_164940_add_description_column.php
new file mode 100644
index 0000000..a998e54
--- /dev/null
+++ b/src/migrations/2015_03_21_164940_add_description_column.php
@@ -0,0 +1,43 @@
+string('description',1000);
+ });
+
+ //
+ Schema::table('term_relations', function ($table) {
+ $table->string('description',1000);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ //
+ Schema::table('terms', function ($table) {
+ $table->dropColumn('description');
+ });
+
+ //
+ Schema::table('term_relations', function ($table) {
+ $table->dropColumn('description');
+ });
+ }
+
+}
\ No newline at end of file