+ children )) {
+ foreach($model->children as $index => $child) {
+ ?>
+
+
+
+
diff --git a/common/modules/comment/views/artbox_comment_list.php b/common/modules/comment/views/artbox_comment_list.php
new file mode 100755
index 0000000..20dc4a9
--- /dev/null
+++ b/common/modules/comment/views/artbox_comment_list.php
@@ -0,0 +1,30 @@
+session->getFlash('artbox_comment_success')) != null) {
+ echo Html::tag('p', $success);
+ }
+ echo ListView::widget([
+ 'dataProvider' => $comments,
+ 'itemOptions' => $item_options,
+ 'itemView' => $item_view,
+ 'summary' => '',
+ ]);
+ Pjax::end();
+
\ No newline at end of file
diff --git a/common/modules/comment/views/artbox_comment_reply.php b/common/modules/comment/views/artbox_comment_reply.php
new file mode 100755
index 0000000..2aed197
--- /dev/null
+++ b/common/modules/comment/views/artbox_comment_reply.php
@@ -0,0 +1,61 @@
+ '.field-' . $text_input_id,
+ 'input' => '#' . $text_input_id,
+ ];
+ $artbox_comment_pid_input_selectors = [
+ 'container' => '.field-' . $artbox_comment_pid_input_id,
+ 'input' => '#' . $artbox_comment_pid_input_id,
+ ];
+ $form = ActiveForm::begin([
+ 'id' => $formId . '-reply',
+ 'action' => Url::to([
+ 'artbox-comment/default/create',
+ 'entity' => $comment_model->encryptedEntity,
+ ]),
+ ]);
+?>
+
+ field($comment_model, 'artbox_comment_pid', [
+ 'selectors' => $artbox_comment_pid_input_selectors,
+ 'inputOptions' => [
+ 'id' => $artbox_comment_pid_input_id,
+ 'class' => 'form-control',
+ ],
+ ])
+ ->hiddenInput()
+ ->label(false);
+ echo $form->field($comment_model, 'text', [
+ 'selectors' => $text_input_selectors,
+ 'inputOptions' => [
+ 'id' => $text_input_id,
+ 'class' => 'form-control',
+ 'cols' => 30,
+ 'rows' => 10,
+ ],
+ ])
+ ->textarea();
+ echo Html::submitButton(Yii::t('artbox-comment', 'Submit'));
+ echo Html::button(Yii::t('artbox-comment', 'Cancel'), [ 'data-action' => 'reply-cancel' ]);
+ ?>
+
+
\ No newline at end of file
diff --git a/common/modules/comment/views/manage/index.php b/common/modules/comment/views/manage/index.php
new file mode 100755
index 0000000..dcd3f50
--- /dev/null
+++ b/common/modules/comment/views/manage/index.php
@@ -0,0 +1,78 @@
+ 'Активный',
+ $searchModel::STATUS_HIDDEN => 'Скрытый',
+ $searchModel::STATUS_DELETED => 'Удаленный',
+ ];
+ Pjax::begin();
+ if(($success = \Yii::$app->session->getFlash('artbox_comment_success')) != null) {
+ echo Html::tag('p', $success);
+ }
+ echo GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'filterModel' => $searchModel,
+ 'columns' => [
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{update} {delete}',
+ ],
+ [
+ 'attribute' => 'artbox_comment_id',
+ 'label' => 'Идентификатор',
+ ],
+ [
+ 'attribute' => 'date_add',
+ 'format' => ['date', 'php:d.m.Y'],
+ 'filter' => false,
+ ],
+ 'text:text',
+ [
+ 'attribute' => 'user_id',
+ 'value' => function($model) {
+ if(!empty($model->user_id)) {
+ return $model->user->username . ' (id:' . $model->user->id . ')';
+ } else {
+ return $model->username.' '.$model->email.' (Гость)';
+ }
+ }
+ ],
+ [
+ 'attribute' => 'status',
+ 'filter' => $statuses,
+ 'value' => function($model) use($statuses) {
+ return $statuses[$model->status];
+ }
+ ],
+ [
+ 'attribute' => 'rating_value',
+ 'label' => $searchModel->getAttributeLabel('rating_value'),
+ 'value' => function($model) {
+ if(!empty($model->rating)) {
+ return $model->rating->value;
+ }
+ return NULL;
+ }
+ ],
+ 'entity',
+ 'entity_id',
+ [
+ 'attribute' => 'children_count',
+ 'label' => $searchModel->getAttributeLabel('children_count'),
+ 'value' => function($model) {
+ return count($model->children);
+ }
+ ],
+ ],
+ ]);
+ Pjax::end();
\ No newline at end of file
diff --git a/common/modules/comment/views/manage/update.php b/common/modules/comment/views/manage/update.php
new file mode 100755
index 0000000..fa9f3de
--- /dev/null
+++ b/common/modules/comment/views/manage/update.php
@@ -0,0 +1,18 @@
+ 'Активный',
+ $model::STATUS_HIDDEN => 'Скрытый',
+ $model::STATUS_DELETED => 'Удаленный',
+ ];
+ $form = ActiveForm::begin();
+ echo $form->field($model, 'text')->textarea();
+ echo $form->field($model, 'status')->dropDownList($statuses);
+ echo Html::submitButton('Обновить');
+ $form->end();
\ No newline at end of file
diff --git a/common/modules/comment/widgets/CommentWidget.php b/common/modules/comment/widgets/CommentWidget.php
new file mode 100755
index 0000000..797b705
--- /dev/null
+++ b/common/modules/comment/widgets/CommentWidget.php
@@ -0,0 +1,367 @@
+ 'artbox_comment_container comments-start', 'id' => 'artbox-comment' ];
+
+ /**
+ * @var string the view file that will render comment form.
+ */
+ public $formView = '@artbox-comment/views/artbox_comment_form';
+
+ /**
+ * Form options
+ * @var array
+ */
+ public $formOptions = [
+ 'class' => 'artbox_form_container',
+ ];
+
+ /**
+ * Params to be passed to form
+ * @var array
+ */
+ public $formParams = [ ];
+
+ /**
+ * @var string the view file that will render comments list.
+ */
+ public $listView = '@artbox-comment/views/artbox_comment_list';
+
+ /**
+ * List options
+ * @var array
+ */
+ public $listOptions = [
+ 'class' => 'artbox_list_container',
+ ];
+
+ /**
+ * List params
+ * @var array
+ */
+ public $listParams = [ ];
+
+ /**
+ * Reply options
+ * @var array
+ */
+ public $replyOptions = [
+ 'style' => 'display: none;',
+ 'class' => 'artbox_comment_reply_container',
+ ];
+
+ /**
+ * Reply view
+ * @var string
+ */
+ public $replyView = '@artbox-comment/views/artbox_comment_reply';
+
+ /**
+ * Comment form ID. If you have multiple forms on the same page, please use unique IDs.
+ * @var string Form ID
+ */
+ public $formId = 'artbox-comment-form';
+
+ /**
+ * Comment list ID. If you have multiple forms on the same page, please use unique IDs.
+ * @var string List ID
+ */
+ public $listId = 'artbox-comment-list';
+
+ /**
+ * Item view
+ * @var string
+ */
+ public $itemView = '@artbox-comment/views/artbox_comment_item';
+
+ /**
+ * Item options
+ * @var array
+ */
+ public $itemOptions = [
+ 'class' => 'artbox_item_container',
+ 'itemprop' => 'review',
+ 'itemscope' => 'itemscope',
+ 'itemtype' => 'http://schema.org/Review',
+ ];
+
+ /**
+ * Entity ID attribute, default to primaryKey() if ActiveRecord and throws exception if not
+ * set
+ * @var string entity id attribute
+ */
+ public $entityIdAttribute;
+
+ /**
+ * Info to be passed to Comment Model
+ * @var string $info Additional info
+ */
+ public $info = NULL;
+
+ /**
+ * Client options to be passed to JS
+ * @var array comment widget client options
+ */
+ public $clientOptions = [ ];
+
+ /**
+ * @todo Check if needed
+ * @var string pjax container id
+ */
+ public $pjaxContainerId;
+
+ public $layout = "{form} {reply_form} {list}";
+
+ /**
+ * Model fully namespaced classname
+ * @var string Model namespace
+ */
+ protected $entity;
+
+ /**
+ * Entity ID for attached model
+ * @var integer Entity ID
+ */
+ protected $entityId;
+
+ /**
+ * Encrypted data to be passed to Controller. Consist of:
+ * * Model::className()
+ * * entityId
+ * * info (optional)
+ * @var string encrypted entity key
+ */
+ protected $encryptedEntityKey;
+
+ /**
+ * Parts for widget
+ * @var array $parts
+ */
+ protected $parts;
+
+ /**
+ * Initializes the widget params.
+ */
+ public function init()
+ {
+ // Module init
+ Yii::$app->getModule(Module::$name);
+ // Model init
+ $model = $this->getModel();
+
+ /**
+ * @todo Check if needed
+ */
+ if(empty( $this->pjaxContainerId )) {
+ $this->pjaxContainerId = 'comment-pjax-container-' . $this->getId();
+ }
+
+ $this->entity = $model::className();
+ // Entity ID init
+ if(!empty( $this->entityIdAttribute ) && $this->model->hasProperty($this->entityIdAttribute)) {
+ $this->entityId = $this->model->{$this->entityIdAttribute};
+ } else {
+ if($this->model instanceof \yii\db\ActiveRecord && !empty( $this->model->getPrimaryKey() )) {
+ $this->entityId = (int) $this->model->getPrimaryKey();
+ } else {
+ throw new InvalidConfigException(/*Yii::t('artbox-comment', 'The "entityIdAttribute" value for widget model cannot be empty.')*/);
+ }
+ }
+
+ // Generate encryptedEntityKey
+ $this->encryptedEntityKey = $this->generateEntityKey();
+
+ $this->registerAssets();
+ }
+
+ /**
+ * Executes the widget.
+ * @return string the result of widget execution to be outputted.
+ */
+ public function run()
+ {
+ /* @var Module $module */
+ $module = Yii::$app->getModule(Module::$name);
+ $commentModelClass = $module->commentModelClass;
+ $commentModel = $this->createModel($commentModelClass, [
+ 'entity' => $this->entity,
+ 'entityId' => $this->entityId,
+ 'encryptedEntity' => $this->encryptedEntityKey,
+ 'scenario' => \Yii::$app->user->getIsGuest()?$commentModelClass::SCENARIO_GUEST:$commentModelClass::SCENARIO_USER,
+ ]);
+ if($module::$enableRating) {
+ $ratingModelClass = $module->ratingModelClass;
+ $ratingModel = $this->createRating($ratingModelClass);
+ } else {
+ $ratingModel = NULL;
+ }
+
+ $comments = $commentModelClass::getTree($this->entity, $this->entityId);
+
+ $this->buildParts($commentModel, $comments, $ratingModel);
+
+ return $this->renderWidget();
+ }
+
+ /**
+ * Register assets.
+ */
+ protected function registerAssets()
+ {
+ $this->clientOptions[ 'formSelector' ] = '#' . $this->formId;
+ $this->clientOptions[ 'listSelector' ] = '#' . $this->listId;
+ $options = Json::encode($this->clientOptions);
+ $view = $this->getView();
+ CommentAsset::register($view);
+ $view->registerJs("jQuery('#{$this->formId}').artbox_comment({$options});");
+ }
+
+ /**
+ * Get encrypted entity key
+ * @return string
+ */
+ protected function generateEntityKey()
+ {
+ return Yii::$app->getSecurity()
+ ->encryptByKey(Json::encode([
+ 'entity' => $this->entity,
+ 'entity_id' => $this->entityId,
+ 'info' => $this->info,
+ ]), Module::$encryptionKey);
+ }
+
+ /**
+ * Create comment model
+ *
+ * @param string $className Full namespaced model
+ * @param array $config Init config
+ *
+ * @return CommentInterface Comment model
+ * @throws InvalidConfigException If object not instance of \yii\base\Model
+ */
+ protected function createModel(string $className, array $config = [ ]): CommentInterface
+ {
+ $options = array_merge($config, [ 'class' => $className ]);
+ $object = Yii::createObject($options);
+ if($object instanceof CommentInterface) {
+ return $object;
+ }
+ throw new InvalidConfigException(/*Yii::t(\'artbox-comment\', \'Comment model must be instance of CommentInterface.\')*/);
+ }
+
+ /**
+ * Create rating model
+ *
+ * @param string $className Full namespaced model
+ * @param array $config Init config
+ *
+ * @return CommentInterface Comment model
+ * @throws InvalidConfigException If object not instance of \yii\base\Model
+ */
+ protected function createRating(string $className, array $config = [ ]): RatingModel
+ {
+ $options = array_merge($config, [ 'class' => $className ]);
+ $object = Yii::createObject($options);
+ if($object instanceof RatingModel) {
+ return $object;
+ }
+ throw new InvalidConfigException(/*Yii::t(\'artbox-comment\', \'Comment model must be instance of RatingModel.\')*/);
+ }
+
+ /**
+ * Build parts for rendering widget
+ *
+ * @param CommentInterface $commentModel
+ * @param ActiveDataProvider $comments
+ */
+ protected function buildParts(CommentInterface $commentModel, ActiveDataProvider $comments, $ratingModel = NULL)
+ {
+ $form_options = $this->formOptions;
+ $this->parts[ 'form' ] = Html::tag(ArrayHelper::remove($form_options, 'tag', 'div'), $this->render($this->formView, [
+ 'comment_model' => $commentModel,
+ 'form_params' => $this->formParams,
+ 'model' => $this->getModel(),
+ 'formId' => $this->formId,
+ 'rating_model' => $ratingModel,
+ ]), $form_options);
+
+ if(!\Yii::$app->user->isGuest) {
+ $reply_options = $this->replyOptions;
+ $this->parts[ 'reply_form' ] = Html::tag(ArrayHelper::remove($reply_options, 'tag', 'div'), $this->render($this->replyView, [
+ 'comment_model' => $commentModel,
+ 'form_params' => $this->formParams,
+ 'model' => $this->getModel(),
+ 'formId' => $this->formId,
+ ]), $reply_options);
+ }
+
+ $list_options = array_merge($this->listOptions, [ 'id' => $this->listId ]);
+ $this->parts[ 'list' ] = Html::tag(ArrayHelper::remove($list_options, 'tag', 'div'), $this->render($this->listView, [
+ 'comment_model' => $commentModel,
+ 'list_params' => $this->listParams,
+ 'model' => $this->getModel(),
+ 'comments' => $comments,
+ 'item_options' => $this->itemOptions,
+ 'item_view' => $this->itemView,
+ ]), $list_options);
+ }
+
+ /**
+ * @return string
+ */
+ protected function renderWidget(): string
+ {
+ $layout = $this->layout;
+ $parts = $this->parts;
+ $options = $this->options;
+ $layout = preg_replace('/{list}/', ArrayHelper::getValue($parts, 'list', ''), $layout);
+ $layout = preg_replace('/{form}/', ArrayHelper::getValue($parts, 'form', ''), $layout);
+ $layout = preg_replace('/{reply_form}/', ArrayHelper::getValue($parts, 'reply_form', ''), $layout);
+ $tag = ArrayHelper::remove($options, 'tag', 'div');
+ return Html::tag($tag, $layout, $options);
+ }
+
+ public function setModel(\yii\base\Model $model)
+ {
+ $this->model = $model;
+ }
+
+ public function getModel(): \yii\base\Model
+ {
+ if(!empty( $this->model )) {
+ return $this->model;
+ }
+ throw new InvalidConfigException(/*Yii::t(\'artbox-comment\', \'The "model" property must be set.\')*/);
+ }
+ }
\ No newline at end of file
diff --git a/common/modules/file/FileUploadAsset.php b/common/modules/file/FileUploadAsset.php
new file mode 100755
index 0000000..1f15894
--- /dev/null
+++ b/common/modules/file/FileUploadAsset.php
@@ -0,0 +1,43 @@
+
+ * @since 2.0
+ */
+class FileUploadAsset extends AssetBundle
+{
+
+
+ /**
+ * @inheritdoc
+ */
+ public function init()
+ {
+ parent::init();
+ $this->sourcePath = __DIR__.'/assets';
+ }
+
+ public $css = [
+ 'css/jquery.fileupload.css',
+ 'css/fileupload/style.css'
+ ];
+
+ public $js = [
+ 'js/vendor/jquery.ui.widget.js',
+ 'js/jquery.iframe-transport.js',
+ 'js/jquery.fileupload.js'
+ ];
+}
diff --git a/common/modules/file/Module.php b/common/modules/file/Module.php
new file mode 100755
index 0000000..374e5f4
--- /dev/null
+++ b/common/modules/file/Module.php
@@ -0,0 +1,15 @@
+').prop('href', options.postMessage)[0],
+ target = loc.protocol + '//' + loc.host,
+ xhrUpload = options.xhr().upload;
+ return {
+ send: function (_, completeCallback) {
+ counter += 1;
+ var message = {
+ id: 'postmessage-transport-' + counter
+ },
+ eventName = 'message.' + message.id;
+ iframe = $(
+ '",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widget_uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled", !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOptions({ disabled: false });
+ },
+ disable: function() {
+ return this._setOptions({ disabled: true });
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+var widget = $.widget;
+
+
+
+}));
diff --git a/common/modules/file/config.php b/common/modules/file/config.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/common/modules/file/config.php
@@ -0,0 +1,3 @@
+$w){
+ return true;
+ }else if($height >$h) {
+ return true;
+ }
+ return false;
+ }
+
+
+ private function getUserPath(){
+ if(isset(Yii::$app->user->id)){
+ return 'user_'.Yii::$app->user->id;
+ }else {
+ return 'guest';
+ }
+ }
+
+ private function resizeImg($w, $h, $imageAlias,$imageAliasSave){
+ $img = Image::getImagine()->open(Yii::getAlias($imageAlias));
+
+ $size = $img->getSize();
+
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $e_width = $w/$h;
+ $e_height = $h/$w;
+
+ $e1_width = $width/$height;
+ $e1_height = $height/$width;
+
+
+
+ if($e_width<$e1_width){
+
+ $new_width = $width*($e_width/$e1_width);
+
+ $y = 0;
+ $x = $width/ 2-($new_width/2);
+ $width = $new_width;
+
+ }else {
+
+ $new_height = $height*($e_height/$e1_height);
+ $x = 0;
+ $y = $height/2-($new_height/2);
+ $height = $new_height;
+ }
+
+
+
+
+ Image::crop($imageAlias, $width, $height,[$x,$y])
+ ->save(Yii::getAlias($imageAliasSave), ['quality' =>
+ 100]);
+
+
+ $imagine = new Imagine();
+ $imagine->open($imageAliasSave)
+ ->resize(new Box($w, $h))
+ ->save($imageAliasSave, array('flatten' => false));
+
+
+
+ }
+
+ private function deleteImages($old_img){
+
+ if(!empty($old_img) && file_exists($_SERVER['DOCUMENT_ROOT'].$old_img)){
+
+ $rootDir = explode("/", $old_img);
+
+ $row = $_SERVER['DOCUMENT_ROOT'].'/'.$rootDir[1].'/'.$rootDir[2].'/'.$rootDir[3].'/';
+
+ $allFiles = scandir($row);
+
+ $allFiles = array_slice($allFiles, 2);
+
+ foreach($allFiles as $oldFile){
+
+ unlink($row.$oldFile);
+
+ }
+
+ }
+ }
+
+ public function actionDeleteImage(){
+
+ $this->enableCsrfValidation = false;
+
+ $request = Yii::$app->request->post();
+
+ if($request){
+ if ($request['old_img']) {
+ $this->deleteImages($request['old_img']);
+ }
+ if(isset($request['action']) && $request['action']=='save'){
+ $object = str_replace('-', '\\',$request['model']);
+ $model = new $object;
+ $model = $model->findOne($request['id']);
+ $model->$request['field'] = $request['new_url'];
+ $model->save();
+ }
+ }
+
+ }
+
+
+ public function actionDownloadPhoto()
+ {
+
+ $model = new ImageSizerForm();
+
+ $request = Yii::$app->request->post();
+
+ if ($request) {
+
+ $model->multi = isset($request['multi'])? 1 : 0;
+
+ $model->file = UploadedFile::getInstance($model, 'file');
+
+ $md5_file = md5_file($model->file->tempName).rand(1, 1000);
+
+ $imgDir = Yii::getAlias('@storage/'.$this->getUserPath().'/'.$md5_file.'/');
+
+ $imageOrigAlias = Yii::getAlias($imgDir.'original'.'.'.$model->file->extension);
+
+ if(!is_dir($imgDir)) {
+ mkdir($imgDir, 0755, true);
+ }
+
+ $model->file->saveAs($imageOrigAlias);
+
+
+ if(isset($request['size'] )){
+
+ $request['size'] = ArrayHelper::toArray(json_decode($request['size']));
+
+ foreach($request['size'] as $size){
+ if($size['width'] && $size['height']){
+
+ $imageAlias = Yii::getAlias($imgDir.$size['width'].'x'.$size['height'].'.'.$model->file->extension);
+
+ $imageLink = '/storage/'.$this->getUserPath().'/'.$md5_file.'/'.$size['width'].'x'.$size['height'].'.'.$model->file->extension;
+
+ $this->resizeImg($size['width'], $size['height'], $imageOrigAlias,$imageAlias);
+
+ }
+ }
+
+ } else {
+
+ $imageLink = '/storage/'.$this->getUserPath().'/'.$md5_file.'/'.'original'.'.'.$model->file->extension;
+
+ }
+
+
+ if($model->multi){
+ $view = $this->renderPartial('/_gallery_item', [
+ 'item' => ['image'=>$imageLink],
+ 'field'=>$request['field']
+ ]);
+ return json_encode(['link'=>$imageLink,
+ 'view' =>$view,
+
+ ]);
+
+
+ } else {
+ $view = $this->renderPartial('/_one_item', [
+ 'item' => ['image'=>$imageLink],
+ 'field'=>$request['field']
+ ]);
+ return json_encode(['link'=>$imageLink,
+ 'view' =>$view,
+ ]);
+ }
+
+
+ }
+ }
+
+
+ public function getex($filename) {
+ return end(explode(".", $filename));
+ }
+
+
+ public function actionImagesUpload(){
+
+ if($_FILES['upload'])
+ {
+ if (($_FILES['upload'] == "none") OR (empty($_FILES['upload']['name'])) )
+ {
+ $message = "Вы не выбрали файл";
+ }
+ else if ($_FILES['upload']["size"] == 0 OR $_FILES['upload']["size"] > 2050000)
+ {
+ $message = "Размер файла не соответствует нормам";
+ }
+ else if (($_FILES['upload']["type"] != "image/jpeg") AND ($_FILES['upload']["type"] != "image/jpeg") AND ($_FILES['upload']["type"] != "image/png") AND ($_FILES['upload']['type'] != 'image/gif'))
+ {
+ $message = "Допускается загрузка только картинок JPG и PNG.";
+ }
+ else if (!is_uploaded_file($_FILES['upload']["tmp_name"]))
+ {
+ $message = "Что-то пошло не так. Попытайтесь загрузить файл ещё раз.";
+ }
+ else{
+ $name =$_FILES['upload']['name'].'.'.$this->getex($_FILES['upload']['name']);
+
+ $path = "../../storage/".$this->getUserPath()."/images/";
+ if(!is_dir($path)) {
+ mkdir($path, 0755, true);
+ }
+
+
+
+ move_uploaded_file($_FILES['upload']['tmp_name'], $path.$name);
+
+ $full_path = '/storage/'.$this->getUserPath().'/images/'.$name;
+
+ $message = "Файл ".$_FILES['upload']['name']." загружен";
+
+
+ }
+ $callback = $_REQUEST['CKEditorFuncNum'];
+ echo '';
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/common/modules/file/models/ImageSizerForm.php b/common/modules/file/models/ImageSizerForm.php
new file mode 100755
index 0000000..b891ab0
--- /dev/null
+++ b/common/modules/file/models/ImageSizerForm.php
@@ -0,0 +1,38 @@
+ 255],
+ [['model', 'form',], 'string'],
+ [['file','img','price_list'], 'file'],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/common/modules/file/views/_gallery_item.php b/common/modules/file/views/_gallery_item.php
new file mode 100755
index 0000000..9aea75e
--- /dev/null
+++ b/common/modules/file/views/_gallery_item.php
@@ -0,0 +1,9 @@
+
+
+
+ = Html::img($item['image'])?>
+
+
\ No newline at end of file
diff --git a/common/modules/file/views/_one_item.php b/common/modules/file/views/_one_item.php
new file mode 100755
index 0000000..fed9ba9
--- /dev/null
+++ b/common/modules/file/views/_one_item.php
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+ = Html::a( Html::img($item['image']),'#',['class'=>'thumbnail']) ?>
+
+
+
diff --git a/common/modules/file/widgets/ImageUploader.php b/common/modules/file/widgets/ImageUploader.php
new file mode 100755
index 0000000..ec7545b
--- /dev/null
+++ b/common/modules/file/widgets/ImageUploader.php
@@ -0,0 +1,63 @@
+render('image_sizer',
+ [
+ 'model'=>$this->model,
+ 'size' => $this->size,
+ 'field' => $this->field,
+ 'height' => $this->height,
+ 'width' => $this->width,
+ 'multi' => $this->multi,
+ 'name' => $this->name,
+ 'remover' => $this->remover
+ ]);
+
+ }
+
+ public function getGallery(){
+ if($this->gallery){
+ $array = explode(",", $this->gallery);
+ if(count($array) > 1){
+ array_pop($array);
+ }
+ return $array;
+ } else {
+ return array();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/common/modules/file/widgets/views/image_sizer.php b/common/modules/file/widgets/views/image_sizer.php
new file mode 100755
index 0000000..eb63a87
--- /dev/null
+++ b/common/modules/file/widgets/views/image_sizer.php
@@ -0,0 +1,203 @@
+tableSchema->primaryKey[0];
+
+?>
+
+
+
+
+ = Html::activeHiddenInput( $model,$field,['id' => "{$field}_picture_link"]) ?>
+
+
+
+
+
+
+
+
+
+ $field): ?>
+
+
+
+ $field):?>
+ = Html::a(Html::img($model->$field),'#',['class'=>'thumbnail']) ?>
+
+
+
+
+
+
+
+
+ =$name?>
+
+ = Html::activeFileInput( new ImageSizerForm(),'file',['id'=>$field, 'data-url'=>Yii::$app->getUrlManager()->createUrl('file/uploader/download-photo')]);?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ =$name?>
+
+ = Html::activeFileInput( new ImageSizerForm(),'file',['id'=>$field, 'data-url'=>Yii::$app->getUrlManager()->createUrl('file/uploader/download-photo'), 'multiple'=> 'multiple' ]);?>
+
+
+ = Html::activeHiddenInput( $model,$field,['id' => "{$field}_picture_link"]) ?>
+
+
+
+
+
+ context->getGallery() as $image){
+ echo $this->render('@common/modules/file/views/_gallery_item', [ 'item' => ['image'=>$image]]);
+ }
+ ?>
+
+
+
+
diff --git a/common/modules/product/CatalogUrlManager.php b/common/modules/product/CatalogUrlManager.php
new file mode 100755
index 0000000..68145c8
--- /dev/null
+++ b/common/modules/product/CatalogUrlManager.php
@@ -0,0 +1,253 @@
+getPathInfo();
+ $paths = explode('/', $pathInfo);
+
+ if(isset($paths[1])) {
+ if(strripos($request->url,'catalog/'.$paths[1].'?') && (!strripos($request->url,'?page')) && (!strripos($request->url,'?sort'))){
+ throw new HttpException(404 ,'Page not found');
+ }
+
+ }
+
+
+ if (!array_key_exists($paths[0], $this->route_map)) {
+ return false;
+ }
+
+ $params = [];
+ if ($paths[0] == 'catalog') {
+ $route = 'catalog/category';
+
+ // Category
+ if (!empty($paths[1])) {
+ $category = CategorySearch::findByAlias($paths[1]);
+ if (empty($category)) {
+ http_redirect(Url::to(['/']));
+ }
+ $params['category'] = $category;
+ }
+ if (!empty($paths[2])) {
+ // Filter
+
+ if (strpos($paths[2], 'filters:') === 0) {
+ $this->parseFilter($paths[2], $params);
+
+ }
+ else if(strpos($paths[2], 'filter:') === 0){
+ $this->parseOldFilter($paths[2], $params);
+ //['catalog/category', 'category' => $category, 'filters' =>$params['filter']]
+
+ $optionsTemplate = FilterHelper::optionsTemplate();
+ array_unshift($optionsTemplate, "special", "brands");
+ $filterView = [];
+ foreach($optionsTemplate as $optionKey){
+ if(isset($params['filter'][$optionKey])){
+ $filterView[$optionKey] = $params['filter'][$optionKey];
+ }
+
+
+ }
+
+
+ Yii::$app->response->redirect(['catalog/category', 'category' => $category, 'filters' =>$filterView],301);
+ }
+ else {
+ throw new HttpException(404 ,'Page not found');
+ }
+ }
+ } elseif ($paths[0] == 'product') {
+ if (!empty($paths[2])) {
+ throw new HttpException(404 ,'Page not found');
+ }
+ $product = ProductSearch::findByAlias($paths[1]);
+ if (empty($product->product_id)) {
+ throw new HttpException(404 ,'Page not found');
+ }
+ $route = 'catalog/product';
+ $params = [
+ 'product' => $product,
+ ];
+ }
+
+ return [$route, $params];
+ }
+ /**
+ * Creates a URL according to the given route and parameters.
+ * @param \yii\web\UrlManager $manager the URL manager
+ * @param string $route the route. It should not have slashes at the beginning or the end.
+ * @param array $params the parameters
+ * @return string|boolean the created URL, or false if this rule cannot be used for creating this URL.
+ */
+ public function createUrl($manager, $route, $params)
+ {
+
+ if (!in_array($route, $this->route_map)) {
+ return false;
+ }
+
+ switch($route) {
+ case 'catalog/category':
+ if (!empty($params['category'])) {
+ $category_alias = is_object($params['category']) ? $params['category']->alias : strtolower($params['category']);
+ $url = 'catalog/'. $category_alias .'/';
+ } else {
+ $url = 'catalog/';
+ }
+
+ $this->setFilterUrl($params, $url);
+
+ foreach ($params as $key => $param) {
+ if (empty($params[$key])) {
+ unset($params[$key]);
+ }
+ }
+
+ if (!empty($params) && ($query = http_build_query($params)) !== '') {
+ $url .= '?' . $query;
+ }
+
+ return $url;
+ break;
+
+ case 'catalog/product':
+ if (!empty($params['product'])) {
+ $product_alias = is_object($params['product']) ? $params['product']->alias : strtolower($params['product']);
+ }
+ $url = 'product/'. $product_alias;
+
+ if (!empty($params) && ($query = http_build_query($params)) !== '') {
+ $url .= '?' . $query;
+ }
+
+
+
+ return $url;
+ break;
+
+// case 'catalog/brands':
+// if (empty($params['brand'])) {
+// return 'brands';
+// } else {
+//
+// $brand_alias = is_object($params['brand']) ? $params['brand']->alias : strtolower($params['brand']);
+// }
+// $url = 'brands/'. $brand_alias .'/';
+//
+// $this->setFilterUrl($params, $url);
+//
+// if (!empty($params) && ($query = http_build_query($params)) !== '') {
+// $url .= '?' . $query;
+// }
+//
+// return $url;
+// break;
+ }
+ }
+
+ private function option_value_encode($value) {
+ return str_replace(array(',', '/'), array('~', '&s;'), $value);
+ }
+
+ private function setFilterUrl(&$params, &$url) {
+ $filter = [];
+ if (!empty($params['filters'])) {
+ foreach ($params['filters'] as $key => $values) {
+ switch($key) {
+ case 'prices':
+ $filter[] = $key .'='. implode(':', $values);
+ break;
+
+ default:
+ foreach($values as &$value) {
+ $value = $this->option_value_encode($value);
+ if (empty($value)) {
+ unset($value);
+ }
+ }
+ $filter[] = $key .'='. implode(',', $values);
+ break;
+ }
+ }
+ if (!empty($filter)) {
+ $url .= 'filters:'. implode(';', $filter);
+ }
+ unset($params['filters']);
+ }
+ }
+
+ private function parseFilter($paths, &$params) {
+ $params['filters'] = [];
+ $filter_str = substr($paths, 8);
+ $filter_options = explode(';', $filter_str);
+ foreach ($filter_options as $filter_option) {
+ if (empty($filter_option)) {
+ continue;
+ }
+ list($filter_key, $filter_option) = explode('=', $filter_option);
+ if($filter_key == 'prices') { // price-interval section
+ $prices = explode(':', $filter_option);
+ $params['filters'][$filter_key] = [
+ 'min' => floatval($prices[0]),
+ 'max' => floatval($prices[1]),
+ ];
+ }
+ else { // brands and other sections
+ $params['filters'][$filter_key] = explode(',', $filter_option);
+ }
+ }
+ }
+
+
+
+ private function parseOldFilter($paths, &$params) {
+ $params['filter'] = [];
+ $filter_str = substr($paths, 7);
+ $filter_options = explode(';', $filter_str);
+ foreach ($filter_options as $filter_option) {
+ if (empty($filter_option)) {
+ continue;
+ }
+ list($filter_key, $filter_option) = explode('=', $filter_option);
+ if($filter_key == 'prices') { // price-interval section
+ $prices = explode(':', $filter_option);
+ $params['filter'][$filter_key] = [
+ 'min' => floatval($prices[0]),
+ 'max' => floatval($prices[1]),
+ ];
+ }
+ elseif (strpos($filter_key, $this->option_prefix) === 0) { // options section
+ $params['filter'][substr($filter_key, 2)] = explode(',', $filter_option);
+ }
+ else { // brands and other sections
+ $params['filter'][$filter_key] = explode(',', $filter_option);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/Module.php b/common/modules/product/Module.php
new file mode 100755
index 0000000..f48c984
--- /dev/null
+++ b/common/modules/product/Module.php
@@ -0,0 +1,24 @@
+owner->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])
+ ->viaTable(ProductOption::tableName(),[ 'product_id'=> $this->owner->tableSchema->primaryKey[0]])
+ ->joinWith('taxGroup')->all();
+ }
+
+
+}
\ No newline at end of file
diff --git a/common/modules/product/config.php b/common/modules/product/config.php
new file mode 100755
index 0000000..a7f3866
--- /dev/null
+++ b/common/modules/product/config.php
@@ -0,0 +1,8 @@
+ [
+ 'category_group' => 1,
+ 'brand_group' => 2,
+ ],
+];
\ No newline at end of file
diff --git a/common/modules/product/controllers/DefaultController.php b/common/modules/product/controllers/DefaultController.php
new file mode 100755
index 0000000..b43058a
--- /dev/null
+++ b/common/modules/product/controllers/DefaultController.php
@@ -0,0 +1,20 @@
+render('index');
+ }
+}
diff --git a/common/modules/product/controllers/ManageController.php b/common/modules/product/controllers/ManageController.php
new file mode 100755
index 0000000..5b382c5
--- /dev/null
+++ b/common/modules/product/controllers/ManageController.php
@@ -0,0 +1,276 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ public function actionDev() {
+ foreach (ProductVariant::find()->where(['>', 'price_old', 0])->all() as $item) {
+ if ($item->price >= $item->price_old || $item->price == 0)
+ print $item->price .' | '. $item->price_old ."
\n";
+ }
+ print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~';
+ }
+
+ /**
+ * Lists all Product models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new ProductSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single Product model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Product model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Product();
+
+ if ($model->load(Yii::$app->request->post())) {
+ $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
+
+ if ($model->save() && $model->imagesUpload) {
+ if ( ($images = $model->imagesUpload()) !== FALSE) {
+ foreach ($images as $image) {
+ $imageModel = new ProductImage();
+ $imageModel->product_id = $model->product_id;
+ $imageModel->image = $image;
+ $imageModel->save();
+ }
+ }
+
+ return $this->redirect(['view', 'id' => $model->product_id]);
+ }
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing Product model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+ if ($model->load(Yii::$app->request->post())) {
+ $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
+ if ($model->save()) {
+// foreach ($model->images as $image) {
+// $image->delete();
+// }
+ if ( ($images = $model->imagesUpload()) !== FALSE) {
+ foreach ($images as $image) {
+ $imageModel = new ProductImage();
+ $imageModel->product_id = $model->product_id;
+ $imageModel->image = $image;
+ $imageModel->save();
+ }
+ }
+
+ return $this->redirect(['view', 'id' => $model->product_id]);
+ }
+ } else {
+ $groups = $model->getTaxGroupsByLevel(0);
+
+ return $this->render('update', [
+ 'model' => $model,
+ 'groups' => $groups,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing Product model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ public function actionDelimg($id)
+ {
+ $image = ProductImage::findOne($id);
+
+ if ($image) {
+ $image->delete();
+ }
+
+ print '1';
+ exit;
+ }
+
+ public function actionIs_top($id) {
+ $model = $this->findModel($id);
+
+ $model->is_top = intval(empty($model->is_top));
+
+ $model->save(false, ['is_top']);
+
+ return $this->redirect(['index']);
+ }
+
+ public function actionIs_new($id) {
+ $model = $this->findModel($id);
+
+ $model->is_new = intval(empty($model->is_new));
+
+ $model->save(false, ['is_new']);
+
+ return $this->redirect(['index']);
+ }
+
+ public function actionAkciya($id) {
+ $model = $this->findModel($id);
+
+ $model->akciya = intval(empty($model->akciya));
+
+ $model->save(false, ['akciya']);
+
+ return $this->redirect(['index']);
+ }
+
+ public function actionImport() {
+ $model = new Import();
+
+ if ($model->load(Yii::$app->request->post())) {
+ $file = UploadedFile::getInstances($model, 'file');
+ $method = 'go'. ucfirst($model->type);
+ $target = Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFile'. ucfirst($model->type));
+ if (empty($file)) {
+ $model->errors[] = 'File not upload';
+ } elseif ($method == 'goPrices' && $file[0]->name != 'file_1.csv') {
+ $model->errors[] = 'File need "file_1.csv"';
+ } elseif ($method == 'goProducts' && $file[0]->name == 'file_1.csv') {
+ $model->errors[] = 'File can not "file_1.csv"';
+ } elseif ($model->validate() && $file[0]->saveAs($target)) {
+ // PROCESS PAGE
+ return $this->render('import-process', [
+ 'model' => $model,
+ 'method' => $model->type,
+ 'target' => $target,
+ ]);
+// $model->$method();
+ } else {
+ $model->errors[] = 'File can not be upload or other error';
+ }
+ }
+
+ return $this->render('import', [
+ 'model' => $model,
+ ]);
+ }
+
+ public function actionProducts() {
+ $from = Yii::$app->request->get('from', 0);
+
+ $model = new Import();
+
+ if (Yii::$app->request->isAjax) {
+ Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+ return $model->goProducts($from, 10);
+ }
+ }
+
+ public function actionPrices() {
+ $from = Yii::$app->request->get('from', 0);
+
+ $model = new Import();
+
+ if (Yii::$app->request->isAjax) {
+ Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+ return $model->goPrices($from, 10);
+ }
+ }
+
+ public function actionExport() {
+ $model = new Export();
+ if (($file = $model->process(Yii::getAlias('@uploadDir')))) {
+ return Yii::$app->response->sendFile($file)->send();
+ }
+ throw new NotFoundHttpException('Error');
+ }
+
+ /**
+ * Finds the Product model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Product the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Product::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/controllers/ProductUnitController.php b/common/modules/product/controllers/ProductUnitController.php
new file mode 100755
index 0000000..7ee6139
--- /dev/null
+++ b/common/modules/product/controllers/ProductUnitController.php
@@ -0,0 +1,124 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all ProductUnit models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new ProductUnitSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single ProductUnit model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new ProductUnit model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new ProductUnit();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->product_unit_id]);
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing ProductUnit model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->product_unit_id]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing ProductUnit model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the ProductUnit model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return ProductUnit the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = ProductUnit::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/controllers/ProductVariantTypeController.php b/common/modules/product/controllers/ProductVariantTypeController.php
new file mode 100755
index 0000000..840f498
--- /dev/null
+++ b/common/modules/product/controllers/ProductVariantTypeController.php
@@ -0,0 +1,124 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all ProductVariantType models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new ProductVariantTypeSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single ProductVariantType model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new ProductVariantType model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new ProductVariantType();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->product_variant_type_id]);
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing ProductVariantType model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->product_variant_type_id]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing ProductVariantType model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the ProductVariantType model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return ProductVariantType the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = ProductVariantType::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/controllers/VariantController.php b/common/modules/product/controllers/VariantController.php
new file mode 100755
index 0000000..4d0ca7b
--- /dev/null
+++ b/common/modules/product/controllers/VariantController.php
@@ -0,0 +1,247 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all ProductVariant models.
+ * @return mixed
+ */
+ public function actionIndex($product_id)
+ {
+ $searchModel = new ProductVariantListSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams,$product_id);
+
+ if ( ($product = Yii::$app->request->get('product_id')) !== null) {
+ $product = Product::findOne($product);
+ }
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ 'product' => $product,
+ 'product_id' => $product_id,
+ ]);
+ }
+
+ /**
+ * Displays a single ProductVariant model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new ProductVariant model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate($product_id)
+ {
+ $model = new ProductVariant();
+ $model->product_id = $product_id;
+ if ($model->load(Yii::$app->request->post())) {
+
+ $model->imagesUpload = UploadedFile::getInstances($model, 'imagesUpload');
+ $model->validate();
+
+ if ($model->save()) {
+
+ if ( ($images = $model->imagesUpload()) !== FALSE) {
+ foreach ($images as $image) {
+ $imageModel = new ProductImage();
+ $imageModel->product_id = $model->product_id;
+ $imageModel->product_variant_id = $model->product_variant_id;
+ $imageModel->image = $image;
+ $imageModel->save();
+ }
+ }
+
+ return $this->redirect(['index', 'product_id' => $product_id]);
+ }
+ } else {
+ $groups = $model->getTaxGroupsByLevel(1);
+
+ return $this->render('create', [
+ 'model' => $model,
+ 'groups' => $groups,
+ 'stocks' => [new ProductStock()],
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing ProductVariant model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $product_id
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($product_id, $id)
+ {
+ $model = $this->findModel($id);
+ if ($model->load(Yii::$app->request->post())) {
+
+ if ($model->save()) {
+
+
+ if ( ($image = UploadedFile::getInstance($model, 'image')) ) {
+ $imageModel = ProductImage::find()->where(['product_variant_id' => $model->product_variant_id])->one();
+
+ if($imageModel instanceof ProductImage) {
+ $imageModel->product_id = $model->product_id;
+ $imageModel->product_variant_id = $model->product_variant_id;
+ $imageModel->image = $image->name;
+ $imageModel->save();
+ } else {
+ $imageModel = new ProductImage();
+ $imageModel->product_id = $model->product_id;
+ $imageModel->product_variant_id = $model->product_variant_id;
+ $imageModel->image = $image->name;
+ $imageModel->save();
+ }
+
+
+ $imgDir = Yii::getAlias('@storage/products/');
+
+ if(!is_dir($imgDir)) {
+ mkdir($imgDir, 0755, true);
+ }
+
+ $image->saveAs(Yii::getAlias('@storage/products/' . $image->name));
+ }
+
+
+ $ProductStocks = Yii::$app->request->post('ProductStock');
+
+ $quantity = 0;
+
+ if(is_array($ProductStocks)){
+
+ foreach($ProductStocks as $index => $ProductStock){
+ $stock = Stock::find()->where(['name'=>$ProductStock['name']])->one();
+ if(!$stock instanceof Stock){
+ $stock = new Stock();
+ $stock->name = $ProductStock['name'];
+ $stock->save();
+ }
+
+ $psModel = ProductStock::find()->where(['product_variant_id'=>$model->product_variant_id, 'stock_id' =>$stock->stock_id ])->one();
+ if(!$psModel instanceof ProductStock){
+ $psModel = new ProductStock;
+ $psModel->load(['ProductStock'=>$ProductStock]);
+ $psModel->stock_id = $stock->stock_id;
+ $psModel->product_variant_id = $model->product_variant_id;
+ $psModel->product_id = $model->product->product_id;
+ $quantity = $quantity + $psModel->quantity;
+ $psModel->validate();
+ $psModel->save();
+ } else {
+ $psModel->load(['ProductStock'=>$ProductStock]);
+ $quantity = $quantity + $psModel->quantity;
+ $psModel->save();
+ }
+
+ }
+ } else {
+ $model->unlinkAll('stocks',true);
+ }
+
+
+ $model->stock = $quantity;
+ $model->save();
+ }
+ return $this->redirect(['index', 'product_id'=>$product_id]);
+
+
+
+
+ } else {
+ $groups = $model->getTaxGroupsByLevel(1);
+
+ return $this->render('update', [
+ 'model' => $model,
+ 'groups' => $groups,
+ 'stocks' => (!empty($model->variantStocks)) ? $model->variantStocks : [new ProductStock],
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing ProductVariant model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($product_id, $id)
+ {
+
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index', 'product_id'=>$product_id]);
+ }
+
+ public function actionDelimg($id)
+ {
+ $image = ProductImage::findOne($id);
+
+ if ($image) {
+ $image->delete();
+ }
+
+ print '1';
+ exit;
+ }
+
+ /**
+ * Finds the ProductVariant model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return ProductVariant the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = ProductVariant::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/helpers/FilterHelper.php b/common/modules/product/helpers/FilterHelper.php
new file mode 100755
index 0000000..e460691
--- /dev/null
+++ b/common/modules/product/helpers/FilterHelper.php
@@ -0,0 +1,89 @@
+where(['is_filter' => 'TRUE'])->all(),'alias');
+ }
+ else
+ {
+ return static::$optionsList;
+ }
+
+ }
+
+ /*
+ * Return custom filter-option link
+ * @var array $filter
+ * @var array $options
+ * @return array
+ */
+ public static function getFilterForOption($filter, $key, $value, $remove = false) {
+
+ $optionsTemplate = self::optionsTemplate();
+ array_unshift($optionsTemplate, "special", "brands");
+
+ $result = $filter;
+
+ if (is_array($value)) {
+ foreach($value as $value_key => $value_items) {
+ if (!is_array($value_items)) {
+ $value_items = [$value_items];
+ }
+ foreach($value_items as $value_item) {
+ if ($remove && isset($result[$key]) && ($i = array_search($value_item, $result[$key][$value_key])) !== FALSE) {
+ unset($result[$key][$value_key][$i]);
+ if (empty($result[$key][$value_key])) {
+ unset($result[$key][$value_key]);
+ }
+ } else {
+ if (!isset($result[$key][$value_key]) || array_search($value_item, $result[$key][$value_key]) === FALSE) {
+ $result[$key][$value_key][] = $value_item;
+ }
+ }
+ }
+ }
+ } else {
+ if ($remove && isset($result[$key]) && ($i = array_search($value, $result[$key])) !== FALSE) {
+ unset($result[$key][$i]);
+ if (empty($result[$key])) {
+ unset($result[$key]);
+ }
+ } else {
+ if (!isset($result[$key]) || array_search($value, $result[$key]) === FALSE) {
+ $result[$key][] = $value;
+ }
+ }
+ }
+
+
+ $filterView = [];
+
+ foreach($optionsTemplate as $optionKey){
+ if(isset($result[$optionKey])){
+ $filterView[$optionKey] = $result[$optionKey];
+ }
+
+
+ }
+
+ return $filterView;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/common/modules/product/helpers/ProductHelper.php b/common/modules/product/helpers/ProductHelper.php
new file mode 100755
index 0000000..992fabd
--- /dev/null
+++ b/common/modules/product/helpers/ProductHelper.php
@@ -0,0 +1,303 @@
+getTree(); // with('categoryName')->
+ }
+
+ public static function getBrands()
+ {
+ return Brand::find(); // ->with('brandName')
+ }
+
+ /*
+ * Return custom filter-option link
+ * @var array $filter
+ * @var array $options
+ * @return array
+ */
+ public static function getFilterForOption($filter, $key, $value, $remove = false)
+ {
+ $result = $filter;
+ if(is_array($value)) {
+ foreach($value as $value_key => $value_items) {
+ if(!is_array($value_items)) {
+ $value_items = [ $value_items ];
+ }
+ foreach($value_items as $value_item) {
+ if($remove && isset( $result[ $key ] ) && ( $i = array_search($value_item, $result[ $key ][ $value_key ]) ) !== false) {
+ unset( $result[ $key ][ $value_key ][ $i ] );
+ if(empty( $result[ $key ][ $value_key ] )) {
+ unset( $result[ $key ][ $value_key ] );
+ }
+ } else {
+ if(!isset( $result[ $key ][ $value_key ] ) || array_search($value_item, $result[ $key ][ $value_key ]) === false) {
+ $result[ $key ][ $value_key ][] = $value_item;
+ }
+ }
+ }
+ }
+ } else {
+ if($remove && isset( $result[ $key ] ) && ( $i = array_search($value, $result[ $key ]) ) !== false) {
+ unset( $result[ $key ][ $i ] );
+ if(empty( $result[ $key ] )) {
+ unset( $result[ $key ] );
+ }
+ } else {
+ if(!isset( $result[ $key ] ) || array_search($value, $result[ $key ]) === false) {
+ $result[ $key ][] = $value;
+ }
+ }
+ }
+ return $result;
+ }
+
+ public static function addLastProsucts($product_id)
+ {
+ $last_products = self::getLastProducts();
+ if(!in_array($product_id, $last_products)) {
+ $last_products[] = intval($product_id);
+ if(count($last_products) > 16) {
+ array_shift($last_products);
+ }
+ Yii::$app->session->set('last_products', $last_products);
+ }
+ }
+
+ public static function getLastProducts($as_object = false)
+ {
+ $last_products = Yii::$app->session->get('last_products', [ ]);
+ if($as_object) {
+ $last_products = Product::find()
+ ->joinWith([ 'variant' ])
+ ->where([ Product::tableName() . '.product_id' => $last_products ])
+ ->andWhere([
+ '!=',
+ ProductVariant::tableName() . '.stock',
+ 0,
+ ])
+ ->all();
+ }
+ return array_reverse($last_products);
+ }
+
+ public static function getSpecialProducts($type, $count, $sort = NULL)
+ {
+ switch($type) {
+ case 'top':
+ $data = [ 'is_top' => true ];
+ break;
+ case 'new':
+ $data = [ 'is_new' => true ];
+ break;
+ case 'promo':
+ $data = [ 'akciya' => true ];
+ break;
+ }
+ return Product::find()
+ ->joinWith('variants')
+ ->where($data)
+ ->andWhere([
+ '!=',
+ ProductVariant::tableName() . '.stock',
+ 0,
+ ])
+ ->limit($count)/*->orderBy($sort)*/
+ ->all();
+ }
+
+ public static function getSimilarProducts($product, $count = 10)
+ {
+ if(!is_object($product)) {
+ $product = Product::find()
+ ->where([ 'product_id' => $product ])
+ ->with('enabledVariants')
+ ->one();
+ }
+
+ if(!$product->properties) {
+ return [ ];
+ }
+ $product_categories = [ ];
+ foreach($product->categories as $category) {
+ $product_categories[] = $category->category_id;
+ }
+ $query = Product::find()
+ ->select('product.product_id')
+ ->innerJoinWith('variant')
+ ->joinWith('category')
+ ->where([
+ '!=',
+ 'product_variant.stock',
+ 0,
+ ])
+ ->andWhere([ 'product_category.category_id' => $product_categories ]);
+ // $query->andWhere(['>=', 'product_variant.price', $product->enabledVariant->price * 0.7]);
+ // $query->andWhere(['<=', 'product_variant.price', $product->enabledVariant->price * 1.3]);
+ foreach($product->properties as $group) {
+ $where = [ ];
+ foreach($group->_options as $option) {
+ $where[] = $option->tax_option_id;
+ }
+ if(!$where) {
+ continue;
+ }
+ $query->innerJoin('product_option to' . $group->tax_group_id, 'to' . $group->tax_group_id . '.product_id = product.product_id');
+ $query->andWhere([ 'to' . $group->tax_group_id . '.option_id' => $where ]);
+ }
+ $query->andWhere([
+ '!=',
+ 'product.product_id',
+ $product->product_id,
+ ]);
+ $query->groupBy('product.product_id');
+ $query->limit($count);
+ $products = $query->asArray()
+ ->all();
+ foreach($products as &$_product) {
+ $_product = Product::findOne($_product[ 'product_id' ]);
+ }
+ return $products;
+ }
+
+ /**
+ * @param ActiveQuery $query
+ * @param $params
+ * @param bool $setPriceLimits
+ */
+ public static function _setQueryParams(&$query, $params, $setPriceLimits = true)
+ {
+ if(!empty( $params[ 'keywords' ] )) {
+ if(!is_array($params[ 'keywords' ])) {
+ $params[ 'keywords' ] = [ $params[ 'keywords' ] ];
+ }
+ foreach($params[ 'keywords' ] as $keyword) {
+ $query->orFilterWhere([
+ 'ilike',
+ Product::tableName() . '.name',
+ $keyword,
+ ]);
+ $query->orFilterWhere([
+ 'ilike',
+ BrandName::tableName() . '.value',
+ $keyword,
+ ]);
+ $query->orFilterWhere([
+ 'ilike',
+ CategoryName::tableName() . '.value',
+ $keyword,
+ ]);
+ $query->orFilterWhere([
+ 'ilike',
+ ProductVariant::tableName() . '.sku',
+ $keyword,
+ ]);
+ }
+ }
+
+ foreach($params as $key => $param) {
+
+ switch($key) {
+ case 'special':
+ foreach($param as $key => $value) {
+ $query->orFilterWhere([ Product::tableName() . '.' . $key => $value ]);
+ }
+ break;
+ case 'brands':
+ $query->andFilterWhere([ Product::tableName() . '.brand_id' => $param ]);
+ break;
+ case 'keywords':
+ break;
+ case 'prices':
+ if($param[ 'min' ] > 0) {
+ $query->andWhere([
+ '>=',
+ ProductVariant::tableName() . '.price',
+ $param[ 'min' ],
+ ]);
+ }
+ if($param[ 'max' ] > 0) {
+ $query->andWhere([
+ '<=',
+ ProductVariant::tableName() . '.price',
+ $param[ 'max' ],
+ ]);
+ }
+ break;
+ default:
+ $query->andWhere(
+ Product::tableName() . '.product_id IN (
+ SELECT DISTINCT products
+ FROM (
+ SELECT product_id AS products
+ FROM product_option
+ INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id
+ INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id
+ WHERE tax_group.alias LIKE \''. $key .'\' AND tax_option.alias IN (\'' . implode('\',\'', $param) . '\') OR product_id IN (
+ (SELECT product_id AS products
+ FROM product_variant_option
+ INNER JOIN product_variant ON product_variant_option.product_variant_id = product_variant.product_variant_id
+ INNER JOIN tax_option ON tax_option.tax_option_id = product_variant_option.option_id
+ INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id
+ WHERE tax_group.alias LIKE \''. $key .'\' AND tax_option.alias IN (\'' . implode('\',\'', $param) . '\'))
+ )
+ ) AS table_name
+ )'
+ );
+ }
+
+ }
+
+ }
+
+ public static function productCountQuery($category = NULL, $params, $excludeKeys = [ ])
+ {
+ $p = [ ];
+ foreach($params as $key => $param) {
+ if(in_array($key, $excludeKeys)) {
+ $p[ $key ] = $param;
+ }
+ }
+ /** @var ActiveQuery $query */
+ if(!empty( $category )) {
+ $query = $category->getProducts();
+ } else {
+ $query = Product::find();
+ }
+ ProductHelper::_setQueryParams($query, $params);
+ $query->select([ 'COUNT(product.product_id)' ]);
+
+ return $query;
+ }
+
+ public static function addLastCategory($category_id) {
+ \Yii::$app->session->set('last_category_id', $category_id);
+ }
+
+ public static function getLastCategory() {
+ return \Yii::$app->session->get('last_category_id');
+ }
+ }
\ No newline at end of file
diff --git a/common/modules/product/models/Brand.php b/common/modules/product/models/Brand.php
new file mode 100755
index 0000000..6836e94
--- /dev/null
+++ b/common/modules/product/models/Brand.php
@@ -0,0 +1,133 @@
+ [
+ 'class' => ArtboxSynonymBehavior::className(),
+ 'keyNameValue' => 'brand_name_id',
+ 'valueModel' => BrandName::className(),
+ 'valueOptionId' => 'brand_id',
+ 'valueFields' => [ // postKey => DBFieldName
+ 'name' => 'value'
+ ],
+ 'slug' => [
+ 'valueKeyName' => 'value',
+ 'slugKeyName' => 'alias',
+ 'translit' => true
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'brand';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['name'], 'string'],
+ [['brand_name_id'], 'integer'],
+ [['meta_desc', 'seo_text'], 'string'],
+ [['alias', 'name'], 'string', 'max' => 250],
+ [['meta_title', 'image'], 'string', 'max' => 255],
+ [['meta_robots'], 'string', 'max' => 50],
+ [['imageUpload'], 'safe'],
+ [['imageUpload'], 'file', 'extensions' => 'jpg, gif, png'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'name' => Yii::t('product', 'Name of the brand'),
+ 'brand_id' => Yii::t('product', 'Brand ID'),
+ 'brand_name_id' => Yii::t('product', 'Brand Name ID'),
+ 'alias' => Yii::t('product', 'Alias'),
+ 'image' => Yii::t('product', 'Image'),
+ 'imageUrl' => Yii::t('product', 'Image'),
+ 'meta_title' => Yii::t('product', 'Meta Title'),
+ 'meta_desc' => Yii::t('product', 'Meta Desc'),
+ 'meta_robots' => Yii::t('product', 'Meta Robots'),
+ 'seo_text' => Yii::t('product', 'Seo Text'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrandName()
+ {
+ return $this->hasOne(BrandName::className(), ['brand_name_id' => 'brand_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrandNames()
+ {
+ return $this->hasMany(BrandName::className(), ['brand_id' => 'brand_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProducts()
+ {
+ return $this->hasMany(Product::className(), ['brand_id' => 'brand_id']);
+ }
+
+ public function getName() {
+ return empty($this->brand_name_id) ? null : $this->brandName->value;
+ }
+
+ public function getImageFile() {
+ return empty($this->image) ? null : Yii::getAlias('@imagesDir/brands/'. $this->image);
+ }
+
+ public function getImageUrl()
+ {
+ return empty($this->image) ? null : Yii::getAlias('@imagesUrl/brands/' . $this->image);
+ }
+}
diff --git a/common/modules/product/models/BrandName.php b/common/modules/product/models/BrandName.php
new file mode 100755
index 0000000..a495c95
--- /dev/null
+++ b/common/modules/product/models/BrandName.php
@@ -0,0 +1,66 @@
+ 250],
+// [['brand_id'], 'exist', 'skipOnError' => true, 'targetClass' => Brand::className(), 'targetAttribute' => ['brand_id' => 'brand_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'brand_name_id' => Yii::t('product', 'Brand Name ID'),
+ 'brand_id' => Yii::t('product', 'Brand ID'),
+ 'value' => Yii::t('product', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrands()
+ {
+ return $this->hasMany(Brand::className(), ['brand_name_id' => 'brand_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrand()
+ {
+ return $this->hasOne(Brand::className(), ['brand_id' => 'brand_id']);
+ }
+}
diff --git a/common/modules/product/models/BrandQuery.php b/common/modules/product/models/BrandQuery.php
new file mode 100755
index 0000000..5351a07
--- /dev/null
+++ b/common/modules/product/models/BrandQuery.php
@@ -0,0 +1,47 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Brand[]|array
+ */
+ public function all($db = null)
+ {
+// $this->with('brandName');
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Brand|array|null
+ */
+ public function one($db = null)
+ {
+// $this->with('brandName');
+ return parent::one($db);
+ }
+
+ /**
+ * Select brand by alias
+ * @param $slug
+ * @return $this
+ */
+ public function byAlias($alias)
+ {
+ $this->andFilterWhere(['alias' => $alias]);
+ return $this;
+ }
+}
diff --git a/common/modules/product/models/BrandSearch.php b/common/modules/product/models/BrandSearch.php
new file mode 100755
index 0000000..f77d91f
--- /dev/null
+++ b/common/modules/product/models/BrandSearch.php
@@ -0,0 +1,168 @@
+with('brandName')
+
+ // add conditions that should always apply here
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+
+ $this->load($params);
+
+ /*if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }*/
+
+ $dataProvider->setSort([
+ 'attributes' => [
+ 'brand_name',
+ 'alias'
+ ]
+ ]);
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'brand_id' => $this->brand_id,
+ 'brand_name_id' => $this->brand_name_id,
+ ]);
+
+
+ $query->andFilterWhere(['ilike', 'alias', $this->alias])
+ ->andFilterWhere(['ilike', 'image', $this->image])
+ ->andFilterWhere(['ilike', 'meta_title', $this->meta_title])
+ ->andFilterWhere(['ilike', 'meta_desc', $this->meta_desc])
+ ->andFilterWhere(['ilike', 'meta_robots', $this->meta_robots])
+ ->andFilterWhere(['ilike', 'seo_text', $this->seo_text]);
+ if (!empty($this->brand_name)) {
+ $query->joinWith('brandName');
+ $query->andFilterWhere(['ilike', 'brand_name.value', $this->brand_name]);
+ }
+
+ $query->orderBy('brand_id', 'asc');
+
+ return $dataProvider;
+ }
+
+ public function getBrands($category = null, $params = [], $productQuery = null) {
+// $queryCount = ProductHelper::productCountQuery($category, $params, ['brands']);
+
+ /*if (!empty($params['prices'])) {
+ if ($params['prices']['min'] > 0) {
+ $queryCount->andWhere(['>=', ProductVariant::tableName() .'.price', $params['prices']['min']]);
+ }
+ if ($params['prices']['max'] > 0) {
+ $queryCount->andWhere(['<=', ProductVariant::tableName() .'.price', $params['prices']['max']]);
+ }
+ }*/
+// if (!empty($params['options'])) {
+// $queryCount->innerJoin(TaxOption::tableName(), TaxOption::tableName())
+// }
+
+ $query = Brand::find()
+ ->select([
+ Brand::tableName() .'.*'
+ ])
+ ->innerJoin(Product::tableName(), Product::tableName() .'.brand_id='. Brand::tableName() .'.brand_id')
+ ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. Product::tableName() .'.product_id')
+ ->with(['brandName']);
+
+
+// $queryCount = Product::find()
+// ->select(['COUNT(product.product_id)'])
+// ->where('product.brand_id = brand.brand_id');
+// $queryCount->andWhere('(SELECT COUNT(pv.product_variant_id) FROM "product_variant" "pv" WHERE pv.stock != 0 AND pv.product_id = product.product_id) > 0');
+// if (!empty($category)) {
+// $queryCount->andWhere('(SELECT COUNT(pc.product_id) FROM product_category pc WHERE pc.product_id = product.product_id AND pc.category_id = '. $category->category_id .') > 0');
+// }
+// if (!empty($params['options'])) {
+// $queryCount->innerJoin('product_option', 'product_option.product_id = product.product_id');
+// $queryCount->innerJoin('tax_option', 'tax_option.tax_option_id = product_option.option_id');
+// $queryCount->innerJoin('tax_group', 'tax_group.tax_group_id = tax_option.tax_group_id');
+// foreach ($params['options'] as $group => $options) {
+// $queryCount->andWhere([
+// 'tax_group.alias' => $group,
+// 'tax_option.alias' => $options
+// ]);
+// }
+//// $query->addSelect("(SELECT COUNT(product_option.product_id) AS products FROM product_option INNER JOIN tax_option ON tax_option.tax_option_id = product_option.option_id INNER JOIN tax_group ON tax_group.tax_group_id = tax_option.tax_group_id WHERE tax_group.alias LIKE '$group' AND tax_option.alias IN (" . implode(',', $options) . ")) AS _items_count");
+// }
+// $query->addSelect(['_items_count' => $queryCount]);
+
+// if ($productQuery) {
+// $productQuery->select(['COUNT(product.product_id)']);
+// $query->addSelect(['_items_count' => $productQuery]);
+// }
+
+
+ $query->innerJoin('product_variant', 'product_variant.product_id = '. Product::tableName() .'.product_id');
+ $query->where(['!=', 'product_variant.stock', 0]);
+ $query->groupBy(Product::tableName() .'.product_id');
+ if (!empty($category)) {
+ $query->andWhere([
+ ProductCategory::tableName() .'.category_id' => $category->category_id
+ ]);
+ }
+ $query->groupBy(Brand::tableName() .'.brand_id');
+
+ return $query;
+ }
+
+ public static function findByAlias($alias) {
+ /** @var CategoryQuery $query */
+ $query = Brand::find()
+ ->with('brandName')
+ ->andFilterWhere(['alias' => $alias]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/product/models/Category.php b/common/modules/product/models/Category.php
new file mode 100755
index 0000000..2f2866a
--- /dev/null
+++ b/common/modules/product/models/Category.php
@@ -0,0 +1,281 @@
+ [
+ 'class' => ArtboxTreeBehavior::className(),
+ 'keyNameGroup' => null,
+ 'keyNamePath' => 'path',
+ ],
+ 'artboxsynonym' => [
+ 'class' => ArtboxSynonymBehavior::className(),
+ 'keyNameValue' => 'category_name_id',
+ 'valueModel' => CategoryName::className(),
+ 'valueOptionId' => 'category_id',
+ 'valueFields' => [ // postKey => DBFieldName
+ 'name' => 'value'
+ ],
+ 'slug' => [
+ 'valueKeyName' => 'value',
+ 'slugKeyName' => 'alias',
+ 'translit' => true
+ ]
+ ],
+ [
+ 'class' => relationBehavior::className(),
+ 'relations' => [
+ 'product_categories' => 'entity2', // Products of category
+ 'tax_group_to_category' => 'entity2',
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'category';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['name'], 'string'],
+ [['parent_id', 'depth', 'category_name_id', 'product_unit_id'], 'integer'],
+ [['path', 'meta_desc', 'h1', 'seo_text'], 'string'],
+ [['meta_title', 'image'], 'string', 'max' => 255],
+ [['meta_robots'], 'string', 'max' => 50],
+ [['alias', 'name'], 'string', 'max' => 250],
+ [['populary'], 'boolean'],
+ [['group_to_category', 'remote_category'], 'safe'],
+ [['category_name_id'], 'exist', 'skipOnError' => true, 'targetClass' => CategoryName::className(), 'targetAttribute' => ['category_name_id' => 'category_name_id']],
+ [['imageUpload'], 'safe'],
+ [['imageUpload'], 'file', 'extensions' => 'jpg, gif, png'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'category_id' => Yii::t('product', 'Category ID'),
+ 'parent_id' => Yii::t('product', 'Parent ID'),
+ 'path' => Yii::t('product', 'Path'),
+ 'depth' => Yii::t('product', 'Depth'),
+ 'image' => Yii::t('product', 'Image'),
+ 'imageUrl' => Yii::t('product', 'Image'),
+ 'meta_title' => Yii::t('product', 'Meta Title'),
+ 'meta_desc' => Yii::t('product', 'Meta Desc'),
+ 'meta_robots' => Yii::t('product', 'Meta Robots'),
+ 'h1' => Yii::t('product', 'h1'),
+ 'seo_text' => Yii::t('product', 'Seo Text'),
+ 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
+ 'alias' => Yii::t('product', 'Alias'),
+ 'populary' => Yii::t('product', 'Populary'),
+ 'name' => Yii::t('product', 'Name'),
+ 'remote_id' => Yii::t('product', 'Remote ID'),
+ ];
+ }
+
+ public static function find()
+ {
+ return new CategoryQuery(get_called_class());
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductUnit()
+ {
+ return $this->hasOne(ProductUnit::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+
+ public function getProducts() {
+ return $this->hasMany(Product::className(), ['product_id' => 'product_id'])
+ ->viaTable('product_category', ['category_id' => 'category_id']);
+// return $this->getRelations('product_categories');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategoryNames()
+ {
+ return $this->hasMany(CategoryName::className(), ['category_id' => 'category_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductCategories()
+ {
+ return $this->hasMany(ProductCategory::className(), ['category_id' => 'category_id']);
+ }
+
+ public function getTaxGroups()
+ {
+ return $this->getRelations('tax_group_to_category');
+ }
+
+ public function getTaxGroupsByLevel($level)
+ {
+ return $this->hasMany(TaxGroup::className(), ['tax_group_id' => 'entity1_id'])
+ ->viaTable('relation', ['entity2_id' => 'category_id'])
+ ->andWhere(['level' => $level]);
+ }
+
+ public function getRemote_category()
+ {
+ return ArtboxTreeHelper::getArrayField($this->remote_id);
+ }
+
+ public function setRemote_category($value)
+ {
+ if (!empty($value) && is_array($value)) {
+ $this->remote_id = ArtboxTreeHelper::setArrayField($value, false);
+ }
+ }
+
+ public function getCategoryName()
+ {
+ return $this->hasOne(CategoryName::className(), ['category_name_id' => 'category_name_id']);
+ }
+
+ public function getName() {
+ return empty($this->categoryName) ? null : $this->categoryName->value;
+ }
+
+ public function getImageFile() {
+ return empty($this->image) ? '/images/no_photo.png' : Yii::getAlias('@imagesDir/categories/'. $this->image);
+ }
+
+ public function getImageUrl()
+ {
+ return empty($this->image) ? '/images/no_photo.png' : Yii::getAlias('@imagesUrl/categories/' . $this->image);
+ }
+
+ public function beforeSave($insert)
+ {
+ if (parent::beforeSave($insert)) {
+
+ if (empty($this->parent_id))
+ $this->parent_id = 0;
+
+ return true;
+ }
+ return false;
+ }
+
+ public function beforeDelete()
+ {
+
+ if(!empty($this->products)){
+ foreach($this->products as $product){
+ $product->delete();
+ }
+ }
+ ProductCategory::deleteAll(['category_id' => $this->category_id]);
+ CategoryName::deleteAll(['category_id' => $this->category_id]);
+ return true;
+ }
+
+ public function getActiveFilters() {
+ $query1 = (new Query())
+ ->distinct()
+ ->select([
+ 'option_id',
+ 'tax_option.*',
+ 'tax_group.*',
+ 'tax_option.alias as option_alias',
+ 'tax_group.alias as group_alias',
+ 'tax_value_string.value as value',
+ 'tax_option.sort AS tax_option_sort',
+ 'tax_group.sort AS tax_group_sort',
+ ])
+ ->from('tax_option')
+ ->innerJoin('product_variant_option', 'tax_option.tax_option_id = product_variant_option.option_id')
+ ->innerJoin('tax_group', 'tax_group.tax_group_id = tax_option.tax_group_id')
+ ->innerJoin('product_variant', 'product_variant.product_variant_id = product_variant_option.product_variant_id')
+ ->innerJoin('product', 'product.product_id = product_variant.product_id')
+ ->innerJoin('product_category', 'product_category.product_id = product.product_id')
+ ->innerJoin('tax_value_string', 'tax_value_string.tax_option_id = tax_option.tax_option_id')
+ ->where(['product_category.category_id' => $this->category_id, 'tax_group.is_filter' => TRUE])
+ ->andWhere(['!=', 'product_variant.stock', 0]);
+
+ $query2 = (new Query())
+ ->distinct()
+ ->select([
+ 'option_id',
+ 'tax_option.*',
+ 'tax_group.*',
+ 'tax_option.alias as option_alias',
+ 'tax_group.alias as group_alias',
+ 'tax_value_string.value as value',
+ 'tax_option.sort AS tax_option_sort',
+ 'tax_group.sort AS tax_group_sort',
+ ])
+ ->from('tax_option')
+ ->innerJoin('product_option', 'tax_option.tax_option_id = product_option.option_id')
+ ->innerJoin('tax_group', 'tax_group.tax_group_id = tax_option.tax_group_id')
+ ->innerJoin('product', 'product.product_id = product_option.product_id')
+ ->innerJoin('product_category', 'product_category.product_id = product.product_id')
+ ->innerJoin('product_variant', 'product_variant.product_id = product.product_id')
+ ->innerJoin('tax_value_string', 'tax_value_string.tax_option_id = tax_option.tax_option_id')
+ ->where(['product_category.category_id' => $this->category_id, 'tax_group.is_filter' => TRUE])
+ ->andWhere(['!=', 'product_variant.stock', 0]);
+ $query3 = (new Query())
+ ->select('*')
+ ->from(['subquery' => $query1->union($query2)])
+ ->orderBy('tax_group_sort, tax_option_sort');
+ return $query3;
+ }
+
+}
diff --git a/common/modules/product/models/CategoryName.php b/common/modules/product/models/CategoryName.php
new file mode 100755
index 0000000..e55331e
--- /dev/null
+++ b/common/modules/product/models/CategoryName.php
@@ -0,0 +1,66 @@
+ 250],
+ [['category_id'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['category_id' => 'category_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'category_name_id' => Yii::t('product', 'Category Name ID'),
+ 'category_id' => Yii::t('product', 'Category ID'),
+ 'value' => Yii::t('product', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategories()
+ {
+ return $this->hasMany(Category::className(), ['category_name_id' => 'category_name_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategory()
+ {
+ return $this->hasOne(Category::className(), ['category_id' => 'category_id']);
+ }
+}
diff --git a/common/modules/product/models/CategoryQuery.php b/common/modules/product/models/CategoryQuery.php
new file mode 100755
index 0000000..7a941c3
--- /dev/null
+++ b/common/modules/product/models/CategoryQuery.php
@@ -0,0 +1,39 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Category[]|array
+ */
+ public function all($db = null)
+ {
+ $this->with('categoryName');
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Category|array|null
+ */
+ public function one($db = null)
+ {
+// $this->joinWith('categoryName');
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/product/models/CategorySearch.php b/common/modules/product/models/CategorySearch.php
new file mode 100755
index 0000000..9e29a9a
--- /dev/null
+++ b/common/modules/product/models/CategorySearch.php
@@ -0,0 +1,116 @@
+with('categoryName');
+
+ // add conditions that should always apply here
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+
+ $this->load($params);
+
+ /*if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }*/
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'category.category_id' => $this->category_id,
+ 'category.parent_id' => $this->parent_id,
+ 'category.category_name_id' => $this->category_name_id,
+ 'category.product_unit_id' => $this->product_unit_id,
+ ]);
+
+ $query->andFilterWhere(['like', 'category.alias', $this->alias]);
+
+ $query->orderBy(['category.path' => SORT_ASC, 'category.depth' => SORT_ASC, 'category.category_id' => SORT_ASC]);
+
+ return $dataProvider;
+ }
+
+ public static function findByAlias($alias) {
+ /** @var CategoryQuery $query */
+ $query = Category::find()
+ ->with('categoryName')
+ ->andFilterWhere(['alias' => $alias]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+
+ public static function findByRemoteID($id) {
+ /** @var CategoryQuery $query */
+ $query = Category::find()
+ ->with('categoryName')
+ ->andFilterWhere(['@>', 'remote_id', ArtboxTreeHelper::setArrayField($id)]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ }
+ return null;
+ }
+
+// public static function findByProductsKeywords($keywords = [], $category = null) {
+//
+// }
+}
diff --git a/common/modules/product/models/Export.php b/common/modules/product/models/Export.php
new file mode 100755
index 0000000..8ed13b4
--- /dev/null
+++ b/common/modules/product/models/Export.php
@@ -0,0 +1,115 @@
+joinWith(['variants'])->where(['!=', ProductVariant::tableName() .'.stock', 0])->select('product.product_id')->all();
+ $products = Product::find()
+ ->with(['variantsWithFilters','brand','categoriesWithName'])->all();
+
+ $i = 0;
+ foreach ($products as $product)
+ {
+
+
+ $i++;
+ /*if ($i>1e2) {
+ break;
+ }*/
+ $mods = [];
+
+ $filterString = $this->convertFilterToString($product->getFilters());
+
+ foreach ($product->variantsWithFilters as $variant)
+ {
+
+ $color = $variant->name;
+
+ $mods[] = $variant->sku .
+ '=' . $this->convertFilterToString($variant->filters) .
+ '=' . $color .
+ '=' . ((!empty($variant->image)) ? $variant->image->image: '').
+ '=' . $variant->stock;
+ }
+
+
+ $fotos = [];
+
+// foreach ($product->images as $image)
+// {
+// $fotos[] = $image->imageUrl;
+// }
+
+// $filters = $product->properties;
+ $categories = [];
+ foreach($product->categoriesWithName as $value){
+ $categorName = ArrayHelper::getColumn($value->categoryNames,'value');
+ $categories[] = $categorName[0];
+
+ }
+
+
+ $categories = implode(',',$categories);
+
+ $list = [
+ $categories,
+ $product->brand->name,
+ $product->name,
+ '',
+ ((! empty($product->description)) ? $product->description : ''),
+ $filterString,
+ (!empty($product->variant)) ? $product->variant->price_old : '',
+ (!empty($product->variant)) ? $product->variant->price : '',
+ intval($product->akciya),
+ '',
+ intval($product->new),
+ intval($product->top),
+ $product->video,
+ implode (',', $fotos),
+ ];
+
+ $to_write = array_merge ($list, $mods);
+ foreach($to_write as &$cell) {
+ $cell = iconv("UTF-8", "WINDOWS-1251", $cell);
+ }
+
+
+ fputcsv($handle, $to_write, ';');
+ }
+
+
+
+ fclose ($handle);
+
+ return $dirName .'/'. $filename;
+ }
+
+
+ public function convertFilterToString($filters){
+ $fittersArray = [];
+ foreach($filters as $filter){
+ $fittersArray[$filter->taxGroup->alias][] = $filter->name;
+ }
+ $filterString=[];
+
+ foreach($fittersArray as $filterName =>$filterRows ){
+ $row = implode(',',$filterRows);
+ $filterString[] = "[{$filterName}:{$row}]";
+
+ }
+ return implode('*',$filterString);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/models/Import.php b/common/modules/product/models/Import.php
new file mode 100755
index 0000000..fb188c4
--- /dev/null
+++ b/common/modules/product/models/Import.php
@@ -0,0 +1,564 @@
+ 'csv'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'file' => Yii::t('product', 'File'),
+ ];
+ }
+
+ public function getType() {
+ if (!$this->type) {
+ $this->type = 'products';
+ }
+ return $this->type;
+ }
+
+ public function goPrices($from = 0, $limit = null) {
+ set_time_limit(0);
+ $new_products = $linked_products = 0;
+
+ if ( !($handle = $this->getProductsFile('uploadFilePrices')) ) {
+ $this->errors[] = 'File not found';
+ return FALSE;
+ }
+
+ $filesize = filesize(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFilePrices'));
+ if ($from) {
+ fseek($handle, $from);
+ }
+
+ $j = 0;
+
+ $is_utf = (preg_match('//u', file_get_contents(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFilePrices'), null, null, null, 1000000)));
+
+ while (($data = fgetcsv ($handle, 10000, ";")) !== FALSE && (empty($limit) || $j++ < $limit))
+ {
+ foreach ($data as &$value)
+ {
+ if (!$is_utf) {
+ $value = iconv ('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
+ }
+ $value = trim ($value);
+ }
+
+ // данные строк
+ $modification_code = @$data[0];
+ $price = floatval(@$data[1]);
+ $price_promo = floatval(@$data[2]);
+ $count = intval(@$data[3]);
+ $city_name = @$data[4];
+ $product_title = @$data[5];
+
+ if (empty ($modification_code)) {
+ continue;
+ }
+ // товары в пути
+ if (empty ($city_name))
+ {
+// $this->saveNotFoundRecord (
+// [$modification_code, $product_title],
+// Yii::getAlias('@uploadFilePricesAway')
+// );
+
+ $this->output[] = 'Товар '. $product_title . ' в пути';
+
+ continue;
+ }
+
+ if ( ($productVariant = ProductVariant::find()->filterWhere(['sku' => $modification_code])->one()) === null ) {
+ // 'Нет даной модификации в базе';
+// $this->saveNotFoundRecord (
+// [$modification_code, $product_title],
+// Yii::getAlias('@uploadFilePricesNoVariant')
+// );
+
+ $this->output[] = 'Для товара '. $product_title . ' не найдено соотвествие';
+
+ continue;
+ }
+
+
+
+
+ // ===== Set stock ====
+ if ( $city_name ) {
+ if ( ($stock = Stock::find()->filterWhere(['name' => trim($city_name)])->one()) === null ) {
+
+ // Create stock
+ $stock = new Stock();
+ $stock->name = trim($city_name);
+ $stock->save();
+ }
+
+ $productStock = ProductStock::find()->where(['product_variant_id' => $productVariant->product_variant_id, 'stock_id' => $stock->stock_id])->one();
+ if(!$productStock instanceof ProductStock) {
+ $productStock = new ProductStock;
+ $productStock->product_variant_id = $productVariant->product_variant_id;
+ $productStock->stock_id = $stock->stock_id;
+ $productStock->product_id = $productVariant->product_id;
+ }
+ $productStock->quantity = $count;
+
+ $productStock->save();
+ $productStocks = ProductStock::find()->where(['product_variant_id' => $productVariant->product_variant_id])->andWhere(['<>', 'stock_id', $stock->stock_id])->all();
+
+ $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
+ } else {
+
+ $productStocks = ProductStock::find()->where(['product_variant_id' => $productVariant->product_variant_id])->all();
+
+ if($productStocks instanceof ProductStock){
+ $quantity = array_sum(ArrayHelper::getColumn($productStocks, 'quantity')) + $count;
+ } else {
+ $quantity = 0;
+ }
+
+ }
+
+ if ($price_promo) {
+ $productVariant->price_old = $price;
+ $productVariant->price = $price_promo;
+ } else {
+ $productVariant->price = $price;
+ $productVariant->price_old = $price_promo;
+ }
+
+ $productVariant->stock = $quantity;
+
+ $productVariant->save();
+
+ $this->output[] = '
Товар '. $product_title .' успешно сохранен';
+ }
+
+ $result = [
+ 'end' => feof($handle),
+ 'from' => ftell($handle),
+ 'totalsize' => $filesize,
+ 'items' => $this->output,
+
+ ];
+
+ fclose ($handle);
+
+ if ($result['end']) {
+ unlink(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFilePrices'));
+ }
+
+ return $result;
+ }
+
+ public function goProducts($from = 0, $limit = null) {
+
+ set_time_limit(0);
+ $new_products = $linked_products = 0;
+
+ if ( !($handle = $this->getProductsFile('uploadFileProducts')) ) {
+ $this->errors[] = 'File not found';
+ return FALSE;
+ }
+
+ $filesize = filesize(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFileProducts'));
+
+
+ if ($from) {
+ fseek($handle, $from);
+ }
+
+ $j = 0;
+
+ $is_utf = (preg_match('//u', file_get_contents(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFileProducts'), null, null, null, 1000000)));
+
+ $result_items = [];
+
+ while (($data = fgetcsv ($handle, 10000, ";")) !== FALSE && (empty($limit) || $j++ < $limit))
+ {
+
+
+ foreach ($data as &$value)
+ {
+ if (!$is_utf) {
+ $value = iconv ('windows-1251', "UTF-8//TRANSLIT//IGNORE", $value);
+ }
+ $value = trim ($value);
+ }
+
+ // будет всегда 19 элементов
+ for ($i = 0; $i <= 18; $i++)
+ {
+ if (! isset ($data[$i]))
+ {
+ $data[$i] = null;
+ }
+ }
+
+
+ // 1 Группа (категория)
+ $catalog_names = explode(',',$data[0]);
+ if (empty ($catalog_names))
+ {
+ $result_items[] = "Не указана категория (строка $j)";
+ continue;
+ }
+
+ // 2 Бренд
+ $brand_name = $data[1];
+ if (empty ($brand_name))
+ {
+ $result_items[] = "Не указан бренд (строка $j)";
+ continue;
+ }
+
+ // 3 Название товара
+ $product_name = $data[2];
+ if (empty ($product_name))
+ {
+ $result_items[] = "Не указано наименование товара (строка $j)";
+ continue;
+ }
+
+ // 4 Описание Укр
+ $product_body_uk = $data[3];
+
+ // 5 Описание Рус
+ $product_body_ru = $data[4];
+
+ // 6 Фильтр (['pol'='мужской']*['god' = '2013']*['volume'='25 л']*['size'='49 x 30 x 20см']*['composition'='600D полиэстер'])
+ $filters = explode ('*', $data[5]);
+
+ // 11 Цена акция
+ $product_cost_old = floatval($data[7]);
+
+ // 10 Цена
+ if ($product_cost_old) {
+ $product_cost_old = floatval($data[6]);
+ $product_cost = floatval($data[7]);
+ }
+
+ // 12 Акция
+ $product_akciya = (bool)$data[8];
+
+ // 13 Сопуд. Тов.
+ $similar = explode (',', $data[9]);
+
+ // 14 Новинки
+ $product_new = (bool)$data[10];
+
+ // 15 Топ продаж
+ $product_top = (bool)$data[11];
+
+
+ // 17 ВИДЕО КОД
+ $product_video = $data[12];
+
+ // 18 Галлерея фото
+ if (trim($data[13])) {
+ $fotos = explode (',', trim($data[13]));
+ }
+
+ // 19 Штрих код товара.
+ // расшифровал - это модификации товара!
+
+ $product_image = explode ('=', $data[14]);
+ $product_image = @$product_image[3];
+
+ if ( ($_product = Product::find()->filterWhere(['ilike', 'name', trim($product_name)])->one()) === null ) {
+ $_product = new Product();
+ }
+
+ $is_new_product = empty($_product->product_id);
+
+ foreach($catalog_names as $catalog_name){
+ // ==== Set category ====
+ if ( ($category = CategoryName::find()->filterWhere(['ilike', 'value', trim($catalog_name)])->one()) === null ) {
+ // Create category
+ $category = new Category();
+ $category->name = trim($catalog_name);
+ $category->save();
+ }
+
+ $category_id[] = $category->category_id;
+ }
+
+
+ $_product->categories = $category_id;
+
+ // ===== Set brand ====
+ if ( $brand_name ) {
+ if ( ($brand = BrandName::find()->filterWhere(['ilike', 'value', trim($brand_name)])->one()) !== null ) {
+ $_product->brand_id = $brand->brand_id;
+ } else {
+ // Create brand
+ $brand = new Brand();
+ $brand->name = trim($brand_name);
+ $brand->save();
+ $_product->brand_id = $brand->brand_id;
+ }
+ }
+
+ $_product->name = $product_name;
+ $_product->video = $product_video;
+ $_product->description = $product_body_ru;
+ $_product->is_top = $product_top;
+ $_product->akciya = $product_akciya;
+ $_product->is_new = $product_new;
+
+ if (!$_product->save()) {
+ $result_items[] = 'Product #'. $_product->name .' not saved' . " (строка $j)";
+ continue;
+ }
+
+
+
+ if (!empty($fotos)) {
+ foreach($fotos as $foto) {
+ $source_image = Yii::getAlias('@uploadDir') . '/product_images/'. urlencode($foto);
+
+ if (file_exists($source_image)) {
+ if (($productImage = ProductImage::find()->andFilterWhere(['ilike', 'image', $foto])->andFilterWhere(['product_id' => $_product->product_id])->one()) === null) {
+ copy($source_image, Yii::getAlias('@productsDir') . "/" . $foto);
+ $productImage = new ProductImage();
+ $productImage->product_id = $_product->product_id;
+ $productImage->image = $foto;
+ $productImage->save();
+ }
+ }
+ }
+ }
+
+
+ // нужно для проставления характеристик относящихся к модификациям
+ $MOD_ARRAY = [];
+
+ for ($i = 14; $i < count ($data); $i ++)
+ {
+ if (! empty ($data[$i]))
+ {
+ $mod_arr = explode ('=', $data[$i]);
+ $mod_art = $mod_arr[0];
+ $variant_filters = explode ('*', $mod_arr[1]);
+ $mod_color = $mod_arr[2];
+ $mod_image = $mod_arr[3];
+ $mod_stock = isset($mod_arr[4]) ?$mod_arr[4]:1;
+ $mod_cost = isset($product_cost) ? floatval($product_cost) : 0;
+ $mod_old_cost = floatval($product_cost_old);
+
+ // Check product variant
+ if ( ($_productVariant = ProductVariant::find()->andFilterWhere(['ilike', 'sku', $mod_art])->andFilterWhere(['product_id' => $_product->product_id])->one()) === null ) {
+ $_productVariant = new ProductVariant();
+ $_productVariant->product_id = $_product->product_id;
+ }
+ $_productVariant->product_unit_id = 1;
+
+ $_productVariant->sku = $mod_art;
+ $_productVariant->price = $mod_cost;
+ $_productVariant->price_old = $mod_old_cost;
+ $_productVariant->stock = $mod_stock;
+
+ $product_variant_type_name = '';
+ if (! empty ($mod_color)) {
+ $product_variant_type_name = 'Цвет';
+ $_productVariant->name = $mod_color;
+ }
+
+ if (! empty ($variant_filters)) {
+
+ $variants_options = $this->saveFilters($variant_filters,1,$category_id);
+
+ }
+
+
+ if (isset($variants_options) && !empty($variants_options)) {
+ $_productVariant->options = $variants_options;
+ }
+
+
+ // ===== Set variant type ====
+ if ( $product_variant_type_name ) {
+ if ( ($product_variant_type = ProductVariantType::find()->filterWhere(['ilike', 'name', $product_variant_type_name])->one()) !== null ) {
+ $_productVariant->product_variant_type_id = $product_variant_type->product_variant_type_id;
+ } else {
+ $product_variant_type = new ProductVariantType();
+ $product_variant_type->name = $product_variant_type_name;
+ $product_variant_type->save();
+ $_productVariant->product_variant_type_id = $product_variant_type->product_variant_type_id;
+ }
+ }
+
+ $_productVariant->save(false);
+
+ $MOD_ARRAY[] = $_productVariant->product_variant_id;
+
+ if ($mod_image) {
+ $source_image = Yii::getAlias('@uploadDir') . '/product_images/'. urlencode($mod_image);
+ if (file_exists($source_image)) {
+ if (($variantImage = ProductImage::find()->andFilterWhere(['ilike', 'image', $mod_image])->andFilterWhere(['product_variant_id' => $_productVariant->product_variant_id])->one()) === null) {
+ copy($source_image, Yii::getAlias('@productsDir') . "/" . $mod_image);
+ $variantImage = new ProductImage();
+ $variantImage->product_id = $_product->product_id;
+ $variantImage->product_variant_id = $_productVariant->product_variant_id;
+ $variantImage->image = $mod_image;
+ $variantImage->save();
+ }
+ }
+ }
+ }
+ }
+
+
+
+ if (! empty ($filters)) {
+
+ $options = $this->saveFilters($filters,0,$category_id);
+
+ }
+
+
+ if (isset($options) && !empty($options)) {
+ $_product->options = $options;
+ }
+
+ $_product->save();
+
+ $result_items[] = "Product {$_product->name} #{$_product->product_id} saved (". ($is_new_product ? 'new product' : 'exists product') .")" . " (строка $j)";
+ }
+
+ $result = [
+ 'end' => feof($handle),
+ 'from' => ftell($handle),
+ 'totalsize' => $filesize,
+ 'items' => $result_items,
+
+ ];
+
+ fclose ($handle);
+
+ if ($result['end']) {
+ unlink(Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@uploadFileProducts'));
+ }
+
+ return $result;
+ }
+
+ private function getProductsFile($file_type) {
+ $filename = Yii::getAlias('@uploadDir') .'/'. Yii::getAlias('@'. $file_type);
+ if (!is_file($filename)) {
+ $this->errors[] = "File $filename not found";
+ return FALSE;
+ }
+ return fopen ($filename, 'r');
+ }
+
+ private function saveNotFoundRecord (array $line, $filename)
+ {
+ $str = implode (';', $line)."\n";
+ $str = iconv ("UTF-8//TRANSLIT//IGNORE", "windows-1251", $str);
+
+ $fg = fopen (Yii::getAlias('@uploadDir') .'/'. $filename, 'a+');
+ fputs ($fg, $str);
+ fclose ($fg);
+ }
+
+
+ /**
+ * @param $filters array of filters like [['pol'='мужской'],['god' = '2013'],['volume'='25 л']*['size'='49 x 30 x 20см'],['composition'='600D полиэстер']]
+ * @param $level 0 for products and 1 for product variant
+ * @param $catalog_names array catalogs id
+ * @return array
+ */
+ private function saveFilters($filters, $level,$catalog_names){
+ $options = [];
+ foreach($filters as $filter) {
+
+ preg_match_all('/\[(.*):(.*)\]/',$filter,$filter);
+
+ if (empty($filter[1][0])) {
+ continue;
+ }
+ $filter_name = trim($filter[1][0]);
+
+ $taxGroup = TaxGroup::find()->where(['alias'=>$filter_name])->one();
+ if(!$taxGroup instanceof TaxGroup){
+ $taxGroup = new TaxGroup();
+ $taxGroup->alias = $filter_name;
+ $taxGroup->level = $level;
+ $taxGroup->name = $filter_name;
+ $taxGroup->module = 'string';
+ $taxGroup->hierarchical = FALSE;
+ $taxGroup->group_to_category = $catalog_names;
+ $taxGroup->is_filter = FALSE;
+ $taxGroup->save();
+ }
+
+ $filters_options = explode(',',$filter[2][0]);
+
+ foreach($filters_options as $filter_options){
+ $value = TaxValueString::find()->innerJoinWith('taxOption')->andFilterWhere(['ilike', 'value', $filter_options])->andFilterWhere(['tax_option.tax_group_id' => $taxGroup->tax_group_id])->one();
+
+ if (!$value instanceof TaxValueString) {
+ // Create option
+ $option = new TaxOption();
+ $option->tax_group_id = $taxGroup->tax_group_id;
+ $option->name = $filter_options;
+ $option->save();
+
+ $value = new TaxValueString();
+ $value->tax_option_id = $option->tax_option_id;
+ $value->value = $filter_options;
+ $value->save();
+
+ $option->default_value = $value->tax_value_id;
+ $option->save();
+ }
+ $options[] = $value->tax_option_id;
+
+ }
+
+
+ }
+
+ return $options;
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/models/Product.php b/common/modules/product/models/Product.php
new file mode 100755
index 0000000..7962c5f
--- /dev/null
+++ b/common/modules/product/models/Product.php
@@ -0,0 +1,441 @@
+ relationBehavior::className(),
+ 'relations' => [
+ 'product_categories' => 'entity1', // Product category
+ 'product_option' => 'entity1' // Product category
+ ]
+ ],
+ [
+ 'class' =>FilterBehavior::className(),
+ ],
+ [
+ 'class' => Slug::className(),
+ 'in_attribute' => 'name',
+ 'out_attribute' => 'alias',
+ 'translit' => true
+ ]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return '{{%product}}';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+// [['categories'], 'required'],
+ [['brand_id'], 'integer'],
+ [['name'], 'string', 'max' => 150],
+ [['alias'], 'string', 'max' => 250],
+ [['categories', 'variants', 'options', 'imagesUpload'], 'safe'],
+// [['imagesUpload'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif', 'maxFiles' => 50],
+ [['description', 'video'], 'safe'],
+ [['is_top', 'is_new', 'akciya'], 'boolean'],
+// [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_id' => Yii::t('product', 'ID'),
+ 'name' => Yii::t('product', 'Name'),
+ 'brand_id' => Yii::t('product', 'Brand'),
+ 'categories' => Yii::t('product', 'Categories'), // relation behavior field
+ 'category' => Yii::t('product', 'Category'), // relation behavior field
+ 'image' => Yii::t('product', 'Image'),
+ 'images' => Yii::t('product', 'Images'),
+ 'description' => Yii::t('product', 'Description'),
+ 'video' => Yii::t('product', 'Video embeded'),
+ 'variants' => Yii::t('product', 'Variants'),
+ 'is_top' => Yii::t('product', 'Is top'),
+ 'is_new' => Yii::t('product', 'Is new'),
+ 'akciya' => Yii::t('product', 'Is promo'),
+ ];
+ }
+
+ public function getUrl() {
+ return '/product/'. $this->alias;
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getBrand()
+ {
+ return $this->hasOne(Brand::className(), ['brand_id' => 'brand_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getImage()
+ {
+ return $this->hasOne(ProductImage::className(), ['product_id' => 'product_id']);
+ }
+
+ /**
+ * fetch stored image url
+ * @return string
+ */
+ public function getImageUrl()
+ {
+ $image = empty($this->variant) ? null : $this->variant->image;
+ return !empty($image) ? $image->imageUrl : '/images/no_photo.png';
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getImages()
+ {
+ return $this->hasMany(ProductImage::className(), ['product_id' => 'product_id'])->where(['product_variant_id' => null]);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getVariant()
+ {
+ return $this->hasOne(ProductVariant::className(), ['product_id' => 'product_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getEnabledVariant()
+ {
+ return $this->hasOne(ProductVariant::className(), ['product_id' => 'product_id'])->andOnCondition(['!=', ProductVariant::tableName() .'.stock', 0]);
+ }
+
+ public function getVariantPrice() {
+ return $this->variant->price;
+ }
+
+ public function getEnabledVariantPrice() {
+ return $this->enabledVariants[0]->price;
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getVariants()
+ {
+ return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id']);
+ }
+
+ public function getEnabledVariants()
+ {
+ return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id'])->andOnCondition(['!=', ProductVariant::tableName() .'.stock', 0])->joinWith('image');
+ }
+
+ /*
+ * Get variants grouped by type
+ */
+ public function getEnabledVariantsGrouped()
+ {
+ $variants = [];
+ foreach ($this->enabledVariants as $variant) {
+ $variants[$variant->product_variant_type_id ? $variant->product_variant_type_id : 1][] = $variant;
+ }
+ if (empty($variants)) {
+ return [];
+ }
+ $ids = array_keys($variants);
+ $variants_type = [];
+ foreach(ProductVariantType::find()->select(['product_variant_type_id', 'name2'])->where(['product_variant_type_id' => $ids])->all() as $variant_type) {
+ $variant_type->_variants = $variants[$variant_type->product_variant_type_id];
+ $variants_type[] = $variant_type;
+ }
+ return $variants_type;
+ }
+
+ public function setVariants($variants) {
+ $this->_variants = $variants;
+ }
+
+ public function getFullName()
+ {
+ return empty($this->brand) ? $this->name : $this->brand->name .' '. $this->name;
+ }
+
+ public function getCategories() {
+ return $this->hasMany(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
+// return $this->getRelations('product_categories');
+ }
+ public function getCategoriesWithName() {
+ return $this->hasMany(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id'])->joinWith('categoryNames');
+// return $this->getRelations('product_categories');
+ }
+
+ public function getCategoriesNames() {
+ $result = [];
+ foreach($this->categories as $category) {
+ $result[] = $category->name;
+ }
+ return $result;
+ }
+
+ public function getVariantsWithFilters(){
+ return $this->hasMany(ProductVariant::className(), ['product_id' => 'product_id'])->with('filters');
+ }
+
+ /**
+ * @return ActiveQuery
+ */
+ public function getCategory() {
+ return $this->hasOne(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
+ }
+
+ public function getOptions() {
+ return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])->viaTable('product_option', ['product_id' => 'product_id']);
+ }
+
+ public function getProperties() {
+ $groups = $options = [];
+ foreach ($this->options as $option) {
+ $options[$option->tax_group_id][] = $option;
+ }
+ foreach (TaxGroup::find()->where(['tax_group_id' => array_keys($options)])->all() as $group) {
+ if (!empty($options[$group->tax_group_id])) {
+ $group->_options = $options[$group->tax_group_id];
+ $groups[] = $group;
+ }
+ }
+ return $groups;
+ }
+
+ public function getActiveProperties($category_id) {
+ $groups = $options = [];
+ foreach ($this->options as $option) {
+ $options[$option->tax_group_id][] = $option;
+ }
+ foreach (TaxGroup::find()->joinWith('categories')->where(['tax_group.tax_group_id' => array_keys($options), 'tax_group.display' => TRUE, 'category.category_id' => $category_id])->all() as $group) {
+ if (!empty($options[$group->tax_group_id])) {
+ $group->_options = $options[$group->tax_group_id];
+ $groups[] = $group;
+ }
+ }
+ return $groups;
+ }
+
+ public function getStocks() {
+ return $this->hasMany(Stock::className(), ['stock_id' => 'stock_id'])->viaTable(ProductStock::tableName(), ['product_id' => 'product_id']);
+ }
+
+ /**
+ * @inheritdoc
+ * @return ProductQuery the active query used by this AR class.
+ */
+ public static function find()
+ {
+ return new ProductQuery(get_called_class());
+ }
+
+ public function getQuantity() {
+ return ProductStock::find()
+ ->where(['product_id' => $this->product_id])
+ ->sum('quantity');
+ }
+
+ public function afterSave($insert, $changedAttributes)
+ {
+ parent::afterSave($insert, $changedAttributes);
+
+// $images = UploadedFile::getInstance($this, 'imagesUpload');
+// var_dump($images);exit;
+
+// if (!empty($this->imagesUpload)) {
+// if (!is_array($this->imagesUpload)) {
+// $this->imagesUpload = [$this->imagesUpload];
+// }
+// foreach($this->imagesUpload as $image) {
+// $image->saveAs((Yii::getAlias('@frontend/web/storage/products/original/' . $image->baseName .'_'. uniqid() . '.' . $image->extension)));
+// }
+//
+//
+// }
+
+ if (!empty($this->_variants)) {
+ $todel = [];
+ foreach ($this->variants ?: [] as $_variant) {
+ $todel[$_variant->product_variant_id] = $_variant->product_variant_id;
+ }
+ foreach ($this->_variants as $_variant) {
+ if (!is_array($_variant)) {
+ return;
+ }
+ if (!empty($_variant['product_variant_id'])) {
+ unset($todel[$_variant['product_variant_id']]);
+ $model = ProductVariant::findOne($_variant['product_variant_id']);
+ } else {
+ $model = new ProductVariant();
+ }
+ $_variant['product_id'] = $this->product_id;
+ $model->load(['ProductVariant' => $_variant]);
+ $model->product_id = $this->product_id;
+ $model->save();
+ }
+ if (!empty($todel)) {
+ ProductVariant::deleteAll(['product_variant_id' => $todel]);
+ }
+ }
+ }
+
+ public function beforeDelete() {
+ ProductImage::deleteAll(['product_id' => $this->product_id]);
+ ProductCategory::deleteAll(['product_id' => $this->product_id]);
+ ProductVariant::deleteAll(['product_id' => $this->product_id]);
+ ProductOption::deleteAll(['product_id' => $this->product_id]);
+ //ProductVariantOption::deleteAll(['product_id' => $this->product_id]);
+ ProductStock::deleteAll(['product_id' => $this->product_id]);
+ Share::deleteAll(['product_id' => $this->product_id]);
+ return true;
+ }
+
+ public function imagesUpload()
+ {
+ if ($this->validate()) {
+ $images = [];
+ foreach ($this->imagesUpload as $image) {
+ $imageName = $image->baseName .'.'. $image->extension;
+ $i = 0;
+ while(file_exists(Yii::getAlias('@imagesDir/products/' . $imageName))) {
+ $i++;
+ $imageName = $image->baseName .'_'. $i .'.'. $image->extension;
+ }
+
+ $image->saveAs(Yii::getAlias('@imagesDir/products/' .$imageName));
+ $images[] = $imageName;
+ }
+ return $images;
+ } else {
+ return false;
+ }
+ }
+
+ public function getImagesHTML() {
+ $op = [];
+ if ($this->images) {
+ foreach ($this->images as $image) {
+ $op[] = \common\components\artboximage\ArtboxImageHelper::getImage($image->imageUrl, 'admin_thumb');
+ }
+ }
+ return $op;
+ }
+
+ public function getImagesConfig() {
+ $op = [];
+ if ($this->images) {
+ foreach ($this->images as $image) {
+ $op[] = [
+ 'caption' => $image->image,
+ 'width' => '120px',
+ 'url' => \yii\helpers\Url::to(['/product/manage/delimg', 'id' => $image->product_image_id]),
+ 'key' => $image->product_image_id,
+ 'extra' => [
+ 'id' => $image->product_image_id,
+ ],
+ ];
+ }
+ }
+ return $op;
+ }
+
+ public function recalculateRating() {
+ /**
+ * @var ProductToRating $averageRating
+ */
+ $average = $this->getComments()->joinWith('rating')->select(['average' => 'avg(artbox_comment_rating.value)::float'])->scalar();
+ if(!$average) {
+ $average = 0;
+ }
+ $averageRating = $this->averageRating;
+ if(!empty($averageRating)) {
+ $averageRating->value = $average;
+ } else {
+ $averageRating = new ProductToRating(['product_id' => $this->product_id, 'value' => $average]);
+ }
+ if($averageRating->save()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function getComments() {
+ return $this->hasMany(CommentModel::className(), ['entity_id' => 'product_id'])->where(['artbox_comment.entity' => self::className(), 'artbox_comment.status' => CommentModel::STATUS_ACTIVE, 'artbox_comment.artbox_comment_pid' => NULL]);
+ }
+
+ public function getAverageRating() {
+ return $this->hasOne(ProductToRating::className(), ['product_id' => 'product_id']);
+ }
+
+ public function getTaxGroupsByLevel($level)
+ {
+ $categories = ArrayHelper::getColumn($this->categories, 'category_id');
+ return TaxGroup::find()->distinct()->innerJoin('relation', 'entity1_id = tax_group_id')->andWhere(['relation.entity2_id' => $categories])->andWhere(['level' => $level]);
+ }
+}
diff --git a/common/modules/product/models/ProductCategory.php b/common/modules/product/models/ProductCategory.php
new file mode 100755
index 0000000..f4d9727
--- /dev/null
+++ b/common/modules/product/models/ProductCategory.php
@@ -0,0 +1,59 @@
+ true, 'targetClass' => Category::className(), 'targetAttribute' => ['category_id' => 'category_id']],
+ [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_id' => Yii::t('product', 'Product'),
+ 'category_id' => Yii::t('product', 'Category'),
+ ];
+ }
+
+ public function getProduct() {
+ return $this->getEntity1();
+ }
+
+ public function getCategory() {
+ return $this->getEntity2();
+ }
+}
diff --git a/common/modules/product/models/ProductImage.php b/common/modules/product/models/ProductImage.php
new file mode 100755
index 0000000..a69a9f2
--- /dev/null
+++ b/common/modules/product/models/ProductImage.php
@@ -0,0 +1,163 @@
+ 255],
+ [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
+ [['product_variant_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductVariant::className(), 'targetAttribute' => ['product_variant_id' => 'product_variant_id']],
+ [['imageUpload'], 'safe'],
+ [['imageUpload'], 'file', 'extensions' => 'jpg, gif, png'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_image_id' => Yii::t('product', 'Product Image ID'),
+ 'product_id' => Yii::t('product', 'Product ID'),
+ 'product_variant_id' => Yii::t('product', 'Product Variant ID'),
+ 'product' => Yii::t('product', 'Product'),
+ 'product_variant' => Yii::t('product', 'Product Variant'),
+ 'image' => Yii::t('product', 'Image'),
+ 'alt' => Yii::t('product', 'Alt'),
+ 'title' => Yii::t('product', 'Title'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProduct()
+ {
+ $return = $this->hasOne(Product::className(), ['product_id' => 'product_id']);
+ if (empty($return)) {
+ $return = $this->productVariant->product_id;
+ }
+ return $return;
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariant()
+ {
+ return $this->hasOne(Product::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+// /**
+// * @inheritdoc
+// * @return ProductImageQuery the active query used by this AR class.
+// */
+// public static function find()
+// {
+// return new ProductImageQuery(get_called_class());
+// }
+
+ /**
+ * fetch stored image file name with complete path
+ * @return string
+ */
+ public function getImageFile()
+ {
+ return isset($this->image) ? '/storage/products/' . $this->image : null;
+ }
+
+ /**
+ * fetch stored image url
+ * @return string
+ */
+ public function getImageUrl()
+ {
+ // return a default image placeholder if your source image is not found
+ return isset($this->image) ? '/storage/products/'. $this->image : '/storage/no_photo.png';
+ }
+
+ /**
+ * Process upload of image
+ *
+ * @return mixed the uploaded image instance
+ */
+ public function uploadImage() {
+ // get the uploaded file instance. for multiple file uploads
+ // the following data will return an array (you may need to use
+ // getInstances method)
+ $image = UploadedFile::getInstance($this, 'imageUpload');
+
+ // if no image was uploaded abort the upload
+ if (empty($image)) {
+ return false;
+ }
+
+ // store the source file name
+ $this->filename = $image->name;
+ $ext = end((explode(".", $image->name)));
+
+ // generate a unique file name
+ $this->image = Yii::$app->security->generateRandomString().".{$ext}";
+
+ // the uploaded image instance
+ return $image;
+ }
+
+ /**
+ * Process deletion of image
+ *
+ * @return boolean the status of deletion
+ */
+ public function deleteImage() {
+ $file = $this->getImageFile();
+
+ // check if file exists on server
+ if (empty($file) || !file_exists($file)) {
+ return false;
+ }
+
+ // check if uploaded file can be deleted on server
+ if (!unlink($file)) {
+ return false;
+ }
+
+ // if deletion successful, reset your file attributes
+ $this->image = null;
+ $this->filename = null;
+
+ return true;
+ }
+}
diff --git a/common/modules/product/models/ProductImageQuery.php b/common/modules/product/models/ProductImageQuery.php
new file mode 100755
index 0000000..d10b794
--- /dev/null
+++ b/common/modules/product/models/ProductImageQuery.php
@@ -0,0 +1,35 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return ProductImage[]|array
+ */
+ public function all($db = null)
+ {
+ $this->where(['product_variant_id' => NULL]);
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return ProductImage|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/product/models/ProductOption.php b/common/modules/product/models/ProductOption.php
new file mode 100755
index 0000000..de5d49f
--- /dev/null
+++ b/common/modules/product/models/ProductOption.php
@@ -0,0 +1,65 @@
+ true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
+ [['option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_id' => Yii::t('product', 'Product ID'),
+ 'option_id' => Yii::t('product', 'Option ID'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProduct()
+ {
+ return $this->hasOne(Product::className(), ['product_id' => 'product_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'option_id']);
+ }
+}
diff --git a/common/modules/product/models/ProductQuery.php b/common/modules/product/models/ProductQuery.php
new file mode 100755
index 0000000..b5cf18c
--- /dev/null
+++ b/common/modules/product/models/ProductQuery.php
@@ -0,0 +1,45 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Product[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Product|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+
+ /**
+ * Select category by alias
+ * @param $slug
+ * @return $this
+ */
+ public function byAlias($alias)
+ {
+ $this->andFilterWhere(['alias' => $alias]);
+ return $this;
+ }
+}
diff --git a/common/modules/product/models/ProductSearch.php b/common/modules/product/models/ProductSearch.php
new file mode 100755
index 0000000..314d941
--- /dev/null
+++ b/common/modules/product/models/ProductSearch.php
@@ -0,0 +1,130 @@
+joinWith(['brand', 'brand.brandNames', 'categories', 'categories.categoryNames', 'variant']);
+
+ $query->groupBy(['product.product_id']);
+ $query->orderBy('product.product_id', 'DESC');
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+
+ if ( !($this->load($params) && $this->validate()) ) {
+ return $dataProvider;
+ }
+
+ $dataProvider->setSort([
+ 'attributes' => [
+ 'name',
+ 'brand_name' => [
+ 'asc' => ['brand_name.value' => SORT_ASC],
+ 'desc' => ['brand_name.value' => SORT_DESC],
+ 'default' => SORT_DESC,
+ 'label' => 'Brand name',
+ ],
+ 'category_name',
+ 'variant_sku',
+ ]
+ ]);
+
+ if (isset($this->is_top)) {
+ $query->andFilterWhere([
+ 'is_top' => (bool)$this->is_top,
+ ]);
+ }
+ if (isset($this->is_new)) {
+ $query->andFilterWhere([
+ 'is_new' => (bool)$this->is_new,
+ ]);
+ }
+ if (isset($this->akciya)) {
+ $query->andFilterWhere([
+ 'akciya' => (bool)$this->akciya,
+ ]);
+ }
+ $query->andFilterWhere([
+ 'product.brand_id' => $this->brand_id,
+ 'product.product_id' => $this->product_id,
+ 'product_category.category_id' => $this->category_id
+ ]);
+
+ $query->andFilterWhere(['ilike', 'product.name', $this->name]);
+ $query->andFilterWhere(['ilike', 'brand_name.value', $this->brand_name]);
+ $query->andFilterWhere(['ilike', 'category_name.value', $this->category_name]);
+ $query->andFilterWhere(['ilike', 'product_variant.sku', $this->variant_sku]);
+
+ return $dataProvider;
+ }
+
+ public static function findByAlias($alias) {
+ /** @var ProductQuery $query */
+ $query = Product::find();
+ $query->byAlias($alias);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested product does not exist.');
+ }
+ }
+
+ public static function findByRemoteID($id) {
+ /** @var CategoryQuery $query */
+ $query = Product::find()
+ ->andFilterWhere(['remote_id' => $id]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ }
+ return null;
+ }
+}
diff --git a/common/modules/product/models/ProductStock.php b/common/modules/product/models/ProductStock.php
new file mode 100755
index 0000000..ead58bc
--- /dev/null
+++ b/common/modules/product/models/ProductStock.php
@@ -0,0 +1,95 @@
+ true, 'targetClass' => Product::className(), 'targetAttribute' => ['product_id' => 'product_id']],
+ [['product_variant_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductVariant::className(), 'targetAttribute' => ['product_variant_id' => 'product_variant_id']],
+ [['stock_id'], 'exist', 'skipOnError' => true, 'targetClass' => Stock::className(), 'targetAttribute' => ['stock_id' => 'stock_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_id' => 'Product ID',
+ 'stock_id' => 'Stock ID',
+ 'quantity' => 'Количество',
+ 'product_variant_id' => 'Product Variant ID',
+ 'name' => "Название"
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProduct()
+ {
+ return $this->hasOne(Product::className(), ['product_id' => 'product_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariant()
+ {
+ return $this->hasOne(ProductVariant::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+
+ public function getName(){
+ return (!empty($this->stock))? $this->stock->name : '';
+ }
+
+ public function setName($value){
+ $this->name = $value;
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getStock()
+ {
+ return $this->hasOne(Stock::className(), ['stock_id' => 'stock_id']);
+ }
+
+
+ public static function primaryKey()
+ {
+ return ["stock_id","product_variant_id"];
+ }
+}
diff --git a/common/modules/product/models/ProductUnit.php b/common/modules/product/models/ProductUnit.php
new file mode 100755
index 0000000..f6dbe42
--- /dev/null
+++ b/common/modules/product/models/ProductUnit.php
@@ -0,0 +1,69 @@
+ 255],
+ [['code'], 'string', 'max' => 50],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
+ 'name' => Yii::t('product', 'Name'),
+ 'code' => Yii::t('product', 'Code'),
+ 'is_default' => Yii::t('product', 'Is Default'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getCategories()
+ {
+ return $this->hasMany(Category::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariants()
+ {
+ return $this->hasMany(ProductVariant::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+}
diff --git a/common/modules/product/models/ProductUnitSearch.php b/common/modules/product/models/ProductUnitSearch.php
new file mode 100755
index 0000000..8b0be90
--- /dev/null
+++ b/common/modules/product/models/ProductUnitSearch.php
@@ -0,0 +1,72 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'product_unit_id' => $this->product_unit_id,
+ 'is_default' => $this->is_default,
+ ]);
+
+ $query->andFilterWhere(['like', 'name', $this->name])
+ ->andFilterWhere(['like', 'code', $this->code]);
+
+ return $dataProvider;
+ }
+}
diff --git a/common/modules/product/models/ProductVariant.php b/common/modules/product/models/ProductVariant.php
new file mode 100755
index 0000000..1054655
--- /dev/null
+++ b/common/modules/product/models/ProductVariant.php
@@ -0,0 +1,315 @@
+ relationBehavior::className(),
+ 'relations' => [
+ 'product_variant_option' => 'entity1' // Product variant options
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'product_variant';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['product_id', 'product_unit_id'], 'required'],
+ [['product_id', 'product_unit_id', 'product_variant_type_id'], 'integer'],
+ [['price', 'price_old', 'stock'], 'number'],
+ [['name', 'sku'], 'string', 'max' => 255],
+ [['remote_id'], 'string', 'max' => 20],
+ [['options', 'imagesUpload'], 'safe'],
+// [['imagesUpload'], 'safe'],
+// [['imagesUpload'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif', 'maxFiles' => 50],
+ [['product_unit_id'], 'exist', 'skipOnError' => true, 'targetClass' => ProductUnit::className(), 'targetAttribute' => ['product_unit_id' => 'product_unit_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_variant_id' => Yii::t('product', 'Product Variant ID'),
+ 'product_id' => Yii::t('product', 'Product ID'),
+ 'name' => Yii::t('product', 'Name'),
+ 'sku' => Yii::t('product', 'Sku'),
+ 'price' => Yii::t('product', 'Price'),
+ 'price_old' => Yii::t('product', 'Price Old'),
+ 'stock' => Yii::t('product', 'Stock'),
+ 'product_unit_id' => Yii::t('product', 'Product Unit ID'),
+ 'product_variant_type_id' => Yii::t('product', 'Product Variant Type ID'),
+ 'stock_caption' => Yii::t('product', 'Stock'),
+ 'image' => Yii::t('product', 'Image'),
+ 'images' => Yii::t('product', 'Images'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductUnit()
+ {
+ return $this->hasOne(ProductUnit::className(), ['product_unit_id' => 'product_unit_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariantType()
+ {
+ return $this->hasOne(ProductVariantType::className(), ['product_variant_type_id' => 'product_variant_type_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProduct()
+ {
+ return $this->hasOne(Product::className(), ['product_id' => 'product_id']);
+ }
+
+ public function getProductStock() {
+ return $this->hasMany(ProductStock::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+ public function getQuantity() {
+ return ProductStock::find()
+ ->where(['product_variant_id' => $this->product_variant_id])
+ ->sum('quantity');
+ }
+
+ public function getStock_caption() {
+ return is_null($this->stock) ? '∞' : ($this->stock > 0 ? Yii::t('product', 'Enable') : Yii::t('product', 'Disable')); // intval($this->stock);
+ }
+
+ public function getVariantStocks(){
+
+ return $this->hasMany(ProductStock::className(),['product_variant_id'=> 'product_variant_id'])->joinWith('stock');
+ }
+
+ public function getStocks(){
+
+ return $this->hasMany(Stock::className(),['stock_id'=>'stock_id'])
+ ->viaTable(ProductStock::tableName(),['product_variant_id'=> 'product_variant_id']);
+ }
+
+
+ public function getFilters(){
+
+ return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])
+ ->viaTable('product_variant_option',[ 'product_variant_id'=> 'product_variant_id'])
+ ->joinWith('taxGroup');
+ }
+
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getImage()
+ {
+ return $this->hasOne(ProductImage::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+ /**
+ * fetch stored image url
+ * @return string
+ */
+ public function getImageUrl()
+ {
+ // return a default image placeholder if your source image is not found
+ return !empty($this->image) ? $this->image->imageUrl : '/images/no_photo.png';
+ }
+
+ public function getFullname() {
+ return empty($this->product) ? null : ($this->product->name . (empty($this->name) ? '' : ' '. $this->name));
+ }
+
+ public function getImagesHTML() {
+ $op = [];
+ if ($this->images) {
+ foreach ($this->images as $image) {
+ $op[] = \common\components\artboximage\ArtboxImageHelper::getImage($image->imageUrl, 'admin_thumb');
+ }
+ }
+ return $op;
+ }
+
+ public function getImagesConfig() {
+ $op = [];
+ if ($this->images) {
+ foreach ($this->images as $image) {
+ $op[] = [
+ 'caption' => $image->image,
+ 'width' => '120px',
+ 'url' => \yii\helpers\Url::to(['/product/manage/delimg', 'id' => $image->product_image_id]),
+ 'key' => $image->product_image_id,
+ 'extra' => [
+ 'id' => $image->product_image_id,
+ ],
+ ];
+ }
+ }
+ return $op;
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getImages()
+ {
+ return $this->hasMany(ProductImage::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+ public function getOptions() {
+ return $this->hasMany(TaxOption::className(), ['tax_option_id' => 'option_id'])->viaTable('product_variant_option', ['product_variant_id' => 'product_variant_id']);
+ }
+
+ public function getProperties() {
+ $groups = $options = [];
+ foreach ($this->options as $option) {
+ $options[$option->tax_group_id][] = $option;
+ }
+ foreach (TaxGroup::find()->where(['tax_group_id' => array_keys($options)])->all() as $group) {
+ if (!empty($options[$group->tax_group_id])) {
+ $group->_options = $options[$group->tax_group_id];
+ $groups[] = $group;
+ }
+ }
+ return $groups;
+ }
+
+ /**
+ * @inheritdoc
+ * @return ProductVariantQuery the active query used by this AR class.
+ */
+ public static function find()
+ {
+ return new ProductVariantQuery(get_called_class());
+ }
+
+ public function getId(){
+ return $this->product_variant_id;
+ }
+
+ public function setStocks($stocks) {
+ $this->stocks = (array) $stocks;
+ }
+
+ public function getCategory() {
+ return $this->hasOne(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
+ }
+
+ public function getCategories() {
+ return $this->hasMany(Category::className(), ['category_id' => 'category_id'])->viaTable('product_category', ['product_id' => 'product_id']);
+ }
+
+ public function getTaxGroupsByLevel($level)
+ {
+ $categories = ArrayHelper::getColumn($this->categories, 'category_id');
+ return TaxGroup::find()->distinct()->innerJoin('relation', 'entity1_id = tax_group_id')->where(['relation.entity2_id' => $categories])->where(['level' => $level]);
+ }
+
+// public function afterSave($insert, $changedAttributes)
+// {
+// if (!is_null($this->stocks)) {
+// //ProductStock::deleteAll(['product_variant_id' => $this->product_variant_id]);
+// $values = [];
+// foreach ($this->stocks as $id => $quantity) {
+// $productStock = ProductStock::find()->where(['product_variant_id' => $this->product_variant_id, 'stock_id' => $id])->one();
+// $productStock->quantity = $quantity;
+// $productStock->save();
+// }
+// }
+// parent::afterSave($insert, $changedAttributes);
+// }
+
+ public function beforeDelete() {
+ ProductVariantOption::deleteAll(['product_variant_id' => $this->product_variant_id]);
+ ProductImage::deleteAll(['product_variant_id' => $this->product_variant_id]);
+ ProductStock::deleteAll(['product_variant_id' => $this->product_variant_id]);
+ return true;
+ }
+
+ public function imagesUpload()
+ {
+ if ($this->validate()) {
+ $images = [];
+ foreach ($this->imagesUpload as $image) {
+ $imageName = $image->baseName .'.'. $image->extension;
+ $i = 0;
+ while(file_exists(Yii::getAlias('@imagesDir/products/' . $imageName))) {
+ $i++;
+ $imageName = $image->baseName .'_'. $i .'.'. $image->extension;
+ }
+
+ $image->saveAs(Yii::getAlias('@imagesDir/products/' .$imageName));
+ $images[] = $imageName;
+ }
+ return $images;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/common/modules/product/models/ProductVariantListSearch.php b/common/modules/product/models/ProductVariantListSearch.php
new file mode 100755
index 0000000..4593951
--- /dev/null
+++ b/common/modules/product/models/ProductVariantListSearch.php
@@ -0,0 +1,82 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }
+
+ if($product_id){
+ $query->andFilterWhere([
+ 'product_id' => $product_id,
+ ]);
+ }
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'product_variant_id' => $this->product_variant_id,
+ 'price' => $this->price,
+ 'price_old' => $this->price_old,
+ 'stock' => $this->stock,
+ 'product_unit_id' => $this->product_unit_id,
+ 'product_variant_type_id' => $this->product_variant_type_id,
+ ]);
+
+ $query->andFilterWhere(['like', 'name', $this->name])
+ ->andFilterWhere(['like', 'sku', $this->sku])
+ ->andFilterWhere(['like', 'remote_id', $this->remote_id]);
+
+ return $dataProvider;
+ }
+}
diff --git a/common/modules/product/models/ProductVariantOption.php b/common/modules/product/models/ProductVariantOption.php
new file mode 100755
index 0000000..c1d30ae
--- /dev/null
+++ b/common/modules/product/models/ProductVariantOption.php
@@ -0,0 +1,65 @@
+ true, 'targetClass' => ProductVariant::className(), 'targetAttribute' => ['product_variant_id' => 'product_variant_id']],
+ [['option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_variant_id' => 'Product Variant ID',
+ 'option_id' => 'Option ID',
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getProductVariant()
+ {
+ return $this->hasOne(ProductVariant::className(), ['product_variant_id' => 'product_variant_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'option_id']);
+ }
+}
diff --git a/common/modules/product/models/ProductVariantQuery.php b/common/modules/product/models/ProductVariantQuery.php
new file mode 100755
index 0000000..011164c
--- /dev/null
+++ b/common/modules/product/models/ProductVariantQuery.php
@@ -0,0 +1,34 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return ProductVariant[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return ProductVariant|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/product/models/ProductVariantSearch.php b/common/modules/product/models/ProductVariantSearch.php
new file mode 100755
index 0000000..4c68e73
--- /dev/null
+++ b/common/modules/product/models/ProductVariantSearch.php
@@ -0,0 +1,147 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ if (!empty($params['product_id'])) {
+ $this->product_id = $params['product_id'];
+ }
+
+ if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }
+
+ $dataProvider->setSort([
+ 'attributes' => [
+ 'name' => [
+ 'asc' => ['product_variant.name' => SORT_ASC],
+ 'desc' => ['product_variant.value' => SORT_DESC],
+ 'default' => SORT_DESC,
+ 'label' => 'Variant name',
+ ],
+ 'brand_name' => [
+ 'asc' => ['brand_name.value' => SORT_ASC],
+ 'desc' => ['brand_name.value' => SORT_DESC],
+ 'default' => SORT_DESC,
+ 'label' => 'Brand name',
+ ],
+ 'category_name',
+ 'sku',
+ ]
+ ]);
+
+ $query->joinWith(['product', 'product.brand.brandNames', 'product.categories', 'product.categories.categoryNames']);
+
+ if (isset($this->is_top)) {
+ $query->andFilterWhere([
+ 'product.is_top' => (bool)$this->is_top,
+ ]);
+ }
+ if (isset($this->is_new)) {
+ $query->andFilterWhere([
+ 'product.is_new' => (bool)$this->is_new,
+ ]);
+ }
+ if (isset($this->akciya)) {
+ $query->andFilterWhere([
+ 'product.akciya' => (bool)$this->akciya,
+ ]);
+ }
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'product_variant.product_id' => $this->product_id,
+ 'product_variant_id' => $this->product_variant_id,
+ ]);
+
+ if (!empty($this->fullname)) {
+ $query->orFilterWhere(['like', 'product_variant.name', $this->fullname]);
+ $query->orFilterWhere(['ilike', 'product.name', $this->fullname]);
+ }
+ $query->andFilterWhere(['ilike', 'product.brand_name.value', $this->brand_name]);
+ $query->andFilterWhere(['ilike', 'product.category_name.value', $this->category_name]);
+ $query->andFilterWhere(['ilike', 'sku', $this->sku]);
+
+ $query->groupBy(['product_variant_id']);
+ $query->orderBy('product_variant.product_id', 'ASC');
+
+ return $dataProvider;
+ }
+
+ public static function findBySku($sku) {
+ /** @var ProductQuery $query */
+ $query = ProductVariant::find()
+ ->andFilterWhere(['sku' => $sku]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ }
+ return;
+ }
+
+ public static function findByRemoteID($id) {
+ /** @var CategoryQuery $query */
+ $query = ProductVariant::find()
+ ->andFilterWhere(['remote_id' => $id]);
+ if (($model = $query->one()) !== null) {
+ return $model;
+ }
+ return;
+ }
+}
diff --git a/common/modules/product/models/ProductVariantType.php b/common/modules/product/models/ProductVariantType.php
new file mode 100755
index 0000000..d8e813a
--- /dev/null
+++ b/common/modules/product/models/ProductVariantType.php
@@ -0,0 +1,49 @@
+ 50],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'product_variant_type_id' => 'Product Variant Type ID',
+ 'name' => 'Name',
+ ];
+ }
+
+ public function getId() {
+ return $this->product_variant_type_id;
+ }
+}
diff --git a/common/modules/product/models/ProductVariantTypeSearch.php b/common/modules/product/models/ProductVariantTypeSearch.php
new file mode 100755
index 0000000..c4804b4
--- /dev/null
+++ b/common/modules/product/models/ProductVariantTypeSearch.php
@@ -0,0 +1,70 @@
+ $query,
+ ]);
+
+ $this->load($params);
+
+ if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'product_variant_type_id' => $this->product_variant_type_id,
+ ]);
+
+ $query->andFilterWhere(['like', 'name', $this->name])
+ ->andFilterWhere(['like', 'name2', $this->name2]);
+
+ return $dataProvider;
+ }
+}
diff --git a/common/modules/product/models/Stock.php b/common/modules/product/models/Stock.php
new file mode 100755
index 0000000..db3e191
--- /dev/null
+++ b/common/modules/product/models/Stock.php
@@ -0,0 +1,55 @@
+ 150],
+ [['name'], 'required'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'stock_id' => Yii::t('product', 'Stock ID'),
+ 'name' => Yii::t('product', 'Name'),
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ * @return StockQuery the active query used by this AR class.
+ */
+ public static function find()
+ {
+ return new StockQuery(get_called_class());
+ }
+}
diff --git a/common/modules/product/models/StockQuery.php b/common/modules/product/models/StockQuery.php
new file mode 100755
index 0000000..2650415
--- /dev/null
+++ b/common/modules/product/models/StockQuery.php
@@ -0,0 +1,34 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Stock[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Stock|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/product/views/default/index.php b/common/modules/product/views/default/index.php
new file mode 100755
index 0000000..3913fe0
--- /dev/null
+++ b/common/modules/product/views/default/index.php
@@ -0,0 +1,12 @@
+
+
= $this->context->action->uniqueId ?>
+
+ This is the view content for action "= $this->context->action->id ?>".
+ The action belongs to the controller "= get_class($this->context) ?>"
+ in the "= $this->context->module->id ?>" module.
+
+
+ You may customize this page by editing the following file:
+ = __FILE__ ?>
+
+
diff --git a/common/modules/product/views/manage/_form.php b/common/modules/product/views/manage/_form.php
new file mode 100755
index 0000000..0199db9
--- /dev/null
+++ b/common/modules/product/views/manage/_form.php
@@ -0,0 +1,142 @@
+
+
+
+
+ ['enctype' => 'multipart/form-data']
+ ]); ?>
+
+ = $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
+
+ = $form->field($model, 'is_top')->checkbox(['label' => 'ТОП']) ?>
+ = $form->field($model, 'is_new')->checkbox(['label' => 'Новинка']) ?>
+ = $form->field($model, 'akciya')->checkbox(['label' => 'Акционный']) ?>
+
+ = $form->field($model, 'description')->widget(\mihaildev\ckeditor\CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?>
+ = $form->field($model, 'video')->textarea(); ?>
+
+ = $form->field($model, 'brand_id')->dropDownList(
+ ArrayHelper::map(ProductHelper::getBrands()->all(), 'brand_id', 'name'),
+ [
+ 'prompt' => Yii::t('product', 'Select brand')
+ ]
+ ) ?>
+
+ = $form->field($model, 'categories')->widget(Select2::className(), [
+ 'data' => ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'category_id', 'name'),
+ 'language' => 'ru',
+ 'options' => [
+ 'placeholder' => Yii::t('product', 'Select categories'),
+ 'multiple' => true,
+ ],
+ 'pluginOptions' => [
+ 'allowClear' => true
+ ],
+ ]
+ ) ?>
+
+ = $form->field($model, 'imagesUpload[]')->widget(\kartik\file\FileInput::classname(), [
+ 'language' => 'ru',
+ 'options' => [
+ 'accept' => 'image/*',
+ 'multiple' => true,
+ ],
+ 'pluginOptions' => [
+ 'allowedFileExtensions' => ['jpg', 'gif', 'png'],
+ 'initialPreview' => !empty($model->imagesHTML) ? $model->imagesHTML : [],
+ 'initialPreviewConfig' => $model->imagesConfig,
+ 'overwriteInitial' => false,
+ 'showRemove' => false,
+ 'showUpload' => false,
+// 'uploadUrl' => empty($model->product_id) ? null : \yii\helpers\Url::to(['/product/manage/uploadImage']),
+ 'uploadAsync' => !empty($model->product_id),
+ 'previewFileType' => 'image',
+ ],
+ ]); ?>
+
+ field($model, 'variants')->widget(MultipleInput::className(), [
+ 'columns' => [
+ [
+ 'name' => 'product_variant_id',
+ 'type' => MultipleInputColumn::TYPE_HIDDEN_INPUT,
+ ],
+ [
+ 'name' => 'name',
+ 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
+ 'title' => Yii::t('product', 'Name'),
+ ],
+ [
+ 'name' => 'sku',
+ 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
+ 'title' => Yii::t('product', 'SKU'),
+ ],
+ [
+ 'name' => 'price',
+ 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
+ 'title' => Yii::t('product', 'Price'),
+ ],
+ [
+ 'name' => 'price_old',
+ 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
+ 'title' => Yii::t('product', 'Old Price'),
+ ],
+ [
+ 'name' => 'product_unit_id',
+ 'type' => MultipleInputColumn::TYPE_DROPDOWN,
+ 'title' => Yii::t('product', 'Unit'),
+ 'items' => ArrayHelper::map(\common\modules\product\models\ProductUnit::find()->all(), 'product_unit_id', 'name'),
+ ],
+ [
+ 'name' => 'stock',
+ 'type' => MultipleInputColumn::TYPE_TEXT_INPUT,
+ 'title' => Yii::t('product', 'Stock'),
+ 'options' => [
+ 'placeholder' => '∞'
+ ],
+ ],
+ [
+ 'name' => 'image',
+ 'type' => 'fileInput',
+ 'title' => Yii::t('product', 'Image'),
+ 'options' => [
+ 'multiple' => false
+ ],
+ ],
+ ],
+ ]);
+ */ ?>
+
+
+ all() as $group) :?>
+ = $form->field($model, 'options')->checkboxList(
+ ArrayHelper::map($group->options, 'tax_option_id', 'ValueRenderFlash'),
+ [
+ 'multiple' => true,
+ 'unselect' => null,
+ ]
+ )->label($group->name);?>
+
+
+
+
+ = Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/manage/_search.php b/common/modules/product/views/manage/_search.php
new file mode 100755
index 0000000..f021b65
--- /dev/null
+++ b/common/modules/product/views/manage/_search.php
@@ -0,0 +1,31 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'name') ?>
+
+ = $form->field($model, 'brand_id') ?>
+
+ = $form->field($model, 'product_id') ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/manage/create.php b/common/modules/product/views/manage/create.php
new file mode 100755
index 0000000..36f73c2
--- /dev/null
+++ b/common/modules/product/views/manage/create.php
@@ -0,0 +1,21 @@
+title = Yii::t('product', 'Create Product');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/manage/import-process.php b/common/modules/product/views/manage/import-process.php
new file mode 100755
index 0000000..af24fce
--- /dev/null
+++ b/common/modules/product/views/manage/import-process.php
@@ -0,0 +1,70 @@
+registerJs("
+
+");
+?>
+
+
+
+
diff --git a/common/modules/product/views/manage/import.php b/common/modules/product/views/manage/import.php
new file mode 100755
index 0000000..81f9a31
--- /dev/null
+++ b/common/modules/product/views/manage/import.php
@@ -0,0 +1,51 @@
+
+
+
diff --git a/common/modules/product/views/manage/index.php b/common/modules/product/views/manage/index.php
new file mode 100755
index 0000000..3c79fc9
--- /dev/null
+++ b/common/modules/product/views/manage/index.php
@@ -0,0 +1,141 @@
+title = Yii::t('product', 'Products');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Product'), ['create'], ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'name',
+ [
+ 'label' => Yii::t('product', 'Brand'),
+ 'attribute' => 'brand_name',
+ 'value' => 'brand.name',
+ 'format' => 'raw',
+ 'filter' => Select2::widget([
+ 'model' => $searchModel,
+ 'attribute' => 'brand_id',
+ 'data' => ArrayHelper::map(ProductHelper::getBrands()->all(), 'brand_id', 'name'),
+ 'language' => 'ru',
+ 'options' => [
+ 'placeholder' => Yii::t('product', 'Select brand'),
+ 'multiple' => false,
+ ],
+ 'pluginOptions' => [
+ 'allowClear' => true
+ ],
+ ])
+ ],
+ [
+ 'label' => Yii::t('product', 'Category'),
+ 'attribute' => 'category_name',
+ 'value' => function($model) {
+ $categories = [];
+ foreach ($model->categories as $category) {
+ $categories[] = $category->name;
+ }
+ return implode(", ", $categories);
+ },
+ 'format' => 'raw',
+ 'filter' => Select2::widget([
+ 'model' => $searchModel,
+ 'attribute' => 'category_id',
+ 'data' => ArtboxTreeHelper::treeMap(ProductHelper::getCategories(), 'category_id', 'name'),
+ 'language' => 'ru',
+ 'options' => [
+ 'placeholder' => Yii::t('product', 'Select category'),
+ 'multiple' => false,
+ ],
+ 'pluginOptions' => [
+ 'allowClear' => true
+ ],
+ ])
+ ],
+ [
+ 'label' => Yii::t('product', 'SKU'),
+ 'attribute' => 'variant_sku',
+ 'value' => 'variant.sku',
+ ],
+ 'variant.price',
+ 'variant.price_old',
+ [
+ 'label' => Yii::t('product', 'Stock'),
+ 'attribute' => 'variant_stock',
+ 'value' => 'variant.stock_caption',
+ ],
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{items} {view} |{is_top} {is_new} {akciya} | {update} {delete}',
+ 'buttons' => [
+ 'is_top' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('product', ($model->is_top ? 'Set not is top' : 'Set is top')),
+ ]);
+ },
+ 'is_new' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('product', ($model->is_new ? 'Set not is new' : 'Set is new')),
+ ]);
+ },
+ 'akciya' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('product', ($model->akciya ? 'Set not is promotion' : 'Set is promotion')),
+ ]);
+ },
+ 'items' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('product', 'Variants'),
+ ]);
+ },
+
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) {
+ switch ($action) {
+ case 'items':
+ return \yii\helpers\Url::to(['/product/variant', 'product_id' => $model->product_id]);
+ break;
+ case 'is_top':
+ return \yii\helpers\Url::to(['manage/is_top', 'id' => $model->product_id]);
+ break;
+ case 'is_new':
+ return \yii\helpers\Url::to(['manage/is_new', 'id' => $model->product_id]);
+ break;
+ case 'akciya':
+ return \yii\helpers\Url::to(['manage/akciya', 'id' => $model->product_id]);
+ break;
+ case 'view':
+ return \yii\helpers\Url::to(['/catalog/product', 'id' => $model->product_id, ['target' => '_blank']]);
+ break;
+ case 'update':
+ return \yii\helpers\Url::to(['manage/update', 'id' => $model->product_id]);
+ break;
+ case 'delete':
+ return \yii\helpers\Url::to(['manage/delete', 'id' => $model->product_id]);
+ break;
+ }
+ }
+ ],
+ ],
+ ]); ?>
+
diff --git a/common/modules/product/views/manage/update.php b/common/modules/product/views/manage/update.php
new file mode 100755
index 0000000..b4b80a5
--- /dev/null
+++ b/common/modules/product/views/manage/update.php
@@ -0,0 +1,24 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Product',
+]) . ' ' . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->product_id]];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'groups' => $groups,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/manage/view.php b/common/modules/product/views/manage/view.php
new file mode 100755
index 0000000..96a750f
--- /dev/null
+++ b/common/modules/product/views/manage/view.php
@@ -0,0 +1,40 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->product_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->product_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'product_id',
+ 'name',
+ 'fullname',
+ 'brand.name',
+ 'category.name',
+ 'image.imageUrl:image'
+ ],
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-unit/_form.php b/common/modules/product/views/product-unit/_form.php
new file mode 100755
index 0000000..f1a1206
--- /dev/null
+++ b/common/modules/product/views/product-unit/_form.php
@@ -0,0 +1,27 @@
+
+
+
diff --git a/common/modules/product/views/product-unit/_search.php b/common/modules/product/views/product-unit/_search.php
new file mode 100755
index 0000000..5fbe4cc
--- /dev/null
+++ b/common/modules/product/views/product-unit/_search.php
@@ -0,0 +1,33 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'product_unit_id') ?>
+
+ = $form->field($model, 'name') ?>
+
+ = $form->field($model, 'code') ?>
+
+ = $form->field($model, 'is_default')->checkbox() ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/product-unit/create.php b/common/modules/product/views/product-unit/create.php
new file mode 100755
index 0000000..5c54fcc
--- /dev/null
+++ b/common/modules/product/views/product-unit/create.php
@@ -0,0 +1,21 @@
+title = Yii::t('product', 'Create Product Unit');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Units'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-unit/index.php b/common/modules/product/views/product-unit/index.php
new file mode 100755
index 0000000..de9aad8
--- /dev/null
+++ b/common/modules/product/views/product-unit/index.php
@@ -0,0 +1,34 @@
+title = Yii::t('product', 'Product Units');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Product Unit'), ['create'], ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+
+ 'name',
+ 'code:html',
+ 'is_default:boolean',
+
+ ['class' => 'yii\grid\ActionColumn'],
+ ],
+ ]); ?>
+
diff --git a/common/modules/product/views/product-unit/update.php b/common/modules/product/views/product-unit/update.php
new file mode 100755
index 0000000..fcd5ef7
--- /dev/null
+++ b/common/modules/product/views/product-unit/update.php
@@ -0,0 +1,23 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Product Unit',
+]) . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Units'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->product_unit_id]];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-unit/view.php b/common/modules/product/views/product-unit/view.php
new file mode 100755
index 0000000..a5fbf82
--- /dev/null
+++ b/common/modules/product/views/product-unit/view.php
@@ -0,0 +1,38 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Units'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->product_unit_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->product_unit_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'product_unit_id',
+ 'name',
+ 'code',
+ 'is_default:boolean',
+ ],
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-variant-type/_form.php b/common/modules/product/views/product-variant-type/_form.php
new file mode 100755
index 0000000..f0a7cfc
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/_form.php
@@ -0,0 +1,25 @@
+
+
+
diff --git a/common/modules/product/views/product-variant-type/_search.php b/common/modules/product/views/product-variant-type/_search.php
new file mode 100755
index 0000000..7b3cdec
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/_search.php
@@ -0,0 +1,31 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'product_variant_type_id') ?>
+
+ = $form->field($model, 'name') ?>
+
+ = $form->field($model, 'name2') ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/product-variant-type/create.php b/common/modules/product/views/product-variant-type/create.php
new file mode 100755
index 0000000..e7d68c8
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/create.php
@@ -0,0 +1,21 @@
+title = Yii::t('product', 'Create Product Variant Type');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Variant Types'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-variant-type/index.php b/common/modules/product/views/product-variant-type/index.php
new file mode 100755
index 0000000..4e44be0
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/index.php
@@ -0,0 +1,32 @@
+title = Yii::t('product', 'Product Variant Types');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Product Variant Type'), ['create'], ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'name',
+ 'name2',
+
+ ['class' => 'yii\grid\ActionColumn'],
+ ],
+ ]); ?>
+
diff --git a/common/modules/product/views/product-variant-type/update.php b/common/modules/product/views/product-variant-type/update.php
new file mode 100755
index 0000000..d4eb6de
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/update.php
@@ -0,0 +1,23 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Product Variant Type',
+]) . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Variant Types'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->product_variant_type_id]];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/product-variant-type/view.php b/common/modules/product/views/product-variant-type/view.php
new file mode 100755
index 0000000..1a54e27
--- /dev/null
+++ b/common/modules/product/views/product-variant-type/view.php
@@ -0,0 +1,37 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Product Variant Types'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->product_variant_type_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->product_variant_type_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'product_variant_type_id',
+ 'name',
+ 'name2',
+ ],
+ ]) ?>
+
+
diff --git a/common/modules/product/views/variant/_form.php b/common/modules/product/views/variant/_form.php
new file mode 100755
index 0000000..37a8ba1
--- /dev/null
+++ b/common/modules/product/views/variant/_form.php
@@ -0,0 +1,149 @@
+registerJs($js, View::POS_END);
+?>
+
+
+ 'dynamic-form',
+ 'options' => ['enctype' => 'multipart/form-data']
+ ]); ?>
+
+ = $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
+
+ = $form->field($model, 'product_id')->hiddenInput()->label(false); ?>
+
+ = $form->field($model, 'sku')->textarea(); ?>
+ = $form->field($model, 'price')->textarea(); ?>
+ = $form->field($model, 'price_old')->textarea(); ?>
+ = $form->field($model, 'image')->widget(\kartik\file\FileInput::classname(), [
+ 'model' => $model,
+ 'attribute' => 'image',
+ 'options' => [
+ 'accept' => 'image/*',
+ 'multiple' => true
+ ],
+ 'pluginOptions' => [
+ 'allowedFileExtensions' => ['jpg','gif','png'],
+ 'initialPreview' => $model->imageUrl ? \common\components\artboximage\ArtboxImageHelper::getImage($model->imageUrl, 'products') : '',
+ 'overwriteInitial' => true,
+ 'showRemove' => true,
+ 'showUpload' => false,
+ ],
+ ]); ?>
+
+ 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
+ 'widgetBody' => '.container-items', // required: css class selector
+ 'widgetItem' => '.item', // required: css class
+ 'limit' => 10, // the maximum times, an element can be added (default 999)
+ 'min' => 0, // 0 or 1 (default 1)
+ 'insertButton' => '.add-item', // css class
+ 'deleteButton' => '.remove-item', // css class
+ 'model' => $stocks[0],
+ 'formId' => 'dynamic-form',
+ 'formFields' => [
+ 'quantity',
+ 'name',
+ ],
+ ]); ?>
+
+
+
+
+ Склады
+
+
+
+
+
+ $stock): ?>
+
+
+ isNewRecord) {
+ echo Html::activeHiddenInput($stock, "[{$i}]stock_id");
+ }
+ ?>
+
+
+ = $form->field($stock, "[{$i}]quantity")->textInput(['maxlength' => true]) ?>
+
+
+ = $form->field($stock, "[{$i}]name")->textInput(['maxlength' => true]) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = $form->field($model, 'product_unit_id')->dropDownList(
+ ArrayHelper::map(\common\modules\product\models\ProductUnit::find()->all(), 'product_unit_id', 'name'),
+ [
+ 'prompt' => Yii::t('product', 'Unit'),
+ ])->label(Yii::t('product', 'Unit')) ?>
+
+
+ all() as $group) :?>
+ = $form->field($model, 'options')->checkboxList(
+ ArrayHelper::map($group->options, 'tax_option_id', 'ValueRenderFlash'),
+ [
+ 'multiple' => true,
+ 'unselect' => null,
+ ]
+ )->label($group->name);?>
+
+
+
+
+ = Html::submitButton($model->isNewRecord ? Yii::t('product', 'Create') : Yii::t('product', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/variant/_search.php b/common/modules/product/views/variant/_search.php
new file mode 100755
index 0000000..00015dc
--- /dev/null
+++ b/common/modules/product/views/variant/_search.php
@@ -0,0 +1,31 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'name') ?>
+
+ = $form->field($model, 'brand_id') ?>
+
+ = $form->field($model, 'product_id') ?>
+
+
+ = Html::submitButton(Yii::t('product', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('product', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/common/modules/product/views/variant/create.php b/common/modules/product/views/variant/create.php
new file mode 100755
index 0000000..1c3d2de
--- /dev/null
+++ b/common/modules/product/views/variant/create.php
@@ -0,0 +1,23 @@
+title = Yii::t('product', 'Create Product');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'groups' => $groups,
+ 'stocks' => $stocks,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/variant/index.php b/common/modules/product/views/variant/index.php
new file mode 100755
index 0000000..4355909
--- /dev/null
+++ b/common/modules/product/views/variant/index.php
@@ -0,0 +1,96 @@
+title = Yii::t('product', 'Variants');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['/product/manage']];
+if (!empty($product)) {
+ $this->params['breadcrumbs'] = [
+ ['label' => Yii::t('product', 'Variants'), 'url' => ['/product/variant']],
+ $product->fullname
+ ];
+} else {
+ $this->params['breadcrumbs'][] = $this->title;
+}
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('product', 'Create Variant'), Url::toRoute(['create','product_id'=> $product_id]), ['class' => 'btn btn-success']) ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+
+ [
+ 'attribute' => 'product_id',
+ 'value' => 'fullname',
+ 'label' => Yii::t('product', 'Name'),
+ 'filter' => \kartik\select2\Select2::widget([
+ 'model' => $searchModel,
+ 'attribute' => 'product_id',
+ 'data' => \yii\helpers\ArrayHelper::map(\common\modules\product\models\Product::find()->orderBy(['name' => 'ASC'])->all(), 'product_id', 'name'),
+ 'language' => 'ru',
+ 'options' => [
+ 'placeholder' => Yii::t('product', 'Select product'),
+ 'multiple' => false,
+ ],
+ 'pluginOptions' => [
+ 'allowClear' => true
+ ],
+ ]),
+ ],
+ 'sku',
+ 'price',
+ 'price_old',
+ 'stock',
+
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'buttons' => [
+ 'view' => function ($url, $model)
+ {
+ return Html::a (
+ '
',
+ Url::to(['view','product_id'=> $model->product_id, 'id' => $model->product_variant_id]),
+ [
+ 'title' => "Просмотр",
+ ]
+ );
+ },
+ 'update' => function ($url, $model)
+ {
+ return Html::a (
+ '
',
+ Url::to(['update','product_id'=> $model->product_id, 'id' => $model->product_variant_id]),
+ [
+ 'title' => "Редактировать",
+ ]
+ );
+ },
+ 'delete' => function ($url, $model)
+ {
+
+ return Html::a('
', Url::to(['delete','product_id'=> $model->product_id, 'id' => $model->product_variant_id]), [
+ 'title' => Yii::t('yii', 'Delete'),
+ 'data-confirm' => Yii::t('yii', 'Are you sure to delete this item?'),
+ 'data-method' => 'post',
+ ]);
+
+ },
+ ],
+ ],
+ ],
+ ]); ?>
+
diff --git a/common/modules/product/views/variant/update.php b/common/modules/product/views/variant/update.php
new file mode 100755
index 0000000..a146f7d
--- /dev/null
+++ b/common/modules/product/views/variant/update.php
@@ -0,0 +1,27 @@
+title = Yii::t('product', 'Update {modelClass}: ', [
+ 'modelClass' => 'Product',
+]) . ' ' . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->product->name, 'url' => ['view', 'id' => $model->product->product_id]];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Variants'), 'url' => Url::to(['/product/variant', 'product_id' => $model->product->product_id])];
+$this->params['breadcrumbs'][] = Yii::t('product', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'groups' => $groups,
+ 'stocks' => $stocks,
+ ]) ?>
+
+
diff --git a/common/modules/product/views/variant/view.php b/common/modules/product/views/variant/view.php
new file mode 100755
index 0000000..5eaecd8
--- /dev/null
+++ b/common/modules/product/views/variant/view.php
@@ -0,0 +1,42 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Products'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->product->name, 'url' => ['view', 'id' => $model->product->product_id]];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('product', 'Variants'), 'url' => ['/product/variant?product_id='. $model->product->product_id]];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('product', 'Update'), ['update', 'id' => $model->product_variant_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('product', 'Delete'), ['delete', 'id' => $model->product_variant_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('product', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'product_id',
+ 'name',
+ 'fullname',
+ 'brand.name',
+ 'category.name',
+ 'image.imageUrl:image'
+ ],
+ ]) ?>
+
+
diff --git a/common/modules/product/widgets/brandsCarouselWidget.php b/common/modules/product/widgets/brandsCarouselWidget.php
new file mode 100755
index 0000000..d907530
--- /dev/null
+++ b/common/modules/product/widgets/brandsCarouselWidget.php
@@ -0,0 +1,21 @@
+with('brandName')->all();
+ return $this->render('brandsCarousel', [
+ 'brands' => $brands,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/widgets/catalogSubmenuWidget.php b/common/modules/product/widgets/catalogSubmenuWidget.php
new file mode 100755
index 0000000..ef9388f
--- /dev/null
+++ b/common/modules/product/widgets/catalogSubmenuWidget.php
@@ -0,0 +1,36 @@
+root_id);
+
+ $categories = $rootCategory->getAllChildren(2, [], 'categoryName')->all();
+ $populary = [];
+ foreach($categories as $category) {
+ if ($category->populary) {
+ $populary[] = $category;
+ }
+ }
+
+ return $this->render('submenu', [
+ 'rootCategory' => $rootCategory,
+ 'rootClass' => $this->rootClass,
+ 'populary' => $populary,
+ 'items' => $rootCategory->buildTree($categories, $rootCategory->category_id)
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/widgets/lastProducts.php b/common/modules/product/widgets/lastProducts.php
new file mode 100755
index 0000000..ab00838
--- /dev/null
+++ b/common/modules/product/widgets/lastProducts.php
@@ -0,0 +1,22 @@
+render('products_block', [
+ 'title' => \Yii::t('product', 'Вы недавно просматривали'),
+ 'class' => 'last-products',
+ 'products' => ProductHelper::getLastProducts(true),
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/widgets/similarProducts.php b/common/modules/product/widgets/similarProducts.php
new file mode 100755
index 0000000..aebd754
--- /dev/null
+++ b/common/modules/product/widgets/similarProducts.php
@@ -0,0 +1,35 @@
+product, $this->count);
+
+ if (!$this->title) {
+ $this->title = Yii::t('product', 'Similar products');
+ }
+
+ return $this->render('products_block', [
+ 'title' => $this->title,
+ 'class' => 'similar-products',
+ 'products' => $products,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/widgets/specialProducts.php b/common/modules/product/widgets/specialProducts.php
new file mode 100755
index 0000000..dd2e00b
--- /dev/null
+++ b/common/modules/product/widgets/specialProducts.php
@@ -0,0 +1,47 @@
+type, $this->count, $this->sort);
+
+ if (!$this->title) {
+ switch($this->type) {
+ case 'top':
+ $this->title = Yii::t('product', 'Top products');
+ break;
+ case 'promo':
+ $this->title = Yii::t('product', 'Promo products');
+ break;
+ case 'new':
+ $this->title = Yii::t('product', 'New products');
+ break;
+ }
+ }
+
+ return $this->render('products_block', [
+ 'title' => $this->title,
+ 'class' => $this->type,
+ 'products' => $products,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/product/widgets/views/brandsCarousel.php b/common/modules/product/widgets/views/brandsCarousel.php
new file mode 100755
index 0000000..0d76762
--- /dev/null
+++ b/common/modules/product/widgets/views/brandsCarousel.php
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/common/modules/product/widgets/views/product_smart.php b/common/modules/product/widgets/views/product_smart.php
new file mode 100755
index 0000000..b47be81
--- /dev/null
+++ b/common/modules/product/widgets/views/product_smart.php
@@ -0,0 +1,64 @@
+
+
+
+
+ is_top) || !empty($product->is_new) || !empty($product->akciya)) :?>
+
+ is_top)) :?>
+ top
+
+ is_new)) :?>
+ new
+
+ akciya)) :?>
+ promo
+
+
+
+
= $product->name ?>
+
+
+
+
+ enabledVariants[0]->price_old != 0 && $product->enabledVariants[0]->price_old != $product->enabledVariants[0]->price) :?>
+ = $product->enabledVariants[0]->price_old ?> грн.
+
+ = $product->enabledVariants[0]->price?> грн.
+
+
+
+
Купить
+
+
+
\ No newline at end of file
diff --git a/common/modules/product/widgets/views/products_block.php b/common/modules/product/widgets/views/products_block.php
new file mode 100755
index 0000000..feae4a3
--- /dev/null
+++ b/common/modules/product/widgets/views/products_block.php
@@ -0,0 +1,31 @@
+
+
+
+
+
= $title?>
+
+
+ = $this->render('product_smart', ['product' => $product]);?>
+
+
+
+
+
+ registerJs($js, View::POS_READY);
+ ?>
+
\ No newline at end of file
diff --git a/common/modules/product/widgets/views/submenu.php b/common/modules/product/widgets/views/submenu.php
new file mode 100755
index 0000000..1a5a82f
--- /dev/null
+++ b/common/modules/product/widgets/views/submenu.php
@@ -0,0 +1,50 @@
+
diff --git a/common/modules/relation/Module.php b/common/modules/relation/Module.php
new file mode 100755
index 0000000..f7cac20
--- /dev/null
+++ b/common/modules/relation/Module.php
@@ -0,0 +1,40 @@
+render('index');
+ }
+}
diff --git a/common/modules/relation/controllers/ManageController.php b/common/modules/relation/controllers/ManageController.php
new file mode 100755
index 0000000..49242a1
--- /dev/null
+++ b/common/modules/relation/controllers/ManageController.php
@@ -0,0 +1,238 @@
+ [
+ 'class' => ContentNegotiator::className(),
+ 'only' => ['autocomplete'],
+ 'formats' => [ 'application/json' => Response::FORMAT_JSON],
+ 'languages' => [
+ 'ru',
+ ],
+ ],*/
+ ];
+ }
+
+ /**
+ * Renders the relations view
+ * @return string
+ */
+ public function actionIndex()
+ {
+ $relations = relationHelper::getRelations();
+ $list = [];
+ foreach ($relations as $key => $relation) {
+ $list[] = [
+ 'key' => $key,
+ 'name' => $relation['name'],
+ 'entity1_label' => $relation['entity1']['label'],
+ 'entity1_model' => $relation['entity1']['model'],
+ 'entity2_label' => $relation['entity2']['label'],
+ 'entity2_model' => $relation['entity2']['model'],
+ ];
+ }
+ return $this->render('relations', [
+ 'relations' => $list
+ ]);
+ }
+ /**
+ * Renders the pars view for
+ * @return string
+ */
+ public function actionPars($relation)
+ {
+ $relation_key = strtolower($relation);
+ $relation = relationHelper::getRelation($relation_key);
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $relation['via']['model']::find(),
+ ]);
+
+ return $this->render('pars', [
+ 'dataProvider' => $dataProvider,
+ 'relation_key' => $relation_key,
+ 'relation' => $relation,
+ ]);
+ }
+
+ public function actionCreate($relation) {
+ $relation_key = strtolower($relation);
+ $relation = relationHelper::getRelation($relation_key);
+
+ $model = new $relation['via']['model'];
+
+ if ($model->load(Yii::$app->request->post())) {
+ $model->save();
+ return $this->redirect(['pars', 'relation' => $relation_key]);
+// return $this->redirect(['update', 'id' => $model->{$relation['entity1']['linked_key']}. ':' .$model->{$relation['entity2']['linked_key']}]);
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+// 'items1' => $query1->limit(100)->all(),
+// 'items2' => $query2->asArray()->all(),
+ 'relation_key' => $relation_key,
+ 'relation' => $relation,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing TaxGroup model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($relation, $id) {
+ $relation_key = strtolower($relation);
+ $relation = relationHelper::getRelation($relation_key);
+
+ list($id1, $id2) = explode(':', $id);
+
+ $model = $this->findModel($relation_key, $id1, $id2);
+
+ if ($model->load(Yii::$app->request->post())) {
+ $connection = Yii::$app->getDb();
+ $transaction = $connection->beginTransaction();
+ try {
+ // Delete links from viaTable
+ $connection->createCommand()
+ ->update
+ (
+ $relation['linked_table'],
+ [
+ $relation['entity1']['linked_key'] => $model->getAttribute($relation['entity1']['linked_key']),
+ $relation['entity2']['linked_key'] => $model->getAttribute($relation['entity2']['linked_key'])
+ ],
+ $this->getWhere($relation_key, $id1, $id2)
+ )
+ ->execute();
+ $transaction->commit();
+ } catch (Exception $ex) {
+ $transaction->rollback();
+ throw $ex;
+ }
+
+ return $this->redirect(['pars', 'relation' => $relation_key]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ 'value1' => $model->entity1->getAttribute($relation['entity1']['listField']),
+ 'value2' => $model->entity2->getAttribute($relation['entity2']['listField']),
+ 'relation_key' => $relation_key,
+ 'relation' => $relation,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing TaxGroup model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($relation, $id)
+ {
+ $relation_key = strtolower($relation);
+ $relation = relationHelper::getRelation($relation_key);
+
+ list($id1, $id2) = explode(':', $id);
+
+ $connection = Yii::$app->getDb();
+ $transaction = $connection->beginTransaction();
+ try {
+ // Delete links from viaTable
+ $connection->createCommand()
+ ->delete
+ (
+ $relation['linked_table'],
+ $this->getWhere($relation_key, $id1, $id2)
+ )
+ ->execute();
+ $transaction->commit();
+ } catch (Exception $ex) {
+ $transaction->rollback();
+ throw $ex;
+ }
+
+ return $this->redirect(['pars', 'relation' => $relation_key]);
+ }
+
+ public function actionAutocomplete() {
+ $relation_key = Yii::$app->request->get('relation_key');
+ $entity = Yii::$app->request->get('entity');
+ $term = Yii::$app->request->get('term');
+ $relation_key = strtolower($relation_key);
+ $relation = relationHelper::getRelation($relation_key);
+
+ /** @var ActiveQuery $query */
+ $query = $relation[$entity]['model']::find();
+
+ if (!empty($relation[$entity]['searchJoin'])) {
+ $query->innerJoinWith($relation[$entity]['searchJoin']);
+ }
+ if (!empty($relation[$entity]['where'])) {
+ $query->where($relation[$entity]['where']);
+ }
+ $query->where(['ilike', $relation[$entity]['searchField'], $term]);
+
+ print json_encode(ArrayHelper::map($query->limit(50)->all(), $relation[$entity]['key'], $relation[$entity]['listField']));
+ exit;
+ }
+
+ /**
+ * Finds the based model for relation on its primaries keys value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param string $relation
+ * @param integer $id1
+ * @param integer $id2
+ * @return ActiveRecord the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($relation, $id1, $id2)
+ {
+ $relation_key = strtolower($relation);
+ $relation = relationHelper::getRelation($relation_key);
+ if (($model = $relation['via']['model']::findOne($this->getWhere($relation_key, $id1, $id2))) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+
+ protected function getWhere($relation_key, $id1, $id2) {
+ $relation = relationHelper::getRelation($relation_key);
+ // @todo Just think - if you need to search keys in the reverse order
+ $where = [
+ $relation['entity1']['linked_key'] => $id1,
+ $relation['entity2']['linked_key'] => $id2,
+ ];
+ if (!empty($relation['alias'])) {
+ $where[$relation['alias']] = $relation_key;
+ }
+ return $where;
+ }
+
+}
diff --git a/common/modules/relation/models/Relation.php b/common/modules/relation/models/Relation.php
new file mode 100755
index 0000000..a7fe4df
--- /dev/null
+++ b/common/modules/relation/models/Relation.php
@@ -0,0 +1,78 @@
+ 50]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'alias' => Yii::t('relation', 'Alias'),
+ 'entity1_id' => Yii::t('relation', 'Entity1 ID'),
+ 'entity2_id' => Yii::t('relation', 'Entity2 ID'),
+ 'entity1' => Yii::t('relation', 'Entity1 ID'),
+ 'entity2' => Yii::t('relation', 'Entity2 ID'),
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ * @return RelationQuery the active query used by this AR class.
+ */
+ public static function find()
+ {
+ return new RelationQuery(get_called_class());
+ }
+
+ public function getRelationSection() {
+ return relationHelper::getRelation($this->alias);
+ }
+
+ public function getEntity1() {
+ return $this->getEntity('entity1');
+ }
+
+ public function getEntity2() {
+ return $this->getEntity('entity2');
+ }
+
+ protected function getEntity($entity) {
+ $relation = $this->getRelationSection();
+ if (!$relation)
+ return;
+ return $this->hasOne($relation[$entity]['model']::className(), [$relation[$entity]['key'] => $relation[$entity]['linked_key']]);
+ }
+}
diff --git a/common/modules/relation/models/RelationQuery.php b/common/modules/relation/models/RelationQuery.php
new file mode 100755
index 0000000..7948f50
--- /dev/null
+++ b/common/modules/relation/models/RelationQuery.php
@@ -0,0 +1,35 @@
+andWhere('[[status]]=1');
+ return $this;
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return Relation[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return Relation|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/relation/relationBehavior.php b/common/modules/relation/relationBehavior.php
new file mode 100755
index 0000000..138977f
--- /dev/null
+++ b/common/modules/relation/relationBehavior.php
@@ -0,0 +1,243 @@
+relations as $relation_key => &$relation) {
+ if (is_string($relation)) {
+ // Get data from module's data
+ $relation_entity = $relation;
+ $relation = $this->_getRelationParams($relation_key);
+ $relation['inner'] = $relation[$relation_entity];
+ $relation['outer'] = $relation[$relation_entity == 'entity1' ? 'entity2' : 'entity1'];
+ $relation['linked_table'] = $relation['via']['model']::tableName();
+ if (!empty($relation['via']['alias'])) {
+ $relation['linked_alias'] = $relation['via']['alias'];
+ }
+ }
+ $this->fields[$relation['field']] = $relation_key;
+
+ }
+ }
+
+ /*
+ * Events for auto-drive relations data
+ */
+ public function events()
+ {
+ return [
+ ActiveRecord::EVENT_AFTER_INSERT => 'relationsAfterSave',
+ ActiveRecord::EVENT_AFTER_UPDATE => 'relationsAfterSave',
+ ActiveRecord::EVENT_BEFORE_DELETE => 'relationBeforeDelete',
+ ];
+ }
+
+ public function relationsAfterSave($insert) {
+
+ if (is_array($modelPrimaryKey = $this->owner->getPrimaryKey())) {
+ throw new ErrorException('This behavior does not support composite primary keys');
+ }
+
+ foreach ($this->relations as $relation_key => $relation) {
+ if (empty($relation['field']) || !is_array($this->{$relation['field']}))
+ continue;
+
+ $values = $this->{$relation['field']};
+
+ /** @var ActiveRecord $model */
+ $model = new $relation['inner']['model'];
+
+ $connection = $model::getDb();
+ $transaction = $connection->beginTransaction();
+
+ $delete_where = [$relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']}];
+ if (!empty($relation['linked_alias'])) {
+ $delete_where[$relation['linked_alias']] = $relation_key;
+ }
+
+ try {
+ // Delete all links from viaTable
+ $connection->createCommand()
+ ->delete
+ (
+ $relation['linked_table'],
+ $delete_where
+ )
+ ->execute();
+
+ if (!empty($values)) {
+
+ foreach($values as $value) {
+ $insertData = [
+ $relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']},
+ $relation['outer']['linked_key'] => $value
+ ];
+ if (!empty($relation['linked_alias'])) {
+ $insertData[$relation['linked_alias']] = $relation_key;
+ }
+
+
+ $connection->createCommand()
+ ->insert
+ (
+ $relation['linked_table'],
+ $insertData
+ )
+ ->execute();
+ }
+ }
+ $transaction->commit();
+
+// $model->link($relation_key, )
+ } catch (Exception $ex) {
+// var_dump($relation_key, $relation);exit;
+ $transaction->rollback();
+ throw $ex;
+ }
+ }
+ }
+
+ public function relationBeforeDelete() {
+ if (is_array($modelPrimaryKey = $this->owner->getPrimaryKey())) {
+ throw new ErrorException('This behavior does not support composite primary keys');
+ }
+ foreach ($this->relations as $relation_key => $relation) {
+ if (empty($relation['field']))
+ continue;
+ $values = $this->{$relation['field']};
+
+ /** @var ActiveRecord $model */
+ $model = new $relation['inner']['model'];
+
+ $connection = $model::getDb();
+ $transaction = $connection->beginTransaction();
+
+ // @todo Refix to ActiveRecord format
+ try {
+ // Delete all links from viaTable
+ $connection->createCommand()
+ ->delete
+ (
+ $relation['linked_table'],
+ [$relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']}]
+ )
+ ->execute();
+ $transaction->commit();
+ } catch (Exception $ex) {
+ $transaction->rollback();
+ throw $ex;
+ }
+ }
+ }
+
+ /**
+ * Get related data for $relation
+ * @params string $relation Relation key
+ */
+ public function getRelations($relation) {
+ $relation = $this->_getRelation($relation);
+ return
+ $this->owner
+ ->hasMany($relation['outer']['model'], [$relation['outer']['key'] => $relation['outer']['linked_key']])
+ ->viaTable($relation['linked_table'], [$relation['inner']['linked_key'] => $relation['inner']['key']]);
+ }
+
+ /*
+ * Get relation params for $relation
+ * @param string $relation Relation key
+ */
+ protected function _getRelation($relation) {
+ $relation = strtolower($relation);
+ return isset($this->relations[$relation]) ? $this->relations[$relation] : null;
+ }
+
+ /**
+ * Return relation data from main app config
+ * @params string $section Relations key
+ */
+ protected function _getRelationParams($section) {
+ $relation = relationHelper::getRelation($section);
+ if (!$relation)
+ throw new Exception('Relation "' . $section . '" not set on this application.');
+ return $relation;
+ }
+
+ protected function _getRelationNameByField($field) {
+ return isset($this->fields[$field]) ? $this->fields[$field] : null;
+ }
+
+ protected function _getRelationByField($field) {
+ return ( isset($this->fields[$field]) && isset($this->relations[$this->fields[$field]]) ) ? $this->relations[$this->fields[$field]] : null;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function canGetProperty($name, $checkVars = true)
+ {
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function canSetProperty($name, $checkVars = true)
+ {
+ return array_key_exists($name, $this->fields) ?
+ true : parent::canSetProperty($name, $checkVars = true);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __set($name, $value) {
+ if (isset($this->fields[$name])) {
+ $this->values[$name] = $value;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __get($name) {
+ if (isset($this->values[$name])) {
+ return $this->values[$name];
+ } else {
+ $relation_key = $this->_getRelationNameByField($name);
+ if (!$relation_key)
+ return;
+
+ return $this->getRelations($relation_key);
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/modules/relation/relationHelper.php b/common/modules/relation/relationHelper.php
new file mode 100755
index 0000000..f90cfab
--- /dev/null
+++ b/common/modules/relation/relationHelper.php
@@ -0,0 +1,60 @@
+getModule('relation');
+
+ if (!is_array($module->relations))
+ return [];
+
+ return $module->relations;
+ }
+
+ /**
+ * Return one relation for key $name
+ * @param string $name
+ * @return string (@todo refix to relationOject)
+ */
+ public static function getRelation($name) {
+ $name = strtolower($name);
+ if (isset(self::$relations[$name])) {
+ return self::$relations[$name];
+ }
+ $relations = self::getRelations();
+ if (isset($relations[$name])) {
+ self::$relations[$name] = self::prepareRelation($relations[$name]);
+ } else {
+ self::$relations[$name] = null;
+ }
+ return self::$relations[$name];
+ }
+
+
+ private static function prepareRelation($relation) {
+ if (!isset($relation['linked_table']) && isset($relation['via']['model'])) {
+ $relation['linked_table'] = $relation['via']['model']::tableName();
+ }
+ return $relation;
+ }
+
+ /**
+ * @param string $name
+ * @return bool
+ */
+ public static function issetRelation($name) {
+ $relations = self::getRelations();
+ return isset($relations[$name]);
+ }
+}
\ No newline at end of file
diff --git a/common/modules/relation/relationObject.php b/common/modules/relation/relationObject.php
new file mode 100755
index 0000000..ae04cb8
--- /dev/null
+++ b/common/modules/relation/relationObject.php
@@ -0,0 +1,29 @@
+_getRelationParams($relation_key);
+ $relation['inner'] = $relation[$relation_entity];
+ $relation['outer'] = $relation[$relation_entity == 'entity1' ? 'entity2' : 'entity1'];
+ $relation['linked_table'] = $relation['via']['model']::tableName();
+ }
+
+ $this->moduleRelations = relationHelper::getRelations();
+
+
+ }
+}
\ No newline at end of file
diff --git a/common/modules/relation/relationQueryTrait.php b/common/modules/relation/relationQueryTrait.php
new file mode 100755
index 0000000..27a0354
--- /dev/null
+++ b/common/modules/relation/relationQueryTrait.php
@@ -0,0 +1,33 @@
+modelClass;
+ self::$model = new $class;
+ }
+ return self::$model;
+ }
+
+ /*public function getRelations($relation) {
+ $model = $this->getModel();
+
+ $relation = $model->_getRelation($relation);
+ return
+ $model->owner
+ ->hasMany($relation['outer']['model'], [$relation['outer']['key'] => $relation['outer']['linked_key']])
+ ->viaTable($relation['linked_table'], [$relation['inner']['linked_key'] => $relation['inner']['key']]);
+ }*/
+}
\ No newline at end of file
diff --git a/common/modules/relation/views/default/index.php b/common/modules/relation/views/default/index.php
new file mode 100755
index 0000000..dc021a6
--- /dev/null
+++ b/common/modules/relation/views/default/index.php
@@ -0,0 +1,12 @@
+
+
= $this->context->action->uniqueId ?>
+
+ This is the view content for action "= $this->context->action->id ?>".
+ The action belongs to the controller "= get_class($this->context) ?>"
+ in the "= $this->context->module->id ?>" module.
+
+
+ You may customize this page by editing the following file:
+ = __FILE__ ?>
+
+
diff --git a/common/modules/relation/views/manage/_form.php b/common/modules/relation/views/manage/_form.php
new file mode 100755
index 0000000..ad32f7c
--- /dev/null
+++ b/common/modules/relation/views/manage/_form.php
@@ -0,0 +1,58 @@
+
+
+
diff --git a/common/modules/relation/views/manage/create.php b/common/modules/relation/views/manage/create.php
new file mode 100755
index 0000000..9728570
--- /dev/null
+++ b/common/modules/relation/views/manage/create.php
@@ -0,0 +1,22 @@
+title = Yii::t('relation', $relation['name']);
+$this->params['breadcrumbs'][] = ['label' => Yii::t('relation', 'Relations'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('relation', $relation['name']), 'url' => ['/relation/manage/pars', 'relation' => $relation_key]];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'relation_key' => $relation_key,
+ 'relation' => $relation,
+ ]) ?>
+
+
diff --git a/common/modules/relation/views/manage/pars.php b/common/modules/relation/views/manage/pars.php
new file mode 100755
index 0000000..7852d4c
--- /dev/null
+++ b/common/modules/relation/views/manage/pars.php
@@ -0,0 +1,54 @@
+title = Yii::t('relation', 'Relation items for {relation}', ['relation' => $relation['name']]);
+$this->params['breadcrumbs'][] = ['label' => Yii::t('relation', 'Relations'), 'url' => ['/relation/manage']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('relation', 'Create relation'), ['create?relation='. $relation_key], ['class' => 'btn btn-success']) ?>
+
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'alias',
+ 'entity1.'. $relation['entity1']['listField'],
+ 'entity2.'. $relation['entity2']['listField'],
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{update} {delete}',
+ 'buttons' => [
+ 'update' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('relation', 'Edit par'),
+ ]);
+ },
+ 'delete' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('relation', 'Delete par'),
+ ]);
+ },
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) use ($relation, $relation_key) {
+ if ($action === 'update') {
+ $url ='/admin/relation/manage/update?relation='. $relation_key .'&id='. $model->{$relation['entity1']['linked_key']} .':'. $model->{$relation['entity2']['linked_key']};
+ return $url;
+ }
+ if ($action === 'delete') {
+ $url ='/admin/relation/manage/delete?relation='. $relation_key .'&id='. $model->{$relation['entity1']['linked_key']} .':'. $model->{$relation['entity2']['linked_key']};
+ return $url;
+ }
+ }
+ ],
+ ],
+ ]); ?>
+
diff --git a/common/modules/relation/views/manage/relations.php b/common/modules/relation/views/manage/relations.php
new file mode 100755
index 0000000..790e0e3
--- /dev/null
+++ b/common/modules/relation/views/manage/relations.php
@@ -0,0 +1,53 @@
+title = Yii::t('relation', 'Relations');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ $relations,
+ 'sort' => [
+ 'attributes' => ['name', 'key', 'entity1_label', 'entity2_label'],
+ ],
+ 'pagination' => [
+ 'pageSize' => 10,
+ ],
+ ]);
+ ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'name',
+ 'key',
+ 'entity1_label',
+ 'entity2_label',
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{view}',
+ 'buttons' => [
+ 'view' => function ($url, $model) {
+ return Html::a('', $url, [
+ 'title' => Yii::t('relation', 'View pars'),
+ ]);
+ },
+ ],
+ 'urlCreator' => function ($action, $model) {
+ if ($action === 'view') {
+ $url ='/admin/relation/manage/pars?relation='. $model['key'];
+ return $url;
+ }
+ }
+ ],
+ ],
+ ]); ?>
+
diff --git a/common/modules/relation/views/manage/update.php b/common/modules/relation/views/manage/update.php
new file mode 100755
index 0000000..cacc640
--- /dev/null
+++ b/common/modules/relation/views/manage/update.php
@@ -0,0 +1,25 @@
+title = Yii::t('relation', $relation['name']);
+$this->params['breadcrumbs'][] = ['label' => Yii::t('relation', 'Relations'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('relation', $relation['name']), 'url' => ['/relation/manage/pars', 'relation' => $relation_key]];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'value1' => $value1,
+ 'value2' => $value2,
+ 'relation_key' => $relation_key,
+ 'relation' => $relation,
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/Module.php b/common/modules/rubrication/Module.php
new file mode 100755
index 0000000..dd3159a
--- /dev/null
+++ b/common/modules/rubrication/Module.php
@@ -0,0 +1,26 @@
+keyNameId === null) {
+ $primaryKey = $owner->primaryKey();
+ if (!isset($primaryKey[0])) {
+ throw new Exception('"' . $owner->className() . '" must have a primary key.');
+ }
+ $this->keyNameId = $primaryKey[0];
+ }
+ }
+
+ /*
+ * Inicialize behavior (read and prepare params)
+ */
+ public function init() {
+ if (empty($this->valueModel)) {
+ $this->valueModel = TaxValueString::className();
+ }
+ if (empty($this->valuePKey)) {
+ $vm = $this->valueModel;
+ $primaryKey = $vm::primaryKey();
+ if (!isset($primaryKey[0])) {
+ throw new Exception('"' . $this->valueModel . '" must have a primary key.');
+ }
+ if (count($primaryKey) > 1) {
+ throw new Exception('"' . $this->valueModel . '" is contains multiple keys.');
+ }
+ $this->valuePKey = $primaryKey[0];
+ }
+ }
+
+ /*
+ * Events for auto-drive default value
+ */
+ public function events() {
+ return [
+ ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert',
+ ActiveRecord::EVENT_AFTER_UPDATE => 'beforeUpdate',
+ ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
+ ];
+ }
+
+ public function getAutoValue() {
+ return $this->owner->hasOne($this->valueModel, [$this->valuePKey => $this->keyNameValue]);
+ }
+
+ public function afterInsert() {
+ /** @var ActiveRecord $valueModel */
+ $valueModel = new $this->valueModel;
+ foreach ($this->valueFields as $key => $field) {
+ $valueModel->setAttribute($field, $this->$key);
+ }
+ $valueModel->setAttribute($this->valueOptionId, $this->owner->getAttribute($this->keyNameId));
+ $valueModel->save();
+ $this->owner->setAttribute($this->keyNameValue, $valueModel->getAttribute($this->valuePKey));
+ $this->owner->{$this->slug['slugKeyName']} = $this->slugify($valueModel->{$this->slug['valueKeyName']});
+ $this->owner->save(false);
+ }
+
+ public function beforeUpdate() {
+ if ($this->owner->getIsNewRecord()) {
+ throw new NotSupportedException('Method "' . $this->owner->className() . '::insert" is not supported for inserting new entitys.');
+ }
+
+ if (!$this->owner->getAttribute($this->keyNameValue)) {
+ return;
+ }
+
+ /** @var ActiveRecord $valueModel */
+ $valueModelName = $this->valueModel;
+ $valueModel = $valueModelName::findOne($this->owner->getAttribute($this->keyNameValue));
+
+ $isave = false;
+ foreach ($this->valueFields as $key => $field) {
+ if ($valueModel->getAttribute($field) == $this->$key) {
+ continue;
+ }
+ $isave = true;
+ $valueModel->setAttribute($field, $this->$key);
+ }
+ if ($isave) {
+ $valueModel->setAttribute($this->valueOptionId, $this->owner->getAttribute($this->keyNameId));
+ $valueModel->save();
+ if (!empty($this->slug) && empty($this->owner->{$this->slug['slugKeyName']})) {
+ $this->owner->{$this->slug['slugKeyName']} = $this->slugify($valueModel->{$this->slug['valueKeyName']});
+ }
+ }
+ }
+
+ public function beforeDelete() {
+ /** @var ActiveRecord $valueModel */
+ $valueModelName = $this->valueModel;
+ $valueModelName::deleteAll([
+ $this->valueOptionId => $this->owner->getAttribute($this->keyNameId)
+ ]);
+ }
+
+ private function slugify( $slug )
+ {
+ return Inflector::slug( TransliteratorHelper::process( $slug ), '-', true );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function canSetProperty($key, $checkVars = true)
+ {
+ return array_key_exists($key, $this->valueFields) ?
+ true : parent::canSetProperty($key, $checkVars = true);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __set($key, $value) {
+ if (isset($this->valueFields[$key])) {
+ $this->values[$key] = $value;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __get($key) {
+ return $this->_getValue($key);
+ }
+
+ public function _getValue($key) {
+ if (isset($this->values[$key])) {
+ return $this->values[$key];
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/modules/rubrication/controllers/DefaultController.php b/common/modules/rubrication/controllers/DefaultController.php
new file mode 100755
index 0000000..cbc303c
--- /dev/null
+++ b/common/modules/rubrication/controllers/DefaultController.php
@@ -0,0 +1,20 @@
+render('index');
+ }
+}
diff --git a/common/modules/rubrication/controllers/TaxGroupController.php b/common/modules/rubrication/controllers/TaxGroupController.php
new file mode 100755
index 0000000..30c37b9
--- /dev/null
+++ b/common/modules/rubrication/controllers/TaxGroupController.php
@@ -0,0 +1,158 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all TaxGroup models.
+ * @param $level integer
+ * @return mixed
+ */
+ public function actionIndex($level)
+ {
+ $dataProvider = new ActiveDataProvider([
+ 'query' => TaxGroup::find()->where(['level' => $level]),
+ ]);
+
+ return $this->render('index', [
+ 'dataProvider' => $dataProvider,
+ 'level' => $level
+ ]);
+ }
+
+ /**
+ * Displays a single TaxGroup model.
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionView($level,$id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new TaxGroup model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @param $level integer
+ * @return mixed
+ */
+ public function actionCreate($level)
+ {
+ $model = new TaxGroup();
+
+ if ($model->load(Yii::$app->request->post()) && $model->validate()) {
+ $model->level = $level;
+ $model->save();
+ return $this->redirect(['index', 'level' => $level]);
+ } else {
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing TaxGroup model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param $level integer
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionUpdate($level,$id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['index', 'level' => $level]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing TaxGroup model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param $level integer
+ * @param integer $id
+ * @return mixed
+ */
+ public function actionDelete($level,$id)
+ {
+ $this->findModel($id)->delete();
+ return $this->redirect(['index', 'level' => $level]);
+ }
+
+ /*
+ * Group-relations
+ */
+ public function actionRelation($id, $relations = ['tax_option_to_group', 'tax_option_to_option']) {
+ $group = $this->findModel($id);
+ $items = [];
+
+ foreach($relations as $relation) {
+ $rows = $group->getRelations($relation)->all();
+ $items = array_merge($items, $rows);
+ }
+
+ return $this->render('relations', [
+ 'items' => $items,
+ 'group' => $group,
+ ]);
+ }
+
+ /*
+ * Rebuilp MP-params for group options
+ */
+ public function actionRebuild($id) {
+ TaxOption::find()->rebuildMP($id);
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the TaxGroup model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return TaxGroup the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = TaxGroup::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+}
diff --git a/common/modules/rubrication/controllers/TaxOptionController.php b/common/modules/rubrication/controllers/TaxOptionController.php
new file mode 100755
index 0000000..e94a90c
--- /dev/null
+++ b/common/modules/rubrication/controllers/TaxOptionController.php
@@ -0,0 +1,174 @@
+ [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all TaxOption models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new TaxOptionSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ $group = TaxGroup::findOne(Yii::$app->request->queryParams['group']);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ 'group' => $group,
+ ]);
+ }
+
+ /**
+ * Displays a single TaxOption model.
+ * @param string $id
+ * @return mixed
+ */
+ public function actionView($id)
+ {
+ $model = $this->findModel($id);
+ $group = TaxGroup::findOne($model->tax_group_id);
+ return $this->render('view', [
+ 'model' => $model,
+ 'group' => $group,
+ ]);
+ }
+
+ /**
+ * Creates a new TaxOption model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new TaxOption();
+ $group = TaxGroup::findOne(Yii::$app->request->queryParams['group']);
+ $valueModelName = $this->getValueModelName($group);
+ $valueModel = new $valueModelName;
+
+ if ($model->load(Yii::$app->request->post())) {
+
+ $model->save();
+
+ $valueModel->tax_option_id = $model->tax_option_id;
+ $valueModel->value = $model->name;
+ $valueModel->save();
+
+ $model->default_value = $valueModel->tax_value_id;
+ $model->save();
+
+ return is_null(Yii::$app->request->post('create_and_new')) ? $this->redirect(['view', 'id' => $model->tax_option_id]) : $this->redirect(array_merge(['create'], Yii::$app->request->queryParams));
+ } else {
+ $model->tax_group_id = $group->tax_group_id;
+ if (!empty(Yii::$app->request->queryParams['parent'])) {
+ $model->parent_id = Yii::$app->request->queryParams['parent'];
+ }
+ return $this->render('create', [
+ 'model' => $model,
+ 'group' => $group,
+ 'valueModel' => $valueModel,
+ ]);
+ }
+ }
+
+ /**
+ * Updates an existing TaxOption model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param string $id
+ * @return mixed
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+ $group = TaxGroup::findOne($model->tax_group_id);
+ $valueModelName = $this->getValueModelName($group);
+ $valueModel = $valueModelName::findOne($model->default_value);
+
+ if ($model->load(Yii::$app->request->post())) {
+ $model->save();
+ $valueModel->tax_option_id = $model->tax_option_id;
+ $valueModel->value = $model->name;
+ $valueModel->save();
+
+ $model->default_value = $valueModel->tax_value_id;
+ $model->save();
+
+ TaxOption::find()->rebuildMP($model->tax_group_id);
+
+ return $this->redirect(['view', 'id' => $model->tax_option_id]);
+ } else {
+ return $this->render('update', [
+ 'model' => $model,
+ 'group' => $group,
+ 'valueModel' => $valueModel,
+ ]);
+ }
+ }
+
+ /**
+ * Deletes an existing TaxOption model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ */
+ public function actionDelete($id)
+ {
+ $model = $this->findModel($id);
+ $group_id = $model->tax_group_id;
+
+ $model->delete();
+
+ return $this->redirect(['index', 'group' => $group_id]);
+ }
+
+ /**
+ * Finds the TaxOption model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param string $id
+ * @return TaxOption the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = TaxOption::findOne($id)) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+
+ protected function getValueModelName($group) {
+ $valueClass = '\common\modules\rubrication\models\TaxValue'. ucfirst($group->module);
+ return class_exists($valueClass) ? $valueClass : FALSE;
+ }
+}
diff --git a/common/modules/rubrication/helpers/RubricationHelper.php b/common/modules/rubrication/helpers/RubricationHelper.php
new file mode 100755
index 0000000..4044373
--- /dev/null
+++ b/common/modules/rubrication/helpers/RubricationHelper.php
@@ -0,0 +1,51 @@
+ Yii::t('order', 'Invisible'),
+ 1 => Yii::t('order', 'Active'),
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ * Returns sort-interval of appropriate options and others
+ * @return array.
+ */
+ static public function SortArray($low = 0, $high = 100) {
+ return range($low, $high);
+ }
+
+ static public function OptionTypes() {
+ if (!is_null(self::$types)) {
+ return self::$types;
+ }
+
+ $module = \Yii::$app->getModule('rubrication');
+
+ if (!is_array($module->types))
+ return [];
+
+ return $module->types;
+
+ }
+
+ public function checkboxList($items, $options = [])
+ {
+ $this->adjustLabelFor($options);
+ $this->parts['{input}'] = Html::activeCheckboxList($this->model, $this->attribute, $items, $options);
+
+ return $this;
+ }
+}
\ No newline at end of file
diff --git a/common/modules/rubrication/models/TaxGroup.php b/common/modules/rubrication/models/TaxGroup.php
new file mode 100755
index 0000000..0bc8b42
--- /dev/null
+++ b/common/modules/rubrication/models/TaxGroup.php
@@ -0,0 +1,141 @@
+ relationBehavior::className(),
+ 'relations' => [
+ 'tax_group_to_category' => 'entity1',
+ ]
+ ],
+ 'slug' => [
+ 'class' => 'common\behaviors\Slug',
+ 'in_attribute' => 'name',
+ 'out_attribute' => 'alias',
+ 'translit' => true
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return 'tax_group';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['name', 'module'], 'required'],
+ [['description', 'settings'], 'string'],
+ [['hierarchical', 'is_filter', 'display'], 'boolean'],
+ [['level', 'sort'], 'integer'],
+ [['alias', 'module'], 'string', 'max' => 50],
+ [['name'], 'string', 'max' => 255],
+ [['group_to_category'], 'safe']
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_group_id' => 'Tax Group ID',
+ 'alias' => 'Alias',
+ 'name' => 'Name',
+ 'description' => 'Description',
+ 'module' => 'Module',
+ 'hierarchical' => 'Hierarchical',
+// 'settings' => 'Settings',
+ 'is_filter' => 'Use in filter',
+ 'sort' => 'Sort',
+ 'display' => 'Display',
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxGroupToGroups()
+ {
+ return $this->hasMany(TaxGroupToGroup::className(), ['tax_group1_id' => 'tax_group_id'])->inverseOf('taxGroup1');
+ }
+
+ public function getCategories()
+ {
+ return $this->hasMany(Category::className(), ['category_id' => 'entity2_id'])
+ ->viaTable('relation', ['entity1_id' => 'tax_group_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxGroupToGroups0()
+ {
+ return $this->hasMany(TaxGroupToGroup::className(), ['tax_group2_id' => 'tax_group_id'])->inverseOf('taxGroup2');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getOptions() {
+ return $this->getTaxOptions();
+ }
+ public function getTaxOptions()
+ {
+ return $this->hasMany(TaxOption::className(), ['tax_group_id' => 'tax_group_id'])->inverseOf('taxGroup');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOptionToGroups()
+ {
+ return $this->hasMany(TaxOptionToGroup::className(), ['tax_group_id' => 'tax_group_id'])->inverseOf('taxGroup');
+ }
+
+ public function getValueModelName($full_path = true) {
+ $valueClass = 'TaxValue'. ucfirst($this->module);
+ $fullClass = '\common\modules\rubrication\models\\'. $valueClass;
+ return class_exists($fullClass) ? $full_path ? $fullClass : $valueClass : FALSE;
+ }
+}
diff --git a/common/modules/rubrication/models/TaxGroupToGroup.php b/common/modules/rubrication/models/TaxGroupToGroup.php
new file mode 100755
index 0000000..b621239
--- /dev/null
+++ b/common/modules/rubrication/models/TaxGroupToGroup.php
@@ -0,0 +1,69 @@
+ 50]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_group1_id' => Yii::t('app', 'Tax Group1 ID'),
+ 'tax_group2_id' => Yii::t('app', 'Tax Group2 ID'),
+ 'alias' => Yii::t('app', 'Alias'),
+ 'sort' => Yii::t('app', 'Sort'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxGroup1()
+ {
+ return $this->hasOne(TaxGroup::className(), ['tax_group_id' => 'tax_group1_id']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxGroup2()
+ {
+ return $this->hasOne(TaxGroup::className(), ['tax_group_id' => 'tax_group2_id']);
+ }
+}
diff --git a/common/modules/rubrication/models/TaxOption.php b/common/modules/rubrication/models/TaxOption.php
new file mode 100755
index 0000000..7a05c44
--- /dev/null
+++ b/common/modules/rubrication/models/TaxOption.php
@@ -0,0 +1,245 @@
+ [
+ 'class' => ArtboxTreeBehavior::className(),
+ 'keyNameGroup' => 'tax_group_id',
+ ],
+ 'slug' => [
+ 'class' => 'common\behaviors\Slug',
+ 'in_attribute' => 'name',
+ 'out_attribute' => 'alias',
+ 'translit' => true
+ ],
+
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return '{{%tax_option}}';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['tax_group_id','name'], 'required'],
+ [['tax_group_id', 'parent_id', 'sort', 'default_value'], 'integer'],
+ [['alias'], 'string', 'max' => 50],
+ [['tax_group_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxGroup::className(), 'targetAttribute' => ['tax_group_id' => 'tax_group_id']],
+// [['parent_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['parent_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
+ 'tax_group_id' => Yii::t('app', 'Tax Group ID'),
+ 'parent_id' => Yii::t('app', 'Parent ID'),
+ 'alias' => Yii::t('app', 'Alias'),
+ 'sort' => Yii::t('app', 'Sort'),
+ 'default_value' => Yii::t('app', 'Default Value'),
+ ];
+ }
+
+ public static function find() {
+ return new TaxOptionQuery(get_called_class());
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxEntityRelations()
+ {
+ return $this->hasMany(TaxEntityRelation::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxOption');
+ }
+
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getGroup()
+ {
+ return $this->getTaxGroup();
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxGroup()
+ {
+ return $this->hasOne(TaxGroup::className(), ['tax_group_id' => 'tax_group_id'])->inverseOf('taxOptions');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOptions()
+ {
+ return $this->hasMany(TaxOption::className(), ['parent_id' => 'tax_option_id'])->inverseOf('parent');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOptionToGroups()
+ {
+ return $this->hasMany(TaxOptionToGroup::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxOption');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOptionToOptions()
+ {
+ return $this->hasMany(TaxOptionToOption::className(), ['tax_option1_id' => 'tax_option_id'])->inverseOf('taxOption1');
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOptionToOptions0()
+ {
+ return $this->hasMany(TaxOptionToOption::className(), ['tax_option2_id' => 'tax_option_id'])->inverseOf('taxOption2');
+ }
+
+
+ public function getTaxValueString(){
+ return $this->hasOne(TaxValueString::className(), ['tax_option_id' => 'tax_option_id']);
+ }
+
+ public function getName(){
+ return (!empty($this->taxValueString)) ? $this->taxValueString->value : '' ;
+ }
+
+
+
+ public function setName($values){
+ $this->name = $values;
+ }
+
+ /**
+ */
+ public function getValue()
+ {
+ $valueClass = $this->getValueModelName();
+ if ($valueClass) {
+ return $this->hasOne($valueClass, ['tax_value_id' => 'default_value', 'tax_option_id' => 'tax_option_id'])->inverseOf('taxOption');
+ }
+ }
+
+ /**
+ */
+ public function getValueRenderFlash()
+ {
+ $valueClass = $this->getValueModelName();
+ $value = $this->value;
+ if ($valueClass && method_exists($valueClass, 'getValueRenderFlash')) {
+ return $valueClass::getValueRenderFlash($value);
+ } elseif(!empty($value)) {
+ return $value->value;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ */
+ public function getValueRenderHTML()
+ {
+ $valueClass = $this->getValueModelName();
+ $value = $this->value;
+ if ($valueClass && method_exists($valueClass, 'getValueRenderHTML')) {
+ return $valueClass::getValueRenderHTML($value);
+ } else {
+ return $value->value;
+ }
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getValues()
+ {
+ if ($valueClass = $this->getValueModelName())
+ return $this->hasMany($valueClass, ['tax_option_id' => 'tax_option_id'])->inverseOf('taxOption')->cascadeOnDelete();
+ }
+
+ public function beforeSave($insert)
+ {
+ if (parent::beforeSave($insert)) {
+
+ if (empty($this->parent_id))
+ $this->parent_id = 0;
+
+
+
+ return true;
+ }
+ return false;
+ }
+
+// public function beforeDelete() {
+// if ( ($model = $this->getValueModelName()) !== FALSE ) {
+//
+// }
+// }
+
+ private function getValueModelName() {
+ $group = $this->taxGroup;
+ $valueClass = '\common\modules\rubrication\models\TaxValue'. ucfirst($group->module);
+ return class_exists($valueClass) ? $valueClass : FALSE;
+ }
+}
diff --git a/common/modules/rubrication/models/TaxOptionQuery.php b/common/modules/rubrication/models/TaxOptionQuery.php
new file mode 100755
index 0000000..9dbc6c2
--- /dev/null
+++ b/common/modules/rubrication/models/TaxOptionQuery.php
@@ -0,0 +1,39 @@
+andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * @inheritdoc
+ * @return TaxOption[]|array
+ */
+ public function all($db = null)
+ {
+ $this->with('value');
+ return parent::all($db);
+ }
+
+ /**
+ * @inheritdoc
+ * @return TaxOption|array|null
+ */
+ public function one($db = null)
+ {
+ $this->with('value');
+ return parent::one($db);
+ }
+}
diff --git a/common/modules/rubrication/models/TaxOptionRelation.php b/common/modules/rubrication/models/TaxOptionRelation.php
new file mode 100755
index 0000000..c5390be
--- /dev/null
+++ b/common/modules/rubrication/models/TaxOptionRelation.php
@@ -0,0 +1,50 @@
+ 50]
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_option1_id' => Yii::t('product', 'Tax Option1 ID'),
+ 'tax_option2_id' => Yii::t('product', 'Tax Option2 ID'),
+ 'alias' => Yii::t('product', 'Alias'),
+ 'sort' => Yii::t('product', 'Sort'),
+ ];
+ }
+}
diff --git a/common/modules/rubrication/models/TaxOptionSearch.php b/common/modules/rubrication/models/TaxOptionSearch.php
new file mode 100755
index 0000000..9cdddb4
--- /dev/null
+++ b/common/modules/rubrication/models/TaxOptionSearch.php
@@ -0,0 +1,76 @@
+tax_group_id = intval($params['group']);
+ unset($params['group']);
+ }
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+
+ $this->load($params);
+
+// if (!$this->validate()) {
+// return $dataProvider;
+// }
+
+ // grid filtering conditions
+ $query->andFilterWhere([
+ 'tax_option_id' => $this->tax_option_id,
+ 'tax_group_id' => $this->tax_group_id,
+ 'parent_id' => $this->parent_id,
+ 'sort' => $this->sort,
+ ]);
+
+ $query->andFilterWhere(['like', 'alias', $this->alias]);
+ $query->andFilterWhere(['like', 'tax_value_string.value', $this->default_value]);
+
+ $query->orderBy(['path_int' => SORT_ASC, 'depth' => SORT_ASC, 'sort' => SORT_ASC]);
+
+ return $dataProvider;
+ }
+}
diff --git a/common/modules/rubrication/models/TaxValueFloat.php b/common/modules/rubrication/models/TaxValueFloat.php
new file mode 100755
index 0000000..a8d76e6
--- /dev/null
+++ b/common/modules/rubrication/models/TaxValueFloat.php
@@ -0,0 +1,58 @@
+ true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['tax_option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_value_id' => Yii::t('app', 'Tax Value ID'),
+ 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
+ 'value' => Yii::t('app', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxValues');
+ }
+}
diff --git a/common/modules/rubrication/models/TaxValueInt.php b/common/modules/rubrication/models/TaxValueInt.php
new file mode 100755
index 0000000..89406f2
--- /dev/null
+++ b/common/modules/rubrication/models/TaxValueInt.php
@@ -0,0 +1,57 @@
+ true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['tax_option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_value_id' => Yii::t('app', 'Tax Value ID'),
+ 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
+ 'value' => Yii::t('app', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxValues');
+ }
+}
diff --git a/common/modules/rubrication/models/TaxValueLink.php b/common/modules/rubrication/models/TaxValueLink.php
new file mode 100755
index 0000000..c6c3d90
--- /dev/null
+++ b/common/modules/rubrication/models/TaxValueLink.php
@@ -0,0 +1,69 @@
+ 150],
+ [['link'], 'string', 'max' => 255],
+ [['tax_option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['tax_option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_value_id' => Yii::t('app', 'Tax Value ID'),
+ 'tax_option_id' => Yii::t('app', 'Tax Option ID'),
+ 'name' => Yii::t('app', 'Name'),
+ 'link' => Yii::t('app', 'Link'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_option_id'])->inverseOf('taxValueLinks');
+ }
+
+ public static function getValueRenderFlash($value) {
+ return $value->name;
+ }
+
+ public static function getValueRenderHTML($value) {
+ return Html::a($value->name, $value->link);
+ }
+}
diff --git a/common/modules/rubrication/models/TaxValueString.php b/common/modules/rubrication/models/TaxValueString.php
new file mode 100755
index 0000000..881110b
--- /dev/null
+++ b/common/modules/rubrication/models/TaxValueString.php
@@ -0,0 +1,58 @@
+ 255],
+ [['tax_option_id'], 'exist', 'skipOnError' => true, 'targetClass' => TaxOption::className(), 'targetAttribute' => ['tax_option_id' => 'tax_option_id']],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'tax_value_id' => Yii::t('rubrication', 'Tax Value ID'),
+ 'tax_option_id' => Yii::t('rubrication', 'Tax Option ID'),
+ 'value' => Yii::t('rubrication', 'Value'),
+ ];
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTaxOption()
+ {
+ return $this->hasOne(TaxOption::className(), ['tax_option_id' => 'tax_option_id']);
+ }
+}
diff --git a/common/modules/rubrication/views/default/index.php b/common/modules/rubrication/views/default/index.php
new file mode 100755
index 0000000..d9e8d45
--- /dev/null
+++ b/common/modules/rubrication/views/default/index.php
@@ -0,0 +1,12 @@
+
+
= $this->context->action->uniqueId ?>
+
+ This is the view content for action "= $this->context->action->id ?>".
+ The action belongs to the controller "= get_class($this->context) ?>"
+ in the "= $this->context->module->id ?>" module.
+
+
+ You may customize this page by editing the following file:
+ = __FILE__ ?>
+
+
diff --git a/common/modules/rubrication/views/tax-group/_form.php b/common/modules/rubrication/views/tax-group/_form.php
new file mode 100755
index 0000000..d2b44e7
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/_form.php
@@ -0,0 +1,49 @@
+
+
+
diff --git a/common/modules/rubrication/views/tax-group/create.php b/common/modules/rubrication/views/tax-group/create.php
new file mode 100755
index 0000000..ddcc890
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/create.php
@@ -0,0 +1,21 @@
+title = Yii::t('rubrication', 'Create Tax Group');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Tax Groups'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/views/tax-group/index.php b/common/modules/rubrication/views/tax-group/index.php
new file mode 100755
index 0000000..705eff0
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/index.php
@@ -0,0 +1,76 @@
+title = Yii::t('rubrication', 'Groups');
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
+
= Html::encode($this->title) ?>
+
+ = Html::a(Yii::t('rubrication', 'Create Group'), Url::to(['/rubrication/tax-group/create', 'level'=> $level]), ['class' => 'btn btn-success']) ?>
+
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+
+ 'name',
+ 'alias',
+ 'description:ntext',
+ 'module',
+ 'hierarchical:boolean',
+ 'is_filter:boolean',
+ // 'settings:ntext',
+
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{update} {options} {relations} {delete} {rebuild}',
+ 'buttons' => [
+ 'options' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('rubrication', 'Options'),
+ ]);
+ },
+ 'relations' => function ($url, $model) {
+ return Html::a('', $url, [
+ 'title' => Yii::t('rubrication', 'Relations'),
+ ]);
+ },
+ 'rebuild' => function ($url, $model) {
+ return Html::a('', $url, [
+ 'title' => Yii::t('rubrication', 'Rebuild cache'),
+ ]);
+ }
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) use ($level) {
+ if ($action === 'options') {
+ $url ='/admin/rubrication/tax-option?group='.$model->tax_group_id;
+ return $url;
+ } elseif ($action === 'relations') {
+ $url ='/admin/rubrication/tax-group/relation&id='.$model->tax_group_id;
+ return $url;
+ } elseif ($action === 'update') {
+ $url =Url::to(['/rubrication/tax-group/update', 'level'=> $level,'id' =>$model->tax_group_id]);
+ return $url;
+ } elseif ($action === 'delete') {
+ $url =Url::to(['/rubrication/tax-group/delete', 'level'=> $level,'id' =>$model->tax_group_id]);
+ return $url;
+ } elseif ($action === 'rebuild') {
+ $url ='/admin/rubrication/tax-group/rebuild?id='.$model->tax_group_id;
+ return $url;
+ }
+ }
+ ],
+ ],
+ ]); ?>
+
+
diff --git a/common/modules/rubrication/views/tax-group/relations.php b/common/modules/rubrication/views/tax-group/relations.php
new file mode 100755
index 0000000..c65a58d
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/relations.php
@@ -0,0 +1,58 @@
+title = Yii::t('relation', 'Relation for Group "{group}"', ['group' => $group->name]);
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Tax Groups'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+//= Html::a(Yii::t('relation', 'Create relation'), ['create?relation='. $relation_key], ['class' => 'btn btn-success']) ?>
+
+
+ $items,
+ 'sort' => [
+ 'attributes' => ['name', 'alias', 'entity1_label', 'entity2_label'],
+ ],
+ 'pagination' => [
+ 'pageSize' => 10,
+ ],
+ ]);
+ ?>
+
+ = GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'name',
+ 'alias',
+ 'entity1_label',
+ 'entity2_label',
+ /*[
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{view}',
+ 'buttons' => [
+ 'view' => function ($url, $model) {
+ return Html::a('', $url, [
+ 'title' => Yii::t('relation', 'View pars'),
+ ]);
+ },
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) {
+ if ($action === 'view') {
+ $url ='/admin/relation/manage/pars?relation='. $model['key'];
+ return $url;
+ }
+ }
+ ],*/
+ ],
+ ]); ?>
+
diff --git a/common/modules/rubrication/views/tax-group/update.php b/common/modules/rubrication/views/tax-group/update.php
new file mode 100755
index 0000000..8414ea0
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/update.php
@@ -0,0 +1,23 @@
+title = Yii::t('rubrication', 'Update {modelClass}: ', [
+ 'modelClass' => 'Tax Group',
+]) . ' ' . $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Groups'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->tax_group_id]];
+$this->params['breadcrumbs'][] = Yii::t('rubrication', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/views/tax-group/view.php b/common/modules/rubrication/views/tax-group/view.php
new file mode 100755
index 0000000..44e1691
--- /dev/null
+++ b/common/modules/rubrication/views/tax-group/view.php
@@ -0,0 +1,43 @@
+title = $model->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Tax Groups'), 'url' => ['index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('rubrication', 'Update'), ['update', 'id' => $model->tax_group_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('rubrication', 'Delete'), ['delete', 'id' => $model->tax_group_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+ = Html::a(Yii::t('rubrication', 'Create Option'), ['tax-option/create?group='. $model->tax_group_id], ['class' => 'btn btn-success']) ?>
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'tax_group_id',
+ 'alias',
+ 'name',
+ 'description:ntext',
+ 'module',
+ 'hierarchical:boolean',
+ 'is_filter:boolean',
+ 'settings:ntext',
+ ],
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/views/tax-option/_form.php b/common/modules/rubrication/views/tax-option/_form.php
new file mode 100755
index 0000000..d73bcbd
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/_form.php
@@ -0,0 +1,64 @@
+
+
+
diff --git a/common/modules/rubrication/views/tax-option/_search.php b/common/modules/rubrication/views/tax-option/_search.php
new file mode 100755
index 0000000..8414c97
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/_search.php
@@ -0,0 +1,37 @@
+
+
+
+
+ ['index'],
+ 'method' => 'get',
+ ]); ?>
+
+ = $form->field($model, 'tax_option_id') ?>
+
+ = $form->field($model, 'tax_group_id') ?>
+
+ = $form->field($model, 'parent_id') ?>
+
+ = $form->field($model, 'alias') ?>
+
+ = $form->field($model, 'sort') ?>
+
+ field($model, 'default_value') ?>
+
+
+ = Html::submitButton(Yii::t('rubrication', 'Search'), ['class' => 'btn btn-primary']) ?>
+ = Html::resetButton(Yii::t('rubrication', 'Reset'), ['class' => 'btn btn-default']) ?>
+
+
+
+
+
diff --git a/common/modules/rubrication/views/tax-option/create.php b/common/modules/rubrication/views/tax-option/create.php
new file mode 100755
index 0000000..55ddf4a
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/create.php
@@ -0,0 +1,25 @@
+title = Yii::t('rubrication', 'Create Tax Option');
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Groups'), 'url' => ['tax-group/index']];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', $group->name), 'url' => ['index', 'group' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', Yii::t('rubrication', 'Options of {name}', ['name' => $group->name])), 'url' => ['index', 'group' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'group' => $group,
+ 'valueModel' => $valueModel,
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/views/tax-option/index.php b/common/modules/rubrication/views/tax-option/index.php
new file mode 100755
index 0000000..dbd2389
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/index.php
@@ -0,0 +1,100 @@
+title = Yii::t('rubrication', 'Options for group "{group}"', ['group' => $group->name]);
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Groups'), 'url' => ['tax-group/index']];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+ render('_search', ['model' => $searchModel]); ?>
+
+
+ = Html::a(Yii::t('rubrication', 'Create Option'), ['create?group='. $group->tax_group_id], ['class' => 'btn btn-success']) ?>
+
+
+hierarchical) :?>
+ $dataProvider,
+// 'filterModel' => $searchModel,
+ 'columns' => [
+ [
+ 'label'=> Yii::t('rubrication', 'Value'),
+ 'content'=>function($data){
+ return str_repeat('-', $data->depth) .' '. $data->ValueRenderFlash;
+ }
+ ],
+ 'alias',
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{view} {update} {delete} {synonim}',
+ 'buttons' => [
+ 'synonim' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('rubrication', 'Synonims'),
+ ]);
+ },
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) {
+ if ($action === 'view') {
+ $url = '/admin/rubrication/tax-option/view?id=' . $model->tax_option_id;
+ return $url;
+ } elseif ($action === 'update') {
+ $url ='/admin/rubrication/tax-option/update?id='.$model->tax_option_id;
+ return $url;
+ } elseif ($action === 'delete') {
+ $url ='/admin/rubrication/tax-option/delete?id='.$model->tax_option_id;
+ return $url;
+ } elseif ($action === 'synonim') {
+ $url ='/admin/rubrication/tax-synonim/delete?id='.$model->tax_option_id;
+ return $url;
+ }
+ }
+ ],
+ ],
+ ]);?>
+
+ $dataProvider,
+// 'filterModel' => $searchModel,
+ 'columns' => [
+ ['class' => 'yii\grid\SerialColumn'],
+ 'valueRenderHTML',
+ 'alias',
+ [
+ 'class' => 'yii\grid\ActionColumn',
+ 'template' => '{update} {delete} {synonim}',
+ 'buttons' => [
+ 'synonim' => function ($url, $model) {
+ return Html::a('
', $url, [
+ 'title' => Yii::t('rubrication', 'Synonims'),
+ ]);
+ },
+ ],
+ 'urlCreator' => function ($action, $model, $key, $index) {
+ if ($action === 'update') {
+ $url ='/admin/rubrication/tax-option/update?id='.$model->tax_option_id;
+ return $url;
+ } elseif ($action === 'delete') {
+ $url ='/admin/rubrication/tax-option/delete?id='.$model->tax_option_id;
+ return $url;
+ } elseif ($action === 'synonim') {
+ $url ='/admin/rubrication/tax-synonim/delete?id='.$model->tax_option_id;
+ return $url;
+ }
+ }
+ ],
+ ],
+ ]);?>
+
+
diff --git a/common/modules/rubrication/views/tax-option/update.php b/common/modules/rubrication/views/tax-option/update.php
new file mode 100755
index 0000000..a0dbb1c
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/update.php
@@ -0,0 +1,26 @@
+title = Yii::t('rubrication', 'Update {modelClass}: ', [
+ 'modelClass' => 'Tax Option',
+]) . ' ' . $model->tax_option_id;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Groups'), 'url' => ['tax-group/index']];
+$this->params['breadcrumbs'][] = ['label' => $group->name, 'url' => ['view', 'id' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', Yii::t('rubrication', 'Options of {name}', ['name' => $group->name])), 'url' => ['index', 'group' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = Yii::t('rubrication', 'Update');
+?>
+
+
+
= Html::encode($this->title) ?>
+
+ = $this->render('_form', [
+ 'model' => $model,
+ 'group' => $group,
+ 'valueModel' => $valueModel,
+ ]) ?>
+
+
diff --git a/common/modules/rubrication/views/tax-option/value/_fields_float.php b/common/modules/rubrication/views/tax-option/value/_fields_float.php
new file mode 100755
index 0000000..6a35b2f
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/value/_fields_float.php
@@ -0,0 +1 @@
+= $form->field($valueModel, 'value')->textInput() ?>
\ No newline at end of file
diff --git a/common/modules/rubrication/views/tax-option/value/_fields_int.php b/common/modules/rubrication/views/tax-option/value/_fields_int.php
new file mode 100755
index 0000000..6a35b2f
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/value/_fields_int.php
@@ -0,0 +1 @@
+= $form->field($valueModel, 'value')->textInput() ?>
\ No newline at end of file
diff --git a/common/modules/rubrication/views/tax-option/value/_fields_link.php b/common/modules/rubrication/views/tax-option/value/_fields_link.php
new file mode 100755
index 0000000..5aeb45e
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/value/_fields_link.php
@@ -0,0 +1,2 @@
+= $form->field($valueModel, 'name')->textInput(['maxlength' => true]) ?>
+= $form->field($valueModel, 'link')->textInput(['maxlength' => true]) ?>
\ No newline at end of file
diff --git a/common/modules/rubrication/views/tax-option/value/_fields_string.php b/common/modules/rubrication/views/tax-option/value/_fields_string.php
new file mode 100755
index 0000000..6a35b2f
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/value/_fields_string.php
@@ -0,0 +1 @@
+= $form->field($valueModel, 'value')->textInput() ?>
\ No newline at end of file
diff --git a/common/modules/rubrication/views/tax-option/view.php b/common/modules/rubrication/views/tax-option/view.php
new file mode 100755
index 0000000..8858d75
--- /dev/null
+++ b/common/modules/rubrication/views/tax-option/view.php
@@ -0,0 +1,46 @@
+title = $model->valueRenderFlash;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', 'Groups'), 'url' => ['tax-group/index']];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', $group->name), 'url' => ['index', 'group' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = ['label' => Yii::t('rubrication', Yii::t('rubrication', 'Options of {name}', ['name' => $group->name])), 'url' => ['index', 'group' => $group->tax_group_id]];
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = Html::a(Yii::t('rubrication', 'Update'), ['update', 'id' => $model->tax_option_id], ['class' => 'btn btn-primary']) ?>
+ = Html::a(Yii::t('rubrication', 'Delete'), ['delete', 'id' => $model->tax_option_id], [
+ 'class' => 'btn btn-danger',
+ 'data' => [
+ 'confirm' => Yii::t('rubrication', 'Are you sure you want to delete this item?'),
+ 'method' => 'post',
+ ],
+ ]) ?>
+ = Html::a(Yii::t('rubrication', 'Create Option'), ['tax-option/create?group='. $model->tax_group_id], ['class' => 'btn btn-success']) ?>
+ parent_id)) :?>
+ = Html::a(Yii::t('rubrication', 'Create Option By {name}', ['name' => $model->parent->ValueRenderFlash]), ['tax-option/create?group='. $model->tax_group_id .'&parent='. $model->parent->tax_option_id], ['class' => 'btn btn-success']) ?>
+
+
+
+ = DetailView::widget([
+ 'model' => $model,
+ 'attributes' => [
+ 'tax_option_id',
+ 'ValueRenderFlash',
+ 'alias',
+ 'parent.ValueRenderFlash',
+ 'group.name',
+ 'sort',
+ ],
+ ]) ?>
+
+
diff --git a/common/translation/ru/app.php b/common/translation/ru/app.php
new file mode 100755
index 0000000..e1eea62
--- /dev/null
+++ b/common/translation/ru/app.php
@@ -0,0 +1,81 @@
+ 'ID',
+ 'username' => 'Имя',
+ 'surname' => 'Фамилия',
+ 'auth_key' => 'Auth Key',
+ 'password_hash' => 'Password Hash',
+ 'password_reset_token' => 'Password Reset Token',
+ 'email' => 'Логин (e-mail)',
+ 'phone' => 'Телефон',
+ 'status' => 'Статус',
+ 'created_at' => 'Created At',
+ 'updated_at' => 'Updated At',
+ 'verifyCode' => 'Код проверки',
+ 'password' => 'Пароль',
+ 'password_repeat' => 'Повторить пароль',
+ 'registration' => 'Регистрация',
+ 'message' => 'Этот {field} уже занят',
+ 'message_match_password' => 'Пароли не совпадают',
+ 'exit' => 'Выход',
+ 'enter' => 'Войти',
+ 'your_personal_area' => 'Вход в личный кабинет',
+ 'forgot_password' => 'Забыли пароль?',
+ 'rememberMe' => 'Запомнить меня',
+ 'articles' => 'Всего товаров',
+ 'code' => 'Код: {0}',
+ 'checkout' => 'оформить заказ',
+ 'sum' => 'Сумма',
+ 'continue_shopping' => 'продолжить покупки',
+ 'edit_personal_data' => 'Редактировать личные данные',
+ 'personal_data' => 'Личные данные',
+ 'my_orders' => 'Мои заказы',
+ 'bookmarks' => 'Закладки',
+ 'basket' => 'Корзина',
+ 'banner_id' => 'Banner ID',
+ 'image' => 'Изображение',
+ 'alt' => 'Описание',
+ 'title' => 'Заголовок',
+ 'url' => 'Ссылка',
+ 'width' => 'Ширина',
+ 'height' => 'Высота',
+ 'blog_id' => 'Blog ID',
+ 'user_id' => 'User ID',
+ 'name' => 'Название',
+ 'link' => 'Ссылка',
+ 'date_add' => 'Дата добавления',
+ 'user_add_id' => 'User Add ID',
+ 'view_count' => 'Количество просмотров',
+ 'description' => 'Описание',
+ 'cover' => 'Фото главное',
+ 'event_id' => 'Event ID',
+ 'alias' => 'Ссылка',
+ 'body' => 'Тело',
+ 'meta_title' => 'Мета заголовок',
+ 'h1' => 'H1',
+ 'seo_text' => 'Сео Текст',
+ 'end_at' => 'Срок действия по',
+ 'order_items_id' => 'Order Items ID',
+ 'order_id' => 'Order ID',
+ 'item_id' => 'Item ID',
+ 'item_count' => 'Количество',
+ 'price' => 'Цена',
+ 'customer_id' => 'Customer ID',
+ 'delivery' => 'Доставка',
+ 'payment' => 'Оплата',
+ 'seo_id' => 'Seo ID',
+ 'controller' => 'Controller',
+ 'seo_category_id' => 'Seo Category ID',
+ 'seo_dynamic_id' => 'Seo Dynamic ID',
+ 'action' => 'Action',
+ 'fields' => 'Поля',
+ 'param' => 'Параметры',
+ 'key' => 'Ключ',
+ 'service_id' => 'Service ID',
+ 'slider_id' => 'Slider ID',
+ 'speed' => 'Скорость',
+ 'duration' => 'Продолжительность',
+ 'slider_image_id' => 'Slider Image ID',
+ 'sort' => 'Сортировка',
+
+];
\ No newline at end of file
diff --git a/common/translation/ru/product.php b/common/translation/ru/product.php
new file mode 100755
index 0000000..ca15056
--- /dev/null
+++ b/common/translation/ru/product.php
@@ -0,0 +1,32 @@
+ 'Категории',
+ 'Create Category' => 'Создать Категорию',
+ 'Name' => 'Наименование',
+ 'Set populary' => 'Сделать популярной',
+ 'Set not populary' => 'Сделать не популярной',
+ 'Remote ID' => 'ID в 1С',
+ 'Search for "{keywords}"' => 'Поиск по "{keywords}"',
+ 'Search for "{keywords}" in category "{category}"' => 'Поиск по "{keywords}" в категории "{category}"',
+ 'Promo products' => 'Акционные товары',
+ 'New products' => 'Новинки',
+ 'Top products' => 'Популярные',
+ 'Similar products' => 'Похожие товары',
+ 'Brands' => 'Бренды',
+ 'Brand' => 'Бренд',
+ 'Categories' => 'Категории',
+ 'Category' => 'Категория',
+ 'Select brand' => 'Выберите бренд',
+ 'Select category' => 'Выберите категорию',
+ 'SKU' => 'Артикул',
+ 'Stock' => 'Остаток',
+ 'Price' => 'Цена',
+ 'Price Old' => 'Старая Цена',
+ 'Products' => 'Товары',
+ 'Product' => 'Товар',
+ 'Variants' => 'Модификации',
+ 'Variant' => 'Модификация',
+ 'Create Product' => 'Создать Товар',
+ 'Enable' => 'Доступно',
+ 'Disable' => 'Отсутсвует',
+];
\ No newline at end of file
diff --git a/common/widgets/Alert.php b/common/widgets/Alert.php
new file mode 100755
index 0000000..5b5bbb2
--- /dev/null
+++ b/common/widgets/Alert.php
@@ -0,0 +1,79 @@
+session->setFlash('error', 'This is the message');
+ * \Yii::$app->session->setFlash('success', 'This is the message');
+ * \Yii::$app->session->setFlash('info', 'This is the message');
+ * ```
+ *
+ * Multiple messages could be set as follows:
+ *
+ * ```php
+ * \Yii::$app->session->setFlash('error', ['Error 1', 'Error 2']);
+ * ```
+ *
+ * @author Kartik Visweswaran
+ * @author Alexander Makarov
+ */
+class Alert extends \yii\bootstrap\Widget
+{
+ /**
+ * @var array the alert types configuration for the flash messages.
+ * This array is setup as $key => $value, where:
+ * - $key is the name of the session flash variable
+ * - $value is the bootstrap alert type (i.e. danger, success, info, warning)
+ */
+ public $alertTypes = [
+ 'error' => 'alert-danger',
+ 'danger' => 'alert-danger',
+ 'success' => 'alert-success',
+ 'info' => 'alert-info',
+ 'warning' => 'alert-warning'
+ ];
+
+ /**
+ * @var array the options for rendering the close button tag.
+ */
+ public $closeButton = [];
+
+ public function init()
+ {
+ parent::init();
+
+ $session = \Yii::$app->session;
+ $flashes = $session->getAllFlashes();
+ $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
+
+ foreach ($flashes as $type => $data) {
+ if (isset($this->alertTypes[$type])) {
+ $data = (array) $data;
+ foreach ($data as $i => $message) {
+ /* initialize css class for each alert box */
+ $this->options['class'] = $this->alertTypes[$type] . $appendCss;
+
+ /* assign unique id to each alert box */
+ $this->options['id'] = $this->getId() . '-' . $type . '-' . $i;
+
+ echo \yii\bootstrap\Alert::widget([
+ 'body' => $message,
+ 'closeButton' => $this->closeButton,
+ 'options' => $this->options,
+ ]);
+ }
+
+ $session->removeFlash($type);
+ }
+ }
+ }
+}
diff --git a/common/widgets/BasketHead.php b/common/widgets/BasketHead.php
new file mode 100755
index 0000000..79535cd
--- /dev/null
+++ b/common/widgets/BasketHead.php
@@ -0,0 +1,50 @@
+session->get('order');
+ unset($sessionData['order_id']);
+ $count = count($sessionData);
+ $price = 0;
+ if(is_array($sessionData) && !empty($sessionData)){
+
+ $variant = ProductVariant::find()->where(['product_variant_id'=>array_keys($sessionData)])->indexBy('product_variant_id')->all();
+
+
+ foreach ($sessionData as $k => $item) {
+ $sessionData[$k]['item'] = $variant[$k];
+ $price += $variant[$k]->price * $sessionData[$k]['num'];
+ }
+
+
+ return $this->render('basket_head',[
+ 'items'=>$sessionData,
+ 'count' => $count,
+ 'price' => $price
+ ]);
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/common/widgets/BasketModal.php b/common/widgets/BasketModal.php
new file mode 100755
index 0000000..8a30fa7
--- /dev/null
+++ b/common/widgets/BasketModal.php
@@ -0,0 +1,44 @@
+session->get('order');
+ unset($sessionData['order_id']);
+ $count = count($sessionData);
+ $price = 0;
+ if(is_array($sessionData) && !empty($sessionData)){
+
+ $variant = ProductVariant::find()->where(['product_variant_id'=>array_keys($sessionData)])->indexBy('product_variant_id')->all();
+
+
+ foreach ($sessionData as $k => $item) {
+ $sessionData[$k]['item'] = $variant[$k];
+ $price += $variant[$k]->price * $sessionData[$k]['num'];
+ }
+
+
+ return $this->render('basket_modal',[
+ 'items'=>$sessionData,
+ 'count' => $count,
+ 'price' => $price
+ ]);
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/common/widgets/FieldEditor.php b/common/widgets/FieldEditor.php
new file mode 100755
index 0000000..fcb7d04
--- /dev/null
+++ b/common/widgets/FieldEditor.php
@@ -0,0 +1,48 @@
+item_id && $this->model){
+ $widgetData = $this->findModel();
+ } else {
+ $widgetData= [new Fields()];
+ }
+
+ return $this->render($this->template.'_field',['model'=>ArrayHelper::toArray($widgetData)]);
+ }
+
+ protected function findModel()
+ {
+
+ if (($model = Fields::find()->where([
+ 'table_id'=>$this->item_id,
+ 'table_name'=>$this->model,
+ 'field_type'=>$this->template,
+ 'language'=>$this->language,
+ ])->all())) {
+
+ return $model;
+
+ } else {
+ return [new Fields()];
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/widgets/Mailer.php b/common/widgets/Mailer.php
new file mode 100755
index 0000000..497b8e7
--- /dev/null
+++ b/common/widgets/Mailer.php
@@ -0,0 +1,60 @@
+IsSMTP();
+ $mail->SMTPOptions = array(
+ 'ssl' => array(
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true
+ )
+ );
+ $mail->Host = "195.248.225.139";
+ $mail->SMTPDebug = true;
+ $mail->SMTPAuth = 0;
+ $mail->Port = 25;
+ $mail->CharSet = 'UTF-8';
+ $mail->Username = "";
+ $mail->Password = "";
+ $mail->SetFrom('Rukzachok.com.ua@gmail.com');
+ $mail->Subject = $this->subject;
+ $mail->MsgHTML($this->render($this->type, ['params' => $this->params]));
+ $address = "Rukzachok.com.ua@gmail.com";
+ $mail->AddAddress($address);
+ $mail->AddAddress($this->email);
+ if(!$mail->send()) {
+
+ \Yii::$app->getSession()->setFlash('error', 'Mailer Error: ' . $mail->ErrorInfo);
+
+ return 'Mailer Error: ' . $mail->ErrorInfo;
+ } else {
+
+
+ return 'Message has been sent';
+ }
+ }
+
+}
+
diff --git a/common/widgets/views/basket_head.php b/common/widgets/views/basket_head.php
new file mode 100755
index 0000000..6b6b021
--- /dev/null
+++ b/common/widgets/views/basket_head.php
@@ -0,0 +1,10 @@
+
+
+

+
+
= Yii::t('app','basket');?> = $count? Html::tag('span',$count,['class'=>'head_basket_count']) :'' ?>
+
+
+
diff --git a/common/widgets/views/basket_modal.php b/common/widgets/views/basket_modal.php
new file mode 100755
index 0000000..96265f0
--- /dev/null
+++ b/common/widgets/views/basket_modal.php
@@ -0,0 +1,53 @@
+
+
+
+
+
+ -
+
+
+
+ product->image)) :?>
+

+
+
![<?= $item['item']->product->image->alt ? $item['item']->product->image->alt : $item['item']->product->name?>](/images/<?= $item['item']->product->image->image?>)
+
+
+
+ =$item['item']->product->name.' '.$item['item']->name?>
+ = Yii::t('app', 'code', '45885-01016049')?>
+
+
+
+
= $item['item']->price * $item['num'] ?>грн.
+
+
+
+
+
+
+
+
+
= Yii::t('app','articles')?>: = $count ?>
+
= Yii::t('app','sum')?>: = $price ?> грн.
+
+
+ = Html::a(Yii::t('app','continue_shopping'),'#', ['class'=> 'close']) ?>
+ = Html::a(Yii::t('app','checkout'), ['orders/first'], ['class'=> 'button']);?>
+
+
diff --git a/common/widgets/views/comment_notify.php b/common/widgets/views/comment_notify.php
new file mode 100755
index 0000000..9ed6242
--- /dev/null
+++ b/common/widgets/views/comment_notify.php
@@ -0,0 +1,39 @@
+
+
+
+
+
+ Rukzachok.com.ua
+
+
+
+
+
Ваш коммертарий успешно опубликован.
+
Добрый день!
+
Ваш комментарий прошел модерацию и успешно опубликован.
+
= $params['comment']->text; ?>
+
Чтобы просмотреть комментарий перейдите по ссылке: Прочесть комментарий
+
+
+
\ No newline at end of file
diff --git a/common/widgets/views/education_field.php b/common/widgets/views/education_field.php
new file mode 100755
index 0000000..b24e544
--- /dev/null
+++ b/common/widgets/views/education_field.php
@@ -0,0 +1,83 @@
+
+
+
+
+
+
diff --git a/common/widgets/views/order.php b/common/widgets/views/order.php
new file mode 100755
index 0000000..fe7d6ec
--- /dev/null
+++ b/common/widgets/views/order.php
@@ -0,0 +1,127 @@
+
+
+
+
+
+ Rukzachok.com.ua
+
+
+
+
+
+
+
Добрый день, name ?>!
+ Ваш заказ получен. В ближайшее время с Вами свяжется менеджер для уточнения деталей
+
+
+
+
+ Заказ №id ?>
+
+
+ На сумму total ?> грн
+ |
+
+ Данные покупателя
+
+ name ?>
+
+ phone ?>
+
+ email ?>
+ |
+
+ Доставка
+
+ city ?>
+
+ adress ?>
+
+ |
+
+ Спасибо за покупку!
+
+
+ |
+
+
+
+
+
+ |
+ Название |
+ Количество |
+ Цена |
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+ ×
+ |
+
+ грн
+ |
+
+
+
+
+
+
+ Всего к оплате:
+ |
+
+ total) ?> грн
+ |
+
+
+
+ |
+
+
+
+

+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/common/widgets/views/password.php b/common/widgets/views/password.php
new file mode 100755
index 0000000..163a4b5
--- /dev/null
+++ b/common/widgets/views/password.php
@@ -0,0 +1,16 @@
+urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $params->password_reset_token]);
+?>
+
+
Hello = Html::encode($params->username) ?>,
+
+
Follow the link below to reset your password:
+
+
= Html::a(Html::encode($resetLink), $resetLink) ?>
+
+
\ No newline at end of file
diff --git a/common/widgets/views/registration.php b/common/widgets/views/registration.php
new file mode 100755
index 0000000..636cb3f
--- /dev/null
+++ b/common/widgets/views/registration.php
@@ -0,0 +1,51 @@
+= 'Спасибо за регистрацию '. $params['name']?>
+
+
+
+
+
+
+ Rukzachok.com.ua
+
+
+
+
+
+
+
Добрый день, = $params['name'] ?>!
+ Спасибо за регистрацию . Приятных покупок в магазине Rukzachok.com.ua
+
+
+

+
+
+
+
+
+
+
diff --git a/common/widgets/views/test.php b/common/widgets/views/test.php
new file mode 100755
index 0000000..41e1cee
--- /dev/null
+++ b/common/widgets/views/test.php
@@ -0,0 +1 @@
+H1
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100755
index 0000000..7a37378
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,66 @@
+{
+ "name": "yiisoft/yii2-app-advanced",
+ "description": "Yii 2 Advanced Project Template",
+ "keywords": ["yii2", "framework", "advanced", "project template"],
+ "homepage": "http://www.yiiframework.com/",
+ "type": "project",
+ "license": "BSD-3-Clause",
+ "support": {
+ "issues": "https://github.com/yiisoft/yii2/issues?state=open",
+ "forum": "http://www.yiiframework.com/forum/",
+ "wiki": "http://www.yiiframework.com/wiki/",
+ "irc": "irc://irc.freenode.net/yii",
+ "source": "https://github.com/yiisoft/yii2"
+ },
+ "minimum-stability": "dev",
+
+ "require": {
+ "php": ">=5.4.0",
+ "yiisoft/yii2": ">=2.0.6",
+ "yiisoft/yii2-bootstrap": "*",
+ "yiisoft/yii2-swiftmailer": "*",
+ "dmstr/yii2-adminlte-asset": "2.*",
+ "yiisoft/yii2-jui": "^2.0",
+ "kartik-v/yii2-widget-select2": "@dev",
+ "mihaildev/yii2-ckeditor": "*",
+ "developeruz/yii2-db-rbac": "*",
+ "nodge/yii2-eauth": "*",
+ "yiisoft/yii2-imagine": "^2.0",
+ "mihaildev/yii2-elfinder": "^1.1",
+ "kartik-v/yii2-widget-colorinput": "*",
+ "2amigos/yii2-transliterator-helper": "*",
+ "rmrevin/yii2-comments": "1.4.*",
+ "bower-asset/admin-lte": "*",
+ "FortAwesome/Font-Awesome": "*",
+ "kartik-v/yii2-widget-datepicker": "*",
+ "unclead/yii2-multiple-input": "~1.0",
+ "codeception/codeception":"*",
+ "phpmailer/phpmailer": "^5.2",
+ "kartik-v/yii2-grid": "@dev",
+ "kartik-v/yii2-mpdf": "@dev",
+ "kartik-v/yii2-widget-fileinput": "@dev",
+ "maxmirazh33/yii2-uploadable-cropable-image": "*",
+ "iutbay/yii2-imagecache": "*",
+ "yurkinx/yii2-image": "dev-master",
+ "cics/yii2-video-embed-widget": "dev-master",
+ "sersid/yii2-owl-carousel-asset": "*",
+ "wbraganca/yii2-dynamicform": "dev-master",
+ "kartik-v/yii2-widget-rating": "*"
+ },
+ "require-dev": {
+ "yiisoft/yii2-codeception": "*",
+ "yiisoft/yii2-debug": "*",
+ "yiisoft/yii2-gii": "*",
+ "yiisoft/yii2-faker": "*"
+ },
+ "config": {
+ "process-timeout": 1800
+ },
+ "extra": {
+ "asset-installer-paths": {
+ "npm-asset-library": "vendor/npm",
+ "bower-asset-library": "vendor/bower"
+ }
+ }
+}
+
diff --git a/console/config/.gitignore b/console/config/.gitignore
new file mode 100755
index 0000000..8ded784
--- /dev/null
+++ b/console/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
\ No newline at end of file
diff --git a/console/config/bootstrap.php b/console/config/bootstrap.php
new file mode 100755
index 0000000..5005cb3
--- /dev/null
+++ b/console/config/bootstrap.php
@@ -0,0 +1,9 @@
+ 'app-console',
+ 'basePath' => dirname(__DIR__),
+ 'bootstrap' => ['log'],
+ 'controllerNamespace' => 'console\controllers',
+ 'components' => [
+ 'log' => [
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
+ ],
+ ],
+ ],
+ ],
+ 'params' => $params,
+];
diff --git a/console/config/params.php b/console/config/params.php
new file mode 100755
index 0000000..4ee7a49
--- /dev/null
+++ b/console/config/params.php
@@ -0,0 +1,4 @@
+ 'admin@example.com',
+];
diff --git a/console/controllers/.gitkeep b/console/controllers/.gitkeep
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/console/controllers/.gitkeep
diff --git a/console/controllers/ImportController.php b/console/controllers/ImportController.php
new file mode 100755
index 0000000..776c8b9
--- /dev/null
+++ b/console/controllers/ImportController.php
@@ -0,0 +1,70 @@
+stderr('Task already executed');
+ return Controller::EXIT_CODE_ERROR;
+ }
+ return fopen ($filename, 'r');
+ }
+
+ public function actionProducts() {
+ if (file_exists(Yii::getAlias('@uploadDir/goProducts.lock'))) {
+ $this->errors[] = 'Task already executed';
+ return Controller::EXIT_CODE_ERROR;
+ }
+ $ff = fopen(Yii::getAlias('@uploadDir/goProducts.lock'), 'w+');
+ fclose($ff);
+ $model = new Import();
+ $model->goProducts(0, null);
+ unlink(Yii::getAlias('@uploadDir/goProducts.lock'));
+ return Controller::EXIT_CODE_NORMAL;
+ }
+
+ public function actionPrices() {
+ if (file_exists(Yii::getAlias('@uploadDir/goPrices.lock'))) {
+ $this->stderr('Task already executed');
+ return Controller::EXIT_CODE_ERROR;
+ }
+ $ff = fopen(Yii::getAlias('@uploadDir/goPrices.lock'), 'w+');
+ fclose($ff);
+ $model = new Import();
+ $data = $model->goPrices(0, null);
+ unlink(Yii::getAlias('@uploadDir/goPrices.lock'));
+ return Controller::EXIT_CODE_NORMAL;
+ }
+
+ private function saveNotFoundRecord (array $line, $filename)
+ {
+ $str = implode (';', $line)."\n";
+ $str = iconv ("UTF-8//TRANSLIT//IGNORE", "windows-1251", $str);
+
+ $fg = fopen (Yii::getAlias('@uploadDir') .'/'. $filename, 'a+');
+ fputs ($fg, $str);
+ fclose ($fg);
+ }
+}
\ No newline at end of file
diff --git a/console/controllers/RbacController.php b/console/controllers/RbacController.php
new file mode 100755
index 0000000..799002f
--- /dev/null
+++ b/console/controllers/RbacController.php
@@ -0,0 +1,46 @@
+authManager;
+
+ // add "createPost" permission
+ $createPost = $auth->createPermission('createPost');
+ $createPost->description = 'Create a post';
+ $auth->add($createPost);
+
+ // add "updatePost" permission
+ $updatePost = $auth->createPermission('updatePost');
+ $updatePost->description = 'Update post';
+ $auth->add($updatePost);
+
+// // add "author" role and give this role the "createPost" permission
+ $author = $auth->createRole('author');
+ $auth->add($author);
+ $auth->addChild($author, $createPost);
+//
+// // add "admin" role and give this role the "updatePost" permission
+// // as well as the permissions of the "author" role
+ $admin = $auth->createRole('admin');
+ $auth->add($admin);
+ $auth->addChild($admin, $updatePost);
+ $auth->addChild($admin, $author);
+//
+// // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()
+// // usually implemented in your User model.
+// $auth->assign($author, 2);
+// $auth->assign($admin, 1);
+
+
+ }
+}
+
+
+
diff --git a/console/migrations/m130524_201442_init.php b/console/migrations/m130524_201442_init.php
new file mode 100755
index 0000000..bb7e48a
--- /dev/null
+++ b/console/migrations/m130524_201442_init.php
@@ -0,0 +1,33 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+ $this->createTable('{{%user}}', [
+ 'id' => $this->primaryKey(),
+ 'username' => $this->string()->notNull()->unique(),
+ 'auth_key' => $this->string(32)->notNull(),
+ 'password_hash' => $this->string()->notNull(),
+ 'password_reset_token' => $this->string()->unique(),
+ 'email' => $this->string()->notNull()->unique(),
+
+ 'status' => $this->smallInteger()->notNull()->defaultValue(10),
+ 'created_at' => $this->integer()->notNull(),
+ 'updated_at' => $this->integer()->notNull(),
+ ], $tableOptions);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%user}}');
+ }
+}
diff --git a/console/migrations/m160126_071717_rubrication.php b/console/migrations/m160126_071717_rubrication.php
new file mode 100755
index 0000000..d88eb02
--- /dev/null
+++ b/console/migrations/m160126_071717_rubrication.php
@@ -0,0 +1,135 @@
+db->driverName === 'mysql') {
+ // Only for MySQL
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+
+ // @todo https://habrahabr.ru/post/138947/
+ } elseif ($this->db->driverName === 'pgsql') {
+ // Only for PostgreSQL
+ // @todo use intarray field for tax_options
+ }
+ $this->createTable('{{%tax_group}}', [
+ 'tax_group_id' => $this->primaryKey(),
+ 'alias' => $this->string(50)->notNull(),
+ 'name' => $this->string(255)->notNull(),
+ 'description' => $this->text(),
+ 'module' => $this->string(50)->notNull(),
+ 'hierarchical' => $this->boolean()->notNull()->defaultValue(false),
+ 'settings' => $this->text()
+ ], $tableOptions);
+
+ $this->createTable('{{%tax_option}}', [
+ 'tax_option_id' => $this->bigPrimaryKey(),
+ 'tax_group_id' => $this->integer()->notNull(),
+ 'parent_id' => $this->integer()->notNull()->defaultValue(0),
+ 'path' => $this->string(),
+ 'depth' => $this->integer(),
+ 'sort' => $this->integer()->notNull()->defaultValue(0),
+ 'default_value' => $this->integer(),
+ 'alias' => $this->string(50)->notNull()->defaultValue(''),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_option_tax_group_id', 'tax_option', 'tax_group_id', 'tax_group', 'tax_group_id', 'CASCADE', 'CASCADE');
+
+ $this->createTable('{{%tax_group_to_group}}', [
+ 'tax_group1_id' => $this->integer()->notNull(),
+ 'tax_group2_id' => $this->integer()->notNull(),
+ 'alias' => $this->string(50)->notNull(),
+ 'sort' => $this->integer(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_group_to_group1', 'tax_group_to_group', 'tax_group1_id', 'tax_group', 'tax_group_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('fki_tax_group_to_group2', 'tax_group_to_group', 'tax_group2_id', 'tax_group', 'tax_group_id', 'CASCADE', 'CASCADE');
+ $this->addPrimaryKey('pki_tax_group_to_group', 'tax_group_to_group', ['tax_group1_id', 'tax_group2_id', 'alias']);
+
+ $this->createTable('{{%tax_option_to_group}}', [
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'tax_group_id' => $this->integer()->notNull(),
+ 'alias' => $this->string(50)->notNull(),
+ 'sort' => $this->integer(),
+ ], $tableOptions);
+ $this->addForeignKey('tax_option_to_group_option_id', 'tax_option_to_group', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('tax_option_to_group_group_id', 'tax_option_to_group', 'tax_group_id', 'tax_group', 'tax_group_id', 'CASCADE', 'CASCADE');
+ $this->addPrimaryKey('pki_tax_option_to_group', 'tax_option_to_group', ['tax_option_id', 'tax_group_id', 'alias']);
+
+ $this->createTable('{{%tax_option_to_option}}', [
+ 'tax_option1_id' => $this->integer()->notNull(),
+ 'tax_option2_id' => $this->integer()->notNull(),
+ 'alias' => $this->string(50)->notNull(),
+ 'sort' => $this->integer(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_option_to_option1', 'tax_option_to_option', 'tax_option1_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('fki_tax_option_to_option2', 'tax_option_to_option', 'tax_option2_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+ $this->addPrimaryKey('pki_tax_option_to_option', 'tax_option_to_option', ['tax_option1_id', 'tax_option2_id', 'alias']);
+
+ /*$this->createTable('{{%tax_entity_relation}}', [
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'entity_id' => $this->integer()->notNull(),
+ 'entity_table_name' => $this->string(50)->notNull(),
+ 'entity_key_name' => $this->string(50)->notNull(),
+ 'alias' => $this->string(50)->notNull(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_entity_relation_option_id', 'tax_entity_relation', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+ $this->addPrimaryKey('pki_tax_entity_relation', 'tax_entity_relation', ['tax_option_id', 'entity_id', 'entity_table_name', 'entity_key_name', 'alias']);*/
+
+ $this->createTable('{{%tax_value_int}}', [
+ 'tax_value_id' => $this->primaryKey(),
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'value' => $this->integer(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_value_int_option_id', 'tax_value_int', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+
+ $this->createTable('{{%tax_value_string}}', [
+ 'tax_value_id' => $this->primaryKey(),
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'value' => $this->string(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_value_string_option_id', 'tax_value_string', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+
+ $this->createTable('{{%tax_value_text}}', [
+ 'tax_value_id' => $this->primaryKey(),
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'value' => $this->text(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_value_text_option_id', 'tax_value_text', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+
+ $this->createTable('{{%tax_value_float}}', [
+ 'tax_value_id' => $this->bigPrimaryKey(),
+ 'tax_option_id' => $this->integer()->notNull(),
+ 'value' => $this->float(),
+ ], $tableOptions);
+ $this->addForeignKey('fki_tax_value_float_option_id', 'tax_value_float', 'tax_option_id', 'tax_option', 'tax_option_id', 'CASCADE', 'CASCADE');
+ }
+
+ public function safeDown()
+ {
+ $this->dropTable('{{%tax_value_int}}');
+ $this->dropTable('{{%tax_value_string}}');
+ $this->dropTable('{{%tax_value_text}}');
+ $this->dropTable('{{%tax_value_float}}');
+// $this->dropTable('{{%tax_entity_relation}}');
+ $this->dropTable('{{%tax_group_to_group}}');
+ $this->dropTable('{{%tax_option_to_group}}');
+ $this->dropTable('{{%tax_option_to_option}}');
+ $this->dropTable('{{%tax_option}}');
+ $this->dropTable('{{%tax_group}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160128_101543_fields.php b/console/migrations/m160128_101543_fields.php
new file mode 100755
index 0000000..0c6b960
--- /dev/null
+++ b/console/migrations/m160128_101543_fields.php
@@ -0,0 +1,29 @@
+createTable('{{%fields}}', [
+ 'id' => $this->primaryKey(),
+ 'table_name' => $this->string(255)->notNull(),
+ 'table_id' => $this->integer(),
+ 'value' => $this->string(255),
+ 'field_name' => $this->string(),
+ 'field_type' => $this->string(32)->notNull(),
+ 'language' => $this->string(3),
+ 'key' => $this->integer(),
+ 'parent_key' => $this->integer()
+ ], $tableOptions);
+
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%fields}}');
+ }
+}
diff --git a/console/migrations/m160208_111900_blog.php b/console/migrations/m160208_111900_blog.php
new file mode 100755
index 0000000..12bcf1d
--- /dev/null
+++ b/console/migrations/m160208_111900_blog.php
@@ -0,0 +1,30 @@
+createTable('{{%blog}}', [
+ 'blog_id' => $this->primaryKey(),
+ 'user_id' => $this->integer()->notNull(),
+ 'name' => $this->string(255)->notNull(),
+ 'link' => $this->string(255),
+ 'date_add' => $this->timestamp()->notNull(),
+ 'user_add_id' => $this->integer(),
+ 'view_count' => $this->integer()->defaultValue(0),
+ 'description' => $this->text(),
+ 'cover' => $this->string(255),
+ ], $tableOptions);
+
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%blog}}');
+ }
+
+}
diff --git a/console/migrations/m160304_054017_realtion.php b/console/migrations/m160304_054017_realtion.php
new file mode 100755
index 0000000..f1fe66b
--- /dev/null
+++ b/console/migrations/m160304_054017_realtion.php
@@ -0,0 +1,44 @@
+db->driverName === 'mysql') {
+ // Only for MySQL
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+
+ // @todo https://habrahabr.ru/post/138947/
+ } elseif ($this->db->driverName === 'pgsql') {
+ // Only for PostgreSQL
+ // @todo use intarray field for tax_options
+ }
+ $this->createTable('{{%relation}}', [
+ 'alias' => $this->string(50)->notNull(),
+ 'entity1_id' => $this->integer()->notNull(),
+ 'entity2_id' => $this->integer()->notNull(),
+ ], $tableOptions);
+ $this->addPrimaryKey('relation_ukey', 'relation', ['alias', 'entity1_id', 'entity2_id']);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%relation}}');
+
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160304_065108_product.php b/console/migrations/m160304_065108_product.php
new file mode 100755
index 0000000..41a175c
--- /dev/null
+++ b/console/migrations/m160304_065108_product.php
@@ -0,0 +1,135 @@
+db->driverName === 'mysql') {
+ // Only for MySQL
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+
+ // @todo https://habrahabr.ru/post/138947/
+ } elseif ($this->db->driverName === 'pgsql') {
+ // Only for PostgreSQL
+ // @todo use intarray field for tax_options
+ }
+
+ $this->createTable('{{%category_name}}', [
+ 'category_name_id' => $this->primaryKey(),
+ 'category_id' => $this->integer()->notNull(),
+ 'value' => $this->string(250),
+ ], $tableOptions);
+
+ $this->createTable('{{%category}}', [
+ 'category_id' => $this->primaryKey(),
+ 'parent_id' => $this->integer()->notNull()->defaultValue(0),
+ 'path' => 'INT[]',
+ 'depth' => $this->integer()->notNull()->defaultValue(0),
+ 'alias' => $this->string(250),
+ 'image' => $this->string(255),
+ 'meta_title' => $this->string(255),
+ 'meta_desc' => $this->text(),
+ 'meta_robots' => $this->string(50),
+ 'seo_text' => $this->text(),
+ 'category_name_id' => $this->integer(),
+ 'product_unit_id' => $this->integer()
+ ], $tableOptions);
+
+ $this->addForeignKey('category_name_fkey', 'category', 'category_name_id', 'category_name', 'category_name_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('category_name_category_fkey', 'category_name', 'category_id', 'category', 'category_id', 'NO ACTION', 'NO ACTION');
+
+ $this->createTable('{{%product_category}}', [
+ 'product_id' => $this->integer()->notNull(),
+ 'category_id' => $this->integer()->notNull(),
+ ], $tableOptions);
+
+ $this->createTable('{{%brand_name}}', [
+ 'brand_name_id' => $this->primaryKey(),
+ 'brand_id' => $this->integer()->notNull(),
+ 'value' => $this->string(250),
+ ], $tableOptions);
+
+ $this->createTable('{{%brand}}', [
+ 'brand_id' => $this->primaryKey(),
+ 'brand_name_id' => $this->integer(),
+ 'alias' => $this->string(250),
+ 'image' => $this->string(255),
+ 'meta_title' => $this->string(255),
+ 'meta_desc' => $this->text(),
+ 'meta_robots' => $this->string(50),
+ 'seo_text' => $this->text(),
+ ], $tableOptions);
+
+ $this->addForeignKey('brand_name_fkey', 'brand', 'brand_name_id', 'brand_name', 'brand_name_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('brand_name_brand_fkey', 'brand_name', 'brand_id', 'brand', 'brand_id', 'NO ACTION', 'NO ACTION');
+
+ $this->createTable('{{%product}}', [
+ 'product_id' => $this->primaryKey(),
+ 'name' => $this->string(255)->notNull(),
+ 'alias' => $this->string(255),
+ 'brand_id' => $this->integer(),
+ 'description' => $this->text(),
+ 'video' => $this->text(),
+ ], $tableOptions);
+
+ $this->addForeignKey('fki_product_id', 'product_category', 'product_id', 'product', 'product_id', 'NO ACTION', 'NO ACTION');
+ $this->addForeignKey('fki_category_id', 'product_category', 'category_id', 'category', 'category_id', 'NO ACTION', 'NO ACTION');
+ $this->addForeignKey('fki_brand_id', 'product', 'brand_id', 'brand', 'brand_id', 'NO ACTION', 'CASCADE');
+
+ $this->createTable('{{%product_variant}}', [
+ 'product_variant_id' => $this->primaryKey(),
+ 'product_id' => $this->integer()->notNull(),
+ 'name' => $this->string(255)->notNull(),
+ 'sku' => $this->string(255)->notNull(),
+ 'price' => $this->float(),
+ 'price_old' => $this->float(),
+ 'stock' => $this->float(),
+ 'product_unit_id' => $this->integer()->notNull(),
+ ], $tableOptions);
+
+ $this->createTable('{{%product_unit}}', [
+ 'product_unit_id' => $this->primaryKey(),
+ 'name' => $this->string(255)->notNull(),
+ 'code' => $this->string(50)->notNull(),
+ 'is_default' => $this->boolean()
+ ], $tableOptions);
+//
+ $this->addForeignKey('product_variant_product_unit_fkey', 'product_variant', 'product_unit_id', 'product_unit', 'product_unit_id', 'CASCADE', 'NO ACTION');
+ $this->addForeignKey('category_product_unit_fkey', 'category', 'product_unit_id', 'product_unit', 'product_unit_id', 'NO ACTION', 'NO ACTION');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('category_name_fkey', 'category');
+ $this->dropForeignKey('category_name_category_fkey', 'category_name');
+ $this->dropForeignKey('brand_name_fkey', 'brand');
+ $this->dropForeignKey('brand_name_brand_fkey', 'brand_name');
+ $this->dropForeignKey('fki_product_id', 'product_category');
+ $this->dropForeignKey('fki_category_id', 'product_category');
+ $this->dropForeignKey('fki_brand_id', 'product');
+ $this->dropForeignKey('product_variant_product_unit_fkey', 'product_variant');
+ $this->dropForeignKey('category_product_unit_fkey', 'category');
+ $this->dropTable('{{%category}}');
+ $this->dropTable('{{%category_name}}');
+ $this->dropTable('{{%product_category}}');
+ $this->dropTable('{{%product}}');
+ $this->dropTable('{{%product_variant}}');
+ $this->dropTable('{{%product_unit}}');
+ $this->dropTable('{{%brand_name}}');
+ $this->dropTable('{{%brand}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160320_174258_customer.php b/console/migrations/m160320_174258_customer.php
new file mode 100755
index 0000000..172287b
--- /dev/null
+++ b/console/migrations/m160320_174258_customer.php
@@ -0,0 +1,35 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+ $this->createTable('{{%customers}}', [
+ 'id' => $this->primaryKey(),
+ 'username' => $this->string()->notNull(),
+ 'surname' => $this->string(),
+ 'auth_key' => $this->string(32)->notNull(),
+ 'password_hash' => $this->string()->notNull(),
+ 'password_reset_token' => $this->string()->unique(),
+ 'email' => $this->string()->notNull()->unique(),
+ 'phone' => $this->string()->notNull()->unique(),
+ 'status' => $this->smallInteger()->notNull()->defaultValue(10),
+ 'created_at' => $this->integer()->notNull(),
+ 'updated_at' => $this->integer()->notNull(),
+ ], $tableOptions);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%customers}}');
+ }
+
+}
diff --git a/console/migrations/m160321_232402_orders1.php b/console/migrations/m160321_232402_orders1.php
new file mode 100755
index 0000000..13e6251
--- /dev/null
+++ b/console/migrations/m160321_232402_orders1.php
@@ -0,0 +1,49 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+ $this->createTable('{{%orders}}', [
+ 'order_id' => $this->primaryKey(),
+ 'customer_id' => $this->integer(),
+ 'name' => $this->string()->notNull(),
+ 'email' => $this->string()->notNull(),
+ 'phone' => $this->string(32)->notNull(),
+ 'delivery' => $this->integer(),
+ 'payment' => $this->integer(),
+ 'code' => $this->string(),
+ 'status' => $this->smallInteger(),
+ 'created_at' => $this->integer()->notNull(),
+ 'updated_at' => $this->integer()->notNull(),
+ ], $tableOptions);
+
+ $this->createTable('{{%order_items}}', [
+ 'order_items_id' => $this->primaryKey(),
+ 'order_id' => $this->integer(),
+ 'item_id' => $this->integer(),
+ 'item_count' => $this->integer(),
+ 'price' => $this->float(),
+ ], $tableOptions);
+
+ $this->addForeignKey('orders_items_fk', '{{%order_items}}', 'order_id', '{{%orders}}', 'order_id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('orders_items_items_fk', '{{%order_items}}', 'item_id', '{{%product}}', 'product_id', 'RESTRICT', 'RESTRICT');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('orders_items_fk', '{{%order_items}}');
+ $this->dropForeignKey('orders_items_items_fk', '{{%order_items}}');
+ $this->dropTable('{{%orders}}');
+ $this->dropTable('{{%order_items}}');
+ }
+
+}
diff --git a/console/migrations/m160323_234304_product_image.php b/console/migrations/m160323_234304_product_image.php
new file mode 100755
index 0000000..9b5a4f0
--- /dev/null
+++ b/console/migrations/m160323_234304_product_image.php
@@ -0,0 +1,45 @@
+db->driverName === 'mysql') {
+ // Only for MySQL
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+
+ // @todo https://habrahabr.ru/post/138947/
+ } elseif ($this->db->driverName === 'pgsql') {
+ // Only for PostgreSQL
+ // @todo use intarray field for tax_options
+ }
+
+ $this->createTable('{{%product_image}}', [
+ 'product_image_id' => $this->integer()->notNull(),
+ 'product_id' => $this->integer()->notNull(),
+ 'image' => $this->string(255),
+ 'alt' => $this->string(255),
+ 'title' => $this->string(255),
+ ], $tableOptions);
+ $this->addForeignKey('product_image_product_fkey', 'product_image', 'product_id', 'product', 'product_id', 'CASCADE', 'CASCADE');
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%product_image}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160324_075409_product_option.php b/console/migrations/m160324_075409_product_option.php
new file mode 100755
index 0000000..54f0373
--- /dev/null
+++ b/console/migrations/m160324_075409_product_option.php
@@ -0,0 +1,44 @@
+db->driverName === 'mysql') {
+ // Only for MySQL
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+
+ // @todo https://habrahabr.ru/post/138947/
+ } elseif ($this->db->driverName === 'pgsql') {
+ // Only for PostgreSQL
+ // @todo use intarray field for tax_options
+ }
+
+ $this->createTable('{{%product_option}}', [
+ 'product_id' => $this->integer()->notNull(),
+ 'option_id' => $this->integer()->notNull(),
+ ], $tableOptions);
+ $this->addPrimaryKey('product_option_pkey', 'product_option', ['product_id', 'option_id']);
+ $this->addForeignKey('product_option_product_fkey', 'product_option', 'product_id', 'product', 'product_id', 'NO ACTION', 'NO ACTION');
+ $this->addForeignKey('product_option_option_fkey', 'product_option', 'option_id', 'tax_option', 'tax_option_id', 'NO ACTION', 'NO ACTION');
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%product_option}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160324_114404_orders_items_items_fk.php b/console/migrations/m160324_114404_orders_items_items_fk.php
new file mode 100755
index 0000000..997b0ae
--- /dev/null
+++ b/console/migrations/m160324_114404_orders_items_items_fk.php
@@ -0,0 +1,21 @@
+dropForeignKey('orders_items_items_fk', '{{%order_items}}');
+ $this->addForeignKey('orders_items_items_fk', '{{%order_items}}', 'item_id', '{{%product_variant}}', 'product_variant_id', 'RESTRICT', 'RESTRICT');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('orders_items_items_fk', '{{%order_items}}');
+ $this->addForeignKey('orders_items_items_fk', '{{%order_items}}', 'item_id', '{{%product}}', 'product_id', 'RESTRICT', 'RESTRICT');
+
+ }
+
+}
diff --git a/console/migrations/m160331_132149_slider.php b/console/migrations/m160331_132149_slider.php
new file mode 100755
index 0000000..8113dec
--- /dev/null
+++ b/console/migrations/m160331_132149_slider.php
@@ -0,0 +1,26 @@
+createTable('{{%slider}}', [
+ 'slider_id' => $this->primaryKey(),
+ 'speed' => $this->integer(4),
+ 'duration' => $this->integer(4),
+ 'title' => $this->string(200),
+ 'status' => $this->smallInteger(1),
+ 'width' => $this->integer(4),
+ 'height' => $this->integer(4),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%slider}}');
+ }
+
+
+}
diff --git a/console/migrations/m160404_081649_banner.php b/console/migrations/m160404_081649_banner.php
new file mode 100755
index 0000000..29a67a8
--- /dev/null
+++ b/console/migrations/m160404_081649_banner.php
@@ -0,0 +1,26 @@
+createTable('{{%banner}}', [
+ 'banner_id' => $this->primaryKey(),
+ 'image' => $this->string(255),
+ 'alt' => $this->string(255),
+ 'title' => $this->string(255),
+ 'url' => $this->string(255),
+ 'status' => $this->smallInteger(1),
+ 'width' => $this->integer(4),
+ 'height' => $this->integer(4),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%banner}}');
+ }
+
+}
diff --git a/console/migrations/m160405_101056_create_slider_images.php b/console/migrations/m160405_101056_create_slider_images.php
new file mode 100755
index 0000000..6259c3b
--- /dev/null
+++ b/console/migrations/m160405_101056_create_slider_images.php
@@ -0,0 +1,37 @@
+createTable('slider_image', [
+ 'slider_image_id' => $this->primaryKey(),
+ 'slider_id' => $this->integer(),
+ 'image' => $this->string(255),
+ 'alt' => $this->string(255),
+ 'title' => $this->string(255),
+ 'url' => $this->string(255),
+ 'status' => $this->smallInteger(1),
+ 'sort' => $this->integer(6),
+ 'price' => $this->float(),
+ ]);
+ $this->addForeignKey('slider_slider_image_fk', 'slider_image', 'slider_id', 'slider', 'slider_id', 'CASCADE', 'CASCADE');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropForeignKey('slider_slider_image_fk', '{{%slider_image}}');
+ $this->dropTable('slider_image');
+ }
+}
diff --git a/console/migrations/m160406_221846_create_page.php b/console/migrations/m160406_221846_create_page.php
new file mode 100755
index 0000000..230ba43
--- /dev/null
+++ b/console/migrations/m160406_221846_create_page.php
@@ -0,0 +1,48 @@
+createTable('page', [
+ 'id' => $this->primaryKey(),
+ 'name'=> $this->string(),
+ 'alias'=> $this->string(),
+ 'title' => $this->string(),
+ 'body'=> $this->text(),
+ 'meta_title'=> $this->string(),
+ 'description' => $this->string(),
+ 'h1'=> $this->string(),
+ 'seo_text'=> $this->text(),
+
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('page');
+ }
+}
diff --git a/console/migrations/m160407_185510_create_event.php b/console/migrations/m160407_185510_create_event.php
new file mode 100755
index 0000000..9d0973f
--- /dev/null
+++ b/console/migrations/m160407_185510_create_event.php
@@ -0,0 +1,38 @@
+createTable('event', [
+ 'event_id' => $this->primaryKey(),
+ 'name'=> $this->string(),
+ 'alias'=> $this->string(),
+ 'body'=> $this->text(),
+ 'image' => $this->string(),
+ 'meta_title'=> $this->string(),
+ 'description' => $this->string(),
+ 'h1'=> $this->string(),
+ 'seo_text'=> $this->text(),
+ 'created_at' => $this->integer(),
+ 'updated_at' => $this->integer(),
+ 'end_at' => $this->integer(),
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('event');
+ }
+}
diff --git a/console/migrations/m160411_211053_create_service.php b/console/migrations/m160411_211053_create_service.php
new file mode 100755
index 0000000..4097776
--- /dev/null
+++ b/console/migrations/m160411_211053_create_service.php
@@ -0,0 +1,37 @@
+createTable('service', [
+ 'service_id' => $this->primaryKey(),
+ 'name'=> $this->string()->notNull(),
+ 'alias'=> $this->string(),
+ 'body'=> $this->text()->notNull(),
+ 'image' => $this->string(),
+ 'meta_title'=> $this->string(),
+ 'description' => $this->string(),
+ 'h1'=> $this->string(),
+ 'seo_text'=> $this->text(),
+ 'created_at' => $this->integer(),
+ 'updated_at' => $this->integer(),
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('service');
+ }
+}
diff --git a/console/migrations/m160411_215739_create_seo.php b/console/migrations/m160411_215739_create_seo.php
new file mode 100755
index 0000000..713653f
--- /dev/null
+++ b/console/migrations/m160411_215739_create_seo.php
@@ -0,0 +1,33 @@
+createTable('seo', [
+ 'seo_id' => $this->primaryKey(),
+ 'url'=> $this->string()->notNull(),
+ 'title'=> $this->string(),
+ 'description' => $this->string(),
+ 'h1'=> $this->string(),
+ 'seo_text'=> $this->text(),
+
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('seo');
+ }
+}
diff --git a/console/migrations/m160412_133944_create_seo_category.php b/console/migrations/m160412_133944_create_seo_category.php
new file mode 100755
index 0000000..3145f2a
--- /dev/null
+++ b/console/migrations/m160412_133944_create_seo_category.php
@@ -0,0 +1,30 @@
+createTable('seo_category', [
+ 'seo_category_id' => $this->primaryKey(),
+ 'name' => $this->string(),
+ 'controller' => $this->string(100),
+ 'status' => $this->smallInteger(1),
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('seo_category');
+ }
+}
diff --git a/console/migrations/m160413_112158_create_seo_dynamic.php b/console/migrations/m160413_112158_create_seo_dynamic.php
new file mode 100755
index 0000000..41ce24e
--- /dev/null
+++ b/console/migrations/m160413_112158_create_seo_dynamic.php
@@ -0,0 +1,39 @@
+createTable('seo_dynamic', [
+ 'seo_dynamic_id' => $this->primaryKey(),
+ 'seo_category_id' => $this->integer(),
+ 'name' => $this->string(200),
+ 'action' => $this->string(200),
+ 'fields' => $this->string(),
+ 'title' => $this->string(),
+ 'h1' => $this->string(),
+ 'description' => $this->string(),
+ 'seo_text' => $this->text(),
+ 'status' => $this->smallInteger()
+ ]);
+
+ $this->addForeignKey('seo_category_seo_dynamic_fk', 'seo_dynamic', 'seo_category_id', 'seo_category', 'seo_category_id', 'CASCADE', 'CASCADE');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropForeignKey('seo_category_seo_dynamic_fk', '{{%seo_dynamic}}');
+ $this->dropTable('seo_dynamic');
+ }
+}
diff --git a/console/migrations/m160414_101644_add_param_to_seo_dynamic.php b/console/migrations/m160414_101644_add_param_to_seo_dynamic.php
new file mode 100755
index 0000000..59d896f
--- /dev/null
+++ b/console/migrations/m160414_101644_add_param_to_seo_dynamic.php
@@ -0,0 +1,26 @@
+addColumn('seo_dynamic', 'param', $this->string());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropColumn('seo_dynamic', 'param');
+ }
+}
diff --git a/console/migrations/m160414_214745_add_key_to_seo_dynamic.php b/console/migrations/m160414_214745_add_key_to_seo_dynamic.php
new file mode 100755
index 0000000..14780b1
--- /dev/null
+++ b/console/migrations/m160414_214745_add_key_to_seo_dynamic.php
@@ -0,0 +1,26 @@
+addColumn('seo_dynamic', 'key', $this->string());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropColumn('seo_dynamic', 'key');
+ }
+}
diff --git a/console/migrations/m160414_214746_add_level_to_tax_group.php b/console/migrations/m160414_214746_add_level_to_tax_group.php
new file mode 100755
index 0000000..a44ba08
--- /dev/null
+++ b/console/migrations/m160414_214746_add_level_to_tax_group.php
@@ -0,0 +1,26 @@
+addColumn('tax_group', 'level', $this->integer());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropColumn('tax_group', 'level');
+ }
+}
diff --git a/console/migrations/m160505_202248_bg.php b/console/migrations/m160505_202248_bg.php
new file mode 100755
index 0000000..99a5944
--- /dev/null
+++ b/console/migrations/m160505_202248_bg.php
@@ -0,0 +1,23 @@
+createTable('bg', [
+ 'id' => $this->primaryKey(),
+ 'title' => $this->string(250)->notNull(),
+ 'url' => $this->string(250)->notNull(),
+ 'image' => $this->string(250)->notNull(),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('bg');
+ }
+
+
+}
diff --git a/console/migrations/m160505_235100_page.php b/console/migrations/m160505_235100_page.php
new file mode 100755
index 0000000..689069e
--- /dev/null
+++ b/console/migrations/m160505_235100_page.php
@@ -0,0 +1,49 @@
+createTable('page', [
+ 'id' => $this->primaryKey(),
+ 'translit'=> $this->string(),
+ 'title'=> $this->string(),
+ 'body'=> $this->text(),
+ 'meta_title'=> $this->string(),
+ 'meta_keywords' => $this->string(),
+ 'meta_description'=> $this->string(),
+ 'seo_text'=> $this->text(),
+ 'h1'=> $this->string(),
+
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function down()
+ {
+ $this->dropTable('page');
+ }
+}
\ No newline at end of file
diff --git a/console/migrations/m160509_121023_articles.php b/console/migrations/m160509_121023_articles.php
new file mode 100755
index 0000000..de97e32
--- /dev/null
+++ b/console/migrations/m160509_121023_articles.php
@@ -0,0 +1,40 @@
+createTable('articles', [
+ 'id' => $this->primaryKey(),
+ 'date'=> $this->date(),
+ 'title'=> $this->string()->notNull(),
+ 'body'=> $this->text()->notNull(),
+ 'image'=> $this->string()->notNull(),
+ 'translit'=> $this->string()->notNull(),
+ 'meta_title'=> $this->string(),
+ 'meta_keywords' => $this->string(),
+ 'meta_description'=> $this->string(),
+ 'seo_text'=> $this->text(),
+ 'h1'=> $this->string(),
+
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('articles');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160509_214535_customer.php b/console/migrations/m160509_214535_customer.php
new file mode 100755
index 0000000..21066ab
--- /dev/null
+++ b/console/migrations/m160509_214535_customer.php
@@ -0,0 +1,44 @@
+createTable('{{%customer}}', [
+
+
+ 'id' => $this->primaryKey(),
+ 'username' => $this->string()->notNull(),
+ 'password' => $this->string()->notNull(),
+ 'name' => $this->string()->notNull(),
+ 'surname' => $this->string(),
+ 'phone' => $this->string(),
+ 'date_time' => $this->date()->defaultExpression('NOW()'),
+ 'sex' => $this->string(32),
+ 'birth_day' => $this->integer(),
+ 'birth_month' => $this->integer(),
+ 'birth_year' => $this->integer(),
+ 'body' => $this->text(),
+ 'group_id' => $this->integer(),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%customer}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160509_231345_auth_assignment.php b/console/migrations/m160509_231345_auth_assignment.php
new file mode 100755
index 0000000..737bff1
--- /dev/null
+++ b/console/migrations/m160509_231345_auth_assignment.php
@@ -0,0 +1,33 @@
+createTable('{{%auth_assignment}}', [
+
+
+ 'item_name' => $this->string(),
+ 'user_id' => $this->integer(),
+ 'created_at' => $this->integer(),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%auth_assignment}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160512_153443_subscribe.php b/console/migrations/m160512_153443_subscribe.php
new file mode 100755
index 0000000..2520be3
--- /dev/null
+++ b/console/migrations/m160512_153443_subscribe.php
@@ -0,0 +1,24 @@
+createTable('{{%subscribe}}', [
+
+
+ 'id' => $this->primaryKey(),
+ 'email' => $this->string()->notNull(),
+ 'sale' => $this->integer()->notNull(),
+ 'sand' => $this->smallInteger()->notNull()->defaultValue(0),
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%subscribe}}');
+ }
+
+}
diff --git a/console/migrations/m160516_222821_orders.php b/console/migrations/m160516_222821_orders.php
new file mode 100755
index 0000000..80bf1ab
--- /dev/null
+++ b/console/migrations/m160516_222821_orders.php
@@ -0,0 +1,72 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+
+ $this->createTable('{{%orders}}', [
+ 'id' => $this->primaryKey(),
+ 'user_id' => $this->integer(),
+ 'name' => $this->string()->notNull(),
+ 'surname' => $this->string()->notNull(),
+ 'patronymic' => $this->string()->notNull(),
+ 'phone' => $this->string(),
+ 'phone2' => $this->string(),
+ 'email' => $this->string(),
+ 'adress' => $this->string(),
+ 'body' => $this->text(),
+ 'total' => $this->float(),
+ 'date_time' => $this->dateTime(),
+ 'date_dedline' => $this->date(),
+ 'reserve' => $this->string(),
+ 'status' => $this->string(),
+ 'comment' => $this->text(),
+ 'label' => $this->integer(),
+ 'pay' => $this->integer(),
+ 'numbercard' => $this->integer(),
+ 'delivery' => $this->string(),
+ 'declaration' => $this->string(),
+ 'stock' => $this->string(),
+ 'consignment' => $this->string(),
+ 'payment' => $this->string(),
+ 'insurance' => $this->string(),
+ 'amount_imposed' => $this->float(),
+ 'shipping_by' => $this->string(),
+ 'city' => $this->string(),
+ ], $tableOptions);
+
+
+ $this->createTable('{{%orders_products}}', [
+ 'id' => $this->primaryKey(),
+ 'order_id' => $this->integer(),
+ 'mod_id' => $this->integer(),
+ 'product_name' => $this->string(),
+ 'name' => $this->string(),
+ 'sku' => $this->string(),
+ 'price' => $this->float(),
+ 'count' => $this->integer(),
+ 'sum_cost' => $this->float(),
+ ], $tableOptions);
+
+ $this->addForeignKey('orders_products_fk', '{{%orders_products}}', 'order_id', '{{%orders}}', 'id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('orders_products_items_fk', '{{%orders_products}}', 'id', '{{%product}}', 'product_id', 'RESTRICT', 'RESTRICT');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('orders_products_fk', '{{%orders_products}}');
+ $this->dropForeignKey('orders_products_items_fk', '{{%orders_products}}');
+ $this->dropTable('{{%orders}}');
+ $this->dropTable('{{%orders_products}}');
+ }
+
+}
\ No newline at end of file
diff --git a/console/migrations/m160516_234753_orders_delivery.php b/console/migrations/m160516_234753_orders_delivery.php
new file mode 100755
index 0000000..29cff5b
--- /dev/null
+++ b/console/migrations/m160516_234753_orders_delivery.php
@@ -0,0 +1,38 @@
+createTable('{{%orders_delivery}}', [
+ 'id' => $this->primaryKey(),
+ 'parent_id' => $this->integer(),
+ 'title' => $this->string(),
+ 'title_ukr' => $this->string(),
+ 'value' => $this->integer(),
+ 'text' => $this->text(),
+ 'text_ukr' => $this->text(),
+ 'sort' => $this->integer(),
+ ]);
+
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%orders_delivery}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160517_072059_delete_product_fk.php b/console/migrations/m160517_072059_delete_product_fk.php
new file mode 100755
index 0000000..28972f9
--- /dev/null
+++ b/console/migrations/m160517_072059_delete_product_fk.php
@@ -0,0 +1,30 @@
+dropForeignKey('orders_products_fk', '{{%orders_products}}');
+ $this->dropForeignKey('orders_products_items_fk', '{{%orders_products}}');
+ }
+
+ public function down()
+ {
+
+ $this->addForeignKey('orders_products_fk', '{{%orders_products}}', 'order_id', '{{%orders}}', 'id', 'CASCADE', 'CASCADE');
+ $this->addForeignKey('orders_products_items_fk', '{{%orders_products}}', 'id', '{{%product}}', 'product_id', 'RESTRICT', 'RESTRICT');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160517_073502_orders_label.php b/console/migrations/m160517_073502_orders_label.php
new file mode 100755
index 0000000..104048e
--- /dev/null
+++ b/console/migrations/m160517_073502_orders_label.php
@@ -0,0 +1,31 @@
+createTable('{{%orders_label}}', [
+ 'id' => $this->primaryKey(),
+ 'name' => $this->string(),
+ 'label' => $this->string()
+ ]);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%orders_label}}');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160518_185644_change_order.php b/console/migrations/m160518_185644_change_order.php
new file mode 100755
index 0000000..07dffdc
--- /dev/null
+++ b/console/migrations/m160518_185644_change_order.php
@@ -0,0 +1,29 @@
+dropColumn('orders', 'surname');
+ $this->dropColumn('orders', 'patronymic');
+ }
+
+ public function down()
+ {
+ $this->addColumn('orders', 'surname','string');
+ $this->addColumn('orders', 'patronymic','string');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160721_152001_create_product_to_rating.php b/console/migrations/m160721_152001_create_product_to_rating.php
new file mode 100755
index 0000000..5898e2f
--- /dev/null
+++ b/console/migrations/m160721_152001_create_product_to_rating.php
@@ -0,0 +1,23 @@
+createTable('product_to_rating', [
+ 'product_to_rating_id' => $this->primaryKey(),
+ 'product_id' => $this->integer()->notNull(),
+ 'value' => $this->float()->defaultValue(0),
+ ]);
+
+ $this->addForeignKey('product_to_rating_product', 'product_to_rating', 'product_id', 'product', 'product_id', 'CASCADE', 'CASCADE');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('product_to_rating_product', 'product_to_rating');
+ $this->dropTable('product_to_rating');
+ }
+}
diff --git a/console/migrations/m160722_150101_remove_product_option_option_fkey.php b/console/migrations/m160722_150101_remove_product_option_option_fkey.php
new file mode 100755
index 0000000..9f60d86
--- /dev/null
+++ b/console/migrations/m160722_150101_remove_product_option_option_fkey.php
@@ -0,0 +1,19 @@
+dropForeignKey('product_option_option_fkey', '{{%product_option}}');
+
+ }
+
+ public function down()
+ {
+ $this->addForeignKey('product_option_option_fkey', 'product_option', 'option_id', 'tax_option', 'tax_option_id', 'NO ACTION', 'NO ACTION');
+
+ }
+
+}
diff --git a/console/migrations/m160722_150611_remove_product_variant_option_id.php b/console/migrations/m160722_150611_remove_product_variant_option_id.php
new file mode 100755
index 0000000..babf023
--- /dev/null
+++ b/console/migrations/m160722_150611_remove_product_variant_option_id.php
@@ -0,0 +1,27 @@
+dropForeignKey('product_variant_option_id', '{{%product_variant_option}}');
+ }
+
+ public function down()
+ {
+ $this->addForeignKey('product_variant_option_id', 'product_variant_option', 'option_variant_id', 'tax_option', 'tax_option_id', 'NO ACTION', 'NO ACTION');
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160722_150612_remove_option_product_variant_id.php b/console/migrations/m160722_150612_remove_option_product_variant_id.php
new file mode 100755
index 0000000..213a477
--- /dev/null
+++ b/console/migrations/m160722_150612_remove_option_product_variant_id.php
@@ -0,0 +1,27 @@
+dropForeignKey('option_product_variant_id', '{{%product_variant_option}}');
+ }
+
+ public function down()
+ {
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160725_154511_remove_product_option_product_fkey.php b/console/migrations/m160725_154511_remove_product_option_product_fkey.php
new file mode 100755
index 0000000..c59c6bb
--- /dev/null
+++ b/console/migrations/m160725_154511_remove_product_option_product_fkey.php
@@ -0,0 +1,27 @@
+dropForeignKey('product_option_product_fkey', '{{%product_option}}');
+ }
+
+ public function down()
+ {
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160725_155127_remove_product_stock_product_variant_id_fkey.php b/console/migrations/m160725_155127_remove_product_stock_product_variant_id_fkey.php
new file mode 100755
index 0000000..40eb68f
--- /dev/null
+++ b/console/migrations/m160725_155127_remove_product_stock_product_variant_id_fkey.php
@@ -0,0 +1,27 @@
+dropForeignKey('product_stock_product_variant_id_fkey', '{{%product_stock}}');
+ }
+
+ public function down()
+ {
+ return false;
+ }
+
+ /*
+ // Use safeUp/safeDown to run migration code within a transaction
+ public function safeUp()
+ {
+ }
+
+ public function safeDown()
+ {
+ }
+ */
+}
diff --git a/console/migrations/m160804_100209_create_article_to_rating.php b/console/migrations/m160804_100209_create_article_to_rating.php
new file mode 100755
index 0000000..7d4ec15
--- /dev/null
+++ b/console/migrations/m160804_100209_create_article_to_rating.php
@@ -0,0 +1,23 @@
+createTable('article_to_rating', [
+ 'article_to_rating_id' => $this->primaryKey(),
+ 'articles_id' => $this->integer()->notNull(),
+ 'value' => $this->float()->defaultValue(0),
+ ]);
+
+ $this->addForeignKey('article_to_rating_article', 'article_to_rating', 'articles_id', 'articles', 'id', 'CASCADE', 'CASCADE');
+ }
+
+ public function down()
+ {
+ $this->dropForeignKey('article_to_rating_article', 'article_to_rating');
+ $this->dropTable('article_to_rating');
+ }
+}
diff --git a/console/migrations/m160810_074009_add_tax_option_sort.php b/console/migrations/m160810_074009_add_tax_option_sort.php
new file mode 100755
index 0000000..9adaf71
--- /dev/null
+++ b/console/migrations/m160810_074009_add_tax_option_sort.php
@@ -0,0 +1,16 @@
+addColumn('tax_group', 'sort', $this->integer()->defaultValue(0));
+ }
+
+ public function down()
+ {
+ $this->dropColumn('tax_group', 'sort');
+ }
+}
diff --git a/console/migrations/m160810_081231_add_tax_option_display.php b/console/migrations/m160810_081231_add_tax_option_display.php
new file mode 100755
index 0000000..e21c4fe
--- /dev/null
+++ b/console/migrations/m160810_081231_add_tax_option_display.php
@@ -0,0 +1,16 @@
+addColumn('tax_group', 'display', $this->boolean()->defaultValue(TRUE));
+ }
+
+ public function down()
+ {
+ $this->dropColumn('tax_group', 'display');
+ }
+}
diff --git a/console/models/.gitkeep b/console/models/.gitkeep
new file mode 100755
index 0000000..5e4debc
--- /dev/null
+++ b/console/models/.gitkeep
@@ -0,0 +1 @@
+*
diff --git a/console/runtime/.gitignore b/console/runtime/.gitignore
new file mode 100755
index 0000000..a3a0c8b
--- /dev/null
+++ b/console/runtime/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/environments/dev/backend/config/main-local.php b/environments/dev/backend/config/main-local.php
new file mode 100755
index 0000000..b909cc5
--- /dev/null
+++ b/environments/dev/backend/config/main-local.php
@@ -0,0 +1,25 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
+
+if (!YII_ENV_TEST) {
+ // configuration adjustments for 'dev' environment
+ $config['bootstrap'][] = 'debug';
+ $config['modules']['debug'] = [
+ 'class' => 'yii\debug\Module',
+ ];
+
+ $config['bootstrap'][] = 'gii';
+ $config['modules']['gii'] = [
+ 'class' => 'yii\gii\Module',
+ ];
+}
+
+return $config;
diff --git a/environments/dev/backend/config/params-local.php b/environments/dev/backend/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/dev/backend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/dev/backend/web/index.php b/environments/dev/backend/web/index.php
new file mode 100755
index 0000000..37d8378
--- /dev/null
+++ b/environments/dev/backend/web/index.php
@@ -0,0 +1,18 @@
+run();
diff --git a/environments/dev/common/config/main-local.php b/environments/dev/common/config/main-local.php
new file mode 100755
index 0000000..45d5ebb
--- /dev/null
+++ b/environments/dev/common/config/main-local.php
@@ -0,0 +1,20 @@
+ [
+ 'db' => [
+ 'class' => 'yii\db\Connection',
+ 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ],
+ 'mailer' => [
+ 'class' => 'yii\swiftmailer\Mailer',
+ 'viewPath' => '@common/mail',
+ // send all mails to a file by default. You have to set
+ // 'useFileTransport' to false and configure a transport
+ // for the mailer to send real emails.
+ 'useFileTransport' => true,
+ ],
+ ],
+];
diff --git a/environments/dev/common/config/params-local.php b/environments/dev/common/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/dev/common/config/params-local.php
@@ -0,0 +1,3 @@
+ ['gii'],
+ 'modules' => [
+ 'gii' => 'yii\gii\Module',
+ ],
+];
diff --git a/environments/dev/console/config/params-local.php b/environments/dev/console/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/dev/console/config/params-local.php
@@ -0,0 +1,3 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
+
+if (!YII_ENV_TEST) {
+ // configuration adjustments for 'dev' environment
+ $config['bootstrap'][] = 'debug';
+ $config['modules']['debug'] = [
+ 'class' => 'yii\debug\Module',
+ ];
+ $config['bootstrap'][] = 'gii';
+ $config['modules']['gii'] = [
+ 'class' => 'yii\gii\Module',
+ ];
+}
+
+return $config;
diff --git a/environments/dev/frontend/config/params-local.php b/environments/dev/frontend/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/dev/frontend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/dev/frontend/web/index.php b/environments/dev/frontend/web/index.php
new file mode 100755
index 0000000..37d8378
--- /dev/null
+++ b/environments/dev/frontend/web/index.php
@@ -0,0 +1,18 @@
+run();
diff --git a/environments/dev/yii b/environments/dev/yii
new file mode 100755
index 0000000..f3b4c13
--- /dev/null
+++ b/environments/dev/yii
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+run();
+exit($exitCode);
diff --git a/environments/index.php b/environments/index.php
new file mode 100755
index 0000000..286620b
--- /dev/null
+++ b/environments/index.php
@@ -0,0 +1,65 @@
+ [
+ * 'path' => 'directory storing the local files',
+ * 'skipFiles' => [
+ * // list of files that should only copied once and skipped if they already exist
+ * ],
+ * 'setWritable' => [
+ * // list of directories that should be set writable
+ * ],
+ * 'setExecutable' => [
+ * // list of files that should be set executable
+ * ],
+ * 'setCookieValidationKey' => [
+ * // list of config files that need to be inserted with automatically generated cookie validation keys
+ * ],
+ * 'createSymlink' => [
+ * // list of symlinks to be created. Keys are symlinks, and values are the targets.
+ * ],
+ * ],
+ * ];
+ * ```
+ */
+return [
+ 'Development' => [
+ 'path' => 'dev',
+ 'setWritable' => [
+ 'backend/runtime',
+ 'backend/web/assets',
+ 'frontend/runtime',
+ 'frontend/web/assets',
+ ],
+ 'setExecutable' => [
+ 'yii',
+ 'tests/codeception/bin/yii',
+ ],
+ 'setCookieValidationKey' => [
+ 'backend/config/main-local.php',
+ 'frontend/config/main-local.php',
+ ],
+ ],
+ 'Production' => [
+ 'path' => 'prod',
+ 'setWritable' => [
+ 'backend/runtime',
+ 'backend/web/assets',
+ 'frontend/runtime',
+ 'frontend/web/assets',
+ ],
+ 'setExecutable' => [
+ 'yii',
+ ],
+ 'setCookieValidationKey' => [
+ 'backend/config/main-local.php',
+ 'frontend/config/main-local.php',
+ ],
+ ],
+];
diff --git a/environments/prod/backend/config/main-local.php b/environments/prod/backend/config/main-local.php
new file mode 100755
index 0000000..d1c8993
--- /dev/null
+++ b/environments/prod/backend/config/main-local.php
@@ -0,0 +1,9 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
diff --git a/environments/prod/backend/config/params-local.php b/environments/prod/backend/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/prod/backend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/prod/common/config/main-local.php b/environments/prod/common/config/main-local.php
new file mode 100755
index 0000000..ea8ef35
--- /dev/null
+++ b/environments/prod/common/config/main-local.php
@@ -0,0 +1,16 @@
+ [
+ 'db' => [
+ 'class' => 'yii\db\Connection',
+ 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ],
+ 'mailer' => [
+ 'class' => 'yii\swiftmailer\Mailer',
+ 'viewPath' => '@common/mail',
+ ],
+ ],
+];
diff --git a/environments/prod/common/config/params-local.php b/environments/prod/common/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/prod/common/config/params-local.php
@@ -0,0 +1,3 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
diff --git a/environments/prod/frontend/config/params-local.php b/environments/prod/frontend/config/params-local.php
new file mode 100755
index 0000000..c1d2298
--- /dev/null
+++ b/environments/prod/frontend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/prod/yii b/environments/prod/yii
new file mode 100755
index 0000000..65c41d0
--- /dev/null
+++ b/environments/prod/yii
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+run();
+exit($exitCode);
diff --git a/frontend/assets/AppAsset.php b/frontend/assets/AppAsset.php
new file mode 100755
index 0000000..d1552ea
--- /dev/null
+++ b/frontend/assets/AppAsset.php
@@ -0,0 +1,38 @@
+
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+ public $basePath = '@webroot';
+ public $baseUrl = '@web';
+ public $css = [
+ 'css/style.css',
+ //'css/comments.css',
+ 'http://fonts.googleapis.com/css?family=Roboto',
+ ];
+ public $js = [
+ ];
+ public $depends = [
+ 'yii\web\JqueryAsset',
+ 'sersid\owlcarousel\Asset'
+ //'yii\web\YiiAsset',
+ //'yii\bootstrap\BootstrapAsset',
+ ];
+
+ public function init() {
+ $this->jsOptions['position'] = View::POS_END;
+ parent::init();
+ }
+}
diff --git a/frontend/assets/IeAsset.php b/frontend/assets/IeAsset.php
new file mode 100755
index 0000000..7ae917e
--- /dev/null
+++ b/frontend/assets/IeAsset.php
@@ -0,0 +1,26 @@
+
+ * @since 2.0
+ */
+class IeAsset extends AssetBundle
+{
+ public $basePath = '@webroot';
+ public $baseUrl = '@web';
+ public $cssOptions = ['condition' => 'lte IE9'];
+ public $css = [
+ 'css/ie.css'
+ ];
+
+
+}
diff --git a/frontend/components/BgWidget.php b/frontend/components/BgWidget.php
new file mode 100755
index 0000000..bf78691
--- /dev/null
+++ b/frontend/components/BgWidget.php
@@ -0,0 +1,30 @@
+getView();
+ $view->registerJs("
+ var heightR = $('.f').height();// высота экрана
+ var widthR = $(window).width();// ширина экрана
+
+ $('#bg').css({'height':heightR+100});
+ ", View::POS_READY, 'bg');
+ $this->bg = Bg::find()->orderBy('random()')->one();
+ }
+
+ public function run(){
+ return '
+';
+ }
+}
+?>
\ No newline at end of file
diff --git a/frontend/components/HreflangWidget.php b/frontend/components/HreflangWidget.php
new file mode 100755
index 0000000..eb7adf4
--- /dev/null
+++ b/frontend/components/HreflangWidget.php
@@ -0,0 +1,52 @@
+requestedRoute, '/')],
+ Yii::$app->request->getQueryParams(),
+ [
+ 'language' => $language,
+ ]
+ );
+ return Url::to($params);
+ }
+
+ public function run(){
+ //$lang = (Yii::$app->language=='ru') ? 'en' : 'ru';
+ $result = '';
+ foreach (Yii::$app->urlManager->languages as $language) {
+ if ($language === Yii::$app->language) {
+ // skip current language
+ continue;
+ }
+
+ $result.= Html::tag(
+ 'link',
+ '',
+ [
+ 'rel' => 'alternate',
+ 'hreflang' => $language,
+ 'href' => $this->translateCurrentRequest($language),
+ ]
+ );
+ }
+ return $result;
+ }
+}
+?>
\ No newline at end of file
diff --git a/frontend/components/SeoComponent.php b/frontend/components/SeoComponent.php
new file mode 100755
index 0000000..060641f
--- /dev/null
+++ b/frontend/components/SeoComponent.php
@@ -0,0 +1,37 @@
+request->isGet) {
+ \Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function($event) {
+ $array = ['%21'=>'!','%22'=>'"','%23'=>'#','%24'=>'$','%25'=>'%','%26'=>'&','%27'=>'\'','%28'=>'(','%29'=>')','%2a'=>'*','%2b'=>'+','%2c'=>',','%2d'=>'-','%2e'=>'.','%2f'=>'/','%3a'=>':','%3b'=>';','%3c'=>'<','%3d'=>'=','%3e'=>'>','%3f'=>'?','%40'=>'@','%5b'=>'[','%5c'=>'\\','%5d'=>']','%5e'=>'^','%5f'=>'_','%60'=>'`','%7b'=>'{','%7c'=>'|','%7d'=>'}','%7e'=>'~'];
+ $url = mb_strtolower (\Yii::$app->request->url);
+
+ $continue = true;
+
+ foreach($array as $sym=>$sym_row){
+ if(strpos($url, $sym)){
+ $url = str_replace($sym, $sym_row, $url);
+ $continue = false;
+
+ }
+ }
+
+ if(!$continue){
+ \Yii::$app->getResponse()->redirect($url);
+ }
+ });
+ }
+
+ return $app;
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/components/Text.php b/frontend/components/Text.php
new file mode 100755
index 0000000..1905d98
--- /dev/null
+++ b/frontend/components/Text.php
@@ -0,0 +1,16 @@
+$count)
+ {
+ //$pos = mb_strpos($text, ' ', $count, 'UTF-8');
+ $text = mb_substr($text, 0, $count, 'UTF-8');
+ return $text.'...';
+ }
+ else
+ return $text;
+ }
+}
\ No newline at end of file
diff --git a/frontend/config/.gitignore b/frontend/config/.gitignore
new file mode 100755
index 0000000..8ded784
--- /dev/null
+++ b/frontend/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
\ No newline at end of file
diff --git a/frontend/config/bootstrap.php b/frontend/config/bootstrap.php
new file mode 100755
index 0000000..6fd199e
--- /dev/null
+++ b/frontend/config/bootstrap.php
@@ -0,0 +1 @@
+ 'app-frontend',
+ 'basePath' => dirname(__DIR__),
+ 'bootstrap' => [
+
+ 'frontend\components\SeoComponent',
+ ],
+ 'controllerNamespace' => 'frontend\controllers',
+ 'modules' => [
+// 'comment' => [
+// 'class' => 'common\modules\comment\Module',
+// 'useRbac' => false,
+// 'rbac' => [
+// 'rules' => [
+// \common\modules\comment\rbac\ArtboxCommentCreateRule::className(),
+// \common\modules\comment\rbac\ArtboxCommentDeleteRule::className(),
+// \common\modules\comment\rbac\ArtboxCommentUpdateRule::className(),
+// \common\modules\comment\rbac\ArtboxCommentUpdateOwnRule::className(),
+// \common\modules\comment\rbac\ArtboxCommentDeleteOwnRule::className(),
+// ],
+// 'permissions' => [
+// [
+// 'name' => common\modules\comment\Permissions::CREATE,
+// 'description' => 'Can create comments',
+// 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentCreateRule())->name,
+// ],
+// [
+// 'name' => common\modules\comment\Permissions::UPDATE,
+// 'description' => 'Can update comments',
+// 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentUpdateRule())->name,
+// ],
+// [
+// 'name' => common\modules\comment\Permissions::DELETE,
+// 'description' => 'Can delete comments',
+// 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentDeleteRule())->name,
+// ],
+// [
+// 'name' => common\modules\comment\Permissions::UPDATE_OWN,
+// 'description' => 'Can update own comments',
+// 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentUpdateOwnRule())->name,
+// ],
+// [
+// 'name' => common\modules\comment\Permissions::DELETE_OWN,
+// 'description' => 'Can delete own comments',
+// 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentDeleteOwnRule())->name,
+// ],
+// ],
+// ],
+//
+// ],
+ ],
+ 'components' => [
+
+ 'authManager' => [
+ 'class' => 'yii\rbac\DbManager',
+ ],
+ 'user' => [
+ 'identityClass' => 'common\models\Customer',
+ 'enableAutoLogin' => true,
+ 'loginUrl' => ['login'],
+ ],
+ 'request'=>[
+ 'cookieValidationKey' => 'ndahjhjjidasuidrqeswuiuirqw89',
+ 'csrfParam' => '_frontendCSRF',
+ 'class' => 'common\components\Request',
+
+ 'web'=> '/frontend/web'
+
+ ],
+
+ 'log' => [
+ 'traceLevel' => YII_DEBUG ? 3 : 0,
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
+ ],
+ ],
+ ],
+ 'errorHandler' => [
+ 'errorAction' => 'site/error',
+ ],
+ /*'imageCache' => [
+ 'class' => 'iutbay\yii2imagecache\ImageCache',
+ 'sourcePath' => '@app/web/images',
+ 'sourceUrl' => '@web/images',
+ 'thumbsPath' => '@app/web/thumbs',
+ 'thumbsUrl' => '@web/thumbs',
+ 'resizeMode' => 'inset',
+ 'sizes' => [
+ 'brandlist' => [128, 128],
+ 'product' => [300, 300],
+ 'product_trumb' => [80, 80],
+ 'product_trumb2' => [100, 100],
+ 'list' => [134, 200],
+ 'product_list2' => [130, 70],
+ 'product_variant' => [42, 42],
+ 'mainmenu' => [160, 170],
+ 'large' => [600, 600],
+ ],
+ ],*/
+ 'urlManager' => [
+ 'enablePrettyUrl' => true,
+ 'showScriptName' => false,
+ 'rules' => [
+ '' => 'site/index',
+ 'login' => 'login/index',
+ 'iam' => 'iam/index',
+ 'text/' => 'text/index',
+ '/text/' => 'text/index',
+ [
+ 'class' => '\common\modules\product\CatalogUrlManager',
+ 'route_map' => [
+ 'catalog' => 'catalog/category',
+ 'product' => 'catalog/product',
+
+ ]
+ ],
+ 'priceparam.xml' => 'site/priceparam',
+ 'price.xml' => 'site/price',
+ 'smstest' => 'site/sms',
+ 'search' => 'search/index',
+// 'catalog' => 'catalog/all',
+// 'catalog/' => 'catalog/index',
+// 'products/search' => 'products/search',
+// 'products/compare' => 'products/compare',
+// 'products/' => 'products/index',
+// 'products//-' => 'products/show',
+ 'news/-' => 'news/show',
+ 'brands' => 'catalog/brands',
+ 'brands/' => 'catalog/brand',
+ 'blog' => 'articles/index',
+ 'blog/-' => 'articles/show',
+ 'event' => 'event/index',
+ 'event/-' => 'event/show',
+ '///' => '//',
+ '//' => '/',
+ '/admin' => 'admin/default/index',
+ '/admin/users' => 'admin/users/index',
+ 'thumbs/' => 'site/thumb',
+ ],
+
+ ],
+
+ ],
+ 'params' => $params,
+];
diff --git a/frontend/config/params.php b/frontend/config/params.php
new file mode 100755
index 0000000..4ee7a49
--- /dev/null
+++ b/frontend/config/params.php
@@ -0,0 +1,4 @@
+ 'admin@example.com',
+];
diff --git a/frontend/controllers/ArticlesController.php b/frontend/controllers/ArticlesController.php
new file mode 100755
index 0000000..c6645bf
--- /dev/null
+++ b/frontend/controllers/ArticlesController.php
@@ -0,0 +1,42 @@
+groupBy('id')->orderBy('id DESC') ;
+ $countQuery = clone $query;
+ $pages = new Pagination(['totalCount' => $countQuery->count(), 'pageSize'=>18]);
+ $pages->forcePageParam = false;
+ $pages->pageSizeParam = false;
+ $news = $query->offset($pages->offset)
+ ->with(['comments.rating', 'averageRating'])
+ ->limit($pages->limit)
+ ->all();
+
+ return $this->render('index', [
+ 'pages'=>$pages,
+ 'news'=>$news,
+ ]);
+ }
+
+ public function actionShow(){
+ if(!$news = Articles::find()->where(['id'=>$_GET['id']])->one())
+ throw new HttpException(404, 'Данной странице не существует!');
+
+ return $this->render('show', [
+ 'news'=>$news,
+ ]);
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/BasketController.php b/frontend/controllers/BasketController.php
new file mode 100755
index 0000000..ceeb021
--- /dev/null
+++ b/frontend/controllers/BasketController.php
@@ -0,0 +1,204 @@
+deleteBasketMod($_GET['deleteID']);
+ return Yii::$app->response->redirect(['basket/index']);
+ }
+
+ if(isset($_POST['update']) && isset($_POST['ProductVariant'])){
+
+ foreach ($_POST['ProductVariant'] as $index=>$row) {
+ $modelOrder->updateBasket($row);
+ }
+ }elseif(isset($_POST['ProductVariant'])){
+// die(print_r($_POST));
+ $body = '';
+ foreach ($_POST['ProductVariant'] as $index=>$row) {
+ $body .= $row['product_name'].' '.$row['name'].' Кол:'.$row['count'].' Цена:'.$row['sum_cost'];
+ $body .= "\n\r";
+ }
+ $body .= "\n\r";
+
+ if ($modelOrder->load(Yii::$app->request->post()) && $modelOrder->save()) {
+ $productV = $_POST['ProductVariant'];
+
+ foreach ($productV as $index=>$row) {
+ $modelOrdersProducts = new OrdersProducts();
+ $mod_id = $row['id'];
+
+ $data['OrdersProducts'] = $row;
+ $data['OrdersProducts']['mod_id'] = $mod_id;
+ $data['OrdersProducts']['order_id'] = $modelOrder->id;
+ $product = ProductVariant::findOne($mod_id);
+ /**
+ * Проверяем товар на наличие
+ */
+
+ if(!$product->stock > 0 || !$product->price > 0 ){
+
+ /**
+ * Добавляем сообщение об ошибке
+ */
+ \Yii::$app->getSession()->setFlash('error', 'К сожалению товара '.$product->name . ' нет в наличии');
+ /**
+ * Удаляем заказ
+ */
+ $modelOrder->delete();
+
+ $basket_mods = $modelOrder->getBasketMods();
+
+ return $this->render('index',[
+ 'modelMod'=>$modelMod,
+ 'basket_mods'=>$basket_mods,
+ 'modelOrder'=>$modelOrder,
+ ]);
+ }else {
+
+ /**
+ * Удаляем товар с массива и сохраняем в заказ
+ */
+ unset($row['id']);
+ $productV[$index]['img'] = \common\components\artboximage\ArtboxImageHelper::getImageSrc($product->image->imageUrl, 'list');
+ $modelOrdersProducts->load($data);
+ $modelOrdersProducts->validate();
+ $modelOrdersProducts->save();
+ }
+
+ }
+
+ /**
+ * Сохраняем заказ
+ */
+
+
+
+ if(!Yii::$app->user->id && !empty($modelOrder->email)){
+ $modelUser = new Customer();
+ $modelUser->role = 'person';
+ $modelUser->username = $modelOrder->email;
+ $modelUser->name = $modelOrder->name;
+ $modelUser->phone = $modelOrder->phone;
+ $modelUser->password = Yii::$app->getSecurity()->generateRandomString(10);
+ $modelUser->group_id = 2;
+ $modelUser->save();
+ }
+ $order = clone $modelOrder;
+ /**
+ * Чистим сессию корзины
+ */
+
+ $modelOrder->clearBasket();
+
+ Mailer::widget(
+ ['type' => 'order',
+ 'subject'=> 'Спасибо за покупку',
+ 'email' => $modelOrder->email,
+ 'params' => [
+ 'order' => $order,
+ 'variants' => $productV,
+ ]
+ ]);
+
+ $text = "# zakaz: ". $order->id .". V blijayshee vremya menedjer svyajetsya s Vami. (044) 303 90 15";
+ Yii::$app->sms->send($order->phone, $text);
+
+ Yii::$app->session['order_data']= ['order' => $order,'variants'=>$productV];
+
+ return $this->redirect(['basket/success',
+ ]);
+ }
+ }
+
+ $basket_mods = $modelOrder->getBasketMods();
+
+ if(!empty(Yii::$app->user->id)){
+ $user = Customer::findOne(Yii::$app->user->id);
+ $modelOrder->email = $user->username;
+ $modelOrder->phone = $user->phone;
+ $modelOrder->name = $user->name;
+ }
+
+
+
+ return $this->render('index', [
+ 'modelMod'=>$modelMod,
+ 'basket_mods'=>$basket_mods,
+ 'modelOrder'=>$modelOrder,
+ ]);
+ }
+
+ public function actionItems(){
+ $modelMod = new Orders;
+
+
+ if(!empty($_GET['deleteID'])){
+ $modelMod->deleteBasketMod($_GET['deleteID']);
+ }
+
+ if(isset($_POST['ProductVariant'])){
+ foreach ($_POST['ProductVariant'] as $index=>$row) {
+ $modelMod->updateBasket($row);
+ }
+ }
+ $basket_mods = $modelMod->getBasketMods();
+ return $this->renderAjax('ajax_items', [
+ 'modelMod'=>$modelMod,
+ 'basket_mods'=>$basket_mods,
+ ]);
+ }
+
+ public function actionInfo()
+ {
+ $modelMod = new Orders();
+ $info = $modelMod->rowBasket();
+ return $this->renderAjax('ajax_info', [
+ 'info'=>$info,
+ ]);
+ }
+
+ public function actionAdd(){
+ $modelOrders = new Orders();
+ if(isset($_GET['mod_id'],$_GET['count']) && $_GET['mod_id']>0 && $_GET['count']>0){
+ $modelOrders->addBasket($_GET['mod_id'],$_GET['count']);
+ }
+
+ Yii::$app->end();
+ }
+
+
+ public function actionSuccess(){
+
+ $orderData = Yii::$app->session->get('order_data');
+ unset($_SESSION['order_data']);
+ return $this->render('success',[
+
+ 'order' => $orderData['order'],
+ 'variants' => $orderData['variants'],
+ ]);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/CabinetController.php b/frontend/controllers/CabinetController.php
new file mode 100755
index 0000000..e60d215
--- /dev/null
+++ b/frontend/controllers/CabinetController.php
@@ -0,0 +1,100 @@
+ [
+ 'class' => AccessControl::className(),
+ 'rules' => [
+ [
+ 'actions' => ['login', 'error'],
+ 'allow' => true,
+ ],
+ [
+ 'actions' => ['logout', 'index', 'create', 'update', 'view', 'delete','my-orders','bookmarks'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+ public function actionIndex(){
+ return $this->render('index');
+ }
+
+ public function actionUpdate(){
+
+
+
+ $model = Yii::$app->user->identity;
+
+
+ if(Yii::$app->request->post()){
+
+ $model->load(Yii::$app->request->post());
+ $model->validate();
+
+ if($model->validate()){
+ $model->save();
+
+ }
+
+ }
+
+
+ return $this->render('update',[
+ 'model' =>$model
+ ]);
+ }
+
+
+ public function actionBookmarks(){
+ return $this->render('bookmarks',[
+
+ ]);
+ }
+
+ public function actionMyOrders(){
+ return $this->render('my-orders',[
+
+ ]);
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/CallController.php b/frontend/controllers/CallController.php
new file mode 100755
index 0000000..f38c460
--- /dev/null
+++ b/frontend/controllers/CallController.php
@@ -0,0 +1,33 @@
+load(Yii::$app->request->post()) && $model->contact('borisenko.pavel@gmail.com')) {
+
+ return Yii::$app->response->redirect(['call/success']);
+ }
+
+ return $this->render('index', [
+ 'model'=>$model,
+ ]);
+ }
+
+
+ public function actionSuccess(){
+ return $this->render('success');
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/CatalogController.php b/frontend/controllers/CatalogController.php
new file mode 100755
index 0000000..b34677e
--- /dev/null
+++ b/frontend/controllers/CatalogController.php
@@ -0,0 +1,229 @@
+request->get('category');
+ $filter = Yii::$app->request->get('filters', [ ]);
+ $filter_check = $filter;
+
+ if(empty( $category->category_id ) && empty( $word )) {
+ return $this->render('catalog');
+ }
+
+ ProductHelper::addLastCategory($category->category_id);
+
+ $params = [ ];
+
+ $optionsList = ArrayHelper::getColumn(TaxGroup::find()
+ ->where([ 'is_filter' => 'TRUE' ])
+ ->all(), 'alias');
+
+ if(!empty( $filter[ 'brands' ] )) {
+ unset( $filter_check[ 'brands' ] );
+ $brands = Brand::find()
+ ->select('brand_id')
+ ->where([
+ 'in',
+ 'alias',
+ $filter[ 'brands' ],
+ ])
+ ->all();
+ $params[ 'brands' ] = [ ];
+ foreach($brands as $brand) {
+ $params[ 'brands' ][] = $brand->brand_id;
+ }
+ }
+
+ if(!empty( $filter[ 'special' ] )) {
+ unset( $filter_check[ 'special' ] );
+ if(!is_array($filter[ 'special' ])) {
+ $filter[ 'special' ] = [ $filter[ 'special' ] ];
+ }
+ if(in_array('new', $filter[ 'special' ])) {
+ $params[ 'special' ][ 'is_new' ] = true;
+ }
+ if(in_array('top', $filter[ 'special' ])) {
+ $params[ 'special' ][ 'is_top' ] = true;
+ }
+ if(in_array('promo', $filter[ 'special' ])) {
+ $params[ 'special' ][ 'akciya' ] = true;
+ }
+ }
+
+ if(!empty( $filter[ 'prices' ] )) {
+ unset( $filter_check[ 'prices' ] );
+ $params[ 'prices' ] = $filter[ 'prices' ];
+ }
+
+ foreach($optionsList as $optionList) {
+
+ if(isset( $filter[ $optionList ] )) {
+ unset( $filter_check[ $optionList ] );
+ $params[ $optionList ] = $filter[ $optionList ];
+ }
+
+ }
+
+ if(!empty( $filter_check )) {
+ $filter = array_diff_key($filter, $filter_check);
+ Yii::$app->response->redirect([
+ 'catalog/category',
+ 'category' => $category,
+ 'filters' => $filter,
+ ], 301);
+ }
+
+ $productModel = new ProductFrontendSearch();
+ //$productQuery = $productModel->getSearchQuery($category, $params);
+ $productProvider = $productModel->search($category, $params);
+
+ $brandModel = new BrandSearch();
+ $brands = $brandModel->getBrands($category, $params)
+ ->all();
+ // Old filters
+ // $optionsQuery = $productModel->optionsForCategory($category, $params);
+ // $groups = [];
+ //
+ //
+ // foreach ($optionsQuery->all() as $option) {
+ // if (!isset($groups[$option->tax_group_id])) {
+ // $groups[$option->tax_group_id] = $option->taxGroup;
+ // $groups[$option->tax_group_id]->_options = [];
+ // }
+ // $groups[$option->tax_group_id]->_options[] = $option;
+ // }
+ // foreach($groups as $i => $group) {
+ // if (empty($group->_options))
+ // unset($groups[$i]);
+ // }
+ // New filters
+ $groups = $category->getActiveFilters()->all();
+ $groups = ArrayHelper::index($groups, null, 'name');
+
+ $priceLimits = $productModel->priceLimits($category, $params);
+
+ /*
+ * Greedy search for comments and rating
+ */
+ $query = $productProvider->query;
+ $query->with([
+ 'comments',
+ 'averageRating',
+ ]);
+ /*
+ * End of greedy search for rating and comments
+ */
+
+ return $this->render('products', [
+ 'category' => $category,
+ 'brandModel' => $brandModel,
+ 'brands' => $brands,
+ 'filter' => $filter,
+ 'params' => $params,
+ 'productModel' => $productModel,
+ 'productProvider' => $productProvider,
+ 'groups' => $groups,
+ 'priceLimits' => $priceLimits,
+ ]);
+
+ }
+
+ public function actionProduct()
+ {
+ /** @var Product $product */
+ $product = Yii::$app->request->get('product');
+
+ if(!$product->enabledVariant) {
+ throw new HttpException(404, 'Товар не найден');
+ }
+
+ ProductHelper::addLastProsucts($product->product_id);
+
+ $category = null;
+ $last_category_id = ProductHelper::getLastCategory();
+ if(!empty($last_category_id)) {
+ $category = $product->getCategory()->andWhere(['category_id' => $last_category_id])->one();
+ }
+ if(empty($category)) {
+ $category = $product->category;
+ }
+
+ return $this->render('product', [
+ 'product' => $product,
+ 'category' => $category,
+ ]);
+ }
+
+ public function actionBrands()
+ {
+ $dataProvider = new ActiveDataProvider([
+ 'query' => Brand::find()
+ ->joinWith('brandName')
+ ->orderBy('brand_name.value'),
+ 'pagination' => [
+ 'pageSize' => -1,
+ ],
+ ]);
+
+ return $this->render('brands', [
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ public function actionBrand($brand)
+ {
+ $brand = BrandSearch::findByAlias($brand);
+
+ $params = [
+ 'brands' => $brand->brand_id,
+ ];
+
+ $productModel = new ProductFrontendSearch();
+ $productProvider = $productModel->search(NULL, $params);
+
+ $priceLimits = $productModel->priceLimits(NULL, $params);
+
+ return $this->render('brand', [
+ 'productModel' => $productModel,
+ 'productProvider' => $productProvider,
+ 'brand' => $brand,
+ 'priceLimits' => $priceLimits,
+ ]);
+ }
+
+ }
diff --git a/frontend/controllers/EventController.php b/frontend/controllers/EventController.php
new file mode 100755
index 0000000..db7a575
--- /dev/null
+++ b/frontend/controllers/EventController.php
@@ -0,0 +1,48 @@
+ Event::find() ]);
+
+ return $this->render('index', [
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+
+
+ public function actionShow($alias)
+ {
+
+ return $this->render('show', [
+ 'model' => $this->findModel($alias),
+ ]);
+ }
+
+
+ protected function findModel($alias)
+ {
+ if (($model = Event::findOne(["alias"=>$alias])) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/IamController.php b/frontend/controllers/IamController.php
new file mode 100755
index 0000000..552ff00
--- /dev/null
+++ b/frontend/controllers/IamController.php
@@ -0,0 +1,161 @@
+ [
+ 'class' => AccessControl::className(),
+ //'only' => ['person'],
+ 'rules' => [
+ [
+ 'actions' => ['index','edit','myorders','show_order','share','price'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+
+ public function actionIndex()
+ {
+ return $this->render(Yii::$app->user->identity->role, [
+ 'model' => Yii::$app->user->identity,
+ ]);
+ }
+
+ public function actionEdit()
+ {
+
+
+ $model = User::findOne(Yii::$app->user->id);
+
+ $model->scenario = 'edit_'.Yii::$app->user->identity->role;
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+
+ return Yii::$app->response->redirect(['/iam/index']);
+
+
+ }
+
+ return $this->render('edit_'.Yii::$app->user->identity->role, [
+ 'model' => $model,
+ ]);
+ }
+
+ public function actionMyorders(){
+
+
+ $model = Orders::find()->where(['user_id'=>Yii::$app->user->id])->orderBy('id DESC')->all();
+
+ return $this->render('myorders',['model'=>$model]);
+
+ }
+
+ public function actionShow_order()
+ {
+ $model = Orders::findOne($_GET['id']);
+
+
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => OrdersProducts::find()->where(['order_id'=>$_GET['id']]),
+ 'pagination' => [
+ 'pageSize' => 20,
+ ],
+ ]);
+ return $this->render('show_order',['model'=>$model,'dataProvider'=>$dataProvider]);
+ }
+
+ public function actionShare(){
+ if(Yii::$app->request->get('id')) {
+ if(!$model = Share::find()->where('user_id=:user_id and product_id=:product_id',[':user_id'=>Yii::$app->user->id,':product_id'=>$_GET['id']])->one())
+ $model = new Share;
+
+ $model->product_id = Yii::$app->request->get('id');
+ $model->save();
+
+ Yii::$app->getSession()->setFlash('success', 'Этот товар добавлен в закладку!');
+ return $this->redirect(Yii::$app->request->referrer);
+ }
+ else {
+ /* $dataProvider = new ActiveDataProvider([
+ 'query' => Share::find()->where(['user_id'=>Yii::$app->user->id])->orderBy('date_time DESC'),
+ 'pagination' => [
+ 'pageSize' => 20,
+ ],
+ ]);*/
+ if(Yii::$app->request->get('deleteID')) {
+ $model = Share::find()->where(['user_id'=>Yii::$app->user->id,'id'=>Yii::$app->request->get('deleteID')])->one();
+ $model->delete();
+ return $this->redirect(Yii::$app->request->referrer);
+ }
+
+ $items = [];
+ foreach(Share::find()->where(['user_id' => Yii::$app->user->id])->all() as $item) {
+ $items[$item->date][] = $item;
+ }
+
+ /* $query = Share::find()->where(['user_id'=>Yii::$app->user->id])->groupBy('date')->orderBy('date DESC');
+ $countQuery = clone $query;
+ $pages = new Pagination(['totalCount' => $countQuery->count(), 'pageSize'=>20]);
+ $pages->forcePageParam = false;
+ $pages->pageSizeParam = false;
+ $share = $query->offset($pages->offset)
+ ->limit($pages->limit)
+ ->all();*/
+ return $this->render('share', ['items' => $items]);
+ }
+ }
+
+
+ public function actionPrice(){
+ if(!empty($_GET['id'])){
+ if(!$model = Price::find()->where('user_id=:user_id and product_id=:product_id',[':user_id'=>Yii::$app->user->id,':product_id'=>$_GET['id']])->one())
+ $model = new Price;
+
+ $model->product_id = $_GET['id'];
+ $model->save();
+
+ Yii::$app->getSession()->setFlash('success', 'Этот товар добавлен в закладку Узнать о снижение цены!');
+ return $this->redirect(Yii::$app->request->referrer);
+ }
+ else{
+ $dataProvider = new ActiveDataProvider([
+ 'query' => Price::find()->where(['user_id'=>Yii::$app->user->id])->orderBy('date_time DESC'),
+ 'pagination' => [
+ 'pageSize' => 20,
+ ],
+ ]);
+ return $this->render('price',['dataProvider'=>$dataProvider]);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/LoginController.php b/frontend/controllers/LoginController.php
new file mode 100755
index 0000000..0304395
--- /dev/null
+++ b/frontend/controllers/LoginController.php
@@ -0,0 +1,50 @@
+user->isGuest) {
+ return $this->goHome();
+ }
+
+ $model = new LoginForm();
+ if ($model->load(Yii::$app->request->post()) && $model->login()) {
+ return $this->goBack();
+ } else {
+ return $this->render('index', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ public function actionLogout()
+ {
+ Yii::$app->user->logout();
+
+ return $this->goHome();
+ }
+
+ public function actionForgot(){
+
+ $model = new Customer;
+ if(!empty($_POST['User']['username'])){
+ if($user = Customer::find()->where(['username'=>$_POST['User']['username']])->one())
+ $user->sendMsg();
+ Yii::$app->getSession()->setFlash('success', 'На указанный Вами эмейл отправленно письмо с паролем!');
+ return $this->refresh();
+ }
+
+ return $this->render('forgot', [
+ 'model' => $model,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/frontend/controllers/NewsController.php b/frontend/controllers/NewsController.php
new file mode 100755
index 0000000..dfc4a04
--- /dev/null
+++ b/frontend/controllers/NewsController.php
@@ -0,0 +1,41 @@
+orderBy('id DESC') ;
+ $countQuery = clone $query;
+ $pages = new Pagination(['totalCount' => $countQuery->count(), 'pageSize'=>18]);
+ $pages->forcePageParam = false;
+ $pages->pageSizeParam = false;
+ $news = $query->offset($pages->offset)
+ ->limit($pages->limit)
+ ->all();
+
+ return $this->render('index', [
+ 'pages'=>$pages,
+ 'news'=>$news,
+ ]);
+ }
+
+ public function actionShow(){
+ if(!$news = News::find()->where(['id'=>$_GET['id']])->one())
+ throw new HttpException(404, 'Данной странице не существует!');
+
+ return $this->render('show', [
+ 'news'=>$news,
+ ]);
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/PageController.php b/frontend/controllers/PageController.php
new file mode 100755
index 0000000..a65088a
--- /dev/null
+++ b/frontend/controllers/PageController.php
@@ -0,0 +1,20 @@
+getPageTranslit($translit))
+ throw new \Exception(404,'The requested page does not exist.');
+ return $this->render('show',['page'=>$page]);
+ }
+}
\ No newline at end of file
diff --git a/frontend/controllers/PostController.php b/frontend/controllers/PostController.php
new file mode 100755
index 0000000..8935ca7
--- /dev/null
+++ b/frontend/controllers/PostController.php
@@ -0,0 +1,20 @@
+ 55]);
+ }
+
+ public function actionView($id)
+ {
+ return 'actionView:'. $id;
+ }
+
+}
diff --git a/frontend/controllers/ProductsController.php b/frontend/controllers/ProductsController.php
new file mode 100755
index 0000000..56e1ff5
--- /dev/null
+++ b/frontend/controllers/ProductsController.php
@@ -0,0 +1,154 @@
+load ($_POST);
+ if (! $catalog = Catalog::find ()->where (['translit' => $_GET['translit']])->with ('parent')->one ())
+ throw new HttpException(404, 'Данной странице не существует!');
+ $query = Products::find ()->where ('catalog_id=:catalog_id OR catalog_parent_id=:catalog_parent_id', [':catalog_id' => $catalog->id, ':catalog_parent_id' => $catalog->id])->with (['catalog'])->innerJoinWith (['cost']);
+ if (! empty($_POST['Products']['minCost']) && ! empty($_POST['Products']['maxCost'])) $query->andWhere ('(cost>=:minCost and cost<=:maxCost)', [':minCost' => $_POST['Products']['minCost'], ':maxCost' => $_POST['Products']['maxCost']]);
+ if (! empty($_GET['brends']))
+ {
+ $b = explode (';', $_GET['brends']);
+ $query->andWhere (['brend_id' => $b]);
+ }
+ if (! empty($_GET['filters']))
+ {
+ $l = explode (';', $_GET['filters']);
+ $items = Filters::find ()->where (['parent_id' => 0])->all ();
+ foreach ($items as $key => $it)
+ {
+ $f = [];
+ foreach ($it->childs as $c)
+ {
+ if (in_array ($c['id'], $l)) $f[] = $c['id'];
+ }
+ if (count ($f) > 0)
+ $query->innerJoin ('productsFilters as filter_' . $key, 'filter_' . $key . '.product_id=products.id')->andWhere (['filter_' . $key . '.filter_id' => $f]);
+ // $childs->leftJoin('productsFilters as pf_'.$key, 'pf_'.$key.'.product_id = productsFilters.product_id')->andWhere(['pf_'.$key.'.filter_id'=>$f]);
+ }
+ }
+ if (! empty($modelProducts->fasovka))
+ {
+ $query->innerJoinWith (['fasovka'])->andWhere ([ProductsFasovka::tableName () . '.fasovka_id' => $modelProducts->fasovka]);
+ }
+ if (! empty($modelProducts->type))
+ {
+ $query->innerJoinWith (['type'])->andWhere ([ProductsType::tableName () . '.type_id' => $modelProducts->type]);
+ }
+ if (! empty($modelProducts->brends))
+ {
+ $query->innerJoinWith (['brends'])->andWhere ([ProductsBrends::tableName () . '.brend_id' => $modelProducts->brends]);
+ }
+ $query->groupBy (['id']);
+ $countQuery = clone $query;
+ $pages = new Pagination(['totalCount' => $countQuery->count (), 'pageSize' => 15]);
+ $pages->forcePageParam = false;
+ $pages->pageSizeParam = false;
+ $products = $query->offset ($pages->offset)
+ ->limit ($pages->limit)
+ ->all ();
+
+ return $this->render ('index', [
+ 'modelProducts' => $modelProducts,
+ 'catalog' => $catalog,
+ 'pages' => $pages,
+ 'products' => $products,
+ ]);
+ }
+
+ public function actionSearch ()
+ {
+ $query = Products::find ()->innerJoinWith (['catalog'])->innerJoinWith (['cost'])->innerJoinWith (['brend']);
+ if (! empty($_GET['search_str']))
+ {
+ $query->andWhere (['like', 'products.name', $_GET['search_str']]);
+ $query->orWhere (['like', 'catalog.name', $_GET['search_str']]);
+ $query->orWhere (['like', 'catalog_brends.name', $_GET['search_str']]);
+ $query->orWhere (['like', 'mod.art', $_GET['search_str']]);
+ }
+ $query->groupBy (['id']);
+ $countQuery = clone $query;
+ $pages = new Pagination(['totalCount' => $countQuery->count (), 'pageSize' => 20]);
+ $pages->forcePageParam = false;
+ $pages->pageSizeParam = false;
+ $products = $query->offset ($pages->offset)
+ ->limit ($pages->limit)
+ ->all ();
+
+ return $this->render ('search', [
+ 'pages' => $pages,
+ 'products' => $products,
+ ]);
+ }
+
+ public function actionShow ()
+ {
+ if (! $catalog = Catalog::find ()->where (['translit' => $_GET['translit_rubric']])->with ('parent')->one ())
+ throw new HttpException(404, 'Данной странице не существует!');
+ if (! $product = Products::find ()->where (['id' => $_GET['id']])->one ())
+ throw new HttpException(404, 'Данной странице не существует!');
+ ViewProduct::add ($product->id);
+
+ return $this->render ('show', [
+ 'catalog' => $catalog,
+ 'product' => $product,
+ ]);
+ }
+
+ public function actionCompare ()
+ {
+ $session = new Session;
+ $session->open ();
+ if (! empty($_GET['id']))
+ {
+ $i = 0;
+ if (isset($session['compare']))
+ {
+ foreach ($session['compare'] as $key => $compare)
+ {
+ if ($_GET['id'] == $compare)
+ {
+ $i++;
+ }
+ }
+ }
+ if ($i == 0)
+ {
+ $data[] = $_GET['id'];
+ $session['compare'] = $data;
+ }
+ Yii::$app->getSession ()->setFlash ('success', 'Этот товар добавлен к сравнению!');
+
+ return $this->redirect (Yii::$app->request->referrer);
+ }
+ else
+ {
+ //print_r($session['compare']);
+ $products = Products::find ()->where (['id' => $session['compare']])->all ();
+
+ return $this->render ('compare', [
+ 'products' => $products,
+ ]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/controllers/RegController.php b/frontend/controllers/RegController.php
new file mode 100755
index 0000000..5d9a599
--- /dev/null
+++ b/frontend/controllers/RegController.php
@@ -0,0 +1,88 @@
+ [
+ 'class' => AccessControl::className(),
+ //'only' => ['person'],
+ 'rules' => [
+ [
+ 'actions' => ['person','captcha'],
+ 'allow' => true,
+ 'roles' => ['?'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+ public function actions()
+ {
+ return [
+ 'captcha' => [
+ 'class' => 'yii\captcha\CaptchaAction',
+ ],
+ ];
+ }
+
+ private function saveUser($scenario = null){
+
+ $model = (!empty($_GET['id'])) ? Customer::findOne($_GET['id']) : new Customer;
+ if(!empty($scenario))$model->scenario = $scenario;
+
+ if ($model->load(Yii::$app->request->post())) {
+ $model->role = "person";
+ $model->group_id = 1;
+ $model->save();
+ $modelLogin = new LoginForm();
+ $modelLogin->username = $model->username;
+ $modelLogin->password = $model->password;
+ $modelLogin->login();
+ Mailer::widget(
+ ['type' => 'registration',
+ 'subject'=> 'Спасибо за регистрацию',
+ 'email' => $model->username,
+ 'params' => [
+ 'name' => $model->username,
+ 'pass' => $model->password,
+ ]
+ ]);
+ $this->redirect(['/iam']);
+ }
+
+ return $model;
+ }
+
+ public function actionPerson()
+ {
+
+ $model = $this->saveUser('person');
+
+ return $this->render('person', [
+ 'model' => $model,
+ ]);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/SearchController.php b/frontend/controllers/SearchController.php
new file mode 100755
index 0000000..a60e80c
--- /dev/null
+++ b/frontend/controllers/SearchController.php
@@ -0,0 +1,76 @@
+request->get('word', ''));
+
+ if (!empty($word))
+ {
+
+
+ if( preg_match('/^\+?\d+$/', $word) && (iconv_strlen($word) > 4)){
+
+ $params['keywords'][] = $word;
+
+ $categoriesQuery = Category::find()
+ ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.category_id = '. Category::tableName() .'.category_id')
+ ->innerJoin(Product::tableName(), Product::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id')
+ ->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id');
+ $categoriesQuery->andWhere(['ilike', 'product.name', $params['keywords'][0]]);
+ $categories = $categoriesQuery->all();
+
+ } else {
+
+ $params['keywords'] = explode(' ', preg_replace("|[\s,.!:&?~();-]|i", " ", $word));
+
+ foreach($params['keywords'] as $i => &$keyword) {
+ $keyword = trim($keyword);
+ if (empty($keyword)) {
+ unset($params['keywords'][$i]);
+ }
+ }
+ array_unshift($params['keywords'], $word);
+
+ $categoriesQuery = Category::find()
+ ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.category_id = '. Category::tableName() .'.category_id')
+ ->innerJoin(Product::tableName(), Product::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id')
+ ->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id');
+ foreach ($params['keywords'] as $keyword) {
+ $categoriesQuery->andWhere(['ilike', 'product.name', $keyword]);
+ }
+ $categoriesQuery->andWhere(['!=', ProductVariant::tableName() .'.stock', 0]);
+ $categories = $categoriesQuery->all();
+ }
+
+ $productModel = new ProductFrontendSearch();
+ $productProvider = $productModel->search(null, $params);
+
+
+ return $this->render(
+ 'index',
+ [
+ 'keywords' => $params['keywords'],
+ 'productModel' => $productModel,
+ 'productProvider' => $productProvider,
+ 'categories' => $categories,
+ ]
+ );
+ }
+ else
+ {
+ throw new HttpException(404, 'Данной странице не существует!');
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/controllers/ServiceController.php b/frontend/controllers/ServiceController.php
new file mode 100755
index 0000000..1b50bf2
--- /dev/null
+++ b/frontend/controllers/ServiceController.php
@@ -0,0 +1,48 @@
+ Service::find() ]);
+
+ return $this->render('index', [
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+
+
+ public function actionView($alias)
+ {
+
+ return $this->render('view', [
+ 'model' => $this->findModel($alias),
+ ]);
+ }
+
+
+ protected function findModel($alias)
+ {
+ if (($model = Service::findOne(["alias"=>$alias])) !== null) {
+ return $model;
+ } else {
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/SiteController.php b/frontend/controllers/SiteController.php
new file mode 100755
index 0000000..e8f0ef6
--- /dev/null
+++ b/frontend/controllers/SiteController.php
@@ -0,0 +1,193 @@
+ 'iutbay\yii2imagecache\ThumbAction',
+ ];
+ }
+
+ public function actionIndex()
+ {
+
+ $modelText = Page::find()->where(['translit'=>'home'])->one();
+
+ return $this->render('index', [
+ 'text'=>$modelText,
+
+ ]);
+ }
+
+
+ public function actionRobots()
+ {
+
+ $file = file_get_contents(robotsTxt, true);//получаем его содержимое
+ return $this->renderPartial('robots', [
+
+ ]);
+ }
+
+ public function actionError(){
+
+ return $this->render('error', [
+ 'code'=>'404',
+// 'message'=>Yii::$app->errorHandler->exception->getMessage(),
+ ]);
+ }
+
+ public function actionPriceparam ()
+ {
+ $category_alias = Yii::$app->request->get('category');
+ $is_count = Yii::$app->request->get('count', false);
+
+ if ( !($category = CategorySearch::findByAlias($category_alias)))
+ {
+ throw new HttpException(404, 'Данной страницы не существует!');
+ }
+
+ $products = $category->products;
+
+ if ($is_count) {
+ print (count($products));
+ exit;
+ }
+
+ set_time_limit (0);
+ header ("Content-Type: text/xml");
+ print '';
+ print "";
+ print "" . date ("Y-m-d h:m") . "";
+ print "Rukzachok";
+ print "";
+ print "";
+ print "";
+
+ print "";
+ print "" . $category->category_id . "";
+ print "";
+ print "" . $category->name . "";
+ print "";
+
+
+ print "";
+ print "";
+ /** @var Product $product */
+ foreach ($products as $product) {
+ /** @var ProductVariant $variant */
+ foreach ($product->enabledVariants as $variant) {
+
+ print "- ";
+ print "" . htmlspecialchars($variant->product_variant_id) . "";
+ print "" . htmlspecialchars($product->category->category_id) . "";
+ print "" . $product->brand->name . "";
+ print "
" . htmlspecialchars($variant->sku) . "
";
+ print "" . htmlspecialchars(substr($category->name, 0, -2)) . " ";
+ print "" . htmlspecialchars($product->name) . " ";
+ print "" . $variant->name . " ";
+ print "" . htmlspecialchars($product->description) . "";
+ print "http://rukzachok.com.ua{$product->url}#{$variant->product_variant_id}";
+ print "http://rukzachok.com.ua{$variant->imageUrl}";
+ print "" . $variant->price . "";
+ print "" . $variant->price_old . "";
+ print "";
+ print "В наличии";
+ print "";
+ print " ";
+ }
+ }
+ print "";
+
+ print "";
+ }
+
+ public function actionPrice()
+ {
+ $category_alias = Yii::$app->request->get('category');
+ $is_count = Yii::$app->request->get('count', false);
+
+ if ( !($category = CategorySearch::findByAlias($category_alias)))
+ {
+ throw new HttpException(404, 'Данной страницы не существует!');
+ }
+
+ $products = $category->products;
+
+ if ($is_count) {
+ print (count($products));
+ exit;
+ }
+
+
+//var_dump($products);die();
+ set_time_limit (0);
+ header ("Content-Type: text/xml");
+ print '';
+ print "";
+ print "" . date ("Y-m-d h:m") . "";
+ print "Rukzachok";
+ print "";
+ print "";
+ print "";
+
+ print "";
+ print "" . $category->category_id . "";
+ print "";
+ print "" . $category->name . "";
+ print "";
+
+ print "";
+ print "";
+ /** @var Product $product */
+ foreach ($products as $product)
+ {
+ /** @var ProductVariant $variant */
+ foreach ($product->enabledVariants as $variant) {
+
+ print "- ";
+ print "" . htmlspecialchars($variant->product_variant_id) . "";
+ print "" . htmlspecialchars($product->category->category_id) . "";
+ print "" . $product->brand->name . "";
+ print "
" . htmlspecialchars($variant->sku) . "
";
+ print "" . htmlspecialchars($product->name)." " .htmlspecialchars($variant->name). " ";
+ print "" . htmlspecialchars($product->description) . "";
+ print "http://rukzachok.com.ua{$product->url}#{$variant->product_variant_id}";
+ print "http://rukzachok.com.ua{$variant->imageUrl}";
+ print "" . $variant->price . "";
+ print "" . $variant->price_old . "";
+ print "";
+ print "В наличии";
+ print "";
+ print " ";
+
+ }
+ }
+
+
+ print "";
+
+ print "";
+
+
+ }
+
+
+}
diff --git a/frontend/controllers/SubscribeController.php b/frontend/controllers/SubscribeController.php
new file mode 100755
index 0000000..51aab8c
--- /dev/null
+++ b/frontend/controllers/SubscribeController.php
@@ -0,0 +1,34 @@
+request->isAjax) {
+ Yii::$app->response->format = Response::FORMAT_JSON;
+ $model->load(Yii::$app->request->post());
+ return ActiveForm::validate($model);
+ } else {
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+
+ Yii::$app->getSession()->setFlash('success', 'Вы успешно подписались на рассылку!');
+ return $this->refresh();
+ }
+ }
+
+ return $this->render('index',['model'=>$model]);
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/TextController.php b/frontend/controllers/TextController.php
new file mode 100755
index 0000000..34e83bf
--- /dev/null
+++ b/frontend/controllers/TextController.php
@@ -0,0 +1,24 @@
+where(['translit'=>$_GET['translit']])->one())
+ throw new HttpException(404, 'Данной странице не существует!');
+
+ return $this->render('index', [
+ 'text'=>$modelText,
+ ]);
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/controllers/error_log b/frontend/controllers/error_log
new file mode 100755
index 0000000..e13edb0
--- /dev/null
+++ b/frontend/controllers/error_log
@@ -0,0 +1 @@
+[23-Mar-2015 04:22:39 UTC] PHP Fatal error: Class 'yii\web\Controller' not found in /home/webplusn/public_html/yii2/controllers/SiteController.php on line 14
diff --git a/frontend/helpers/TextHelper.php b/frontend/helpers/TextHelper.php
new file mode 100755
index 0000000..c247f64
--- /dev/null
+++ b/frontend/helpers/TextHelper.php
@@ -0,0 +1,24 @@
+')
+ {
+ if ($asHtml) {
+ return static::truncateHtml($string, $length, $suffix, $encoding ?: Yii::$app->charset);
+ }
+
+ if (mb_strlen($string, $encoding ?: Yii::$app->charset) > $length) {
+ return strip_tags(trim(mb_substr($string, 0, $length, $encoding ?: Yii::$app->charset)) . $suffix, $html);
+ } else {
+ return strip_tags($string, $html);
+ }
+
+
+ }
+}
diff --git a/frontend/models/ContactForm.php b/frontend/models/ContactForm.php
new file mode 100755
index 0000000..845de8e
--- /dev/null
+++ b/frontend/models/ContactForm.php
@@ -0,0 +1,59 @@
+ 'Verification Code',
+ ];
+ }
+
+ /**
+ * Sends an email to the specified email address using the information collected by this model.
+ *
+ * @param string $email the target email address
+ * @return boolean whether the email was sent
+ */
+ public function sendEmail($email)
+ {
+ return Yii::$app->mailer->compose()
+ ->setTo($email)
+ ->setFrom([$this->email => $this->name])
+ ->setSubject($this->subject)
+ ->setTextBody($this->body)
+ ->send();
+ }
+}
diff --git a/frontend/models/LoginForm.php b/frontend/models/LoginForm.php
new file mode 100755
index 0000000..c7e7d6e
--- /dev/null
+++ b/frontend/models/LoginForm.php
@@ -0,0 +1,89 @@
+'Логин',
+ 'password'=>'Пароль',
+ 'rememberMe'=>'Запомнить',
+ ];
+ }
+
+ /**
+ * Validates the password.
+ * This method serves as the inline validation for password.
+ *
+ * @param string $attribute the attribute currently being validated
+ * @param array $params the additional name-value pairs given in the rule
+ */
+ public function validatePassword($attribute, $params)
+ {
+ if (!$this->hasErrors()) {
+ $user = $this->getUser();
+
+ if (!$user || !$user->validatePassword($this->password)) {
+ $this->addError($attribute, 'Incorrect username or password.');
+ }
+ }
+ }
+
+ /**
+ * Logs in a user using the provided username and password.
+ * @return boolean whether the user is logged in successfully
+ */
+ public function login()
+ {
+ if ($this->validate()) {
+ return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Finds user by [[username]]
+ *
+ * @return Customer|null
+ */
+ public function getUser()
+ {
+ if ($this->_user === false) {
+ $this->_user = Customer::findByUsername($this->username);
+ }
+
+ return $this->_user;
+ }
+}
diff --git a/frontend/models/PasswordResetRequestForm.php b/frontend/models/PasswordResetRequestForm.php
new file mode 100755
index 0000000..fb239c1
--- /dev/null
+++ b/frontend/models/PasswordResetRequestForm.php
@@ -0,0 +1,68 @@
+ 'trim'],
+ ['email', 'required'],
+ ['email', 'email'],
+ ['email', 'exist',
+ 'targetClass' => '\common\models\User',
+ 'filter' => ['status' => User::STATUS_ACTIVE],
+ 'message' => 'There is no user with such email.'
+ ],
+ ];
+ }
+
+ /**
+ * Sends an email with a link, for resetting the password.
+ *
+ * @return boolean whether the email was send
+ */
+ public function sendEmail()
+ {
+ /* @var $user User */
+ $user = User::findOne([
+ 'status' => User::STATUS_ACTIVE,
+ 'email' => $this->email,
+ ]);
+
+ if (!$user) {
+ return false;
+ }
+
+ if (!User::isPasswordResetTokenValid($user->password_reset_token)) {
+ $user->generatePasswordResetToken();
+ }
+
+ if (!$user->save()) {
+ return false;
+ }
+
+ return Yii::$app
+ ->mailer
+ ->compose(
+ ['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'],
+ ['user' => $user]
+ )
+ ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
+ ->setTo($this->email)
+ ->setSubject('Password reset for ' . \Yii::$app->name)
+ ->send();
+ }
+}
diff --git a/frontend/models/ProductFrontendSearch.php b/frontend/models/ProductFrontendSearch.php
new file mode 100755
index 0000000..2f9bc9a
--- /dev/null
+++ b/frontend/models/ProductFrontendSearch.php
@@ -0,0 +1,185 @@
+ $this->getSearchQuery($category, $params),
+ 'pagination' => [
+ 'pageSize' => 16,
+ ],
+ 'sort' => [
+ 'attributes' => [
+ 'name' => [
+ 'asc' => ['name' => SORT_ASC],
+ 'desc' => ['name' => SORT_DESC],
+ 'default' => SORT_DESC,
+ 'label' => 'имени',
+ ],
+ 'price' => [
+ 'asc' => [ProductVariant::tableName() .'.price' => SORT_ASC],
+ 'desc' => [ProductVariant::tableName() .'.price' => SORT_DESC],
+ 'default' => SORT_DESC,
+ 'label' => 'по цене',
+ ],
+ ],
+ ]
+ ]);
+
+ if (!$this->validate()) {
+ return $dataProvider;
+ }
+
+
+
+ return $dataProvider;
+ }
+
+ public function getSearchQuery($category = null, $params = []) {
+ if (!empty($category)) {
+ /** @var ActiveQuery $query */
+// $query = $category->getRelations('product_categories');
+ $query = $category->getProducts();
+ } else {
+ $query = Product::find();
+ }
+ $query->select(['product.*']);
+ $query->joinWith(['enabledVariants','brand', 'brand.brandName', 'category', 'category.categoryName']);
+
+ $query->groupBy(['product.product_id', 'product_variant.price']);
+
+ ProductHelper::_setQueryParams($query, $params);
+
+ $query->andWhere(['!=', ProductVariant::tableName() .'.stock', 0]);
+
+ return $query;
+ }
+
+ public function optionsForCategory($category = null, $params = []) {
+ $query = TaxOption::find()
+ ->select([
+ TaxOption::tableName() .'.*',
+ ])
+ ->leftJoin(ProductOption::tableName(), ProductOption::tableName() .'.option_id='. TaxOption::tableName() .'.tax_option_id')
+ ->joinWith('taxGroup')
+ ->where([TaxGroup::tableName() .'.is_filter' => true]);
+
+ $query->innerJoin('product_variant', 'product_variant.product_id = '. ProductOption::tableName() .'.product_id');
+ $query->andWhere(['!=', 'product_variant.stock', 0]);
+ $query->groupBy(TaxOption::tableName() .'.tax_option_id');
+// $query->having(['>', 'COUNT(product_variant.product_variant_id)', 0]);
+
+ if (!empty($category)) {
+ $query->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.product_id='. ProductOption::tableName() .'.product_id');
+ $query->andWhere([ProductCategory::tableName() .'.category_id' => $category->category_id]);
+ }
+
+ $query->orderBy(TaxOption::tableName() .'.sort', SORT_ASC);
+ $query->limit(null);
+
+// $queryCount = ProductOption::find()
+// ->select(['COUNT('. ProductOption::tableName() .'.product_id)'])
+// ->where(ProductOption::tableName() .'.option_id = '. TaxOption::tableName() .'.tax_option_id');
+// $queryCount->andWhere('(SELECT COUNT(pv.product_variant_id) FROM "product_variant" "pv" WHERE pv.stock != 0 AND pv.product_id = '. ProductOption::tableName() .'.product_id) > 0');
+// if (!empty($category)) {
+// $queryCount->andWhere('(SELECT COUNT(pc.product_id) FROM product_category pc WHERE pc.product_id = '. ProductOption::tableName() .'.product_id AND pc.category_id = '. $category->category_id .') > 0');
+// }
+// if (!empty($params['options'])) {
+// $queryCount->innerJoin('tax_option', 'tax_option.tax_option_id = product_option.option_id');
+// $queryCount->innerJoin('tax_group', 'tax_group.tax_group_id = tax_option.tax_group_id');
+// foreach ($params['options'] as $group => $options) {
+// $queryCount->andWhere([
+// 'tax_group.alias' => $group,
+// 'tax_option.alias' => $options
+// ]);
+// }
+// }
+// if (!empty($params['brands'])) {
+// $queryCount->innerJoin(Product::tableName(), 'product.product_id='. ProductOption::tableName() .'.product_id');
+// $queryCount->andWhere(['product.brand_id' => $params['brands']]);
+// }
+// if (!empty($params['prices'])) {
+// if ($params['prices']['min'] > 0) {
+// $queryCount->andWhere(['>=', 'pv.price', $params['prices']['min']]);
+// }
+// if ($params['prices']['max'] > 0) {
+// $queryCount->andWhere(['<=', 'pv.price', $params['prices']['max']]);
+// }
+// }
+// $query->addSelect(['_items_count' => $queryCount]);
+
+ return $query;
+ }
+
+ public function priceLimits($category = null, $params = []) {
+ if (!empty($category)) {
+ /** @var ActiveQuery $query */
+// $query = $category->getRelations('product_categories');
+ $query = $category->getProducts();
+ } else {
+ $query = Product::find();
+ }
+ $query->joinWith('variant');
+
+ // Price filter fix
+ unset($params['prices']);
+
+ ProductHelper::_setQueryParams($query, $params, false);
+
+// $query->select([
+// 'MIN('. ProductVariant::tableName() .'.price) AS priceMIN',
+// 'MAX('. ProductVariant::tableName() .'.price) AS priceMAX',
+// ]);
+
+ return [
+ 'min' => $query->min(ProductVariant::tableName() .'.price'),
+ 'max' => $query->max(ProductVariant::tableName() .'.price'),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/frontend/models/ResetPasswordForm.php b/frontend/models/ResetPasswordForm.php
new file mode 100755
index 0000000..d92b49e
--- /dev/null
+++ b/frontend/models/ResetPasswordForm.php
@@ -0,0 +1,65 @@
+_user = User::findByPasswordResetToken($token);
+ if (!$this->_user) {
+ throw new InvalidParamException('Wrong password reset token.');
+ }
+ parent::__construct($config);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ ['password', 'required'],
+ ['password', 'string', 'min' => 6],
+ ];
+ }
+
+ /**
+ * Resets password.
+ *
+ * @return boolean if password was reset.
+ */
+ public function resetPassword()
+ {
+ $user = $this->_user;
+ $user->setPassword($this->password);
+ $user->removePasswordResetToken();
+
+ return $user->save(false);
+ }
+}
diff --git a/frontend/models/SignupForm.php b/frontend/models/SignupForm.php
new file mode 100755
index 0000000..7c7d9c0
--- /dev/null
+++ b/frontend/models/SignupForm.php
@@ -0,0 +1,106 @@
+ 'trim'],
+ ['username', 'required'],
+ [['username','surname'], 'string', 'min' => 2, 'max' => 255],
+
+ ['email', 'filter', 'filter' => 'trim'],
+ ['email', 'required'],
+ ['email', 'email'],
+ [['email','phone'], 'string', 'max' => 255],
+ ['email', 'unique', 'targetClass' => '\common\models\Customers', 'message' => Yii::t('app','message',[
+ 'field' => 'Email'
+ ])],
+
+ [['phone'], 'unique', 'targetClass' => '\common\models\Customers', 'message' => Yii::t('app','message',[
+ 'field' => 'Телефон'
+ ])],
+
+ ['password_repeat', 'required'],
+ ['password_repeat', 'compare', 'compareAttribute'=>'password', 'message'=> Yii::t('app', 'message_match_password') ],
+
+ ['password', 'required'],
+ ['password', 'string', 'min' => 6],
+
+ [
+ 'verifyCode',
+ 'safe',
+ 'on'=>[SignupForm::SCENARIO_AJAX]
+ ],
+ [
+ 'verifyCode',
+ 'captcha',
+ 'on'=>[SignupForm::SCENARIO_SUBMIT]
+ ],
+ [
+ 'verifyCode',
+ 'captcha',
+ 'on'=>[SignupForm::SCENARIO_DEFAULT]
+ ],
+
+
+
+ ];
+ }
+
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'verifyCode' => 'Verification Code',
+ ];
+ }
+
+ /**
+ * Signs user up.
+ *
+ * @return Customers|null the saved model or null if saving fails
+ */
+ public function signup()
+ {
+
+ if (!$this->validate()) {
+ return null;
+ }
+
+ $user = new Customers();
+ $user->username = $this->username;
+ $user->surname = $this->surname;
+ $user->email = $this->email;
+ $user->phone = $this->phone;
+ $user->setPassword($this->password);
+ $user->generateAuthKey();
+ $user->validate();
+ return $user->save() ? $user : null;
+ }
+}
diff --git a/frontend/page/show.php b/frontend/page/show.php
new file mode 100755
index 0000000..b7febbd
--- /dev/null
+++ b/frontend/page/show.php
@@ -0,0 +1,4 @@
+title = $page->title;
+$this->params['breadcrumbs'][] = $this->title;
+echo $page->body;
\ No newline at end of file
diff --git a/frontend/views/articles/index.php b/frontend/views/articles/index.php
new file mode 100755
index 0000000..9a8b535
--- /dev/null
+++ b/frontend/views/articles/index.php
@@ -0,0 +1,85 @@
+getModule('artbox-comment');
+ CommentAsset::register($this);
+?>
+title = 'Блог';
+ $this->registerMetaTag([
+ 'name' => 'description',
+ 'content' => 'Блог',
+ ]);
+ $this->registerMetaTag([
+ 'name' => 'keywords',
+ 'content' => 'Блог',
+ ]);
+?>
+
+
+
+
+
+
+
Блог
+
+
+
+
+
+
+ = LinkPager::widget([
+ 'pagination' => $pages,
+ 'registerLinkTags' => true,
+ ]); ?>
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/articles/show.php b/frontend/views/articles/show.php
new file mode 100755
index 0000000..cf9b469
--- /dev/null
+++ b/frontend/views/articles/show.php
@@ -0,0 +1,63 @@
+
+title = $news->meta_title;
+$this->params['seo']['title'] = !empty($this->title) ?$this->title :$news->title;
+$this->registerMetaTag(['name' => 'description', 'content' => $news->meta_description]);
+?>
+
+
+
+
+
+
+
=$news->title?>
+
+ = Html::img(\common\components\artboximage\ArtboxImageHelper::getImageSrc($news->imageUrl, 'product'), ['class'=>'blog-show-img float-left'])?>
+ =$news->body?>
+
=$news->date?>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/basket/_popup.php b/frontend/views/basket/_popup.php
new file mode 100755
index 0000000..7bc62a6
--- /dev/null
+++ b/frontend/views/basket/_popup.php
@@ -0,0 +1,29 @@
+
+
+
+
+
+
Товар добавлен в корзину
+
+
+
+ Загрузка...
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/basket/ajax_info.php b/frontend/views/basket/ajax_info.php
new file mode 100755
index 0000000..0c17748
--- /dev/null
+++ b/frontend/views/basket/ajax_info.php
@@ -0,0 +1,5 @@
+
+Корзина =$info->count?>
\ No newline at end of file
diff --git a/frontend/views/basket/ajax_items.php b/frontend/views/basket/ajax_items.php
new file mode 100755
index 0000000..77c89ca
--- /dev/null
+++ b/frontend/views/basket/ajax_items.php
@@ -0,0 +1,33 @@
+
+ false, 'options' => [
+ 'class' => 'basket_form2'
+]]); ?>
+$item):?>
+
+ field($item,'['.$i.']id')->hiddenInput()->label(false); ?>
+
+
+ = \common\components\artboximage\ArtboxImageHelper::getImage($item->imageUrl, 'product_basket')?>
+
+
+
=$item->product_name?>
+
+ price_old>0):?>
=$item->price_old?> грн.
+
=$item->price?> грн.
+
+
+
+
field($item,'['.$i.']count',['template'=>'{input}'])->textInput(['type'=>'number','class' => 'item_num','disabled1'=>true])->label(false); ?>
+
+
=$item->sum_cost?> грн.
+
+
+
+
+
+
Всего: =$modelMod->getSumCost()?> грн.
+
+
\ No newline at end of file
diff --git a/frontend/views/basket/index.php b/frontend/views/basket/index.php
new file mode 100755
index 0000000..89fce9f
--- /dev/null
+++ b/frontend/views/basket/index.php
@@ -0,0 +1,193 @@
+title = 'Корзина';
+$this->registerMetaTag(['name' => 'description', 'content' => 'Корзина']);
+$this->registerMetaTag(['name' => 'keywords', 'content' => 'Корзина']);
+
+$this->registerJsFile(Yii::$app->request->baseUrl.'/js/jquery.mask.js',['position'=>View::POS_END,'depends'=>['yii\web\YiiAsset']]);
+
+$this->registerJs("
+$('#orders-phone,#orders-phone2').mask('(000) 000-0000');
+", View::POS_READY, 'mask');
+
+
+$this->registerJs("
+$('#orders-delivery input[type=\"radio\"]').click(function(){
+ $('.hidden_box').addClass('activeShow')
+ $('.delivery-data').hide();
+ $('#delivery-data-'+$(this).val()).show();
+});
+", View::POS_READY, 'order-delivery');
+?>
+
+//= Breadcrumbs::widget([
+// 'links' => [
+// 'Корзина'
+// ],
+// ]) ?>
+
+
+
+
+
+
+
+
Корзина
+
+ session->getFlash ('success')): ?>
+
= $flash ?>
+
+ session->getFlash ('error')): ?>
+
= $flash ?>
+
+ false]); ?>
+
+
+
+
+$item):?>
+
+
+ = \common\components\artboximage\ArtboxImageHelper::getImage($item->imageUrl, 'product_basket')?>
+
+
+
=$item->product_name?>
+
Код: =$item->sku?>, цвет: =$item->name?>
+ field($item,'['.$i.']id')->hiddenInput()->label(false); ?>
+ field($item,'['.$i.']product_name')->hiddenInput()->label(false); ?>
+ field($item,'['.$i.']sku')->hiddenInput()->label(false); ?>
+ field($item,'['.$i.']name')->hiddenInput()->label(false); ?>
+ field($item,'['.$i.']price')->hiddenInput()->label(false); ?>
+ field($item,'['.$i.']sum_cost')->hiddenInput()->label(false); ?>
+
+
цена за один =$item->price?> грн, цена =$item->sum_cost?> грн
+
field($item,'['.$i.']count')->textInput(['type'=>'number'])->label(false); ?>
+
+
Удалить
+
+
+
+
+
+ "update",'class'=>'submit4 fl ')); ?>
+
+
+
+
+ = $form->field($modelOrder, 'total')->hiddenInput(['value'=>$modelOrder->getSumCost()])->label(false); ?>
+ Общая сумма: =$modelOrder->getSumCost();?> грн.
+
+
+ = Html::a('Продолжить покупки', ['/site/index'], ['class'=>'btn-success cont_shopping']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/basket/success.php b/frontend/views/basket/success.php
new file mode 100755
index 0000000..0ec7e0f
--- /dev/null
+++ b/frontend/views/basket/success.php
@@ -0,0 +1,52 @@
+title = 'Корзина';
+$this->registerMetaTag(['name' => 'description', 'content' => 'Корзина']);
+$this->registerMetaTag(['name' => 'keywords', 'content' => 'Корзина']);
+
+if(isset($variants) && isset($order)){
+ $orderData = "
+ ga('require', 'ecommerce');
+ ga('ecommerce:addTransaction', {
+ 'id': {$order->id}, // где ID - транзакции, обязательно
+ });";
+
+ foreach($variants as $row){
+ $orderData .= "
+ ga('ecommerce:addItem', {
+ 'id': {$order->id}, // ID - транзакции, обязательно
+ 'name': \"{$row['product_name']} {$row['name']}\", // Имя товара
+ 'price': {$row['price']}, // Цена товара
+ 'quantity': {$row['count']} // Количество
+ });";
+
+ }
+ $orderData .= "ga('ecommerce:send');";
+ $this->registerJs ($orderData, View::POS_END);
+
+}
+
+
+?>
+
+
+
+
+
+
+
Корзина
+Ваш заказ принят! Большое Спасибо! Менеджер с Вами свяжется в ближайшее время.
+
+
diff --git a/frontend/views/cabinet/bookmarks.php b/frontend/views/cabinet/bookmarks.php
new file mode 100755
index 0000000..804d20d
--- /dev/null
+++ b/frontend/views/cabinet/bookmarks.php
@@ -0,0 +1,24 @@
+title = 'Закладки';
+$this->params['breadcrumbs'][] = $this->title;
+use yii\helpers\Html;
+use yii\helpers\Url;
+use yii\widgets\ActiveForm;
+?>
+
+''
+]); ?>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/cabinet/index.php b/frontend/views/cabinet/index.php
new file mode 100755
index 0000000..0cd910e
--- /dev/null
+++ b/frontend/views/cabinet/index.php
@@ -0,0 +1,18 @@
+title = 'Moй кабинет';
+$this->params['breadcrumbs'][] = $this->title;
+
+?>
+
+
+
Имя
+
e-mail
+
Телефон
+
+
+
+
+
= Yii::$app->user->identity->name ?>
+
= Yii::$app->user->identity->email ?>
+
= Yii::$app->user->identity->phone ?>
+
\ No newline at end of file
diff --git a/frontend/views/cabinet/my-orders.php b/frontend/views/cabinet/my-orders.php
new file mode 100755
index 0000000..72f32c9
--- /dev/null
+++ b/frontend/views/cabinet/my-orders.php
@@ -0,0 +1,24 @@
+title = 'Мои заказы';
+$this->params['breadcrumbs'][] = $this->title;
+use yii\helpers\Html;
+use yii\helpers\Url;
+use yii\widgets\ActiveForm;
+?>
+
+''
+]); ?>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/cabinet/update.php b/frontend/views/cabinet/update.php
new file mode 100755
index 0000000..dbb8439
--- /dev/null
+++ b/frontend/views/cabinet/update.php
@@ -0,0 +1,56 @@
+title = 'Редактировать личные данные';
+ $this->params['breadcrumbs'][] = $this->title;
+ use yii\helpers\Html;
+ use yii\helpers\Url;
+ use yii\widgets\ActiveForm;
+?>
+
+''
+]); ?>
+
+
+
+
+
+ = $form->field($model, 'email', [
+ 'template' => '',
+ ]) ?>
+
+
+
+ = $form->field($model, 'username',[
+ 'template' => '',
+ ])->textInput() ?>
+
+
+
+ = $form->field($model, 'surname',[
+ 'template' => '',
+ ])->textInput() ?>
+
+
+
+ = $form->field($model, 'phone', [
+ 'template' => '',
+ ])->textInput() ?>
+
+
+
+
+ = Html::submitButton(Yii::t('app', 'registration'), ['class' => 'my_cust_cabinet_btn']) ?>
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/call/index.php b/frontend/views/call/index.php
new file mode 100755
index 0000000..a4c7685
--- /dev/null
+++ b/frontend/views/call/index.php
@@ -0,0 +1,34 @@
+
+title = 'Обратный звонок';
+$this->registerMetaTag(['name' => 'description', 'content' => 'Обратный звонок']);
+$this->registerMetaTag(['name' => 'keywords', 'content' => 'Обратный звонок']);
+?>
+
+
+//= Breadcrumbs::widget([
+// 'links' => [
+// 'Обратный звонок'
+// ],
+// ]) ?>
+
+
+
+
+
+
+
Обратный звонок
+
+
+= $form->errorSummary($model); ?>
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/call/success.php b/frontend/views/call/success.php
new file mode 100755
index 0000000..daf91d5
--- /dev/null
+++ b/frontend/views/call/success.php
@@ -0,0 +1,32 @@
+
+title = 'Обратный звонок';
+$this->registerMetaTag(['name' => 'description', 'content' => 'Обратный звонок']);
+$this->registerMetaTag(['name' => 'keywords', 'content' => 'Обратный звонок']);
+?>
+
+
+
+
+
+
+
Обратный звонок
+
+ Мы получили от Вас сообщение! Мы свяжемся с Вами в ближайшее время.
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/catalog/_catalog_box.php b/frontend/views/catalog/_catalog_box.php
new file mode 100755
index 0000000..fa669ce
--- /dev/null
+++ b/frontend/views/catalog/_catalog_box.php
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/frontend/views/catalog/all.php b/frontend/views/catalog/all.php
new file mode 100755
index 0000000..9aa7c4f
--- /dev/null
+++ b/frontend/views/catalog/all.php
@@ -0,0 +1,39 @@
+title = 'Каталог';
+$this->registerMetaTag(['name' => 'description', 'content' => 'Каталог']);
+$this->registerMetaTag(['name' => 'keywords', 'content' => 'Каталог']);
+
+?>
+
+
+
+
Каталог
+ /**foreach($catalogs as $item):?>
+
+
+
+
+
+
+
diff --git a/frontend/views/catalog/brand.php b/frontend/views/catalog/brand.php
new file mode 100755
index 0000000..75cee4b
--- /dev/null
+++ b/frontend/views/catalog/brand.php
@@ -0,0 +1,50 @@
+title = $brand->name;
+$this->params['breadcrumbs'][] = ['label' => Yii::t('products', 'Brands'), 'url' => ['catalog/brands']];
+$this->params['breadcrumbs'][] = $brand->name;
+
+$this->params['seo']['fields']['name'] = $brand->name;
+
+$this->registerCssFile (Yii::getAlias('@web/css/ion.rangeSlider.css'));
+$this->registerCssFile (Yii::getAlias('@web/css/ion.rangeSlider.skinHTML5.css'));
+$this->registerJsFile (Yii::getAlias('@web/js/ion.rangeSlider.js'));
+?>
+
+
+
+
+
+
+
= $brand->name ?>
+
+
+ models as $product) :?>
+
+
+
+
+
+ totalCount > $productProvider->pagination->pageSize) :?>
+ = \yii\widgets\LinkPager::widget([
+ 'pagination' => $productProvider->pagination,
+ 'options' => ['class' => 'pagination pull-right'],
+ 'registerLinkTags' => true,
+ ]);
+ ?>
+
+
+
+
+
+ = \common\modules\product\widgets\lastProducts::widget()?>
+
\ No newline at end of file
diff --git a/frontend/views/catalog/brands.php b/frontend/views/catalog/brands.php
new file mode 100755
index 0000000..a3f2f50
--- /dev/null
+++ b/frontend/views/catalog/brands.php
@@ -0,0 +1,28 @@
+params['breadcrumbs'][] = Yii::t('product', 'Brands');
+
+$this->params['seo']['seo_text'] = 'Brands SEO-text';
+$this->params['seo']['h1'] = Yii::t('product', 'Brands');
+$this->params['seo']['description'] = 'Brands DESCRIPTION';
+$this->params['seo']['fields']['name'] = 'Brands NAME FROM FIELD';
+$this->params['seo']['key']= 'brands';
+?>
+
+
+
+
+
= $this->params['seo']['h1']?>
+
+
+
\ No newline at end of file
diff --git a/frontend/views/catalog/catalog.php b/frontend/views/catalog/catalog.php
new file mode 100755
index 0000000..9d1a618
--- /dev/null
+++ b/frontend/views/catalog/catalog.php
@@ -0,0 +1,21 @@
+title = 'Каталог';
+$this->params['breadcrumbs'][] = ['label' => 'Каталог'];
+?>
+
+
+
+
+
Каталог
+ = \frontend\widgets\Rubrics::widget(['wrapper' => 'rubrics', 'includes' => [130,131,132,133,134]])?>
+
+
+
+ = \common\modules\product\widgets\specialProducts::widget(['type' => 'promo'])?>
+ = \common\modules\product\widgets\specialProducts::widget(['type' => 'new'])?>
+ = \common\modules\product\widgets\specialProducts::widget(['type' => 'top'])?>
+ = \common\modules\product\widgets\lastProducts::widget()?>
+
diff --git a/frontend/views/catalog/categories.php b/frontend/views/catalog/categories.php
new file mode 100755
index 0000000..cefd71b
--- /dev/null
+++ b/frontend/views/catalog/categories.php
@@ -0,0 +1,45 @@
+title = $category->name;
+foreach($category->getParents()->all() as $parent) {
+ $this->params['breadcrumbs'][] = ['label' => $parent->name, 'url' => ['catalog/category', 'category' => $parent]];
+}
+$this->params['breadcrumbs'][] = $this->title;
+?>
+= $this->title ?>
+
+
+
+
+
+ getAllChildrenTree(2, [], 'categoryName') as $category) :?>
+
+
+ image)) :?>
+
![<?= $category['item']->name?>](<?= $category['item']->image?>)
+
+

+
+
= $category['item']->name?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/catalog/index.php b/frontend/views/catalog/index.php
new file mode 100755
index 0000000..d376416
--- /dev/null
+++ b/frontend/views/catalog/index.php
@@ -0,0 +1,45 @@
+
+title = $catalog->meta_title;
+$this->params['seo']['fields']['meta-title'] = $catalog->meta_title;
+$this->registerMetaTag(['name' => 'description', 'content' => $catalog->meta_description]);
+$this->registerMetaTag(['name' => 'keywords', 'content' => $catalog->meta_keywords]);
+//?>
+
+//= Breadcrumbs::widget([
+//
+// 'links' => [ ['label'=>'Каталог','url'=>['catalog/all']],
+// $catalog->name],
+// ]) ?>
+
+
+
+
+
+
+
+ = $this->render('_catalog_box',['catalog'=>$catalog]) ?>
+
+
+
+
=$catalog->name?>
+
+
+ childs as $item):?>
+
+
+
+
+ =$catalog->body?>
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/views/catalog/product.php b/frontend/views/catalog/product.php
new file mode 100755
index 0000000..5450f51
--- /dev/null
+++ b/frontend/views/catalog/product.php
@@ -0,0 +1,316 @@
+params[ 'seo' ][ 'key' ] = $category->categoryName->value;
+ $this->params[ 'seo' ][ 'fields' ][ 'name' ] = $product->fullname;
+ $this->params[ 'seo' ][ 'h1' ] = !empty( Seo::widget([ 'row' => 'h1' ]) ) ? Seo::widget([ 'row' => 'h1' ]) : $product->fullname;
+
+ //$this->params['seo']['title'] = "Купить " . substr($product->category->categoryName->value, 0, -2) . " " . $product->fullname . " в Киеве, Харькове, Украине: цены, отзывы - Rukzachok.com.ua";
+ //$this->params['seo']['description'] = "Заказать " . substr($product->category->categoryName->value, 0, -2) . " " . $product->fullname . " - самые модные и стильные рюкзаки в Украине по лучшим ценам. Интернет магазин рюкзаков Rukzachok.com.ua";
+ $this->title = $product->fullname;
+ //$this->title = (! empty($product->meta_title)) ? $product->meta_title : $product->fullname;
+ //$this->registerMetaTag (['name' => 'description', 'content' => ((! empty($product->meta_description)) ? $product->meta_description : $product->fullname)]);
+ //$this->registerMetaTag (['name' => 'keywords', 'content' => $product->meta_keywords]);
+
+ //foreach($product->category->getParents()->all() as $parent) {
+ // $this->params['breadcrumbs'][] = ['label' => $parent->categoryName->value, 'url' => ['catalog/category', 'category' => $parent]];
+ //}
+ $this->params[ 'breadcrumbs' ][] = [
+ 'label' => 'Каталог',
+ 'url' => [ 'catalog/category' ],
+ ];
+ $this->params[ 'breadcrumbs' ][] = [
+ 'label' => $category->categoryName->value,
+ 'url' => [
+ 'catalog/category',
+ 'category' => $category,
+ ],
+ ];
+ $this->params[ 'breadcrumbs' ][] = $product->fullname . ' #' . $product->enabledVariants[ 0 ]->sku;
+
+ $this->registerJs('
+
+ var checkData = function($index)
+ {
+ var sourceNew = $(".productLeftBar .product_mod > li").eq($index);
+ $(".productLeftBar .product_mod > li").removeClass("active")
+ sourceNew.addClass("active");
+ var $source = sourceNew.find("a");
+ var $target = $(".productLeftBar .cost_box");
+
+ $("#cost").text($source.data("cost"));
+ $("#old_cost").text($source.data("old_cost"));
+
+ if (parseInt ($source.data("old_cost")) == 0)
+ {
+ $target.find("strike").hide();
+ }
+ else
+ {
+ $target.find("strike").show();
+ }
+
+ $("#product_id").val($source.data("id"));
+ $("#art").text($source.data("art"));
+ $("#color").text($source.data("color"));
+ $("#pic").attr("src",$source.data("image"));
+ $("#picoriginal").attr("href",$source.data("imageoriginal"));
+ }
+
+ $(".product_mod > li").click(function()
+ {
+ checkData($(this).index());
+
+ Shadowbox.setup($("#picoriginal"));
+
+ return false;
+ });
+
+ checkData(0);
+
+ ', View::POS_READY, 'fasovka');
+
+ $this->registerJs("
+ $('#nav_product li a').addClass('active');
+ $('#nav_product li').find('.info').toggle();
+
+ $('#nav_product li a').bind('click',function()
+ {
+ if($(this).parent().find('.info').css('display')=='none')$(this).addClass('active');
+ else $(this).removeClass('active');
+ $(this).parent().find('.info').toggle();
+
+ return false;
+ });
+ ", View::POS_READY, 'nav_product');
+
+ $this->registerCssFile(Yii::$app->request->BaseUrl . '/js/shadowbox-3.0.3/shadowbox.css');
+ $this->registerJsFile(Yii::$app->request->baseUrl . '/js/shadowbox-3.0.3/shadowbox.js', [
+ 'position' => View::POS_END,
+ 'depends' => [ 'yii\web\JqueryAsset' ],
+ ]);
+ $this->registerJs("
+ Shadowbox.init({
+
+ });
+ ", View::POS_READY, 'Shadowbox');
+?>
+
+session->getFlash('success')): ?>
+ = $flash ?>
+
+
+
+
+
= Seo::widget([ 'row' => 'h1' ]) ?>
+ enabledVariantsGrouped as $variantGroup) : ?>
+
= $variantGroup->name2 ?>
+
+
+
+
+
+
+
код:
цвет:
+
+
+
+ = $variant->price_old ?> грн.
+ = $variant->price ?> грн.
+
+
+
+
Купить
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+

+
+
+
+
+
*/ ?>
+
+
+
+
+ - Характеристики
+
+
Бренд: = $product->brand->name ?>
+ getActiveProperties($category->category_id) as $group): ?>
+
= $group->name ?> _options as $option) : ?> = $option->ValueRenderHTML ?>
+
+
+
+ - Описание
+
+
+ = $product->description ?>
+
+
+
+ video ) && strpos($product->video, '.jpg') === false && strpos($product->video, '.png') === false) : ?>
+ - Видео
+
+ video, '
+
+
+
+
+
+
+
+
+
+ = \common\modules\product\widgets\similarProducts::widget([ 'product' => $product ]) ?>
+ = \common\modules\product\widgets\specialProducts::widget([ 'type' => 'promo' ]) ?>
+ = \common\modules\product\widgets\specialProducts::widget([ 'type' => 'new' ]) ?>
+ = \common\modules\product\widgets\specialProducts::widget([ 'type' => 'top' ]) ?>
+ = \common\modules\product\widgets\lastProducts::widget() ?>
+
+registerJs("
+ var productHash = window.location.hash;
+ productHash = productHash.replace('#','')
+
+ var productUl = $('ul.product_mod li')
+ var productA = productUl.find('a#'+productHash)
+ productUl.removeClass('active')
+ productA.parent().addClass('active')
+ var dataLink = productA.attr('data-imageoriginal')
+ var dataImg = productA.attr('data-image')
+
+ $('#pic').attr('src',dataImg)
+ $('#pic').parent().attr('href',dataLink)
+ ", View::POS_READY, 'new_script');
+?>
\ No newline at end of file
diff --git a/frontend/views/catalog/product_item.php b/frontend/views/catalog/product_item.php
new file mode 100755
index 0000000..9560e7e
--- /dev/null
+++ b/frontend/views/catalog/product_item.php
@@ -0,0 +1,113 @@
+getModule('artbox-comment');
+ CommentAsset::register($this);
+?>
+