Updated search

This commit is contained in:
Lucas Bartholemy 2015-06-27 05:57:44 +02:00
parent fa4147a38b
commit 9877d2f909
39 changed files with 486 additions and 493 deletions

View File

@ -19,8 +19,10 @@
"yiisoft/yii2-bootstrap": "*",
"yiisoft/yii2-swiftmailer": "*",
"raoul2000/yii2-jcrop-widget": "*",
"cebe/markdown": "1.0.2",
"yiisoft/yii2-jui": "^2.0",
"zendframework/zend-http": "*"
"zendframework/zend-http": "*",
"nqxcode/zendsearch": "^2.0"
},
"suggest": {
"zendframework/zend-ldap": "LDAP authentication"
@ -29,7 +31,8 @@
"yiisoft/yii2-codeception": "*",
"yiisoft/yii2-debug": "*",
"yiisoft/yii2-gii": "*",
"yiisoft/yii2-faker": "*"
"yiisoft/yii2-faker": "*",
"yiisoft/yii2-apidoc": "^2.0"
},
"config": {
"process-timeout": 1800,

View File

@ -29,9 +29,12 @@ return [
],
],
],
'search' => array(
'class' => 'humhub\core\search\engine\ZendLuceneSearch',
),
'moduleManager' => [
'class' => '\humhub\components\ModuleManager'
],
],
'db' => $db,
],
'params' => $params,

View File

