如何正确地从撇号片段中覆盖方法 "self.list"

How to override method "self.list" from apostrophe-pieces properly

我正在尝试通过模拟您可以找到它的语言环境的字段自动过滤一个片段。为此,我覆盖了我作品中的 self.list 方法,它确实有效,但我真的不知道我是否以最好的方式完成了它。

我知道我可以使用 apostrophe-workflow 管理我的项目的不同区域设置,我也可以在我的作品中添加一个过滤器并用它进行过滤,但是这些替代方法都不能解决我的问题,因为我想要那个当片段模态列出它们时,它会自动显示在我正在谈论的字段中具有具体值的片段。

字段声明代码给你看

{
  name: 'locale',
  label: 'Locale',
  type: 'string',
  contextual: true
}   

我还展示了 self.list 方法的覆盖。

self.list = function(req, options, callback) {
        var cursor;
        var filters = options.filters || options;
        if (options.chooser) {
          cursor = self.find(req);
        } else {
          cursor = self.findForEditing(req);
        }
        if (options.format === 'allIds') {
          cursor.projection({ _id: 1 });
        } else {
          cursor.perPage(self.options.perPage || 10);
        }
        cursor.queryToFilters(filters);

        var results = {};

        return async.series({

        toCount: function(callback) {
            if (options.format === 'allIds') {
              return callback(null);
            }
            return cursor
            .toCount(function(err, count) {
                if (err) {
                  return callback(err);
                }
                results.total = count;
                results.totalPages = cursor.get('totalPages');
                return callback(null);
            });
        },

        populateFilters: function(callback) {
            if (options.format === 'allIds') {
              return callback(null);
            }

            // Populate manage view filters by the same technique used
            // for the `piecesFilters` option of `apostrophe-pieces-pages`

            var allowedFilters = options.chooser ? _.filter(self.filters, function(item) {
              return item.allowedInChooser !== false;
            }) : self.filters;
            results.filters = {
              options: [],
              q: filters.search,
              choices: {}
            };

            return async.eachSeries(allowedFilters, function(filter, callback) {
            // The choices for each filter should reflect the effect of all filters
            // except this one (filtering by topic pares down the list of categories and
            // vice versa)
              var _cursor = cursor.clone();
              // The default might not be good for our purposes. Set it to
              // `null`, which appropriate filters, like `trash`, understand to mean
              // "I am interested in things that are ignored by default and also live things"
              _cursor[filter.name](null);
              return _cursor.toChoices(filter.name, { legacyFilterChoices: true }, function(err, choices) {
                  if (err) {
                    return callback(err);
                  }
                  // Array of all filter objects allowed in this context:
                  //
                  // results.filters.options = [ { name: 'published', choices: [ ... usual ... ], def: ... } ]
                  //
                  // Single object with a property containing the PRESENT value of EACH filter:
                  //
                  // results.filters.choices = {
                  //   published: true
                  // }
                  var _filter = _.clone(filter);
                  results.filters.options.push(_.assign(_filter, { choices: choices }));
                  // These are the "choices you have made," not the "choices you can make."
                  results.filters.choices[_filter.name] = filters[_filter.name];
                  return callback(null);
              });
            }, callback);

        },

        toArray: function(callback) {
            return cursor
            .toArray(function(err, pieces) {
                if (err) {
                  return callback(err);
                }
                if (options.format === 'allIds') {
                  results.ids = _.pluck(pieces, '_id');
                  return callback(null);
                }
                results.skip = cursor.get('skip');
                results.limit = cursor.get('limit');
                results.page = cursor.get('page');
                for( var i = 0; i < pieces.length; i++){
                  if (typeof pieces[i].locale != 'undefined') {
                    if(pieces[i].locale != req.locale) {
                      pieces.splice(i, 1);
                      i--;
                    }
                    else {
                      if(!self.apos.permissions.can(req, 'admin')) {
                        if(pieces[i].userId != req.user._id) {
                          pieces.splice(i, 1);
                          i--;
                        }
                      }
                    }
                  }
                }
                results.pieces = pieces;
                return callback(null);
            });
        }

        }, function(err) {
        if (err) {
            return callback(err);
        }
        // Helps the frontend display the active sort and filter states
        results.cursor = cursor;
        return callback(null, results);
        });
      };

如您所见,我只是重写了 toArray 函数。我对此有两个主要疑问。

  1. 它适用于少量的碎片,但我不知道它是否能正常使用大量的碎片。

  2. 有没有办法只覆盖 toArray 函数而不必覆盖所有 self.list 方法?

提前致谢!

首先,我应该注意到 apostrophe-workflow 确实做到了这一点 — 它只会获取具有适当 workflowLocale 的文档。所以我不确定您是否出于正确的原因拒绝使用该模块。我建议您先认真试驾一下,确保您了解它已经提供的功能。

继续讨论您的问题的具体细节,覆盖整个 list 方法绝对是最不向前兼容的方法,并且没有解决用户可能在前端看到的问题。

此外,像这样在 toArray 调用之后进行过滤会破坏分页。前端会请求第1页,查询一页的价值,结果只有一半是locale,所以你得到半页。

你可能会做的是从 apostrophe-workflow 借用,它是这样说的(针对你的用例进行了简化):

// in lib/modules/YOUR-PIECES-MODULE/lib/cursor.js
module.exports = {
  construct: function(self, options) {
    self.addFilter('workflowLocale', {
      def: true,
      finalize: function() {
        var setting = self.get('workflowLocale');
        if (setting === null) {
          return;
        }
        if (setting === true) {
          setting = self.get('req').locale;
        }
        self.and({ locale: setting });
      }
    }
  }
});

此代码为您的作品类型的光标添加了一个新的光标过滤方法,这样它将默认按 req.locale 自动过滤它们。

同样,这是工作流为您所做的一部分,所以也请考虑一下。也许您想要本地化但根本不想要新更改的提交过程;这可能是这样做的一个很好的理由。