Задать вопрос
  • Не могу понять для чего нужны Entities в ООП PHP, Yii?

    @thyratr0n
    Есть разные подходы к пониманию смысла этих вещей.
    Entities чаще всего используются в контексте DDD-подхода. Там это означает то, что объект может изменять свое состояние (фигура может менять цвет, стакан может заполняться и тд). Супротив Entities выступают т.н. ValueObject, которые используются только для чтения и менять свое состояние не могут.
    И те, и другие используются в бизнес-логике приложения и генерируются либо хранилищами (storage), либо сервисам (в зависимости от выбранного подхода).

    В контексте же Yii понятие Entity не применяется. ибо там структурной единицей бизнес-логики выступают экземпляры ActiveRecord чаще всего (сам фреймворк к этому располагает), либо, иногда, наследники Model.

    Главное - это то, что сущность не обязательна должна сохраняться as is, т.е. иметь четкую проекцию в БД, ибо сущностью может выступать экземпляр паттерна Композит - все зависит от хранилища/сервиса, который это дело будет "CRUD'ить".
    Ответ написан
    2 комментария
  • Какие ещё, помимо базовых, возможности ES6+ очень востребованны и часто используются?

    alienworkshop
    @alienworkshop Автор вопроса
    Нашёл фишку. Называется Proxy
    Прокси (proxy) – особый объект, смысл которого – перехватывать обращения к другому объекту и, при необходимости, модифицировать их.

    let proxy = new Proxy(target, handler)

    target – объект, обращения к которому надо перехватывать.
    handler – объект с «ловушками»: функциями-перехватчиками для операций к target.


    let my_arr = [];
    // Proxy(target, handler)
    let arr_proxy = new Proxy(my_arr, {
      get(target, prop) {
        console.log(`\n Getting ${prop}`);
        console.log(`Perform needed actions after getting ${prop}`);
        return target[prop];
      },
    
      set(target, prop, value) {
        console.log(`\n Setting ${prop} ${value}`);
        console.log(`Perform needed actions after setting ${prop} ${value}`);
        target[prop] = value;
        return true;
      }
    })
    
    arr_proxy.push('dsfdgdf')


    5b28ff962b8f1640202295.png

    https://learn.javascript.ru/proxy
    Ответ написан
    1 комментарий
  • Как вывести категории у которых есть записи?

    proudmore
    @proudmore
    SELECT c.category_id, COUNT(r.record_id) AS records
    FROM category AS c
    LEFT JOIN records AS r USING(record_id)
    GROUP BY c.record_id
    HAVING records > 5
    Ответ написан
    2 комментария
  • Ckeditor, после добавленного видео с YouTube отображается рамка с текстом Iframe. В чем тонкости?

    У CKEditor есть плагин iframe, который заменяет все iframe элементы вот таким вот, как они называют, fake object. Но это происходит только при трансформации данных. То есть сначала youtube плагин вставляет iframe с видео не учитывая остальные плагины, а когда вы переключаетесь в режим wysiwyg из режима html, то ckeditor применяет трансформации своих плагинов. В данном случае, это недоработка разработчиков плагина youtube - они не учли и не позаботились об этом.

    Лучшим решением будет вариант на основе виджетов, как стандартный https://ckeditor.com/cke4/addon/embed - но там нет настроек видео, увы.
    Ответ написан
    1 комментарий
  • Как получить email из facebook?

    sayber
    @sayber Куратор тега PHP
    Да, я программирую на PHP и еще асинхронно!
    Как я это делал - вам надо по адресу https://developers.facebook.com/tools/explorer/
    нажать кнопочку get access token и сделать как на картинке ниже
    3c43fdab79d945aa90c3c384653b3302.png
    Ответ написан
    Комментировать
  • Авторизация на PHP?

    AlexMaxTM
    @AlexMaxTM
    На любом фреймворке это уже все реализовано, нужно только настроить. Если хотите изобрести велосипед, посмотрите как это сделано там, тогда совершите меньше ошибок.
    Ответ написан
    Комментировать
  • Вывод новостей в зависимости от кол-ва комментариев и текущей даты в Yii2?

    Не?
    SELECT *
    FROM news n
      INNER JOIN news_comments nc ON n.news_id = nc.news_id
    GROUP BY n.news_id
    ORDER BY COUNT(nc.comment_id) DESC, n.date DESC


    Тоже самое можно и с помощью Query составить

    News::find()->where(['news.visibility'=>1])
    ->innerJoin(['nc' => NewsComments::tableName()], 'nc.news_id = news.id')
    ->groupBy('news.id')
    ->orderBy('COUNT(nc.id) DESC, news.date DESC');
    Ответ написан
    6 комментариев
  • Переопределить метод find через функцию в Модели?

    @matperez
    Вам нужно создать свой класс. Какой-нибудь ItemQuery. Наследовать его от yii\easyii\components\ActiveQuery и добавить туда трейт MultilingualTrait и его уже возвращать из Item::find(). И будет вам счатье.
    Ответ написан
    7 комментариев
  • Что не так делаю при выборе строк за текущий месяц в Yii2?

    webinar
    @webinar Куратор тега Yii
    Учим yii: https://youtu.be/-WRMlGHLgRg
    1 что надо понять, это в каком формате дата в базе. Если в виде даты, а не числа, то mysql так:
    WHERE MONTH(`date`) = MONTH(NOW()) AND YEAR(`date`) = YEAR(NOW())

    А в yii2 используя AR, видимо так (но стоит проверить):
    SomeModel::find()->andWhere("MONTH(`date`) = MONTH(NOW()) AND YEAR(`date`) = YEAR(NOW())")->all();
    Ответ написан
    3 комментария
  • Cannot read property 'data' of undefined, после Ajax, Rivets.js?

    lazalu68
    @lazalu68
    Salmon
    В общем проблема была в повторной инициализации приложения и попытке установки обработчика для элемента управления приложения сторонними средствами - с помощью jQuery.

    Можно байндить только нужный вам контейнер, это вроде решение с минимальным изменением кода. Просто после добавления элементов в список байндите их:

    $.ajax({
        url: '/demo.php',
        type: 'POST',
        data: data,
        success: function (html) {
            $goods_list.empty().append(html);
            rivets.bind($goods_list, model);
            toTopAfterAjaxUpdatePagination();
        }
    });


    Изменённый код main.js
    var $ = jQuery;
    
    $(function(){
      var $goods_list = $('ul.goods__list'),
          model = {
            data: JSON.parse(localStorage.getItem('g_zakazi')) || {
              title: 'Welcome',
              //juzer_id: $('#juzer-id').text(),
              subtotal: 0,
              zakazi: []
            },
            controller: controller
          };
    
      rivets.bind(document.querySelector('#rivetsSpace'), model);
    
      $('.goods__pagination').on('click', '.goods__page', function(){
    
        console.log('Клик по пагинации');
        var data = { id: $(this).text() };
    
            $.ajax({
                url: '/demo.php',
                type: 'POST',
                data: data,
                success: function (html) {
                    //console.log(data);
                    $goods_list.empty().append(html);
                    rivets.bind($goods_list, model);
                    toTopAfterAjaxUpdatePagination();
                }
            });
      });
    
    });
    
    function returnFalse(){
      console.log('Выходим');
      return false;
    }
    
    var controller = {
    
      onAtbClick: function(e, model) {
           var ID = $(this).data("id");
    
              var goods = model.data.zakazi.filter(function (goods) {
                      return goods.ID === ID;
              })[0];
    
              if (goods) {
                  goods.quantity++;
                  returnFalse();
    
              } else {
    
                model.data.zakazi.push({
                      ID: ID,
                      quantity: 1
    
                    });
              }
    
    		model.controller.updatePrice(model.data);
    		model.controller.saveData(model.data);
    
       },
    
       updatePrice: function(data) {
        var zakazi = data.zakazi,
          product,
          subtotal = 0;
    
        data.subtotal = subtotal;
    
      },
    
       removeGoods: function(e, model) {
    
            e.stopImmediatePropagation();
    
            var index = model.index,
                zakazi = model.data.zakazi;
    
          zakazi.splice(index, 1);
          model.controller.saveData(model.data);
    
        },
    	
       saveData: function(data) {
        localStorage.setItem( 'g_zakazi', JSON.stringify( data ) );
       }
    }
    
    function toTopAfterAjaxUpdatePagination() {
      var scrollGoods = $('section.goods').offset().top;
      $(document).scrollTop(scrollGoods - 50);
    }
    
    
    
    rivets.formatters.length = function(val) {
      return val.length;
    };
    Вариант решения который не подошёл

    Не знаю как это вообще делают, но у меня получилось решить с помощью индивидуального байнда для каждого элемента. Можно было конечно и с помощью компонента оформить, было бы красивее и проще, но в целом это уже детали, можно сделать как нравится. Вот архив. То есть теперь при загрузке приложения в глобальной области видимости создаётся массив для инициализации блока goods:

    window.items = [
    	{ id: 1 },
    	{ id: 2 },
    	{ id: 3 },
    	...
    ]

    При инициализации приложения этот массив обрабатывается с помощью функции контроллера processGoods:

    model.$goods_list.append( controller.processGoods(window.items, model) );
    ...
    var controller = {
        processGoods: function(data, model) {
          var elements = new Array(data.length),
              temp_fragment = document.createDocumentFragment();
    
          for (var i = 0; i < data.length; i++) {
            elements[ i ] = model.controller.createElementFromTemplate('goods__item', model);
            rivets.bind(elements[i], Object.assign({ item: data[i] }, model));
            temp_fragment.appendChild( elements[ i ] );
          }
    
          return temp_fragment;
        },
        createElementFromTemplate: function(item, model) {
          return document.importNode(model.templates[ item ].content.children[0], true);
        },
        ...
    }

    Также эта функция участвует при обработке данных пришедших от pagination запроса:

    $('.goods__pagination').on('click', '.goods__page', function() {
        var data = {
            id: $(this).text()
        };
        $.ajax({
            url: '/demo.php',
            type: 'POST',
            data: data,
            dataType: 'json',
            success: function(data) {
                model.$goods_list.empty().append( controller.processGoods(data, model) );
                toTopAfterAjaxUpdatePagination();
            }
        });
    });
    Ответ написан
    1 комментарий
  • Как добавить в CKEDITOR навигацию выравнивая текста?

    lazalu68
    @lazalu68
    Salmon
    Второй пример на сайте.

    Код второго примера.
    CKEDITOR.replace( 'editor1', {
    		// Define the toolbar: http://docs.ckeditor.com/#!/guide/dev_toolbar
    		// The full preset from CDN which we used as a base provides more features than we need.
    		// Also by default it comes with a 3-line toolbar. Here we put all buttons in a single row.
    		toolbar: [
    			{ name: 'document', items: [ 'Print' ] },
    			{ name: 'clipboard', items: [ 'Undo', 'Redo' ] },
    			{ name: 'styles', items: [ 'Format', 'Font', 'FontSize' ] },
    			{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat', 'CopyFormatting' ] },
    			{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
    			{ name: 'align', items: [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] },
    			{ name: 'links', items: [ 'Link', 'Unlink' ] },
    			{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote' ] },
    			{ name: 'insert', items: [ 'Image', 'Table' ] },
    			{ name: 'tools', items: [ 'Maximize' ] },
    			{ name: 'editing', items: [ 'Scayt' ] }
    		],
    		// Since we define all configuration options here, let's instruct CKEditor to not load config.js which it does by default.
    		// One HTTP request less will result in a faster startup time.
    		// For more information check http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-customConfig
    		customConfig: '',
    		// Sometimes applications that convert HTML to PDF prefer setting image width through attributes instead of CSS styles.
    		// For more information check:
    		//  - About Advanced Content Filter: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
    		//  - About Disallowed Content: http://docs.ckeditor.com/#!/guide/dev_disallowed_content
    		//  - About Allowed Content: http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules
    		disallowedContent: 'img{width,height,float}',
    		extraAllowedContent: 'img[width,height,align]',
    		// Enabling extra plugins, available in the full-all preset: http://ckeditor.com/presets-all
    		extraPlugins: 'tableresize,uploadimage,uploadfile',
    		/*********************** File management support ***********************/
    		// In order to turn on support for file uploads, CKEditor has to be configured to use some server side
    		// solution with file upload/management capabilities, like for example CKFinder.
    		// For more information see http://docs.ckeditor.com/#!/guide/dev_ckfinder_integration
    		// Uncomment and correct these lines after you setup your local CKFinder instance.
    		// filebrowserBrowseUrl: 'http://example.com/ckfinder/ckfinder.html',
    		// filebrowserUploadUrl: 'http://example.com/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files',
    		/*********************** File management support ***********************/
    		// Make the editing area bigger than default.
    		height: 800,
    		// An array of stylesheets to style the WYSIWYG area.
    		// Note: it is recommended to keep your own styles in a separate file in order to make future updates painless.
    		contentsCss: [ 'https://cdn.ckeditor.com/4.6.1/full-all/contents.css', 'mystyles.css' ],
    		// This is optional, but will let us define multiple different styles for multiple editors using the same CSS file.
    		bodyClass: 'document-editor',
    		// Reduce the list of block elements listed in the Format dropdown to the most commonly used.
    		format_tags: 'p;h1;h2;h3;pre',
    		// Simplify the Image and Link dialog windows. The "Advanced" tab is not needed in most cases.
    		removeDialogTabs: 'image:advanced;link:advanced',
    		// Define the list of styles which should be available in the Styles dropdown list.
    		// If the "class" attribute is used to style an element, make sure to define the style for the class in "mystyles.css"
    		// (and on your website so that it rendered in the same way).
    		// Note: by default CKEditor looks for styles.js file. Defining stylesSet inline (as below) stops CKEditor from loading
    		// that file, which means one HTTP request less (and a faster startup).
    		// For more information see http://docs.ckeditor.com/#!/guide/dev_styles
    		stylesSet: [
    			/* Inline Styles */
    			{ name: 'Marker', element: 'span', attributes: { 'class': 'marker' } },
    			{ name: 'Cited Work', element: 'cite' },
    			{ name: 'Inline Quotation', element: 'q' },
    			/* Object Styles */
    			{
    				name: 'Special Container',
    				element: 'div',
    				styles: {
    					padding: '5px 10px',
    					background: '#eee',
    					border: '1px solid #ccc'
    				}
    			},
    			{
    				name: 'Compact table',
    				element: 'table',
    				attributes: {
    					cellpadding: '5',
    					cellspacing: '0',
    					border: '1',
    					bordercolor: '#ccc'
    				},
    				styles: {
    					'border-collapse': 'collapse'
    				}
    			},
    			{ name: 'Borderless Table', element: 'table', styles: { 'border-style': 'hidden', 'background-color': '#E6E6FA' } },
    			{ name: 'Square Bulleted List', element: 'ul', styles: { 'list-style-type': 'square' } }
    		]
    	} );


    Ответ написан
    3 комментария
  • Сформировать через цикл такую html вложенность тегов?

    ThunderCat
    @ThunderCat Куратор тега PHP
    {PHP, MySql, HTML, JS, CSS} developer
    гуглим рекурсия вывод дерева и находим массу интересного, например тут
    Ответ написан
    2 комментария
  • Выбор постов через hasMany по передаваемой метке в url?

    webinar
    @webinar Куратор тега Yii
    Учим yii: https://youtu.be/-WRMlGHLgRg
    class Tags extends ActiveRecord
    {
        public function getPages()
        {
             return $this->hasMany(Statjiblog::className(), ['id' => 'post_id'])->viaTable('{{%statjiblogtags}}', ['tag_id' => 'id']);
        }
    }


    public function actionPage($slug){
      $model = Tags::find()->andWhere(['slug'=>$slug])->one();
      foreach($model->pages as $page){
          echo $page->title;
      }
    }

    Ну или с другой строны, через join;
    Ответ написан
  • Есть ли шаблоны приложений для Android?

    iLLuzor
    @iLLuzor
    Java, Kotlin, Android Developer
    Где же могут быть примеры? Может в официальной документации?
    Надо же, действительно они там есть.
    Ответ написан
    2 комментария
  • Как правильнее передать номер комнаты для чата?

    @RaulDuke
    Если верно понимаю, это скорее вопрос структуры данных бэка. И при всей кажущейся простоте задача чата с комнатами для некоторых бэкендов оказывается не такой уж простой (например, для Firebase это нетривиальная задача).

    На вскидку, я бы делал такую структуру:

    db: {
      users: {
        id: 111,
        name: 'Rostislav',
        room: 8888,
      },
      rooms: {
        id: 8888,
        messages: [...],
        owner: 111,
        public: true
      }
    }


    При нажатии кнопки войти отдаем серверу id комнаты, если существует он проверяет все что нужно Вам проверить и отдает хозяина комнаты с сообщениями.
    Ответ написан
    Комментировать
  • Кросс доменный запрос с http на https через ajax или fetch?

    devspec
    @devspec
    Помогло? Отметь решением
    Во-первых, кросс-доменные запросы работают только тогда, когда сервер возвращает Allow-Control-Allow-Origin: *
    Во-вторых, можете попробовать поставить processData: false в параметры вашего ajax-запроса.
    $.ajax({
        type: "POST",
        url: api_url,
        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
        processData: false,
        data: JSON.stringify(pd),
        success: function (result) {
            // ...
        }
    });
    Ответ написан
    1 комментарий
  • Загружать фото в Облако через сервер на котором лежит php(WordPress) сайт?

    @bunpavvlad
    Добрый день. В чем проблема переопределения метода сохранения фото на сервере. Что бы он сохранял фото сразу в облако или сначала на сервер, а потом отправлял это фото в облако и после успешной загрузки, при необходимости удалять исходник с сервера.

    При показе фото выводить его через скрипт например generic.php?src=path/to/photo
    Путь можно сделать более "чпушным"
    В скрипте обратиться к облаку если файл есть показать его, если нет показать какой-то свой дефолтный.
    Можно использовать Яндекс.диск (на него есть php клиент)

    Но такой метод вряд ли подойдёт для высоких нагрузок. И скорость отдачи картинки будет ниже чем обычная отрисовка
    Ответ написан
    Комментировать
  • Преобразовать textarea в ckeditor подгруженного в DOM через ajax?

    ThunderCat
    @ThunderCat Куратор тега JavaScript
    {PHP, MySql, HTML, JS, CSS} developer
    код:CKEDITOR.replace('txtArea'); вы полняем по загрузке аяксом хтмля.

    хтмл:<textarea name="txtArea"></textarea>
    Ответ написан
    1 комментарий
  • Листалка pdf в виде книги на сайте?

    Justique
    @Justique
    Ответ написан
    Комментировать
  • Как теперь правильно вывести пагинацию?

    webinar
    @webinar Куратор тега Yii
    Учим yii: https://youtu.be/-WRMlGHLgRg
    А зачем сменили код экшена? Все было правильно. Просто надо было заменить:
    $query = Statjiblog::find();
    на
    $query = Statjiblog::find()->with('categorys');
    Ответ написан
    8 комментариев