Egorka
7 years ago
20 changed files with 276 additions and 225 deletions
@ -0,0 +1,59 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $model \core\forms\user\ProfileEditForm */ |
||||||
|
/* @var $user \core\entities\user\User */ |
||||||
|
|
||||||
|
use yii\bootstrap\ActiveForm; |
||||||
|
use yii\helpers\Html; |
||||||
|
|
||||||
|
$this->title = Yii::t('user', 'Profile: {username}', ['username' => $user->username]); |
||||||
|
$this->params['breadcrumbs'][] = ['label' => $user->username, 'url' => ['view', 'id' => $user->id]]; |
||||||
|
$this->params['breadcrumbs'][] = Yii::t('user', 'Profile'); |
||||||
|
?> |
||||||
|
<div class="user-profile"> |
||||||
|
|
||||||
|
<?php $form = ActiveForm::begin(); ?> |
||||||
|
|
||||||
|
<div class="row"> |
||||||
|
<div class="col-md-3"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-body"> |
||||||
|
<div style="text-align: center"> |
||||||
|
<img style="width: 300px" src="<?= Yii::$app->avatar->show(Yii::$app->user->identity->user->username, null, null, Yii::$app->user->identity->user->user_pic) ?>?<?= rand(10, 5000) ?>" class="img-circle" alt="<?= Yii::$app->user->identity->user->username ?>"/>
|
||||||
|
</div> |
||||||
|
<!-- < ?= $form->field($model, 'user_pic')->fileInput() ?> --> |
||||||
|
<?= $form->field($model, 'user_pic')->widget(\kartik\widgets\FileInput::class, [ |
||||||
|
'options' => [ |
||||||
|
'accept' => 'image/*' |
||||||
|
], |
||||||
|
'pluginOptions' => [ |
||||||
|
'showPreview' => false, |
||||||
|
'showCaption' => true, |
||||||
|
'showRemove' => true, |
||||||
|
'showUpload' => false |
||||||
|
], |
||||||
|
]); ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="col-md-6"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-body"> |
||||||
|
<?= $form->field($model, 'username')->textInput(['maxLength' => true]) ?> |
||||||
|
<?= $form->field($model, 'email')->textInput(['maxLength' => true]) ?> |
||||||
|
<?= $form->field($model, 'password')->passwordInput(['maxLength' => true]) ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<?= Html::submitButton(Yii::t('buttons', 'Save'), ['class' => 'btn btn-primary']) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
|
||||||
|
</div> |
@ -1,171 +0,0 @@ |
|||||||
<?php |
|
||||||
/** |
|
||||||
* Created by Error202 |
|
||||||
* Date: 18.08.2017 |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace core\components\avatar_generator; |
|
||||||
|
|
||||||
use core\entities\user\User; |
|
||||||
use Yii; |
|
||||||
use yii\helpers\FileHelper; |
|
||||||
use yii\imagine\Image; |
|
||||||
use yii\web\NotFoundHttpException; |
|
||||||
|
|
||||||
class AvatarGenerator |
|
||||||
{ |
|
||||||
public $originPath; |
|
||||||
public $cachePath; |
|
||||||
|
|
||||||
public function __construct() |
|
||||||
{ |
|
||||||
$this->originPath = Yii::getAlias('@staticRoot') . '/origin'; |
|
||||||
$this->cachePath = Yii::getAlias('@staticRoot') . '/cache'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $type |
|
||||||
* @param string $name |
|
||||||
* @param array|null $options |
|
||||||
* |
|
||||||
* @return string |
|
||||||
* @throws NotFoundHttpException |
|
||||||
* @throws \yii\base\Exception |
|
||||||
*/ |
|
||||||
public function image(string $type, string $name, array $options = null): string |
|
||||||
{ |
|
||||||
$originPath = $this->originPath . '/' . $type; |
|
||||||
$origin = $originPath . '/' . $name; |
|
||||||
|
|
||||||
if (!file_exists($origin)) |
|
||||||
{ |
|
||||||
return ''; |
|
||||||
} |
|
||||||
|
|
||||||
$cachePath = $this->cachePath . '/' . $type; |
|
||||||
$cache = $cachePath . '/' . (isset($options['newName']) ? $options['newName'] : $name); |
|
||||||
|
|
||||||
$cacheUrl = Yii::getAlias('@static') . '/cache/' . $type . '/' . $name; |
|
||||||
|
|
||||||
if (isset($options['size'])) |
|
||||||
{ |
|
||||||
$size = $options['size']; |
|
||||||
} |
|
||||||
|
|
||||||
if (!isset($options['regenerate'])) |
|
||||||
{ |
|
||||||
$options['regenerate'] = false; |
|
||||||
} |
|
||||||
|
|
||||||
if (!file_exists($origin)) |
|
||||||
{ |
|
||||||
throw new NotFoundHttpException('Image "' . $name . '" does not exists.'); |
|
||||||
} |
|
||||||
|
|
||||||
if (!file_exists($cache) || $options['regenerate'] == true) |
|
||||||
{ |
|
||||||
FileHelper::createDirectory($cachePath, 0755, true); |
|
||||||
if (empty($size)) { |
|
||||||
//$size = isset(Yii::$app->params['imageSizes'][$type]) ? Yii::$app->params['imageSizes'][$type] : Yii::$app->params['imageSizes']['default']; |
|
||||||
$size = [300, 300]; |
|
||||||
} |
|
||||||
Image::thumbnail($origin, $size[0], $size[1])->save($cache); |
|
||||||
} |
|
||||||
return $cacheUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public function avatar(int $id): string |
|
||||||
{ |
|
||||||
if (!$user = User::findOne($id)) |
|
||||||
{ |
|
||||||
throw new NotFoundHttpException('User does not exists.'); |
|
||||||
} |
|
||||||
if (empty($user->user_pic) || !file_exists($this->originPath . '/avatar/' . $user->user_pic)) |
|
||||||
{ |
|
||||||
$user->user_pic = $this->generateAvatarByName($user->username); |
|
||||||
$user->save(); |
|
||||||
} |
|
||||||
return $this->image('avatar', $user->user_pic); |
|
||||||
} |
|
||||||
|
|
||||||
public function generateAvatarFromFile($file) |
|
||||||
{ |
|
||||||
$fileName = md5('avatar-' . md5($file) . time()) . '.png'; |
|
||||||
$originPath = $this->originPath . '/avatar'; |
|
||||||
$origin = $originPath . '/' . $fileName; |
|
||||||
FileHelper::createDirectory($originPath, 0755, true); |
|
||||||
copy($file, $origin); |
|
||||||
return $fileName; |
|
||||||
} |
|
||||||
|
|
||||||
public function generateAvatarByName(string $name): string |
|
||||||
{ |
|
||||||
$width = 300; |
|
||||||
$height = 300; |
|
||||||
$fontSize = 100; |
|
||||||
$font = Yii::getAlias('@core') . '/components/avatar_generator/Play-Bold.ttf'; |
|
||||||
|
|
||||||
$parts = explode(' ', $name); |
|
||||||
$text = is_array($parts) && count($parts)>1 ? mb_substr($parts[0],0,1,"UTF-8") . mb_substr($parts[1],0,1,"UTF-8") : mb_substr($name,0,1,"UTF-8"); |
|
||||||
|
|
||||||
$fileName = md5('avatar-' . $name . time()) . '.png'; |
|
||||||
|
|
||||||
$originPath = $this->originPath . '/avatar'; |
|
||||||
$origin = $originPath . '/' . $fileName; |
|
||||||
|
|
||||||
FileHelper::createDirectory($originPath, 0755, true); |
|
||||||
|
|
||||||
$img = imagecreatetruecolor($width, $height); |
|
||||||
|
|
||||||
$bgcolor = substr(md5($name), 0, 6); |
|
||||||
|
|
||||||
$rgb = []; |
|
||||||
list($rgb['r'], $rgb['g'], $rgb['b']) = sscanf($bgcolor, "%02x%02x%02x"); |
|
||||||
$rgb['rgb'] = $rgb['b'] + ($rgb['g'] << 0x8) + ($rgb['r'] << 0x10); |
|
||||||
|
|
||||||
$contrast = $this->RgbContrast($rgb['r'], $rgb['g'], $rgb['b']); |
|
||||||
|
|
||||||
$fillColor = imagecolorallocate($img, $rgb['r'], $rgb['g'], $rgb['b']); |
|
||||||
imagefill($img, 0,0, $fillColor); |
|
||||||
|
|
||||||
$cor = imagecolorallocate($img, $contrast['r'], $contrast['g'], $contrast['b']); |
|
||||||
|
|
||||||
$box = imageftbbox( $fontSize, 0, $font, $text ); |
|
||||||
$x = ($width - ($box[2] - $box[0])) / 2; |
|
||||||
$y = ($height - ($box[1] - $box[7])) / 2; |
|
||||||
$y -= $box[7]; |
|
||||||
|
|
||||||
imagettftext($img, $fontSize, 0, $x, $y, $cor, $font, $text); |
|
||||||
imagepng($img, $origin); |
|
||||||
imagedestroy($img); |
|
||||||
return $fileName; |
|
||||||
} |
|
||||||
|
|
||||||
public function getPath(string $type): string |
|
||||||
{ |
|
||||||
if (!file_exists($this->originPath . '/' . $type)) |
|
||||||
{ |
|
||||||
mkdir($this->originPath . '/' . $type, 0777, true); |
|
||||||
} |
|
||||||
return $this->originPath . '/' . $type; |
|
||||||
} |
|
||||||
|
|
||||||
public function remove(string $type, string $fileName = null): void |
|
||||||
{ |
|
||||||
if ($fileName && file_exists($this->originPath . '/' . $type . '/' . $fileName)) { |
|
||||||
unlink($this->originPath . '/' . $type . '/' . $fileName); |
|
||||||
} |
|
||||||
|
|
||||||
if ($fileName && file_exists($this->cachePath . '/' . $type . '/' . $fileName)) { |
|
||||||
unlink($this->cachePath . '/' . $type . '/' . $fileName); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function RgbContrast($r, $g, $b) { |
|
||||||
return array( |
|
||||||
'r' => ($r < 128) ? 255 : 0, |
|
||||||
'g' => ($g < 128) ? 255 : 0, |
|
||||||
'b' => ($b < 128) ? 255 : 0 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
Binary file not shown.
@ -0,0 +1,81 @@ |
|||||||
|
### Модули |
||||||
|
|
||||||
|
Модули располагаются в папке `common/modules` |
||||||
|
|
||||||
|
Папка модуля должна содержать основной файл, например, `BlogModule.php` следующего содержания |
||||||
|
```php |
||||||
|
<?php |
||||||
|
|
||||||
|
namespace common\modules\blog; |
||||||
|
use core\components\modules\ModuleInterface; |
||||||
|
use yii\helpers\ArrayHelper; |
||||||
|
|
||||||
|
class BlogModule extends \yii\base\Module implements ModuleInterface |
||||||
|
{ |
||||||
|
// Папка контроллеров модуля |
||||||
|
public $controllerNamespace = 'common\modules\blog\controllers'; |
||||||
|
|
||||||
|
// Инициализация модуля |
||||||
|
public function init() |
||||||
|
{ |
||||||
|
parent::init(); |
||||||
|
// custom initialization code goes here |
||||||
|
} |
||||||
|
|
||||||
|
// Автозапуск модуля |
||||||
|
public function bootstrap($app) |
||||||
|
{ |
||||||
|
// Добавление правила поиска по данному модулю |
||||||
|
$app->params['search_rules'][] = "SELECT title, content, CONCAT('/blog/manage/post/view/', id) AS url FROM {{blog_posts}}"; |
||||||
|
|
||||||
|
// Добавление правила роутинга |
||||||
|
$app->getUrlManager()->addRules([ |
||||||
|
'blog' => 'blog/post/index', |
||||||
|
]); |
||||||
|
|
||||||
|
// Добавление правил роутинга, в случае использования классов |
||||||
|
$app->getUrlManager()->addRules([ |
||||||
|
['class' => 'common\modules\blog\urls\BlogPostUrlRule'], |
||||||
|
['class' => 'common\modules\blog\urls\BlogCategoryUrlRule'], |
||||||
|
]); |
||||||
|
|
||||||
|
// Добавление локализации |
||||||
|
$app->getI18n()->translations = ArrayHelper::merge($app->getI18n()->translations, [ |
||||||
|
'blog' => [ |
||||||
|
'class' => 'yii\i18n\PhpMessageSource', |
||||||
|
'basePath' => '@common/modules/blog/messages', |
||||||
|
], |
||||||
|
'blog_public' => [ |
||||||
|
'class' => 'yii\i18n\PhpMessageSource', |
||||||
|
'basePath' => '@common/modules/blog/messages', |
||||||
|
], |
||||||
|
]); |
||||||
|
|
||||||
|
// Добавление пунктов в меню администратора |
||||||
|
if (basename($app->getBasePath()) === 'backend') { |
||||||
|
$app->params['adminMenu'][] = [ |
||||||
|
'label' => \Yii::t( 'blog', 'Blog' ), |
||||||
|
'icon' => 'book', |
||||||
|
'items' => [ |
||||||
|
[ |
||||||
|
'label' => \Yii::t( 'blog', 'Categories' ), |
||||||
|
'icon' => 'caret-right', |
||||||
|
'url' => [ '/blog/manage/category/index' ] |
||||||
|
], |
||||||
|
[ |
||||||
|
'label' => \Yii::t( 'blog', 'Posts' ), |
||||||
|
'icon' => 'caret-right', |
||||||
|
'url' => [ '/blog/manage/post/index' ] |
||||||
|
], |
||||||
|
[ |
||||||
|
'label' => \Yii::t( 'blog', 'Comments' ), |
||||||
|
'icon' => 'caret-right', |
||||||
|
'url' => [ '/blog/manage/comment/index' ] |
||||||
|
], |
||||||
|
], |
||||||
|
'visible' => \Yii::$app->user->can( 'admin' ) || \Yii::$app->user->can( 'BlogManagement' ) |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,18 @@ |
|||||||
|
# Zertex CMS |
||||||
|
Система управления сайтом на Yii2 |
||||||
|
|
||||||
|
**Для разработчика** |
||||||
|
|
||||||
|
* [Модули](Modules.md) |
||||||
|
|
||||||
|
#### Дополнительные параметры Yii::$app |
||||||
|
|
||||||
|
1. `$app->params['search_rules']` - Массив правил для поиска. |
||||||
|
|
||||||
|
Пример: |
||||||
|
```php |
||||||
|
$app->params['search_rules'][] = "SELECT title, content, CONCAT('/blog/manage/post/view/', id) AS url FROM {{blog_posts}}"; |
||||||
|
``` |
||||||
|
Поиск осуществляется по полям TITLE и CONTENT. В качестве URL указывается ссылка на конкрутную запись. |
||||||
|
|
||||||
|
Если название полей отличаются от TITLE и CONTENT, но, сгласно правилам SQL, указывайте ваше поле, затем `as TITLE` или `as CONTENT` |
Loading…
Reference in new issue