├── COPYING.txt ├── LICENSE ├── composer.json └── src ├── Acl ├── Acl.php ├── Contracts │ └── Aclable.php └── Traits │ └── HasAcl.php ├── Categories ├── Category.php ├── CategorySearcher.php ├── Column.php ├── Command │ └── CreateRootCategory.php ├── Search │ └── CategorySearch.php ├── Traits │ ├── HasCategories.php │ └── HasCategory.php └── Validation │ └── CategoryValidator.php ├── Collection.php ├── Command ├── BaseCommand.php ├── Contracts │ └── CommandInterface.php ├── Database │ ├── DropTable.php │ ├── EmptyTable.php │ └── ExecuteSQLFile.php └── FileSystem │ └── DeleteFolderRecursively.php ├── ComponentEntity.php ├── Content ├── Article.php ├── Category.php ├── Command │ └── CreateUncategorisedCategory.php ├── ContentType.php ├── Controller │ └── ArticlesController.php ├── Entity │ ├── Article.php │ └── Category.php ├── Model │ └── ArticlesModel.php ├── Search │ ├── ArticleSearch.php │ └── CategorySearch.php ├── Traits │ ├── HasArticle.php │ └── HasArticles.php └── Validation │ └── ArticleValidator.php ├── Contracts ├── AssociatedEntity.php ├── ComponentEntityInterface.php ├── EntityInterface.php └── ExceptionInterface.php ├── Core ├── Client │ ├── Administrator.php │ ├── BaseClient.php │ ├── Client.php │ ├── ClientInterface.php │ └── Site.php ├── Command │ └── CreateRootAsset.php ├── Contracts │ └── Publishable.php ├── CoreColumn.php ├── Entity │ ├── Asset.php │ └── Module.php └── Traits │ ├── HasAccess.php │ ├── HasAncestors.php │ ├── HasAsset.php │ ├── HasAssociations.php │ ├── HasChildren.php │ ├── HasClient.php │ ├── HasDescendants.php │ ├── HasEvents.php │ ├── HasFeatured.php │ ├── HasImages.php │ ├── HasInstances.php │ ├── HasLevel.php │ ├── HasLink.php │ ├── HasLinks.php │ ├── HasMetadata.php │ ├── HasParams.php │ ├── HasParent.php │ ├── HasPublishDown.php │ ├── HasPublishUp.php │ ├── HasSingleton.php │ ├── HasState.php │ └── HasUrls.php ├── Decorator.php ├── Entity.php ├── Exception ├── DeleteException.php ├── InvalidEntityData.php ├── LoadEntityDataError.php └── SaveException.php ├── Extensions └── Entity │ ├── ActiveComponent.php │ ├── Component.php │ ├── Extension.php │ └── Traits │ └── HasComponent.php ├── Fields ├── Column.php ├── Field.php ├── FieldGroup.php └── Traits │ └── HasFields.php ├── Helper ├── ArrayHelper.php └── ClassName.php ├── Installer └── DependencyInstaller.php ├── MVC ├── Controller │ ├── AdminController.php │ ├── FormController.php │ └── Traits │ │ ├── HasAssociatedEntity.php │ │ ├── HasEntityCreate.php │ │ ├── HasEntityDelete.php │ │ ├── HasEntityGet.php │ │ ├── HasEntitySave.php │ │ ├── HasEntitySearch.php │ │ └── HasEntityUpdate.php ├── JSONResponse.php ├── Model │ ├── AdminModel.php │ ├── ListModel.php │ ├── ModelWithStateInterface.php │ ├── QueryModifier │ │ ├── BaseQueryModifier.php │ │ ├── DateGreaterInColumn.php │ │ ├── DateGreaterOrEqualInColumn.php │ │ ├── DateLowerInColumn.php │ │ ├── DateLowerOrEqualInColumn.php │ │ ├── DateRangeInColumn.php │ │ ├── NotEmptyColumn.php │ │ ├── NotNullInColumn.php │ │ ├── NullInColumn.php │ │ ├── QueryModifierInterface.php │ │ ├── SearchInColumns.php │ │ ├── ValuesInColumn.php │ │ └── ValuesNotInColumn.php │ ├── State │ │ ├── Filter │ │ │ ├── BaseFilter.php │ │ │ ├── Boolean.php │ │ │ ├── Custom.php │ │ │ ├── DateFilter.php │ │ │ ├── DateRangeFilter.php │ │ │ ├── DateTimeFilter.php │ │ │ ├── Escaped.php │ │ │ ├── FilterInterface.php │ │ │ ├── Integer.php │ │ │ ├── IntegerBoolean.php │ │ │ ├── PositiveInteger.php │ │ │ ├── StringFilter.php │ │ │ └── StringQuoted.php │ │ ├── FilteredProperty.php │ │ ├── FilteredState.php │ │ ├── PopulableProperty.php │ │ ├── Property.php │ │ ├── PropertyInterface.php │ │ ├── State.php │ │ └── StateInterface.php │ └── Traits │ │ ├── HasContext.php │ │ ├── HasFilteredState.php │ │ ├── HasQueryModifiers.php │ │ └── HasSearch.php ├── Request.php ├── ResponseStatus.php └── View │ ├── FormView.php │ ├── HTMLView.php │ ├── ItemFormView.php │ ├── ItemView.php │ ├── ListView.php │ └── Traits │ └── HasAssociatedEntity.php ├── Messages └── Message.php ├── Routing └── RouteGenerator.php ├── Searcher ├── BaseSearcher.php ├── DatabaseSearcher.php └── SearcherInterface.php ├── Table ├── AbstractNestedTable.php ├── AbstractTable.php ├── TableFinder.php ├── TableInterface.php └── Traits │ ├── HasAsset.php │ ├── HasAutoEvents.php │ ├── HasCommonChecks.php │ ├── HasFixedGetProperties.php │ ├── HasInstanceName.php │ ├── HasInstancePrefix.php │ ├── HasKeysComparator.php │ └── HasLanguageStrings.php ├── Tags ├── Search │ └── TagSearch.php ├── Tag.php └── Traits │ └── HasTags.php ├── Traits ├── HasApp.php ├── HasLayoutData.php ├── HasMailer.php ├── HasMessages.php ├── HasRedirect.php └── HasStaticCache.php ├── Translation ├── Contracts │ ├── Translatable.php │ └── Translator.php ├── Traits │ └── HasTranslations.php ├── Translator.php └── TranslatorWithFallback.php ├── Users ├── AuthorUserGroup.php ├── Column.php ├── Command │ ├── CreatePredefinedUserGroups.php │ └── CreatePredefinedViewLevels.php ├── Contracts │ └── Ownerable.php ├── GuestUserGroup.php ├── GuestViewLevel.php ├── ManagerUserGroup.php ├── PredefinedUserGroup.php ├── PredefinedViewLevel.php ├── PublicUserGroup.php ├── PublicViewLevel.php ├── RegisteredUserGroup.php ├── RegisteredViewLevel.php ├── Search │ └── UserSearch.php ├── SpecialViewLevel.php ├── SuperUsersUserGroup.php ├── SuperUsersViewLevel.php ├── Traits │ ├── HasAuthor.php │ ├── HasEditor.php │ ├── HasOwner.php │ ├── HasUser.php │ ├── HasUserGroups.php │ ├── HasUsers.php │ └── HasViewLevels.php ├── User.php ├── UserGroup.php └── ViewLevel.php └── Validation ├── Contracts ├── Rule.php ├── Validable.php └── Validator.php ├── Exception └── ValidationException.php ├── Rule.php ├── Rule ├── CustomRule.php ├── IsEmptyDate.php ├── IsEmptyString.php ├── IsInteger.php ├── IsNegativeInteger.php ├── IsNotEmptyDate.php ├── IsNotEmptyString.php ├── IsNotNull.php ├── IsNull.php ├── IsNullOrEmptyString.php ├── IsNullOrPositiveInteger.php ├── IsPositiveInteger.php ├── IsString.php ├── IsZeroOrPositiveInteger.php ├── NoSubstrCount.php └── SubstrCount.php ├── Traits └── HasValidation.php └── Validator.php /COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2017 Roberto Segura López 2 | 3 | Each file included in this library is licensed under GNU LESSER GENERAL PUBLIC LICENSE 4 | 5 | See LICENSE for the full text of the GNU LESSER GENERAL PUBLIC LICENSE. 6 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phproberto/joomla-entity", 3 | "description": "Entities for Joomla!", 4 | "keywords": ["joomla", "entity", "orm"], 5 | "homepage": "https://github.com/phproberto/joomla-entity", 6 | "license": "LGPL-2.1+", 7 | "authors": [ 8 | { 9 | "name": "Roberto Segura López", 10 | "email": "roberto@phproberto.com", 11 | "homepage": "http://phproberto.com" 12 | } 13 | ], 14 | "config": { 15 | "process-timeout":0 16 | }, 17 | "require": { 18 | "php": "^7.0" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "Phproberto\\Joomla\\Entity\\": "src/" 23 | } 24 | }, 25 | "autoload-dev": { 26 | "psr-4": { 27 | "Phproberto\\Joomla\\Entity\\Tests\\": "tests/tests" 28 | } 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^4.8.35", 32 | "joomla/coding-standards": "~2.0@alpha", 33 | "squizlabs/php_codesniffer": "^2.8" 34 | }, 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "2.0-dev" 38 | } 39 | }, 40 | "scripts": { 41 | "clean" : "cd ./build && gulp clean", 42 | "copy" : "cd ./build && gulp copy", 43 | "cs" : "./vendor/bin/phpcs", 44 | "dev" : "cd ./build && gulp", 45 | "release" : "cd ./build && gulp release", 46 | "setup" : "cd ./build && npm install && cp gulp-config.dist.json gulp-config.json", 47 | "test" : "./vendor/bin/phpunit", 48 | "testFailFast" : "./vendor/bin/phpunit --stop-on-failure", 49 | "testWithCoverage" : "./vendor/bin/phpunit --coverage-html tests/coverage", 50 | "watch" : "cd ./build && gulp watch" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Acl/Contracts/Aclable.php: -------------------------------------------------------------------------------- 1 | hasId()) 53 | { 54 | return $this->component()->option() . '.' . $this->name() . '.' . $this->id(); 55 | } 56 | 57 | return $this->component()->option(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Categories/CategorySearcher.php: -------------------------------------------------------------------------------- 1 | 0, 36 | 'rgt' => 1, 37 | 'level' => 0, 38 | 'extension' => $db->q('system'), 39 | 'title' => $db->q('ROOT'), 40 | 'alias' => $db->q('root'), 41 | 'published' => 1, 42 | 'access' => 1 43 | ]; 44 | 45 | $query = $db->getQuery(true) 46 | ->insert($db->qn('#__categories')) 47 | ->columns(array_keys($data)) 48 | ->values(implode(',', array_values($data))); 49 | 50 | $db->setQuery($query); 51 | 52 | if (!$db->execute()) 53 | { 54 | throw new \RuntimeException("Error creating root category: " . $db->stderr(true)); 55 | } 56 | 57 | return Category::find($db->insertid()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Categories/Traits/HasCategories.php: -------------------------------------------------------------------------------- 1 | categories) 39 | { 40 | $this->categories = $this->loadCategories(); 41 | } 42 | 43 | return $this->categories; 44 | } 45 | 46 | /** 47 | * Clear already loaded categories. 48 | * 49 | * @return self 50 | */ 51 | public function clearCategories() 52 | { 53 | $this->categories = null; 54 | 55 | return $this; 56 | } 57 | 58 | /** 59 | * Check if this entity has an associated category. 60 | * 61 | * @param integer $id Category identifier 62 | * 63 | * @return boolean 64 | */ 65 | public function hasCategory($id) 66 | { 67 | return $this->categories()->has($id); 68 | } 69 | 70 | /** 71 | * Check if this entity has associated categories. 72 | * 73 | * @return boolean 74 | */ 75 | public function hasCategories() 76 | { 77 | return !$this->categories()->isEmpty(); 78 | } 79 | 80 | /** 81 | * Load associated categories from DB. 82 | * 83 | * @return Collection 84 | */ 85 | abstract protected function loadCategories(); 86 | } 87 | -------------------------------------------------------------------------------- /src/Categories/Validation/CategoryValidator.php: -------------------------------------------------------------------------------- 1 | addRules( 34 | [ 35 | 'access' => new Rule\IsNullOrPositiveInteger('Valid view level identifier'), 36 | 'extension' => new Rule\IsNotEmptyString('Not empty extension'), 37 | 'level' => new Rule\IsNullOrPositiveInteger('Valid level'), 38 | 'parent_id' => new Rule\IsNullOrPositiveInteger('Valid parent'), 39 | 'title' => new Rule\IsNotEmptyString('Not empty title') 40 | ] 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Command/BaseCommand.php: -------------------------------------------------------------------------------- 1 | config = new Registry($options); 37 | } 38 | 39 | /** 40 | * Factory method. 41 | * 42 | * @param array $arguments Arguments for the instance. 43 | * 44 | * @return static 45 | */ 46 | public static function instance(array $arguments = []) 47 | { 48 | return (new \ReflectionClass(get_called_class()))->newInstanceArgs($arguments); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Command/Contracts/CommandInterface.php: -------------------------------------------------------------------------------- 1 | tableName = $name; 47 | $this->db = isset($options['db']) ? $options['db'] : Factory::getDbo(); 48 | 49 | unset($options['db']); 50 | 51 | parent::__construct($options); 52 | } 53 | 54 | /** 55 | * Execute the command. 56 | * 57 | * @return mixed 58 | */ 59 | public function execute() 60 | { 61 | try 62 | { 63 | $result = $this->db->dropTable($this->tableName); 64 | } 65 | catch (\RuntimeException $e) 66 | { 67 | throw new \RuntimeException(sprintf('Error dropping DB table `%s`: %s', $this->tableName, $e->getMessage())); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Command/Database/EmptyTable.php: -------------------------------------------------------------------------------- 1 | tableName = $name; 47 | $this->db = isset($options['db']) ? $options['db'] : Factory::getDbo(); 48 | 49 | unset($options['db']); 50 | 51 | parent::__construct($options); 52 | } 53 | 54 | /** 55 | * Execute the command. 56 | * 57 | * @return mixed 58 | */ 59 | public function execute() 60 | { 61 | try 62 | { 63 | $query = $this->db->getQuery(true) 64 | ->delete($this->db->qn($this->tableName)); 65 | 66 | $this->db->setQuery($query); 67 | $this->db->execute(); 68 | } 69 | catch (\RuntimeException $e) 70 | { 71 | throw new \RuntimeException(sprintf('Error emptying DB table `%s`: %s', $this->tableName, $e->getMessage())); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Command/Database/ExecuteSQLFile.php: -------------------------------------------------------------------------------- 1 | file = $filePath; 47 | $this->db = isset($options['db']) ? $options['db'] : Factory::getDbo(); 48 | 49 | unset($options['db']); 50 | 51 | parent::__construct($options); 52 | } 53 | 54 | /** 55 | * Execute the command. 56 | * 57 | * @return mixed 58 | */ 59 | public function execute() 60 | { 61 | $sql = file_get_contents($this->file); 62 | 63 | foreach ($this->db->splitSql($sql) as $query) 64 | { 65 | try 66 | { 67 | $this->db->setQuery($query)->execute(); 68 | } 69 | catch (\Exception $e) 70 | { 71 | // If the query fails we will go on. It just means the index to be dropped does not exist. 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Command/FileSystem/DeleteFolderRecursively.php: -------------------------------------------------------------------------------- 1 | folder = trim($folder); 39 | 40 | parent::__construct($options); 41 | } 42 | 43 | /** 44 | * Execute the command. 45 | * 46 | * @return boolean 47 | */ 48 | public function execute() 49 | { 50 | if (!is_dir($this->folder)) 51 | { 52 | return true; 53 | } 54 | 55 | $files = glob($this->folder . '/*'); 56 | 57 | foreach ($files as $file) 58 | { 59 | if (is_dir($file)) 60 | { 61 | self::instance([$file])->execute(); 62 | 63 | continue; 64 | } 65 | 66 | if (!@unlink($file)) 67 | { 68 | $error = sprintf("Error deleting file: `%s`", $file); 69 | 70 | throw new \RuntimeException($error); 71 | } 72 | } 73 | 74 | if (!rmdir($this->folder)) 75 | { 76 | $error = sprintf("Error deleting folder: `%s`", $this->folder); 77 | 78 | throw new \RuntimeException($error); 79 | } 80 | 81 | return true; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/ComponentEntity.php: -------------------------------------------------------------------------------- 1 | component()->tablesFolder()); 44 | } 45 | catch (\Exception $e) 46 | { 47 | // Avoid folder not found exceptions and hope joomla resolves the table 48 | } 49 | 50 | return parent::table($name, $prefix, $options); 51 | } 52 | 53 | /** 54 | * Associated table prefix. 55 | * 56 | * @return string 57 | * 58 | * @since __DEPLOY_VERSION__ 59 | */ 60 | public function tablePrefix() 61 | { 62 | return $this->component()->prefix(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Content/Article.php: -------------------------------------------------------------------------------- 1 | 'Uncategorised', 35 | 'alias' => 'uncategorised', 36 | 'parent_id' => Category::root()->id() 37 | ] 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Content/Controller/ArticlesController.php: -------------------------------------------------------------------------------- 1 | db; 32 | 33 | $query = parent::searchQuery() 34 | ->where($db->qn('c.extension') . ' = ' . $db->q('com_content')); 35 | 36 | // Filter: tag 37 | if (null !== $this->options->get('filter.tag_id')) 38 | { 39 | $tagIds = ArrayHelper::toInteger((array) $this->options->get('filter.tag_id')); 40 | 41 | $query->leftJoin( 42 | $db->quoteName('#__contentitem_tag_map', 'tagmap') 43 | . ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('c.id') 44 | . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote(Category::contentTypeAlias()) 45 | )->where($db->qn('tagmap.tag_id') . ' IN(' . implode(',', $tagIds) . ')'); 46 | } 47 | 48 | return $query; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Content/Traits/HasArticle.php: -------------------------------------------------------------------------------- 1 | article) 46 | { 47 | $this->article = $this->loadArticle(); 48 | } 49 | 50 | return $this->article; 51 | } 52 | 53 | /** 54 | * Get the name of the column that stores article. 55 | * 56 | * @return string 57 | */ 58 | protected function getColumnArticle() 59 | { 60 | return 'article_id'; 61 | } 62 | 63 | /** 64 | * Check if this entity has an associated article. 65 | * 66 | * @return boolean 67 | */ 68 | public function hasArticle() 69 | { 70 | return $this->getArticle()->hasId(); 71 | } 72 | 73 | /** 74 | * Load the article from the database. 75 | * 76 | * @return Article 77 | */ 78 | protected function loadArticle() 79 | { 80 | $column = $this->getColumnArticle(); 81 | $data = $this->all(); 82 | 83 | if (array_key_exists($column, $data)) 84 | { 85 | return Article::find($data[$column]); 86 | } 87 | 88 | return new Article; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Content/Traits/HasArticles.php: -------------------------------------------------------------------------------- 1 | articles = null; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Get the associated articles. 43 | * 44 | * @param boolean $reload Force data reloading 45 | * 46 | * @return Collection 47 | */ 48 | public function articles($reload = false) 49 | { 50 | if ($reload || null === $this->articles) 51 | { 52 | $this->articles = $this->loadArticles(); 53 | } 54 | 55 | return $this->articles; 56 | } 57 | 58 | /** 59 | * Check if this entity has an associated article. 60 | * 61 | * @param integer $id Article identifier 62 | * 63 | * @return boolean 64 | */ 65 | public function hasArticle($id) 66 | { 67 | return $this->articles()->has($id); 68 | } 69 | 70 | /** 71 | * Check if this entity has associated articles. 72 | * 73 | * @return boolean 74 | */ 75 | public function hasArticles() 76 | { 77 | return !$this->articles()->isEmpty(); 78 | } 79 | 80 | /** 81 | * Load associated articles from DB. 82 | * 83 | * @return Collection 84 | */ 85 | abstract protected function loadArticles(); 86 | } 87 | -------------------------------------------------------------------------------- /src/Content/Validation/ArticleValidator.php: -------------------------------------------------------------------------------- 1 | addRules( 34 | [ 35 | 'title' => new Rule\IsNotEmptyString('Not empty title'), 36 | 'catid' => new Rule\IsPositiveInteger('Valid category identifier'), 37 | 'access' => new Rule\IsNullOrPositiveInteger('Valid view level identifier') 38 | ] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Contracts/AssociatedEntity.php: -------------------------------------------------------------------------------- 1 | id = static::ID; 33 | } 34 | 35 | /** 36 | * Get client identifier. 37 | * 38 | * @return integer 39 | */ 40 | public function getId() 41 | { 42 | return $this->id; 43 | } 44 | 45 | /** 46 | * Get client name 47 | * 48 | * @return string 49 | */ 50 | public function getName() 51 | { 52 | return static::NAME; 53 | } 54 | 55 | /** 56 | * Is this admin client? 57 | * 58 | * @return boolean 59 | */ 60 | public function isAdmin() 61 | { 62 | return $this->id === Administrator::ID; 63 | } 64 | 65 | /** 66 | * Is this site client? 67 | * 68 | * @return boolean 69 | */ 70 | public function isSite() 71 | { 72 | return $this->id === Site::ID; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Core/Client/Client.php: -------------------------------------------------------------------------------- 1 | isAdmin() ? self::admin() : self::site(); 28 | } 29 | 30 | /** 31 | * Retrieve admin client. 32 | * 33 | * @return Admin 34 | */ 35 | public static function admin() 36 | { 37 | return new Administrator; 38 | } 39 | 40 | /** 41 | * Retrieve site client. 42 | * 43 | * @return Site 44 | */ 45 | public static function site() 46 | { 47 | return new Site; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Core/Client/ClientInterface.php: -------------------------------------------------------------------------------- 1 | 0, 36 | 'rgt' => 1, 37 | 'level' => 0, 38 | 'name' => $db->q('root.1'), 39 | 'title' => $db->q('Root Asset'), 40 | 'rules' => $db->q( 41 | '{' 42 | . '"core.login.site":{"6":1,"2":1},"core.login.admin":{"6":1},"core.login.offline":{"6":1},' 43 | . '"core.admin":{"8":1},"core.manage":{"7":1},"core.create":{"6":1,"3":1},"core.delete":{"6":1},' 44 | . '"core.edit":{"6":1,"4":1},"core.edit.state":{"6":1,"5":1},"core.edit.own":{"6":1,"3":1}' 45 | . '}' 46 | ) 47 | ]; 48 | 49 | $query = $db->getQuery(true) 50 | ->insert($db->qn('#__assets')) 51 | ->columns(array_keys($data)) 52 | ->values(implode(',', array_values($data))); 53 | 54 | $db->setQuery($query); 55 | 56 | if (!$db->execute()) 57 | { 58 | throw new \RuntimeException("Error creating root asset: " . $db->stderr(true)); 59 | } 60 | 61 | return Asset::find($db->insertid()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Core/Contracts/Publishable.php: -------------------------------------------------------------------------------- 1 | 0]); 70 | 71 | static::$root = $root->isLoaded() ? $root : CreateRootAsset::instance()->execute(); 72 | 73 | return static::$root; 74 | } 75 | 76 | /** 77 | * Get a table. 78 | * 79 | * @param string $name The table name. Optional. 80 | * @param string $prefix The class prefix. Optional. 81 | * @param array $options Configuration array for model. Optional. 82 | * 83 | * @return \JTable 84 | * 85 | * @codeCoverageIgnore 86 | */ 87 | public function table($name = '', $prefix = null, $options = array()) 88 | { 89 | $name = $name ?: 'Asset'; 90 | $prefix = $prefix ?: 'JTable'; 91 | 92 | return parent::table($name, $prefix, $options); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Core/Traits/HasAncestors.php: -------------------------------------------------------------------------------- 1 | ancestors()->get($id); 35 | } 36 | 37 | /** 38 | * Get the Ascendants of an entity. 39 | * 40 | * @return Collection 41 | */ 42 | public function ancestors() 43 | { 44 | return $this->searchAncestors(); 45 | } 46 | 47 | /** 48 | * Check if this entity has a specific ancestor. 49 | * 50 | * @param int $id Ascendant identifier 51 | * 52 | * @return boolean 53 | */ 54 | public function hasAncestor($id) 55 | { 56 | return $this->ancestors()->has($id); 57 | } 58 | 59 | /** 60 | * Check if this entity has ancestors. 61 | * 62 | * @return boolean 63 | */ 64 | public function hasAncestors() 65 | { 66 | return !$this->ancestors()->isEmpty(); 67 | } 68 | 69 | /** 70 | * Search entity ancestors. 71 | * 72 | * @param array $options Search options. For filters, limit, ordering, etc. 73 | * 74 | * @return Collection 75 | */ 76 | abstract public function searchAncestors(array $options = []); 77 | } 78 | -------------------------------------------------------------------------------- /src/Core/Traits/HasAsset.php: -------------------------------------------------------------------------------- 1 | asset) 59 | { 60 | $this->asset = $this->loadAsset(); 61 | } 62 | 63 | return $this->asset; 64 | } 65 | 66 | /** 67 | * Load the asset from the database. 68 | * 69 | * @return Asset 70 | */ 71 | protected function loadAsset() 72 | { 73 | try 74 | { 75 | $assetId = (int) $this->get($this->columnAlias(CoreColumn::ASSET)); 76 | } 77 | catch (\Exception $e) 78 | { 79 | $assetId = 0; 80 | } 81 | 82 | return $assetId ? Asset::find($assetId) : new Asset; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Core/Traits/HasChildren.php: -------------------------------------------------------------------------------- 1 | children()->get($id); 35 | } 36 | 37 | /** 38 | * Get the children of this entity. 39 | * 40 | * @return Collection 41 | */ 42 | public function children() 43 | { 44 | return $this->searchChildren(); 45 | } 46 | 47 | /** 48 | * Check if this entity has an specific child. 49 | * 50 | * @param int $id Ascendant identifier 51 | * 52 | * @return boolean 53 | */ 54 | public function hasChild($id) 55 | { 56 | return $this->children()->has($id); 57 | } 58 | 59 | /** 60 | * Check if this entity has children. 61 | * 62 | * @return boolean 63 | */ 64 | public function hasChildren() 65 | { 66 | return !$this->children()->isEmpty(); 67 | } 68 | 69 | /** 70 | * Search entity children. 71 | * 72 | * @param array $options Search options. For filters, limit, ordering, etc. 73 | * 74 | * @return Collection 75 | */ 76 | abstract public function searchChildren(array $options = []); 77 | } 78 | -------------------------------------------------------------------------------- /src/Core/Traits/HasClient.php: -------------------------------------------------------------------------------- 1 | client = new Administrator; 41 | 42 | return $this; 43 | } 44 | 45 | /** 46 | * Get the associated client. 47 | * 48 | * @param boolean $reload Force reloading 49 | * 50 | * @return ClientInterface 51 | */ 52 | public function client($reload = false) 53 | { 54 | if ($reload || null === $this->client) 55 | { 56 | $this->client = $this->loadClient(); 57 | } 58 | 59 | return $this->client; 60 | } 61 | 62 | /** 63 | * Load the client from the database. 64 | * 65 | * @return Category 66 | */ 67 | protected function loadClient() 68 | { 69 | $clientId = (int) $this->get($this->columnAlias(CoreColumn::CLIENT)); 70 | 71 | return $clientId ? Client::admin() : Client::site(); 72 | } 73 | 74 | /** 75 | * Switch to site client. 76 | * 77 | * @return self 78 | */ 79 | public function site() 80 | { 81 | $this->client = new Site; 82 | 83 | return $this; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Core/Traits/HasDescendants.php: -------------------------------------------------------------------------------- 1 | descendants()->get($id); 35 | } 36 | 37 | /** 38 | * Get the descendants of this entity. 39 | * 40 | * @return Collection 41 | */ 42 | public function descendants() 43 | { 44 | return $this->searchDescendants(); 45 | } 46 | 47 | /** 48 | * Check if this entity has an specific descendant. 49 | * 50 | * @param int $id Ascendant identifier 51 | * 52 | * @return boolean 53 | */ 54 | public function hasDescendant($id) 55 | { 56 | return $this->descendants()->has($id); 57 | } 58 | 59 | /** 60 | * Check if this entity has descendants. 61 | * 62 | * @return boolean 63 | */ 64 | public function hasDescendants() 65 | { 66 | return !$this->descendants()->isEmpty(); 67 | } 68 | 69 | /** 70 | * Search entity descendants. 71 | * 72 | * @param array $options Search options. For filters, limit, ordering, etc. 73 | * 74 | * @return Collection 75 | */ 76 | abstract public function searchDescendants(array $options = []); 77 | } 78 | -------------------------------------------------------------------------------- /src/Core/Traits/HasFeatured.php: -------------------------------------------------------------------------------- 1 | get($this->columnAlias(CoreColumn::FEATURED)); 56 | 57 | return $featured ? true : false; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Core/Traits/HasInstances.php: -------------------------------------------------------------------------------- 1 | link) 44 | { 45 | $this->link = $this->loadLink(); 46 | } 47 | 48 | return $this->link; 49 | } 50 | 51 | /** 52 | * Get the URL slug. 53 | * 54 | * @return string 55 | */ 56 | public function slug() 57 | { 58 | $slug = $this->id(); 59 | 60 | if (!$slug) 61 | { 62 | return null; 63 | } 64 | 65 | if ($this->has('alias')) 66 | { 67 | $slug .= ':' . $this->get('alias'); 68 | } 69 | 70 | return $slug; 71 | } 72 | 73 | /** 74 | * Load the link to this entity. 75 | * 76 | * @return string 77 | */ 78 | abstract protected function loadLink(); 79 | } 80 | -------------------------------------------------------------------------------- /src/Core/Traits/HasMetadata.php: -------------------------------------------------------------------------------- 1 | metadata) 57 | { 58 | $this->metadata = $this->json($this->columnAlias(CoreColumn::METADATA)); 59 | } 60 | 61 | return $this->metadata; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Core/Traits/HasParent.php: -------------------------------------------------------------------------------- 1 | parentId() > 0; 40 | } 41 | 42 | /** 43 | * Load the parent entity. 44 | * 45 | * @return EntityInterface 46 | */ 47 | protected function loadParent() 48 | { 49 | $column = $this->parentColumn(); 50 | $data = $this->all(); 51 | 52 | if (empty($data[$column])) 53 | { 54 | return new static; 55 | } 56 | 57 | return static::find($data[$column]); 58 | } 59 | 60 | /** 61 | * Retrieve the parent entity. 62 | * 63 | * @return EntityInterface 64 | */ 65 | public function parent() 66 | { 67 | if (null === $this->parent) 68 | { 69 | $this->parent = $this->loadParent(); 70 | } 71 | 72 | return $this->parent; 73 | } 74 | 75 | /** 76 | * Retrieve parent identifier. 77 | * 78 | * @return integer 79 | */ 80 | public function parentId() 81 | { 82 | $column = $this->parentColumn(); 83 | 84 | if (!$this->has($column)) 85 | { 86 | return 0; 87 | } 88 | 89 | return (int) $this->get($column); 90 | } 91 | 92 | /** 93 | * Column used to store the parent identifier. 94 | * 95 | * @return string 96 | */ 97 | public function parentColumn() 98 | { 99 | return $this->columnAlias(CoreColumn::PARENT); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Core/Traits/HasPublishDown.php: -------------------------------------------------------------------------------- 1 | get($this->columnAlias(CoreColumn::PUBLISH_DOWN)); 39 | } 40 | 41 | /** 42 | * Has this entity a publish down date? 43 | * 44 | * @return boolean 45 | */ 46 | public function hasPublishDown() 47 | { 48 | $publishDown = $this->getPublishDown(); 49 | 50 | return !empty($publishDown) && $publishDown !== $this->nullDate(); 51 | } 52 | 53 | /** 54 | * Check if this entity is published down. 55 | * 56 | * @return boolean 57 | */ 58 | public function isPublishedDown() 59 | { 60 | if (!$this->hasPublishDown()) 61 | { 62 | return false; 63 | } 64 | 65 | return \JFactory::getDate($this->getPublishDown()) <= \JFactory::getDate(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Core/Traits/HasPublishUp.php: -------------------------------------------------------------------------------- 1 | get($this->columnAlias(CoreColumn::PUBLISH_UP)); 39 | } 40 | 41 | /** 42 | * Has this entity a publish up date? 43 | * 44 | * @return boolean 45 | */ 46 | public function hasPublishUp() 47 | { 48 | $publishUp = $this->getPublishUp(); 49 | 50 | return !empty($publishUp) && $publishUp !== $this->nullDate(); 51 | } 52 | 53 | /** 54 | * Check if this entity is published up. 55 | * 56 | * @return boolean 57 | */ 58 | public function isPublishedUp() 59 | { 60 | if (!$this->hasPublishUp()) 61 | { 62 | return true; 63 | } 64 | 65 | return \JFactory::getDate($this->getPublishUp()) <= \JFactory::getDate(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Core/Traits/HasSingleton.php: -------------------------------------------------------------------------------- 1 | entity = $entity; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Exception/DeleteException.php: -------------------------------------------------------------------------------- 1 | %s", $entity->name() . '::' . $entity->id(), $table->getError()); 34 | 35 | return new static($msg, 500); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Exception/InvalidEntityData.php: -------------------------------------------------------------------------------- 1 | id() . '`) is empty.', 500); 33 | } 34 | 35 | /** 36 | * Data is empty. 37 | * 38 | * @param EntityInterface $entity Entity with empty data 39 | * 40 | * @return static 41 | */ 42 | public static function missingPrimaryKey(EntityInterface $entity) 43 | { 44 | return new static( 45 | 'Data for entity ' . get_class($entity) . ' (id: `' . $entity->id() . '`)' 46 | . ' does not contain primary key (column: ' . $entity->primaryKey() . ')', 47 | 500 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Exception/LoadEntityDataError.php: -------------------------------------------------------------------------------- 1 | id() . '`) data: ' . $error, 500); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Exception/SaveException.php: -------------------------------------------------------------------------------- 1 | hasId()) 35 | { 36 | $msg = sprintf("Save failed trying to create `%s`:
%s", $entity->name(), $table->getError()); 37 | 38 | return new static($msg, 500); 39 | } 40 | 41 | $msg = sprintf("Save failed trying to save `%s`:
%s", $entity->name() . '::' . $entity->id(), $table->getError()); 42 | 43 | return new static($msg, 500); 44 | } 45 | 46 | /** 47 | * Entity did not pass validation. 48 | * 49 | * @param EntityInterface $entity Entity with empty data 50 | * @param ValidationException $exception Validation exception 51 | * 52 | * @return static 53 | */ 54 | public static function validation(EntityInterface $entity, ValidationException $exception) 55 | { 56 | if (!$entity->hasId()) 57 | { 58 | $msg = sprintf("Validation failed trying to create `%s`:
%s", $entity->name(), $exception->getMessage()); 59 | 60 | return new static($msg, 500); 61 | } 62 | 63 | $msg = sprintf("Validation failed trying to save `%s`:
%s", $entity->name() . '::' . $entity->id(), $exception->getMessage()); 64 | 65 | return new static($msg, 500); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Extensions/Entity/ActiveComponent.php: -------------------------------------------------------------------------------- 1 | option(); 34 | 35 | if (!$option) 36 | { 37 | throw new \RuntimeException('Unable to detect active component option'); 38 | } 39 | 40 | $table = $this->table(); 41 | 42 | if (!$table->load(array('element' => $option, 'type' => 'component'))) 43 | { 44 | throw LoadEntityDataError::tableError($this, $table->getError()); 45 | } 46 | 47 | $data = $table->getProperties(true); 48 | 49 | if (!array_key_exists($this->primaryKey(), $data)) 50 | { 51 | throw InvalidEntityData::missingPrimaryKey($this); 52 | } 53 | 54 | $this->id = (int) $data[$this->primaryKey()]; 55 | 56 | return $data; 57 | } 58 | 59 | /** 60 | * Get the active option. 61 | * 62 | * @return string 63 | */ 64 | public function option() 65 | { 66 | return \JApplicationHelper::getComponentName(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Extensions/Entity/Traits/HasComponent.php: -------------------------------------------------------------------------------- 1 | component) 44 | { 45 | $this->component = $this->loadComponent(); 46 | } 47 | 48 | return $this->component; 49 | } 50 | 51 | /** 52 | * Try to guess component option from class prefix 53 | * 54 | * @return mixed null (not found) | string (found) 55 | */ 56 | protected function componentOption() 57 | { 58 | if (null === $this->componentOption) 59 | { 60 | $this->componentOption = $this->componentOptionFromClass(); 61 | } 62 | 63 | return $this->componentOption; 64 | } 65 | 66 | /** 67 | * Try to guess component option from class. 68 | * 69 | * @return string 70 | */ 71 | protected function componentOptionFromClass() 72 | { 73 | $class = get_class($this); 74 | 75 | if (false !== strpos($class, '\\')) 76 | { 77 | $suffix = rtrim(strstr($class, 'Entity'), '\\'); 78 | $parts = explode("\\", $suffix); 79 | 80 | return array_key_exists(1, $parts) ? 'com_' . strtolower($parts[1]) : null; 81 | } 82 | 83 | return 'com_' . strtolower(strstr($class, 'Entity', true)); 84 | } 85 | 86 | /** 87 | * Load associated component 88 | * 89 | * @return Component 90 | * 91 | * @throws \InvalidArgumentException Wrong option received 92 | * @throws \RuntimeException Component not found 93 | */ 94 | protected function loadComponent() 95 | { 96 | return Component::fromOption($this->componentOption()); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Fields/Column.php: -------------------------------------------------------------------------------- 1 | hasId()) 39 | { 40 | return $fields; 41 | } 42 | 43 | $db = $this->getDbo(); 44 | $query = $db->getQuery(true) 45 | ->select('f.*') 46 | ->from($db->qn('#__fields', 'f')) 47 | ->where($db->qn('f.group_id') . ' = ' . (int) $this->id()); 48 | 49 | $db->setQuery($query); 50 | 51 | $items = $db->loadObjectList() ?: []; 52 | 53 | foreach ($items as $item) 54 | { 55 | $field = Field::find($item->id)->bind($item); 56 | 57 | $fields->add($field); 58 | } 59 | 60 | return $fields; 61 | } 62 | 63 | /** 64 | * Get a table instance. Defauts to \JTableUser. 65 | * 66 | * @param string $name Table name. Optional. 67 | * @param string $prefix Class prefix. Optional. 68 | * @param array $options Configuration array for the table. Optional. 69 | * 70 | * @return \JTable 71 | * 72 | * @throws \InvalidArgumentException 73 | */ 74 | public function table($name = '', $prefix = null, $options = array()) 75 | { 76 | $name = $name ?: 'Group'; 77 | $prefix = $prefix ?: 'FieldsTable'; 78 | 79 | if ($prefix === 'FieldsTable') 80 | { 81 | return $this->component()->table($name); 82 | } 83 | 84 | return parent::table($name, $prefix, $options); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Helper/ArrayHelper.php: -------------------------------------------------------------------------------- 1 | 0; 36 | } 37 | ) 38 | ) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Helper/ClassName.php: -------------------------------------------------------------------------------- 1 | inNamespace(); 33 | } 34 | 35 | /** 36 | * Retrieve class namespace. 37 | * 38 | * @param object $class Class instance 39 | * 40 | * @return string 41 | */ 42 | public static function namespace($class): string 43 | { 44 | return (new \ReflectionClass($class))->getNamespaceName(); 45 | } 46 | 47 | /** 48 | * Get the namespace parts. 49 | * 50 | * @param object $class Class instance 51 | * 52 | * @return string[] 53 | */ 54 | public static function namespaceParts($class): array 55 | { 56 | return explode('\\', self::namespace($class)); 57 | } 58 | 59 | /** 60 | * Guess the entity class 61 | * 62 | * @param object $class Class instance 63 | * 64 | * @return string 65 | */ 66 | public static function parentNamespace($class): string 67 | { 68 | $namespace = self::namespace($class); 69 | 70 | return substr($namespace, 0, strrpos($namespace, '\\')); 71 | } 72 | 73 | /** 74 | * Retrieve class name without namespace. 75 | * 76 | * @param object $class Class instance 77 | * 78 | * @return string 79 | */ 80 | public static function withoutNamespace($class): string 81 | { 82 | return (new \ReflectionClass($class))->getShortName(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/MVC/Controller/AdminController.php: -------------------------------------------------------------------------------- 1 | modelPrefix) 41 | { 42 | $this->{'model_prefix'} = $this->modelPrefix; 43 | } 44 | 45 | parent::__construct($config); 46 | } 47 | 48 | /** 49 | * Gets the name of the latest extending class. 50 | * For a class named ContentControllerArticles will return Articles 51 | * 52 | * @return string 53 | */ 54 | public function instanceName() 55 | { 56 | $class = get_class($this); 57 | 58 | if (false !== strpos($class, '\\')) 59 | { 60 | return (new \ReflectionClass($this))->getShortName(); 61 | } 62 | 63 | $name = strstr($class, 'Controller'); 64 | $name = str_replace('Controller', '', $name); 65 | 66 | return strtolower($name); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/MVC/Controller/FormController.php: -------------------------------------------------------------------------------- 1 | getShortName(); 46 | } 47 | 48 | $name = strstr($class, 'Controller'); 49 | $name = str_replace('Controller', '', $name); 50 | 51 | return strtolower($name); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/MVC/Model/ModelWithStateInterface.php: -------------------------------------------------------------------------------- 1 | callback = $callback; 45 | $this->query = $query; 46 | } 47 | 48 | /** 49 | * Execute the callback. 50 | * 51 | * @return void 52 | */ 53 | protected function callback() 54 | { 55 | if ($this->callback) 56 | { 57 | call_user_func_array($this->callback, array($this->query)); 58 | } 59 | } 60 | 61 | /** 62 | * Isolated factory communication to ease testing. 63 | * 64 | * @return \JDatabaseDriver 65 | * 66 | * @codeCoverageIgnore 67 | */ 68 | protected function getDbo() 69 | { 70 | return Factory::getDbo(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/DateGreaterInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $this->query->where(sprintf('%s > %s', $db->qn($this->column), $value)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/DateGreaterOrEqualInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $this->query->where(sprintf('%s >= %s', $db->qn($this->column), $value)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/DateLowerInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $this->query->where(sprintf('%s < %s', $db->qn($this->column), $value)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/DateLowerOrEqualInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $this->query->where(sprintf('%s <= %s', $db->qn($this->column), $value)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/DateRangeInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $dates = array_filter( 69 | explode(' - ', $value), 70 | function ($date) 71 | { 72 | $format = "/^'([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])'/"; 73 | 74 | return preg_match($format, $date); 75 | } 76 | ); 77 | 78 | if (count($dates) != 2) 79 | { 80 | continue; 81 | } 82 | 83 | $this->query->where(sprintf('%s >= %s', $db->qn($this->column), $dates[0])); 84 | $this->query->where(sprintf('%s <= %s', $db->qn($this->column), $dates[1])); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/NotEmptyColumn.php: -------------------------------------------------------------------------------- 1 | column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | $this->callback(); 58 | 59 | $db = $this->getDbo(); 60 | 61 | $values = array_map([$db, 'quote'], $this->emptyValues); 62 | 63 | $this->query->where($db->qn($this->column) . ' IS NOT NULL') 64 | ->where($db->qn($this->column) . ' NOT IN (' . implode(', ', $values) . ')'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/NotNullInColumn.php: -------------------------------------------------------------------------------- 1 | column = $column; 39 | } 40 | 41 | /** 42 | * Apply the query filter. 43 | * 44 | * @return void 45 | */ 46 | public function apply() 47 | { 48 | $this->callback(); 49 | 50 | $db = $this->getDbo(); 51 | 52 | $this->query->where($db->qn($this->column) . ' IS NOT NULL'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/NullInColumn.php: -------------------------------------------------------------------------------- 1 | column = $column; 39 | } 40 | 41 | /** 42 | * Apply the query filter. 43 | * 44 | * @return void 45 | */ 46 | public function apply() 47 | { 48 | $this->callback(); 49 | 50 | $db = $this->getDbo(); 51 | 52 | $this->query->where($db->qn($this->column) . ' IS NULL'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/QueryModifierInterface.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->columns = $columns; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | foreach ($this->values as $value) 67 | { 68 | $like = $db->quote('%' . trim($value, "'") . '%'); 69 | $whereParts = array(); 70 | 71 | foreach ($this->columns as $column) 72 | { 73 | $whereParts[] = sprintf('%s', $db->qn($column) . ' LIKE ' . $like); 74 | } 75 | 76 | $where = sprintf('(%s)', implode(' OR ', $whereParts)); 77 | 78 | $this->query->where($where); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/ValuesInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 47 | $this->column = $column; 48 | } 49 | 50 | /** 51 | * Apply the query filter. 52 | * 53 | * @return void 54 | */ 55 | public function apply() 56 | { 57 | if (!$this->values) 58 | { 59 | return; 60 | } 61 | 62 | $this->callback(); 63 | 64 | $db = $this->getDbo(); 65 | 66 | if (count($this->values) == 1) 67 | { 68 | $this->query->where($db->qn($this->column) . ' = ' . reset($this->values)); 69 | 70 | return; 71 | } 72 | 73 | $this->query->where($db->qn($this->column) . ' IN (' . implode(',', $this->values) . ')'); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/MVC/Model/QueryModifier/ValuesNotInColumn.php: -------------------------------------------------------------------------------- 1 | values = $values; 33 | $this->column = $column; 34 | } 35 | 36 | /** 37 | * Apply the query filter. 38 | * 39 | * @return void 40 | */ 41 | public function apply() 42 | { 43 | if (!$this->values) 44 | { 45 | return; 46 | } 47 | 48 | $this->callback(); 49 | 50 | $db = $this->getDbo(); 51 | 52 | if (count($this->values) == 1) 53 | { 54 | $this->query->where($db->qn($this->column) . ' <> ' . reset($this->values)); 55 | 56 | return; 57 | } 58 | 59 | $this->query->where($db->qn($this->column) . ' NOT IN (' . implode(',', $this->values) . ')'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/Boolean.php: -------------------------------------------------------------------------------- 1 | filterValueFunction = $filterValueFunction; 46 | $this->prepareValueFunction = $prepareValueFunction; 47 | } 48 | 49 | /** 50 | * Determine if a value will be used or not. 51 | * 52 | * @param mixed $value Value to filter 53 | * 54 | * @return boolean 55 | */ 56 | protected function filterValue($value) 57 | { 58 | return call_user_func($this->filterValueFunction, $value); 59 | } 60 | 61 | /** 62 | * Prepare value. 63 | * 64 | * @param mixed $value Value to prepare 65 | * 66 | * @return mixed 67 | */ 68 | public function prepareValue($value) 69 | { 70 | $value = parent::prepareValue($value); 71 | 72 | if (!$this->prepareValueFunction) 73 | { 74 | return $value; 75 | } 76 | 77 | return call_user_func($this->prepareValueFunction, $value); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/DateFilter.php: -------------------------------------------------------------------------------- 1 | 0; 40 | } 41 | 42 | /** 43 | * Prepare value. 44 | * 45 | * @param mixed $value Value to prepare 46 | * 47 | * @return mixed 48 | */ 49 | public function prepareValue($value) 50 | { 51 | $value = parent::prepareValue($value); 52 | 53 | if (!is_string($value) && !is_numeric($value)) 54 | { 55 | return null; 56 | } 57 | 58 | return (string) $value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/DateRangeFilter.php: -------------------------------------------------------------------------------- 1 | 0 && $test[4] > 0 && $test[4] > $test[1]; 40 | } 41 | 42 | /** 43 | * Prepare value. 44 | * 45 | * @param mixed $value Value to prepare 46 | * 47 | * @return mixed 48 | */ 49 | public function prepareValue($value) 50 | { 51 | $value = parent::prepareValue($value); 52 | 53 | if (!is_string($value) && !is_numeric($value)) 54 | { 55 | return null; 56 | } 57 | 58 | return (string) $value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/DateTimeFilter.php: -------------------------------------------------------------------------------- 1 | 0; 40 | } 41 | 42 | /** 43 | * Prepare value. 44 | * 45 | * @param mixed $value Value to prepare 46 | * 47 | * @return mixed 48 | */ 49 | public function prepareValue($value) 50 | { 51 | $value = parent::prepareValue($value); 52 | 53 | if (!is_string($value) && !is_numeric($value)) 54 | { 55 | return null; 56 | } 57 | 58 | return (string) $value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/Escaped.php: -------------------------------------------------------------------------------- 1 | getDbo()->escape($value); 39 | } 40 | 41 | /** 42 | * Isolated factory communication to ease testing. 43 | * 44 | * @return \JDatabaseDriver 45 | */ 46 | protected function getDbo() 47 | { 48 | return Factory::getDbo(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/FilterInterface.php: -------------------------------------------------------------------------------- 1 | 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MVC/Model/State/Filter/StringFilter.php: -------------------------------------------------------------------------------- 1 | getDbo()->quote($value); 53 | } 54 | 55 | /** 56 | * Isolated factory communication to ease testing. 57 | * 58 | * @return \JDatabaseDriver 59 | */ 60 | protected function getDbo() 61 | { 62 | return Factory::getDbo(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/MVC/Model/State/FilteredProperty.php: -------------------------------------------------------------------------------- 1 | property = $property; 47 | $this->filter = $filter ?: new StringQuoted; 48 | } 49 | 50 | /** 51 | * Redirect any missing method call to decorated property. 52 | * 53 | * @param string $method Method name 54 | * @param array $params Method parameters 55 | * 56 | * @return mixed 57 | */ 58 | public function __call($method, $params) 59 | { 60 | return call_user_func_array([$this->property, $method], $params); 61 | } 62 | 63 | /** 64 | * Filter a value for this property. 65 | * 66 | * @param mixed $value Value to filter 67 | * 68 | * @return mixed 69 | */ 70 | public function filter($value) 71 | { 72 | return $this->filter->filter($value); 73 | } 74 | 75 | /** 76 | * Can this property be populated from request? 77 | * 78 | * @return boolean 79 | */ 80 | public function isPopulable() 81 | { 82 | return $this->property->isPopulable(); 83 | } 84 | 85 | /** 86 | * Retrieve the property identifier. 87 | * 88 | * @return string 89 | */ 90 | public function key() 91 | { 92 | return $this->property->key(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/MVC/Model/State/FilteredState.php: -------------------------------------------------------------------------------- 1 | property($key)->filter($value); 38 | } 39 | catch (\RuntimeException $e) 40 | { 41 | $filter = new StringQuoted; 42 | 43 | return $filter->filter($value); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/MVC/Model/State/PopulableProperty.php: -------------------------------------------------------------------------------- 1 | key = $key; 51 | } 52 | 53 | /** 54 | * Retrieve the property identifier. 55 | * 56 | * @return string 57 | */ 58 | public function key() 59 | { 60 | return $this->key; 61 | } 62 | 63 | /** 64 | * Can this property be populated from request? 65 | * 66 | * @return boolean 67 | */ 68 | public function isPopulable() 69 | { 70 | return $this->isPopulable; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/MVC/Model/State/PropertyInterface.php: -------------------------------------------------------------------------------- 1 | context; 36 | } 37 | 38 | /** 39 | * Sets the context. 40 | * 41 | * @param string $context The context 42 | * 43 | * @return void 44 | */ 45 | public function setContext($context) 46 | { 47 | $this->context = $context; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/MVC/Model/Traits/HasFilteredState.php: -------------------------------------------------------------------------------- 1 | stateProperties()); 33 | } 34 | 35 | /** 36 | * Get the properties that will be available in this model state. 37 | * 38 | * @return array 39 | */ 40 | protected function stateProperties() 41 | { 42 | return [ 43 | 'list.limit' => new FilteredProperty( 44 | new PopulableProperty('list.limit'), 45 | new Filter\Integer 46 | ), 47 | 'list.start' => new FilteredProperty( 48 | new PopulableProperty('list.start'), 49 | new Filter\Integer 50 | ) 51 | ]; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/MVC/Model/Traits/HasQueryModifiers.php: -------------------------------------------------------------------------------- 1 | apply(); 32 | } 33 | 34 | /** 35 | * Apply an array of query modifiers. 36 | * 37 | * @param QueryModifierInterface[] $modifiers Query modifiers to apply 38 | * 39 | * @return void 40 | */ 41 | public function applyQueryModifiers(array $modifiers) 42 | { 43 | foreach ($modifiers as $modifier) 44 | { 45 | $modifier->apply(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/MVC/Model/Traits/HasSearch.php: -------------------------------------------------------------------------------- 1 | state = new \JObject; 52 | $this->{'__state_set'} = true; 53 | 54 | foreach ($state as $key => $value) 55 | { 56 | $this->setState($key, $value); 57 | } 58 | 59 | return $this->getItems(); 60 | } 61 | 62 | /** 63 | * Search items and return a collection of entities with the results of ->search() 64 | * 65 | * @param string $entityClass Entity to bind item data 66 | * @param array $state Model state 67 | * 68 | * @return Collection 69 | */ 70 | public function searchCollection(string $entityClass, array $state = []) 71 | { 72 | return new Collection( 73 | array_map( 74 | function ($entityData) use ($entityClass) 75 | { 76 | $entity = new $entityClass; 77 | $id = $entityData->{$entity->primaryKey()}; 78 | 79 | return $entityClass::find($id)->bind($entityData); 80 | }, 81 | $this->search($state) 82 | ) 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/MVC/View/FormView.php: -------------------------------------------------------------------------------- 1 | getModel(); 30 | 31 | return array_merge( 32 | parent::loadLayoutData(), 33 | [ 34 | 'form' => $model->getForm(), 35 | 'model' => $model 36 | ] 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/MVC/View/ItemView.php: -------------------------------------------------------------------------------- 1 | entityClass(); 40 | $entity = new $entityClass; 41 | $entity->bind($this->getLayoutData()['item']->getProperties(true)); 42 | 43 | if (!$entity->acl()->canView()) 44 | { 45 | $msg = Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'); 46 | 47 | $this->addMessage($msg, 'error'); 48 | 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | 56 | /** 57 | * Load layout data. 58 | * 59 | * @return self 60 | */ 61 | protected function loadLayoutData() 62 | { 63 | $model = $this->getModel(); 64 | 65 | $data = array_merge( 66 | parent::loadLayoutData(), 67 | [ 68 | 'item' => $model->getItem(), 69 | 'return' => Factory::getApplication()->input->getString('return', ''), 70 | 'model' => $model 71 | ] 72 | ); 73 | 74 | if ($this instanceof AssociatedEntity) 75 | { 76 | $entityClass = $this->entityClass(); 77 | $parts = explode('\\', $entityClass); 78 | $entityName = lcfirst(end($parts)); 79 | $data['entity'] = $entityClass::find($data['item']->id)->bind($data['item']->getProperties(true)); 80 | $data[$entityName] = $data['entity']; 81 | } 82 | 83 | return $data; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/MVC/View/ListView.php: -------------------------------------------------------------------------------- 1 | getModel(); 33 | 34 | $data = array_merge( 35 | parent::loadLayoutData(), 36 | [ 37 | 'items' => $model->getItems(), 38 | 'state' => $model->getState(), 39 | 'pagination' => $model->getPagination(), 40 | 'filterForm' => $model->getFilterForm(), 41 | 'activeFilters' => $model->getActiveFilters(), 42 | 'model' => $model 43 | ] 44 | ); 45 | 46 | if ($this instanceof AssociatedEntity) 47 | { 48 | $entityClass = $this->entityClass(); 49 | $parts = explode('\\', $entityClass); 50 | $entityName = lcfirst(end($parts)); 51 | $entitiesName = Inflector::getInstance()->toPlural($entityName); 52 | 53 | $data['entities'] = new Collection( 54 | array_map( 55 | function ($itemData) use ($entityClass) 56 | { 57 | return $entityClass::find($itemData->{'id'})->bind($itemData); 58 | }, 59 | $data['items'] 60 | ) 61 | ); 62 | 63 | $data[$entitiesName] = $data['entities']; 64 | } 65 | 66 | foreach ($data as $key => $value) 67 | { 68 | if ('view' === $key) 69 | { 70 | continue; 71 | } 72 | 73 | $this->{$key} = $value; 74 | } 75 | 76 | return $data; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Messages/Message.php: -------------------------------------------------------------------------------- 1 | options = new Registry(array_merge($this->defaultOptions(), $options)); 37 | $this->options->separator = '|'; 38 | } 39 | 40 | /** 41 | * Default options to initialise searcher. 42 | * 43 | * @return array 44 | */ 45 | public function defaultOptions() 46 | { 47 | return []; 48 | } 49 | 50 | /** 51 | * Factory method. 52 | * 53 | * @param array $options Options for the searcher. 54 | * 55 | * @return static 56 | */ 57 | public static function instance(array $options = []) 58 | { 59 | return new static($options); 60 | } 61 | 62 | /** 63 | * Retrieve searcher options. 64 | * 65 | * @return Registry 66 | */ 67 | public function options() 68 | { 69 | return $this->options; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Searcher/SearcherInterface.php: -------------------------------------------------------------------------------- 1 | prefix() . 'Table'; 39 | 40 | Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/' . $component->option() . '/tables'); 41 | 42 | $table = Table::getInstance($name, $prefix, $config); 43 | 44 | if (!$table instanceof Table) 45 | { 46 | throw new \InvalidArgumentException( 47 | sprintf('Cannot find the table %s in component %s.', $name, $option) 48 | ); 49 | } 50 | 51 | return $table; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Table/TableInterface.php: -------------------------------------------------------------------------------- 1 | {'_tbl_keys'} as $k) 44 | { 45 | $keys[] = (int) $this->$k; 46 | } 47 | 48 | $prefix = $this->getAssetPrefix(); 49 | 50 | return ($prefix ? $prefix . '.' : '') . strtolower($this->getInstanceName()) . '.' . implode('.', $keys); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Table/Traits/HasFixedGetProperties.php: -------------------------------------------------------------------------------- 1 | getProperties(\ReflectionProperty::IS_PUBLIC); 34 | 35 | foreach ($properties as $property) 36 | { 37 | // For B/C we will keep the shit underscore private identification 38 | if ('_' == substr($property->name, 0, 1)) 39 | { 40 | continue; 41 | } 42 | 43 | $vars[$property->name] = $this->{$property->name}; 44 | } 45 | 46 | return $vars; 47 | } 48 | 49 | return get_object_vars($this); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Table/Traits/HasInstanceName.php: -------------------------------------------------------------------------------- 1 | instanceName) 36 | { 37 | $this->instanceName = strtolower(str_replace('Table', '', strstr(get_class($this), 'Table'))); 38 | } 39 | 40 | return $this->instanceName; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Table/Traits/HasInstancePrefix.php: -------------------------------------------------------------------------------- 1 | instancePrefix) 35 | { 36 | $this->instancePrefix = strtolower(strstr(get_class($this), 'Table', true)); 37 | } 38 | 39 | return $this->instancePrefix; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Table/Traits/HasKeysComparator.php: -------------------------------------------------------------------------------- 1 | {'_tbl_keys'} as $k) 32 | { 33 | if (!property_exists($this, $k) || $this->{$k} !== $table->{$k}) 34 | { 35 | return false; 36 | } 37 | } 38 | 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Table/Traits/HasLanguageStrings.php: -------------------------------------------------------------------------------- 1 | textPrefix)) 35 | { 36 | $this->textPrefix = 'LIB_' . strtoupper($this->getInstancePrefix()) . '_' . strtoupper($this->getInstanceName()); 37 | } 38 | 39 | return $this->textPrefix; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Tags/Tag.php: -------------------------------------------------------------------------------- 1 | hasId()) 60 | { 61 | return null; 62 | } 63 | 64 | \JLoader::register('TagsHelperRoute', JPATH_BASE . '/components/com_tags/helpers/route.php'); 65 | 66 | return \JRoute::_(\TagsHelperRoute::getTagRoute($this->id() . '-' . $this->get('alias'))); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Traits/HasApp.php: -------------------------------------------------------------------------------- 1 | app) 48 | { 49 | $this->app = $this->activeApplication(); 50 | } 51 | 52 | return $this->app; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Traits/HasLayoutData.php: -------------------------------------------------------------------------------- 1 | layoutData[__CLASS__])) 35 | { 36 | $this->layoutData[__CLASS__] = $this->loadLayoutData(); 37 | } 38 | 39 | return $this->layoutData[__CLASS__]; 40 | } 41 | 42 | /** 43 | * Load layout data. 44 | * 45 | * @return array 46 | */ 47 | abstract protected function loadLayoutData(); 48 | } 49 | -------------------------------------------------------------------------------- /src/Traits/HasMessages.php: -------------------------------------------------------------------------------- 1 | messages[$type])) 40 | { 41 | $this->messages[$type] = array(); 42 | } 43 | 44 | $this->messages[$type][] = $message; 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Inject any pending message into the Joomla app. 51 | * 52 | * @param CMSApplication $app Application to inject the messages 53 | * 54 | * @return self 55 | */ 56 | protected function enqueueMessagesInApp(CMSApplication $app) 57 | { 58 | $systemMessages = $this->getMessages(); 59 | 60 | if (!$systemMessages) 61 | { 62 | return $this; 63 | } 64 | 65 | foreach ($systemMessages as $messageType => $messages) 66 | { 67 | foreach ($messages as $message) 68 | { 69 | $app->enqueueMessage($message, $messageType); 70 | } 71 | } 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * Get the system messages generated by this view. 78 | * 79 | * @param string $type Optional type selector 80 | * 81 | * @return array 82 | */ 83 | public function getMessages($type = null) 84 | { 85 | return $type && isset($this->messages[$type]) ? $this->messages[$type] : $this->messages; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Traits/HasRedirect.php: -------------------------------------------------------------------------------- 1 | redirect); 53 | } 54 | 55 | /** 56 | * Redirect to the URL. 57 | * 58 | * @return void 59 | * 60 | * @since 1.2.0 61 | */ 62 | public function redirect() 63 | { 64 | Factory::getApplication()->redirect($this->redirectUrl); 65 | } 66 | 67 | /** 68 | * Retrieve the active redirect url. 69 | * 70 | * @param boolean $route Process URL with Route? 71 | * 72 | * @return string 73 | */ 74 | protected function redirectUrl($route = true) 75 | { 76 | if (null === $this->redirectUrl) 77 | { 78 | $this->redirectUrl = $this->defaultRedirectUrl(); 79 | } 80 | 81 | return $route ? Route::_($this->redirectUrl, false) : $this->redirectUrl; 82 | } 83 | 84 | /** 85 | * Set the active redirect URL. 86 | * 87 | * @param string $url URL to redirect the user 88 | * 89 | * @return self 90 | */ 91 | public function setRedirectUrl($url) 92 | { 93 | $this->redirectUrl = $url; 94 | 95 | return $this; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Translation/Contracts/Translatable.php: -------------------------------------------------------------------------------- 1 | isEntityLanguage() ? $this->entity->get($column) : $this->translation()->get($column); 31 | 32 | if ($this->validator()->isValidColumnValue($column, $value)) 33 | { 34 | return $value; 35 | } 36 | 37 | if ($this->isEntityLanguage()) 38 | { 39 | return $default; 40 | } 41 | 42 | $value = $this->entity->get($column); 43 | 44 | $isValid = $this->validator()->isValidColumnValue($column, $value); 45 | 46 | return $isValid ? $value : $default; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Users/AuthorUserGroup.php: -------------------------------------------------------------------------------- 1 | RegisteredUserGroup::instanceOrCreate()->id(), 39 | 'title' => self::TITLE 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Users/Column.php: -------------------------------------------------------------------------------- 1 | PublicUserGroup::create(), 38 | 'guest' => GuestUserGroup::create(), 39 | 'registered' => RegisteredUserGroup::create(), 40 | 'super-users' => SuperUsersUserGroup::create() 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Users/Command/CreatePredefinedViewLevels.php: -------------------------------------------------------------------------------- 1 | PublicViewLevel::create(), 38 | 'registered' => RegisteredViewLevel::create(), 39 | 'special' => SpecialViewLevel::create(), 40 | 'guest' => GuestViewLevel::create(), 41 | 'super-users' => SuperUsersViewLevel::create() 42 | ]; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Users/Contracts/Ownerable.php: -------------------------------------------------------------------------------- 1 | PublicUserGroup::instanceOrCreate()->id(), 39 | 'title' => self::TITLE 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Users/GuestViewLevel.php: -------------------------------------------------------------------------------- 1 | self::TITLE, 39 | 'rules' => json_encode( 40 | [ 41 | GuestUserGroup::instanceOrCreate()->id() 42 | ] 43 | ) 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Users/ManagerUserGroup.php: -------------------------------------------------------------------------------- 1 | PublicUserGroup::instanceOrCreate()->id(), 39 | 'title' => self::TITLE 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Users/PredefinedViewLevel.php: -------------------------------------------------------------------------------- 1 | isLoaded()) 39 | { 40 | throw new \RuntimeException('Cannot find view level: ' . json_encode($data)); 41 | } 42 | 43 | $this->id = $viewLevel->id(); 44 | $this->bind($viewLevel->all()); 45 | } 46 | 47 | /** 48 | * Create the view level. 49 | * 50 | * @param array|\stdClass $data Data to store 51 | * 52 | * @return static 53 | */ 54 | public static function create($data = null) 55 | { 56 | ViewLevel::create(static::predefinedData()); 57 | 58 | return static::instance(); 59 | } 60 | 61 | /** 62 | * Retrieve the cached instance. 63 | * 64 | * @return static 65 | */ 66 | public static function instance() 67 | { 68 | $viewLevel = new static; 69 | 70 | return static::find($viewLevel->id()); 71 | } 72 | 73 | /** 74 | * Retrieve the view level if exists or create it on the fly. 75 | * 76 | * @return static 77 | * 78 | * @throws \RuntimeException 79 | */ 80 | public static function instanceOrCreate() 81 | { 82 | try 83 | { 84 | return static::instance(); 85 | } 86 | catch (\Exception $e) 87 | { 88 | return static::create(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Users/PublicUserGroup.php: -------------------------------------------------------------------------------- 1 | self::PARENT_ID 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Users/PublicViewLevel.php: -------------------------------------------------------------------------------- 1 | self::TITLE, 39 | 'rules' => json_encode( 40 | [ 41 | PublicUserGroup::instanceOrCreate()->id() 42 | ] 43 | ) 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Users/RegisteredUserGroup.php: -------------------------------------------------------------------------------- 1 | PublicUserGroup::instanceOrCreate()->id(), 39 | 'title' => self::TITLE 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Users/RegisteredViewLevel.php: -------------------------------------------------------------------------------- 1 | self::TITLE, 41 | 'rules' => json_encode( 42 | [ 43 | RegisteredUserGroup::instanceOrCreate()->id(), 44 | ManagerUserGroup::instanceOrCreate()->id(), 45 | SuperUsersUserGroup::instanceOrCreate()->id() 46 | ] 47 | ) 48 | ]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Users/SpecialViewLevel.php: -------------------------------------------------------------------------------- 1 | self::TITLE, 41 | 'rules' => json_encode( 42 | [ 43 | AuthorUserGroup::instanceOrCreate()->id(), 44 | ManagerUserGroup::instanceOrCreate()->id(), 45 | SuperUsersUserGroup::instanceOrCreate()->id() 46 | ] 47 | ) 48 | ]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Users/SuperUsersUserGroup.php: -------------------------------------------------------------------------------- 1 | PublicUserGroup::instanceOrCreate()->id(), 39 | 'title' => self::TITLE 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Users/SuperUsersViewLevel.php: -------------------------------------------------------------------------------- 1 | self::TITLE, 39 | 'rules' => json_encode( 40 | [ 41 | SuperUsersUserGroup::instanceOrCreate()->id() 42 | ] 43 | ) 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Users/Traits/HasUserGroups.php: -------------------------------------------------------------------------------- 1 | userGroups = null; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Get the associated user groups. 41 | * 42 | * @return Collection 43 | */ 44 | public function userGroups() 45 | { 46 | if (null === $this->userGroups) 47 | { 48 | $this->userGroups = $this->loadUserGroups(); 49 | } 50 | 51 | return $this->userGroups; 52 | } 53 | 54 | /** 55 | * Check if this entity has an associated user group. 56 | * 57 | * @param integer $id User identifier 58 | * 59 | * @return boolean 60 | */ 61 | public function hasUserGroup($id) 62 | { 63 | return $this->userGroups()->has($id); 64 | } 65 | 66 | /** 67 | * Check if this entity has associated user groups. 68 | * 69 | * @return boolean 70 | */ 71 | public function hasUserGroups() 72 | { 73 | return !$this->userGroups()->isEmpty(); 74 | } 75 | 76 | /** 77 | * Load associated user groups from DB. 78 | * 79 | * @return Collection 80 | */ 81 | abstract protected function loadUserGroups(); 82 | } 83 | -------------------------------------------------------------------------------- /src/Users/Traits/HasUsers.php: -------------------------------------------------------------------------------- 1 | users = null; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Get the associated users. 41 | * 42 | * @return Collection 43 | */ 44 | public function users() 45 | { 46 | if (null === $this->users) 47 | { 48 | $this->users = $this->loadUsers(); 49 | } 50 | 51 | return $this->users; 52 | } 53 | 54 | /** 55 | * Check if this entity has an associated user. 56 | * 57 | * @param integer $id User identifier 58 | * 59 | * @return boolean 60 | */ 61 | public function hasUser($id) 62 | { 63 | return $this->users()->has($id); 64 | } 65 | 66 | /** 67 | * Check if this entity has associated users. 68 | * 69 | * @return boolean 70 | */ 71 | public function hasUsers() 72 | { 73 | return !$this->users()->isEmpty(); 74 | } 75 | 76 | /** 77 | * Load associated users from DB. 78 | * 79 | * @return Collection 80 | */ 81 | abstract protected function loadUsers(); 82 | } 83 | -------------------------------------------------------------------------------- /src/Users/Traits/HasViewLevels.php: -------------------------------------------------------------------------------- 1 | viewLevels = null; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Get the associated view levels. 41 | * 42 | * @return Collection 43 | */ 44 | public function viewLevels() 45 | { 46 | if (null === $this->viewLevels) 47 | { 48 | $this->viewLevels = $this->loadViewLevels(); 49 | } 50 | 51 | return $this->viewLevels; 52 | } 53 | 54 | /** 55 | * Check if this entity has an associated view level. 56 | * 57 | * @param integer $id View level identifier 58 | * 59 | * @return boolean 60 | */ 61 | public function hasViewLevel($id) 62 | { 63 | return $this->viewLevels()->has($id); 64 | } 65 | 66 | /** 67 | * Check if this entity has associated view levels. 68 | * 69 | * @return boolean 70 | */ 71 | public function hasViewLevels() 72 | { 73 | return !$this->viewLevels()->isEmpty(); 74 | } 75 | 76 | /** 77 | * Load associated view levels. 78 | * 79 | * @return Collection 80 | */ 81 | abstract protected function loadViewLevels(); 82 | } 83 | -------------------------------------------------------------------------------- /src/Users/UserGroup.php: -------------------------------------------------------------------------------- 1 | hasId()) 35 | { 36 | return new Collection; 37 | } 38 | 39 | $users = array_map( 40 | function ($item) 41 | { 42 | return User::find($item->id)->bind($item); 43 | }, 44 | $this->usersModel()->getItems() ?: array() 45 | ); 46 | 47 | return new Collection($users); 48 | } 49 | 50 | /** 51 | * Get a table instance. Defauts to \JTableUser. 52 | * 53 | * @param string $name Table name. Optional. 54 | * @param string $prefix Class prefix. Optional. 55 | * @param array $options Configuration array for the table. Optional. 56 | * 57 | * @return \JTable 58 | * 59 | * @throws \InvalidArgumentException 60 | */ 61 | public function table($name = '', $prefix = null, $options = array()) 62 | { 63 | $name = $name ?: 'Usergroup'; 64 | $prefix = $prefix ?: 'JTable'; 65 | 66 | return parent::table($name, $prefix, $options); 67 | } 68 | 69 | /** 70 | * Get an instance of the users model. 71 | * 72 | * @return \UsersModelUsersModel 73 | */ 74 | protected function usersModel() 75 | { 76 | \JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_users/models', 'UsersModel'); 77 | 78 | $model = \JModelLegacy::getInstance('Users', 'UsersModel', array('ignore_request' => true)); 79 | 80 | if ($this->hasId()) 81 | { 82 | $model->setState('filter.group_id', $this->id()); 83 | } 84 | 85 | return $model; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Users/ViewLevel.php: -------------------------------------------------------------------------------- 1 | has('rules')) 55 | { 56 | return $userGroups; 57 | } 58 | 59 | $rules = $this->get('rules'); 60 | $ids = array_unique( 61 | array_filter( 62 | empty($rules) ? [] : json_decode($rules) 63 | ) 64 | ); 65 | 66 | foreach ($ids as $id) 67 | { 68 | $userGroups->add(UserGroup::find($id)); 69 | } 70 | 71 | return $userGroups; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Validation/Contracts/Rule.php: -------------------------------------------------------------------------------- 1 | name() . ($entity->hasId() ? '::' . $entity->id() : null); 35 | $msg = sprintf("`%s` is not valid:
* ", $entityName); 36 | 37 | if (count($errors)) 38 | { 39 | $msg .= implode("
* ", $errors); 40 | } 41 | 42 | return new static($msg, 500); 43 | } 44 | 45 | /** 46 | * Entity did not pass validation. 47 | * 48 | * @param string $column Entity with empty data 49 | * @param RuleContract[] $failedRules Rule failed 50 | * 51 | * @return static 52 | */ 53 | public static function invalidColumn($column, array $failedRules) 54 | { 55 | $errors = array(); 56 | 57 | foreach ($failedRules as $rule) 58 | { 59 | $errors[] = sprintf("`%s` does not pass `%s` validation rule", $column, $rule->name()); 60 | } 61 | 62 | return new static(implode("
* ", $errors), 500); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Validation/Rule.php: -------------------------------------------------------------------------------- 1 | name = $name; 45 | } 46 | 47 | /** 48 | * Check if a value is not valid. 49 | * 50 | * @param mixed $value Value to check 51 | * 52 | * @return boolean 53 | */ 54 | public function fails($value) 55 | { 56 | return !$this->passes($value); 57 | } 58 | 59 | /** 60 | * Id of this rule. 61 | * 62 | * @return string 63 | */ 64 | public function id() 65 | { 66 | if (null === $this->id) 67 | { 68 | $this->id = spl_object_hash($this); 69 | } 70 | 71 | return $this->id; 72 | } 73 | 74 | /** 75 | * Name of this rule. 76 | * 77 | * @return string 78 | */ 79 | public function name() 80 | { 81 | return null === $this->name ? get_class($this) : \JText::_($this->name); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Validation/Rule/CustomRule.php: -------------------------------------------------------------------------------- 1 | validator = $validator; 41 | } 42 | 43 | /** 44 | * Check if a value is valid. 45 | * 46 | * @param mixed $value Value to check 47 | * 48 | * @return boolean 49 | */ 50 | public function passes($value) 51 | { 52 | return call_user_func_array($this->validator, array($value)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Validation/Rule/IsEmptyDate.php: -------------------------------------------------------------------------------- 1 | nullDate())); 33 | } 34 | 35 | /** 36 | * Get the empty date for the active DB driver. 37 | * 38 | * @return string 39 | * 40 | * @codeCoverageIgnore 41 | */ 42 | protected function nullDate() 43 | { 44 | return \JFactory::getDbo()->getNullDate(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Validation/Rule/IsEmptyString.php: -------------------------------------------------------------------------------- 1 | passes($value) || $emptyStringValidator->passes($value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Validation/Rule/IsNullOrPositiveInteger.php: -------------------------------------------------------------------------------- 1 | name); 34 | 35 | if ($isNullRule->passes($value)) 36 | { 37 | return true; 38 | } 39 | 40 | $isPositiveIntegerRule = new IsPositiveInteger($this->name); 41 | 42 | return $isPositiveIntegerRule->passes($value); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Validation/Rule/IsPositiveInteger.php: -------------------------------------------------------------------------------- 1 | 0; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Validation/Rule/IsString.php: -------------------------------------------------------------------------------- 1 | 0 || (int) $value === 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Validation/Rule/NoSubstrCount.php: -------------------------------------------------------------------------------- 1 | substr = $substr; 41 | } 42 | 43 | /** 44 | * Check if a value is valid. 45 | * 46 | * @param mixed $value Value to check 47 | * 48 | * @return boolean 49 | */ 50 | public function passes($value) 51 | { 52 | return substr_count($value, $this->substr) > 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Validation/Traits/HasValidation.php: -------------------------------------------------------------------------------- 1 | validator()->isValid(); 39 | } 40 | 41 | /** 42 | * Set validator. 43 | * 44 | * @param ValidatorContract $validator Validator to use 45 | * 46 | * @return self 47 | */ 48 | public function setValidator(ValidatorContract $validator) 49 | { 50 | $this->validator = $validator; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Retrieve entity validator. 57 | * 58 | * @return ValidatorContract 59 | */ 60 | public function validator() 61 | { 62 | if (null === $this->validator) 63 | { 64 | $this->validator = new Validator($this); 65 | } 66 | 67 | return $this->validator; 68 | } 69 | 70 | /** 71 | * Validate this entity. 72 | * 73 | * @return boolean 74 | * 75 | * @throws ValidationException 76 | */ 77 | public function validate() 78 | { 79 | return $this->validator()->validate(); 80 | } 81 | } 82 | --------------------------------------------------------------------------------