@ -47,6 +47,9 @@ $config = [
],
],
],
'search' => array(
'class' => 'humhub\core\search\engine\ZendLuceneSearch',
),
'i18n' => [
'class' => 'humhub\components\i18n\I18N',
'translations' => [

View File

@ -16,6 +16,20 @@ namespace humhub\components\console;
class Application extends \yii\console\Application
{
/**
* @event ActionEvent an event raised on init of application.
*/
const EVENT_ON_INIT = 'onInit';
/**
* @inheritdoc
*/
public function init()
{
parent::init();
$this->trigger(self::EVENT_ON_INIT);
}
/**
* Returns the configuration of the built-in commands.
* @return array the configuration of the built-in commands.

View File

@ -12,19 +12,6 @@ namespace humhub\core\activity;
class Module extends \yii\base\Module
{
public $isCoreModule = true;
/**
* Inits the activity module
*/
public function init()
{
$this->setImport(array(
'activity.models.*',
'activity.behaviors.*',
));
}
/**
* Formatted the activity content before delivery
*

View File

@ -6,17 +6,19 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search;
/**
* Description of SearchModuleEvents
*
* @author luke
*/
class SearchModuleEvents
class Events extends \yii\base\Object
{
public static function onTopMenuRightInit($event)
{
$event->sender->addWidget('application.modules_core.search.widgets.SearchMenuWidget');
$event->sender->addWidget(widgets\SearchMenu::className());
}
public static function onAfterSaveComment($event)
@ -28,4 +30,11 @@ class SearchModuleEvents
}
}
public static function onConsoleApplicationInit($event)
{
$application = $event->sender;
$application->controllerMap['search'] = commands\SearchController::className();
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'humhub\core\search\controllers';
}

View File

@ -1,26 +0,0 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
class SearchModule extends HWebModule
{
public $isCoreModule = true;
public function init()
{
$this->setImport(array(
'post.models.*',
'post.behaviors.*',
));
}
public function rebuild()
{
}
}

View File

@ -1,22 +1,17 @@
<?php
# Disable until migrated
return;
use humhub\widgets\TopMenuRightStack;
use humhub\core\search\Events;
use humhub\components\console\Application;
Yii::app()->moduleManager->register(array(
Yii::$app->moduleManager->register(array(
'isCoreModule' => true,
'id' => 'search',
'class' => 'application.modules_core.search.SearchModule',
'import' => array(
'application.modules_core.search.*',
'application.modules_core.search.interfaces.*',
'application.modules_core.search.engine.*',
'application.modules_core.search.libs.*',
),
// Events to Catch
'class' => \humhub\core\search\Module::className(),
'events' => array(
array('class' => 'TopMenuRightStackWidget', 'event' => 'onInit', 'callback' => array('SearchModuleEvents', 'onTopMenuRightInit')),
array('class' => 'Comment', 'event' => 'onAfterSave', 'callback' => array('SearchModuleEvents', 'onAfterSaveComment')),
array('class' => TopMenuRightStack::className(), 'event' => TopMenuRightStack::EVENT_INIT, 'callback' => array(Events::className(), 'onTopMenuRightInit')),
array('class' => Application::className(), 'event' => Application::EVENT_ON_INIT, 'callback' => array(Events::className(), 'onConsoleApplicationInit')),
//array('class' => 'Comment', 'event' => 'onAfterSave', 'callback' => array('SearchModuleEvents', 'onAfterSaveComment')),
),
));
?>

View File

@ -1,43 +0,0 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
/**
* Searchable Behavior
*
* @author Lucas Bartholemy <lucas@bartholemy.com>
* @package humhub.behaviors
* @since 0.5
*/
class HSearchableBehavior extends HActiveRecordBehavior
{
public function afterSave($event)
{
if ($this->getOwner() instanceof ISearchable) {
Yii::app()->search->update($this->getOwner());
} else {
throw new CException("Owner of HSearchableBehavior must be implement interface ISearchable");
}
parent::afterSave($event);
}
public function afterDelete($event)
{
if ($this->getOwner() instanceof ISearchable) {
Yii::app()->search->delete($this->getOwner());
} else {
throw new CException("Owner of HSearchableBehavior must be implement interface ISearchable");
}
parent::afterDelete($event);
}
}
?>

View File

@ -0,0 +1,55 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\behaviors;
use yii\db\ActiveRecord;
use yii\base\Behavior;
use yii\console\Exception;
/**
* Searchable Behavior
*
* @author Lucas Bartholemy <lucas@bartholemy.com>
* @package humhub.behaviors
* @since 0.5
*/
class Searchable extends Behavior
{
public function events()
{
return [
ActiveRecord::EVENT_AFTER_DELETE => 'afterDelete',
ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
ActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
];
}
public function afterSave($event)
{
if ($this->owner instanceof \humhub\core\search\interfaces\Searchable) {
Yii::$app->search->update($this->owner);
} else {
throw new Exception("Owner of HSearchableBehavior must be implement interface ISearchable");
}
}
public function afterDelete($event)
{
if ($this->getOwner() instanceof \humhub\core\search\interfaces\Searchable) {
Yii::$app->search->delete($this->getOwner());
} else {
throw new Exception("Owner of HSearchableBehavior must be implement interface ISearchable");
}
}
}
?>

View File

@ -0,0 +1,65 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\commands;
use Yii;
/**
* Search Tools
*
* @package humhub.modules_core.search.console
* @since 0.12
*/
class SearchController extends \yii\console\controller
{
/**
* Optimizes the search index
*/
public function actionOptimize()
{
print "Optimizing search index: ";
Yii::$app->search->optimize();
print "OK!\n\n";
}
/**
* Rebuilds the search index
*/
public function actionRebuild()
{
print "Rebuild search index: ";
Yii::$app->search->rebuild();
print "OK!\n\n";
}
/**
* Search the index
*
* @param string $searchString
* @return type
*/
public function actionFind($keyword)
{
$pageSize = 10;
$model = "";
$page = 1;
print "Searching for: " . $keyword . " \n";
$results = Yii::$app->search->find($keyword, [
'pageSize' => $pageSize,
'page' => $page,
'model' => ($model != "") ? explode(",", $model) : null
]);
print_r($results);
}
}

View File

@ -1,82 +0,0 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
/**
* Console tool for search
*
* @package humhub.modules_core.search.console
* @since 0.12
*/
class SearchCli extends HConsoleCommand
{
public function init()
{
$this->printHeader('Search Console');
return parent::init();
}
public function actionOptimize()
{
print "Optimizing search index: ";
Yii::app()->search->optimize();
print "OK!\n\n";
}
public function actionRebuild()
{
print "Rebuild search index: ";
Yii::app()->search->rebuild();
print "OK!\n\n";
}
public function actionFind($args, $page = 1, $pageSize = 5, $model = "")
{
if (!isset($args[0])) {
print "Error: Keyword parameter required!\n\n";
print $this->getHelp();
return;
}
$keyword = $args[0];
print "Searching for: " . $keyword . " \n";
$results = Yii::app()->search->find($keyword, [
'pageSize' => $pageSize,
'page' => $page,
'model' => ($model != "") ? explode(",", $model) : null
]);
print_r($results);
}
public function getHelp()
{
return <<<EOD
USAGE
yiic search [action] [parameter]
DESCRIPTION
This command provides console support for search.
EXAMPLES
* yiic search find [keyword]
Searches index for given keyword
* yiic search rebuild
Rebuilds search index
* yiic search optimize
Optimizes the search index
EOD;
}
}

View File

@ -6,6 +6,14 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\controllers;
use Yii;
use humhub\components\Controller;
use humhub\core\space\models\Space;
use humhub\core\user\models\User;
use humhub\models\Setting;
/**
* Search Controller provides search functions inside the application.
*
@ -21,46 +29,19 @@ class SearchController extends Controller
const SCOPE_SPACE = "space";
const SCOPE_CONTENT = "content";
/**
* @return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* @return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'users' => array('@', (HSetting::Get('allowGuestAccess', 'authentication_internal')) ? "?" : "@"),
),
array('deny', // deny all users
'users' => array('*'),
),
);
}
public function actionIndex()
{
$keyword = Yii::app()->request->getParam('keyword', "");
$scope = Yii::app()->request->getParam('scope', "");
$page = (int) Yii::app()->request->getParam('page', 1);
$limitSpaceGuids = Yii::app()->request->getParam('limitSpaceGuids', "");
$keyword = Yii::$app->request->get('keyword', "");
$scope = Yii::$app->request->get('scope', "");
$page = (int) Yii::$app->request->get('page', 1);
$limitSpaceGuids = Yii::$app->request->get('limitSpaceGuids', "");
$limitSpaces = array();
if ($limitSpaceGuids !== "") {
foreach (explode(",", $limitSpaceGuids) as $guid) {
$guid = trim($guid);
if ($guid != "") {
$space = Space::model()->findByAttributes(array('guid' => trim($guid)));
$space = Space::findOne(['guid' => trim($guid)]);
if ($space !== null) {
$limitSpaces[] = $space;
}
@ -71,32 +52,32 @@ class SearchController extends Controller
$options = [
'page' => $page,
'sort' => ($keyword == '') ? 'title' : null,
'pageSize' => HSetting::Get('paginationSize'),
'pageSize' => Setting::Get('paginationSize'),
'limitSpaces' => $limitSpaces
];
if ($scope == self::SCOPE_CONTENT) {
$options['type'] = 'Content';
} elseif ($scope == self::SCOPE_SPACE) {
$options['model'] = 'Space';
$options['model'] = Space::className();
} elseif ($scope == self::SCOPE_USER) {
$options['model'] = 'User';
$options['model'] = User::className();
} else {
$scope = self::SCOPE_ALL;
}
$searchResultSet = Yii::app()->search->find($keyword, $options);
$searchResultSet = Yii::$app->search->find($keyword, $options);
// Create Pagination Class
$pagination = new CPagination($searchResultSet->total);
$pagination->setPageSize($searchResultSet->pageSize);
$pagination = new \yii\data\Pagination;
$pagination->totalCount = $searchResultSet->total;
$pagination->pageSize = $searchResultSet->pageSize;
$this->render('index', array(
'scope' => $scope,
'keyword' => $keyword,
'results' => $searchResultSet->getResultInstances(),
'pagination' => $pagination,
'totals' => $this->getTotals($keyword, $options),
'limitSpaceGuids' => $limitSpaceGuids
return $this->render('index', array(
'scope' => $scope,
'keyword' => $keyword,
'results' => $searchResultSet->getResultInstances(),
'pagination' => $pagination,
'totals' => $this->getTotals($keyword, $options),
'limitSpaceGuids' => $limitSpaceGuids
));
}
@ -105,10 +86,12 @@ class SearchController extends Controller
*/
public function actionMentioning()
{
$results = array();
$keyword = Yii::app()->request->getParam('keyword', "");
\Yii::$app->response->format = 'json';
$searchResultSet = Yii::app()->search->find($keyword, [
$results = array();
$keyword = Yii::$app->request->get('keyword', "");
$searchResultSet = Yii::$app->search->find($keyword, [
'model' => array('User', 'Space'),
'pageSize' => 10
]);
@ -123,8 +106,7 @@ class SearchController extends Controller
);
}
echo CJSON::encode($results);
Yii::app()->end();
return $results;
}
protected function getTotals($keyword, $options)
@ -137,12 +119,12 @@ class SearchController extends Controller
unset($options['page']);
unset($options['pageSize']);
$searchResultSetCount = Yii::app()->search->find($keyword, array_merge($options, ['model' => 'User']));
$searchResultSetCount = Yii::$app->search->find($keyword, array_merge($options, ['model' => 'User']));
$totals[self::SCOPE_USER] = $searchResultSetCount->total;
$searchResultSetCount = Yii::app()->search->find($keyword, array_merge($options, ['model' => 'Space']));
$searchResultSetCount = Yii::$app->search->find($keyword, array_merge($options, ['model' => 'Space']));
$totals[self::SCOPE_SPACE] = $searchResultSetCount->total;
$searchResultSetCount = Yii::app()->search->find($keyword, array_merge($options, ['type' => 'Content']));
$searchResultSetCount = Yii::$app->search->find($keyword, array_merge($options, ['type' => 'Content']));
$totals[self::SCOPE_CONTENT] = $searchResultSetCount->total;
$totals[self::SCOPE_ALL] = $totals[self::SCOPE_CONTENT] + $totals[self::SCOPE_SPACE] + $totals[self::SCOPE_USER];

View File

@ -6,25 +6,29 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\engine;
use humhub\core\search\interfaces\Searchable;
use humhub\core\content\models\Content;
use humhub\core\user\models\User;
use humhub\core\space\models\Space;
use humhub\models\Setting;
/**
* Description of HSearchComponent
*
* @since 0.12
* @author luke
*/
abstract class HSearchComponent extends CApplicationComponent
abstract class Search extends \yii\base\Component
{
const EVENT_ON_REBUILD = 'onRebuild';
const DOCUMENT_TYPE_USER = 'user';
const DOCUMENT_TYPE_SPACE = 'space';
const DOCUMENT_TYPE_CONTENT = 'content';
const DOCUMENT_TYPE_OTHER = 'other';
public function __construct()
{
Yii::app()->interceptor->intercept($this);
}
/**
* Retrieves results from search
*
@ -50,9 +54,9 @@ abstract class HSearchComponent extends CApplicationComponent
/**
* Stores an object in search.
*
* @param ISearchable $object
* @param Searchable $object
*/
public function add(ISearchable $object)
public function add(Searchable $object)
{
}
@ -60,9 +64,9 @@ abstract class HSearchComponent extends CApplicationComponent
/**
* Updates an object in search index.
*
* @param ISearchable $object
* @param Searchable $object
*/
public function update(ISearchable $object)
public function update(Searchable $object)
{
}
@ -70,9 +74,9 @@ abstract class HSearchComponent extends CApplicationComponent
/**
* Deletes an object in search.
*
* @param ISearchable $object
* @param Searchable $object
*/
public function delete(ISearchable $object)
public function delete(Searchable $object)
{
}
@ -80,7 +84,7 @@ abstract class HSearchComponent extends CApplicationComponent
/**
* Deletes all objects from search index.
*
* @param ISearchable $object
* @param Searchable $object
*/
public function flush()
{
@ -93,9 +97,7 @@ abstract class HSearchComponent extends CApplicationComponent
public function rebuild()
{
$this->flush();
if ($this->hasEventHandler('onRebuild'))
$this->onRebuild(new CEvent($this));
$this->trigger(self::EVENT_ON_REBUILD);
$this->optimize();
}
@ -107,16 +109,7 @@ abstract class HSearchComponent extends CApplicationComponent
}
/**
* This event is raised after the rebuild is performed.
* @param CEvent $event the event parameter
*/
public function onRebuild($event)
{
$this->raiseEvent('onRebuild', $event);
}
protected function getMetaInfoArray(ISearchable $obj)
protected function getMetaInfoArray(Searchable $obj)
{
$meta = array();
$meta['type'] = $this->getDocumentType($obj);
@ -125,7 +118,7 @@ abstract class HSearchComponent extends CApplicationComponent
// Add content related meta data
if ($meta['type'] == self::DOCUMENT_TYPE_CONTENT) {
$meta['containerModel'] = get_class($obj->content->container);
$meta['containerModel'] = $obj->content->container->className();
$meta['containerPk'] = $obj->content->container->id;
$meta['visibility'] = $obj->content->visibility;
} else {
@ -135,13 +128,13 @@ abstract class HSearchComponent extends CApplicationComponent
return $meta;
}
protected function getDocumentType(ISearchable $obj)
protected function getDocumentType(Searchable $obj)
{
if ($obj instanceof Space) {
return self::DOCUMENT_TYPE_SPACE;
} elseif ($obj instanceof User) {
return self::DOCUMENT_TYPE_USER;
} elseif ($obj instanceof HActiveRecordContent) {
} elseif ($obj instanceof \humhub\core\content\components\activerecords\Content) {
return self::DOCUMENT_TYPE_CONTENT;
} else {
return self::DOCUMENT_TYPE_OTHER;
@ -154,7 +147,7 @@ abstract class HSearchComponent extends CApplicationComponent
$options['page'] = 1;
if (!isset($options['pageSize']) || $options['pageSize'] == "")
$options['pageSize'] = HSetting::Get('paginationSize');
$options['pageSize'] = Setting::Get('paginationSize');
if (!isset($options['checkPermissions'])) {
$options['checkPermissions'] = true;

View File

@ -6,60 +6,68 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\engine;
use Yii;
use humhub\core\search\interfaces\Searchable;
use humhub\core\content\models\Content;
use humhub\core\search\libs\SearchResult;
use humhub\core\search\libs\SearchResultSet;
/**
* ZendLucenceSearch Engine
*
* @since 0.12
* @author luke
*/
class ZendLuceneSearch extends HSearchComponent
class ZendLuceneSearch extends Search
{
public $index = null;
public function add(ISearchable $obj)
public function add(Searchable $obj)
{
// Get Primary Key
$attributes = $obj->getSearchAttributes();
$index = $this->getIndex();
$doc = new ZendSearch\Lucene\Document();
$doc = new \ZendSearch\Lucene\Document();
// Add Meta Data fields
foreach ($this->getMetaInfoArray($obj) as $fieldName => $fieldValue) {
$doc->addField(ZendSearch\Lucene\Document\Field::Text($fieldName, $fieldValue));
$doc->addField(\ZendSearch\Lucene\Document\Field::Text($fieldName, $fieldValue));
}
// Add provided search infos
foreach ($attributes as $key => $val) {
$doc->addField(ZendSearch\Lucene\Document\Field::Text($key, $val, 'UTF-8'));
$doc->addField(\ZendSearch\Lucene\Document\Field::Text($key, $val, 'UTF-8'));
}
if ($obj instanceof HActiveRecordContent) {
if ($obj instanceof \humhub\core\content\components\activerecords\Content) {
$comments = "";
foreach (Comment::model()->findAllByAttributes(array('object_id' => $obj->getPrimaryKey(), 'object_model' => get_class($obj))) as $comment) {
$comments .= " ".$comment->message;
$comments .= " " . $comment->message;
}
$doc->addField(ZendSearch\Lucene\Document\Field::Text('comments', $comments, 'UTF-8'));
$doc->addField(\ZendSearch\Lucene\Document\Field::Text('comments', $comments, 'UTF-8'));
}
if (Yii::app() instanceof CConsoleApplication) {
if (\Yii::$app->request->isConsoleRequest) {
print ".";
}
$index->addDocument($doc);
$index->commit();
}
public function update(ISearchable $object)
public function update(Searchable $object)
{
$this->delete($object);
$this->add($object);
$this->optimize();
}
public function delete(ISearchable $obj)
public function delete(Searchable $obj)
{
$index = $this->getIndex();
@ -74,7 +82,7 @@ class ZendLuceneSearch extends HSearchComponent
public function flush()
{
$indexPath = $this->getIndexPath();
foreach (new DirectoryIterator($indexPath) as $fileInfo) {
foreach (new \DirectoryIterator($indexPath) as $fileInfo) {
if ($fileInfo->isDot())
continue;
unlink($indexPath . $fileInfo->getFilename());
@ -91,9 +99,9 @@ class ZendLuceneSearch extends HSearchComponent
$keyword = str_replace(array('*', '?', '_', '$'), ' ', strtolower($keyword));
if (!isset($options['sortField']) || $options['sortField'] == "") {
$hits = new ArrayObject($index->find($this->buildQuery($keyword, $options)));
$hits = new \ArrayObject($index->find($this->buildQuery($keyword, $options)));
} else {
$hits = new ArrayObject($index->find($this->buildQuery($keyword, $options), $options['sortField']));
$hits = new \ArrayObject($index->find($this->buildQuery($keyword, $options), $options['sortField']));
}
$resultSet = new SearchResultSet();
@ -101,7 +109,7 @@ class ZendLuceneSearch extends HSearchComponent
$resultSet->pageSize = $options['pageSize'];
$resultSet->page = $options['page'];
$hits = new LimitIterator($hits->getIterator(), ($options['page'] - 1) * $options['pageSize'], $options['pageSize']);
$hits = new \LimitIterator($hits->getIterator(), ($options['page'] - 1) * $options['pageSize'], $options['pageSize']);
foreach ($hits as $hit) {
$document = $hit->getDocument();
@ -118,57 +126,57 @@ class ZendLuceneSearch extends HSearchComponent
protected function buildQuery($keyword, $options)
{
$query = new ZendSearch\Lucene\Search\Query\Boolean();
$query = new \ZendSearch\Lucene\Search\Query\Boolean();
foreach (explode(" ", $keyword) as $k) {
// Require at least 3 non-wildcard characters
if (strlen($k) > 2) {
$term = new ZendSearch\Lucene\Index\Term($k . "*");
$query->addSubquery(new ZendSearch\Lucene\Search\Query\Wildcard($term), true);
$term = new \ZendSearch\Lucene\Index\Term($k . "*");
$query->addSubquery(new \ZendSearch\Lucene\Search\Query\Wildcard($term), true);
}
}
// Add model filter
if (isset($options['model']) && $options['model'] != "") {
if (is_array($options['model'])) {
$boolQuery = new ZendSearch\Lucene\Search\Query\MultiTerm();
$boolQuery = new \ZendSearch\Lucene\Search\Query\MultiTerm();
foreach ($options['model'] as $model) {
$boolQuery->addTerm(new ZendSearch\Lucene\Index\Term(strtolower($model), 'model'));
$boolQuery->addTerm(new \ZendSearch\Lucene\Index\Term(strtolower($model), 'model'));
}
$query->addSubquery($boolQuery, true);
} else {
$term = new ZendSearch\Lucene\Index\Term(strtolower($options['model']), 'model');
$query->addSubquery(new ZendSearch\Lucene\Search\Query\Term($term), true);
$term = new \ZendSearch\Lucene\Index\Term(strtolower($options['model']), 'model');
$query->addSubquery(new \ZendSearch\Lucene\Search\Query\Term($term), true);
}
}
// Add type filter
if (isset($options['type']) && $options['type'] != "") {
if (is_array($options['type'])) {
$boolQuery = new ZendSearch\Lucene\Search\Query\MultiTerm();
$boolQuery = new \ZendSearch\Lucene\Search\Query\MultiTerm();
foreach ($options['type'] as $model) {
$boolQuery->addTerm(new ZendSearch\Lucene\Index\Term(strtolower($type), 'type'));
$boolQuery->addTerm(new \ZendSearch\Lucene\Index\Term(strtolower($type), 'type'));
}
$query->addSubquery($boolQuery, true);
} else {
$term = new ZendSearch\Lucene\Index\Term(strtolower($options['type']), 'type');
$query->addSubquery(new ZendSearch\Lucene\Search\Query\Term($term), true);
$term = new \ZendSearch\Lucene\Index\Term(strtolower($options['type']), 'type');
$query->addSubquery(new \ZendSearch\Lucene\Search\Query\Term($term), true);
}
}
if ($options['checkPermissions']) {
$permissionQuery = new ZendSearch\Lucene\Search\Query\Boolean();
if ($options['checkPermissions'] && !Yii::$app->request->isConsoleRequest) {
$permissionQuery = new \ZendSearch\Lucene\Search\Query\Boolean();
//--- Public Content
$permissionQuery->addSubquery(new ZendSearch\Lucene\Search\Query\Term(new ZendSearch\Lucene\Index\Term(Content::VISIBILITY_PUBLIC, 'visibility')));
$permissionQuery->addSubquery(new \ZendSearch\Lucene\Search\Query\Term(new \ZendSearch\Lucene\Index\Term(Content::VISIBILITY_PUBLIC, 'visibility')));
//--- Private Space Content
$privateSpaceContentQuery = new ZendSearch\Lucene\Search\Query\Boolean();
$privateSpaceContentQuery->addSubquery(new ZendSearch\Lucene\Search\Query\Term(new ZendSearch\Lucene\Index\Term(Content::VISIBILITY_PRIVATE, 'visibility')), true);
$privateSpaceContentQuery->addSubquery(new ZendSearch\Lucene\Search\Query\Term(new ZendSearch\Lucene\Index\Term('space', 'containerModel')), true);
$privateSpacesListQuery = new ZendSearch\Lucene\Search\Query\MultiTerm();
$privateSpaceContentQuery = new \ZendSearch\Lucene\Search\Query\Boolean();
$privateSpaceContentQuery->addSubquery(new \ZendSearch\Lucene\Search\Query\Term(new \ZendSearch\Lucene\Index\Term(Content::VISIBILITY_PRIVATE, 'visibility')), true);
$privateSpaceContentQuery->addSubquery(new \ZendSearch\Lucene\Search\Query\Term(new \ZendSearch\Lucene\Index\Term('space', 'containerModel')), true);
$privateSpacesListQuery = new \ZendSearch\Lucene\Search\Query\MultiTerm();
foreach (SpaceMembership::GetUserSpaces() as $space) {
$privateSpacesListQuery->addTerm(new ZendSearch\Lucene\Index\Term($space->id, 'containerPk'));
foreach (\humhub\core\space\models\Membership::GetUserSpaces() as $space) {
$privateSpacesListQuery->addTerm(new \ZendSearch\Lucene\Index\Term($space->id, 'containerPk'));
}
$privateSpaceContentQuery->addSubquery($privateSpacesListQuery, true);
@ -179,11 +187,11 @@ class ZendLuceneSearch extends HSearchComponent
if (count($options['limitSpaces']) > 0) {
$spaceBaseQuery = new ZendSearch\Lucene\Search\Query\Boolean();
$spaceBaseQuery->addSubquery(new ZendSearch\Lucene\Search\Query\Term(new ZendSearch\Lucene\Index\Term('space', 'containerModel')), true);
$spaceIdQuery = new ZendSearch\Lucene\Search\Query\MultiTerm();
$spaceBaseQuery = new \ZendSearch\Lucene\Search\Query\Boolean();
$spaceBaseQuery->addSubquery(new \ZendSearch\Lucene\Search\Query\Term(new \ZendSearch\Lucene\Index\Term('space', 'containerModel')), true);
$spaceIdQuery = new \ZendSearch\Lucene\Search\Query\MultiTerm();
foreach ($options['limitSpaces'] as $space) {
$spaceIdQuery->addTerm(new ZendSearch\Lucene\Index\Term($space->id, 'containerPk'));
$spaceIdQuery->addTerm(new \ZendSearch\Lucene\Index\Term($space->id, 'containerPk'));
}
$spaceBaseQuery->addSubquery($spaceIdQuery, true);
$query->addSubquery($spaceBaseQuery, true);
@ -205,16 +213,14 @@ class ZendLuceneSearch extends HSearchComponent
if ($this->index != null)
return $this->index;
Yii::setPathOfAlias('ZendSearch', Yii::getPathOfAlias('application.modules_core.search.extensions.ZendSearch'));
ZendSearch\Lucene\Search\QueryParser::setDefaultEncoding('utf-8');
ZendSearch\Lucene\Analysis\Analyzer\Analyzer::setDefault(new ZendSearch\Lucene\Analysis\Analyzer\Common\Utf8Num\CaseInsensitive());
ZendSearch\Lucene\Search\QueryParser::setDefaultOperator(ZendSearch\Lucene\Search\QueryParser::B_AND);
\ZendSearch\Lucene\Search\QueryParser::setDefaultEncoding('utf-8');
\ZendSearch\Lucene\Analysis\Analyzer\Analyzer::setDefault(new \ZendSearch\Lucene\Analysis\Analyzer\Common\Utf8Num\CaseInsensitive());
\ZendSearch\Lucene\Search\QueryParser::setDefaultOperator(\ZendSearch\Lucene\Search\QueryParser::B_AND);
try {
$index = ZendSearch\Lucene\Lucene::open($this->getIndexPath());
} catch (Exception $ex) {
$index = ZendSearch\Lucene\Lucene::create($this->getIndexPath());
$index = \ZendSearch\Lucene\Lucene::open($this->getIndexPath());
} catch (\ZendSearch\Lucene\Exception\RuntimeException $ex) {
$index = \ZendSearch\Lucene\Lucene::create($this->getIndexPath());
}
$this->index = $index;
@ -223,7 +229,7 @@ class ZendLuceneSearch extends HSearchComponent
protected function getIndexPath()
{
$path = Yii::app()->getRuntimePath() . DIRECTORY_SEPARATOR . "searchdb" . DIRECTORY_SEPARATOR;
$path = Yii::getAlias('@runtime/searchdb/');
if (!is_dir($path)) {
mkdir($path);

View File

@ -6,6 +6,8 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\interfaces;
/**
* Interface for Searchable Models
*
@ -13,7 +15,7 @@
* @since 0.5
* @author Luke
*/
interface ISearchable
interface Searchable
{
public function getSearchAttributes();

View File

@ -6,6 +6,8 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\libs;
/**
* Description of SearchResult
*

View File

@ -6,6 +6,8 @@
* @license https://www.humhub.com/licences
*/
namespace humhub\core\search\libs;
/**
* Description of SearchResult
*
@ -25,13 +27,11 @@ class SearchResultSet
foreach ($this->results as $result) {
$modelClass = $result->model;
$model = call_user_func(array($modelClass, 'model'));
$instance = $model->findByPk($result->pk);
$instance = $modelClass::findOne(['id' => $result->pk]);
if ($instance !== null) {
$instances[] = $instance;
} else {
Yii::log('Could not load search result ' . $result->model . " - " . $result->pk, CLogger::LEVEL_ERROR);
\Yii::error('Could not load search result ' . $result->model . " - " . $result->pk);
}
}

View File

@ -1,12 +1,15 @@
<?php
class m150510_102900_update extends EDbMigration
use yii\db\Schema;
use yii\db\Migration;
class m150510_102900_update extends Migration
{
public function up()
{
if (HSetting::isInstalled()) {
Yii::app()->search->rebuild();
if (\humhub\models\Setting::isInstalled()) {
\Yii::$app->search->rebuild();
}
}

View File

@ -1,4 +1,9 @@
<?php
use yii\helpers\Url;
use yii\helpers\Html;
use humhub\core\search\controllers\SearchController;
?>
<div class="container">
<div class="row">
<div class="col-md-12">
@ -6,25 +11,28 @@
<div class="panel-heading"><?php echo Yii::t('base', 'Search'); ?></div>
<div class="panel-body">
<?php echo CHtml::beginForm($this->createUrl('index'), 'GET'); ?>
<?php echo Html::beginForm(Url::to(['index']), 'GET'); ?>
<div class="input-group">
<?php echo CHtml::textField('keyword', $keyword, array('placeholder' => 'Keyword', 'class' => 'form-control')); ?>
<?php echo Html::textInput('keyword', $keyword, array('placeholder' => 'Keyword', 'class' => 'form-control')); ?>
<span class="input-group-btn">
<?php echo CHtml::submitButton(Yii::t('base', 'Search'), array('class' => 'btn btn-primary pull-right')); ?>
<?php echo Html::submitButton(Yii::t('base', 'Search'), array('class' => 'btn btn-primary pull-right')); ?>
</span>
</div>
<br />
Search only in certain spaces:
<?php echo CHtml::textField('limitSpaceGuids', $limitSpaceGuids, array('placeholder' => 'Specify space', 'style' => 'width:200px', 'id' => 'space_filter')); ?>
<?php echo Html::textInput('limitSpaceGuids', $limitSpaceGuids, array('placeholder' => 'Specify space', 'style' => 'width:200px', 'id' => 'space_filter')); ?>
<?php
$this->widget('application.modules_core.space.widgets.SpacePickerWidget', array(
'inputId' => 'space_filter',
'value' => $limitSpaceGuids,
));
/*
$this->widget('application.modules_core.space.widgets.SpacePickerWidget', array(
'inputId' => 'space_filter',
'value' => $limitSpaceGuids,
));
*
*/
?>
<?php echo CHtml::endForm(); ?>
<?php echo Html::endForm(); ?>
</div>
</div>
</div>
@ -33,20 +41,20 @@
<div class="row">
<div class="col-md-2">
<div class="panel panel-default">
<div class="panel-heading"><?php echo Yii::t('DirectoryModule.views_directory_layout', '<strong>Search </strong> results'); ?></div>
<div class="panel-heading"><?php echo Yii::t('SearchModule.views_directory_layout', '<strong>Search </strong> results'); ?></div>
<div class="list-group">
<a href='<?php echo $this->createUrl('//search/search/index', array('keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_ALL)); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_ALL): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('DirectoryModule.views_directory_layout', 'All'); ?> (<?php echo $totals[SearchController::SCOPE_ALL]; ?>)</div></div>
<a href='<?php echo Url::to(['/search/search/index', 'keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_ALL]); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_ALL): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('SearchModule.views_directory_layout', 'All'); ?> (<?php echo $totals[SearchController::SCOPE_ALL]; ?>)</div></div>
</a>
<br />
<a href='<?php echo $this->createUrl('//search/search/index', array('keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_CONTENT)); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_CONTENT): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('DirectoryModule.views_directory_layout', 'Content'); ?> (<?php echo $totals[SearchController::SCOPE_CONTENT]; ?>)</div></div>
<a href='<?php echo Url::to(['/search/search/index', 'keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_CONTENT]); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_CONTENT): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('SearchModule.views_directory_layout', 'Content'); ?> (<?php echo $totals[SearchController::SCOPE_CONTENT]; ?>)</div></div>
</a>
<a href='<?php echo $this->createUrl('//search/search/index', array('keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_USER)); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_USER): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('DirectoryModule.views_directory_layout', 'Users'); ?> (<?php echo $totals[SearchController::SCOPE_USER]; ?>)</div></div>
<a href='<?php echo Url::to(['/search/search/index', 'keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_USER]); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_USER): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('SearchModule.views_directory_layout', 'Users'); ?> (<?php echo $totals[SearchController::SCOPE_USER]; ?>)</div></div>
</a>
<a href='<?php echo $this->createUrl('//search/search/index', array('keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_SPACE)); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_SPACE): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('DirectoryModule.views_directory_layout', 'Spaces'); ?> (<?php echo $totals[SearchController::SCOPE_SPACE]; ?>)</div></div>
<a href='<?php echo Url::to(['/search/search/index', 'keyword' => $keyword, 'limitSpaceGuids' => $limitSpaceGuids, 'scope' => SearchController::SCOPE_SPACE]); ?>' class="list-group-item <?php if ($scope == SearchController::SCOPE_SPACE): ?>active<?php endif; ?>">
<div><div class="edit_group "><?php echo Yii::t('SearchModule.views_directory_layout', 'Spaces'); ?> (<?php echo $totals[SearchController::SCOPE_SPACE]; ?>)</div></div>
</a>
</div>
</div>
@ -59,7 +67,7 @@
<?php if (count($results) > 0): ?>
<?php foreach ($results as $result): ?>
<?php if ($result instanceof HActiveRecordContent || $result instanceof HActiveRecordContentContainer) : ?>
<?php if ($result instanceof humhub\core\content\components\activerecords\Content || $result instanceof humhub\core\content\components\activerecords\ContentContainer) : ?>
<?php echo $result->getWallOut(); ?>
<?php else: ?>
No Output for Class <?php echo get_class($result); ?>
@ -72,7 +80,7 @@
</ul>
<div class="pagination-container"><?php $this->widget('HLinkPager', array('pages' => $pagination)); ?></div>
<div class="pagination-container"><?php //$this->widget('HLinkPager', array('pages' => $pagination)); ?></div>
</div>
@ -83,9 +91,9 @@
<script>
<?php foreach (explode(" ", $keyword) as $k) : ?>
$(".searchResults").highlight("<?php echo CHtml::encode($k); ?>");
$(".searchResults").highlight("<?php echo Html::encode($k); ?>");
$(document).ajaxComplete(function (event, xhr, settings) {
$(".searchResults").highlight("<?php echo CHtml::encode($k); ?>");
$(".searchResults").highlight("<?php echo Html::encode($k); ?>");
});
<?php endforeach; ?>
</script>

View File

@ -0,0 +1,12 @@
<?php
namespace humhub\core\search\widgets;
class SearchMenu extends \yii\base\Widget
{
public function run()
{
return $this->render('searchMenu', array());
}
}

View File

@ -1,18 +0,0 @@
<?php
class SearchMenuWidget extends HWidget
{
public function init()
{
$assetPrefix = Yii::app()->assetManager->publish(dirname(__FILE__) . '/../assets', true, 0, defined('YII_DEBUG'));
//Yii::app()->clientScript->registerScriptFile($assetPrefix . '/searchmenu.js');
//Yii::app()->clientScript->setJavaScriptVariable('searchAjaxUrl', $this->createUrl('//search/search/index', array('mode' => 'quick', 'keyword' => '-searchKeyword-')));
}
public function run()
{
$this->render('searchMenu', array());
}
}

View File

@ -1,5 +1,11 @@
<?php
use yii\helpers\Url;
use yii\helpers\Html;
?>
<li class="dropdown">
<a href="<?php echo $this->createUrl('//search/search/index', array('limitSpaceGuids' => Yii::app()->request->getParam('sguid'))); ?>" id="search-menu" class="dropdown-toggle" >
<a href="<?php echo Url::to(['/search/search/index', 'limitSpaceGuids' => Yii::$app->request->get('sguid')]); ?>" id="search-menu" class="dropdown-toggle" >
<i class="fa fa-search"></i></a>
</li>
<!--<li class="dropdown">

View File

@ -8,6 +8,9 @@
namespace humhub\core\space;
use Yii;
use humhub\core\space\models\Space;
/**
* Description of Events
*
@ -23,9 +26,9 @@ class Events extends \yii\base\Object
*/
public static function onSearchRebuild($event)
{
foreach (Space::model()->findAll() as $obj) {
foreach (Space::find()->all() as $obj) {
if ($obj->visibility != Space::VISIBILITY_NONE) {
Yii::app()->search->add($obj);
Yii::$app->search->add($obj);
}
}
}

View File

@ -1,69 +0,0 @@
<?php
/**
* SpaceModule provides all space related classes & functions.
*
* @author Luke
* @package humhub.modules_core.space
* @since 0.5
*/
class SpaceModule extends HWebModule
{
public $isCoreModule = true;
public function init()
{
$this->setImport(array(
'space.models.*',
'space.forms.*',
'space.controllers.*',
'space.widgets.*',
));
}
/**
* On rebuild of the search index, rebuild all space records
*
* @param type $event
*/
public static function onSearchRebuild($event)
{
foreach (Space::model()->findAll() as $obj) {
if ($obj->visibility != Space::VISIBILITY_NONE) {
Yii::app()->search->add($obj);
}
}
}
/**
* On User delete, also delete his space related stuff
*
* @param type $event
*/
public static function onUserDelete($event)
{
$user = $event->sender;
// Check if the user owns some spaces
foreach (SpaceMembership::GetUserSpaces($user->id) as $space) {
if ($space->isSpaceOwner($user->id)) {
throw new CHttpException(500, Yii::t('SpaceModule.base', 'Could not delete user who is a space owner! Name of Space: {spaceName}', array('spaceName' => $space->name)));
}
}
// Cancel all space memberships
foreach (SpaceMembership::model()->findAllByAttributes(array('user_id' => $user->id)) as $membership) {
$membership->space->removeMember($user->id);
}
// Cancel all space invites by the user
foreach (SpaceMembership::model()->findAllByAttributes(array('originator_user_id' => $user->id, 'status' => SpaceMembership::STATUS_INVITED)) as $membership) {
$membership->space->removeMember($membership->user_id);
}
return true;
}
}

View File

@ -1,11 +1,16 @@
<?php
use humhub\core\search\engine\Search;
use humhub\core\user\models\User;
use humhub\core\space\Events;
Yii::$app->moduleManager->register(array(
'id' => 'space',
'class' => \humhub\core\space\Module::className(),
'isCoreModule' => true,
'events' => array(
array('class' => humhub\core\user\models\User::className(), 'event' => 'onBeforeDelete', 'callback' => array('SpaceModule', 'onUserDelete')),
array('class' => User::className(), 'event' => User::EVENT_BEFORE_DELETE, 'callback' => array(Events::className(), 'onUserDelete')),
array('class' => Search::className(), 'event' => Search::EVENT_ON_REBUILD, 'callback' => array(Events::className(), 'onSearchRebuild')),
),
));
?>

View File

@ -26,7 +26,7 @@ use humhub\core\activity\models\Activity;
* @property string $ldap_dn
* @property integer $auto_add_new_members
*/
class Space extends \humhub\core\content\components\activerecords\ContentContainer
class Space extends \humhub\core\content\components\activerecords\ContentContainer implements \humhub\core\search\interfaces\Searchable
{
// Join Policies

View File

@ -1,3 +1,7 @@
<?php
use yii\helpers\Html;
?>
<div class="panel panel-default">
<div class="panel-body">
@ -9,8 +13,8 @@
</a>
<div class="media-body">
<!-- show username with link and creation time-->
<h4 class="media-heading"><a href="<?php echo $space->getUrl(); ?>"><?php echo CHtml::encode($space->displayName); ?></a> </h4>
<h5><?php echo CHtml::encode($space->description); ?></h5>
<h4 class="media-heading"><a href="<?php echo $space->getUrl(); ?>"><?php echo Html::encode($space->displayName); ?></a> </h4>
<h5><?php echo Html::encode($space->description); ?></h5>
</div>
</div>

View File

@ -5,10 +5,16 @@ namespace humhub\core\user;
class Events extends \yii\base\Object
{
public static function onLoad()
/**
* On rebuild of the search index, rebuild all user records
*
* @param type $event
*/
public static function onSearchRebuild($event)
{
print "cb";
die();
foreach (models\User::find()->all() as $obj) {
\Yii::$app->search->add($obj);
}
}
}

View File

@ -1,13 +1,15 @@
<?php
use \humhub\core\user\models\User;
use humhub\core\user\models\User;
use humhub\core\search\engine\Search;
use humhub\core\user\Events;
\Yii::$app->moduleManager->register(array(
'id' => 'user',
'class' => \humhub\core\user\Module::className(),
'isCoreModule' => true,
'events' => array(
//array('class' => User::className(), 'event' => User::EVENT_INIT, 'callback' => array('app\modules\user\Events', 'onLoad')),
array('class' => Search::className(), 'event' => Search::EVENT_ON_REBUILD, 'callback' => array(Events::className(), 'onSearchRebuild')),
)
));
?>

View File

@ -27,7 +27,7 @@ use humhub\models\Setting;
* @property string $last_login
* @property integer $visibility
*/
class User extends \humhub\core\content\components\activerecords\ContentContainer implements \yii\web\IdentityInterface
class User extends \humhub\core\content\components\activerecords\ContentContainer implements \yii\web\IdentityInterface, \humhub\core\search\interfaces\Searchable
{
/**
@ -247,52 +247,52 @@ class User extends \humhub\core\content\components\activerecords\ContentContaine
}
}
\humhub\core\user\models\Setting::deleteAll(['user_id'=>$this->id]);
\humhub\core\user\models\Setting::deleteAll(['user_id' => $this->id]);
// Disable all enabled modules
/*
foreach ($this->getAvailableModules() as $moduleId => $module) {
if ($this->isModuleEnabled($moduleId)) {
$this->disableModule($moduleId);
}
}
Yii::app()->search->delete($this);
foreach ($this->getAvailableModules() as $moduleId => $module) {
if ($this->isModuleEnabled($moduleId)) {
$this->disableModule($moduleId);
}
}
Yii::app()->search->delete($this);
// Delete user session
UserHttpSession::model()->deleteAllByAttributes(array('user_id' => $this->id));
// Delete Profile Image
$this->getProfileImage()->delete();
// Delete user session
UserHttpSession::model()->deleteAllByAttributes(array('user_id' => $this->id));
// Delete all pending invites
UserInvite::model()->deleteAllByAttributes(array('user_originator_id' => $this->id));
// Delete Profile Image
$this->getProfileImage()->delete();
UserFollow::model()->deleteAllByAttributes(array('user_id' => $this->id));
UserFollow::model()->deleteAllByAttributes(array('object_model' => 'User', 'object_id' => $this->id));
// Delete all pending invites
UserInvite::model()->deleteAllByAttributes(array('user_originator_id' => $this->id));
// Delete all group admin assignments
GroupAdmin::model()->deleteAllByAttributes(array('user_id' => $this->id));
UserFollow::model()->deleteAllByAttributes(array('user_id' => $this->id));
UserFollow::model()->deleteAllByAttributes(array('object_model' => 'User', 'object_id' => $this->id));
// Delete wall entries
WallEntry::model()->deleteAllByAttributes(array('wall_id' => $this->wall_id));
// Delete all group admin assignments
GroupAdmin::model()->deleteAllByAttributes(array('user_id' => $this->id));
// Delete user profile
Profile::model()->deleteAllByAttributes(array('user_id' => $this->id));
// Delete wall entries
WallEntry::model()->deleteAllByAttributes(array('wall_id' => $this->wall_id));
// Deletes all content created by this user
foreach (Content::model()->findAllByAttributes(array('user_id' => $this->id)) as $content) {
$content->delete();
}
foreach (Content::model()->findAllByAttributes(array('created_by' => $this->id)) as $content) {
$content->delete();
}
// Delete user profile
Profile::model()->deleteAllByAttributes(array('user_id' => $this->id));
// Delete all passwords
foreach (UserPassword::model()->findAllByAttributes(array('user_id' => $this->id)) as $password) {
$password->delete();
}
*/
// Deletes all content created by this user
foreach (Content::model()->findAllByAttributes(array('user_id' => $this->id)) as $content) {
$content->delete();
}
foreach (Content::model()->findAllByAttributes(array('created_by' => $this->id)) as $content) {
$content->delete();
}
// Delete all passwords
foreach (UserPassword::model()->findAllByAttributes(array('user_id' => $this->id)) as $password) {
$password->delete();
}
*/
return parent::beforeDelete();
}
@ -404,7 +404,7 @@ class User extends \humhub\core\content\components\activerecords\ContentContaine
$wall->save();
$this->wall_id = $wall->id;
$this->update(false, ['wall_id']);
}
@ -489,7 +489,7 @@ class User extends \humhub\core\content\components\activerecords\ContentContaine
public function getWallOut()
{
return Yii::app()->getController()->widget('application.modules_core.user.widgets.UserWallWidget', array('user' => $this), true);
return \humhub\core\user\widgets\UserWall::widget(['user' => $this]);
}
/**
@ -536,10 +536,8 @@ class User extends \humhub\core\content\components\activerecords\ContentContaine
'title' => $this->profile->title,
);
$profile = $this->getProfile();
if (!$profile->isNewRecord) {
foreach ($profile->getProfileFields() as $profileField) {
if (!$this->profile->isNewRecord) {
foreach ($this->profile->getProfileFields() as $profileField) {
$attributes['profile_' . $profileField->internal_name] = $profileField->getUserValue($this, true);
}
}

View File

@ -1,16 +1,20 @@
<?php
use yii\helpers\Html;
?>
<div class="panel panel-default" id="user-wall-<?php echo $user->id; ?>">
<div class="panel-body">
<div class="media">
<a href="<?php echo $user->getProfileUrl(); ?>" class="pull-left">
<a href="<?php echo $user->getUrl(); ?>" class="pull-left">
<img class="media-object img-rounded user-image user-<?php echo $user->guid; ?>" alt="40x40" data-src="holder.js/40x40" style="width: 40px; height: 40px;"
src="<?php echo $user->getProfileImage()->getUrl(); ?>"
width="40" height="40"/>
</a>
<div class="media-body">
<!-- show username with link and creation time-->
<h4 class="media-heading"><a href="<?php echo $user->getProfileUrl(); ?>"><?php echo CHtml::encode($user->displayName); ?></a> </h4>
<h5><?php echo CHtml::encode($user->profile->title); ?></h5>
<h4 class="media-heading"><a href="<?php echo $user->getUrl(); ?>"><?php echo Html::encode($user->displayName); ?></a> </h4>
<h5><?php echo Html::encode($user->profile->title); ?></h5>
</div>
</div>

View File

@ -43,6 +43,7 @@ Development - Modules
* [Notifications](dev-module-notifications.md)
* [Search](dev-module-search.md)
* [CronJobs](dev-module-cron.md)
* [Console](dev-module-console.md)
* [Special Topics](dev-module-special-topics.md)
Theming

View File

@ -11,15 +11,23 @@
- CronJobs
- Tests
- HSetting -> Add Caching & Co -> E-Mailing (New Test Setting)
- Space Header
- Directory
- Comments / Like
- Files
- Edit Posts
- Enricher Text
- Markdown Editor
- Handling Old Module Loading Fails
- Check CSRF Proteceted
- Check CSRF Protection
- Update Docs
- Change licence class header
- Add Var Types to View Files
-
## Bugs
- Log Table not created on Installation
## Core Changes

View File

@ -4,9 +4,10 @@ Here you will learn how you can adapt existing modules to working fine with actu
## to 0.20
**Update to Yii 2**
**Important: This relases updates to Yii 2!**
See more details here: [HumHub 0.20 Migration](dev-migrate-0-20.md)
This release requires a migration of all modules/themes.
Find more details here: [HumHub 0.20 Migration](dev-migrate-0-20.md)
## to 0.12

View File

@ -0,0 +1,35 @@
Console
=======
You can also add own console controller by events.
## Autostart Example
```php
<?php
use humhub\core\search\Events;
use humhub\components\console\Application;
Yii::$app->moduleManager->register(array(
'isCoreModule' => true,
'id' => 'search',
'class' => \humhub\core\search\Module::className(),
'events' => array(
array('class' => Application::className(), 'event' => Application::EVENT_ON_INIT, 'callback' => array(Events::className(), 'onConsoleApplicationInit')),
),
));
?>
```
## Callback Example
```php
public static function onConsoleApplicationInit($event) {
$application = $event->sender;
$application->controllerMap['search'] = commands\SearchController::className();
}
```