パッチ適用コード

場合によっては、UI の動作をカスタマイズする必要があります。多くの一般的なニーズはサポートされている API でカバーされています。 たとえば、すべてのレジストリは優れた拡張ポイントです。フィールドレジストリでは、特殊なフィールドコンポーネントを追加/削除できます。 またはメインコンポーネントレジストリでは、常に表示されるコンポーネントを追加できます。

しかし、十分ではない場合があります。その場合、オブジェクトやクラスを修正する必要があるかもしれません。 そのために、Odoo は patch ユーティリティ関数を提供します。 ほとんどの場合、制御できない他のコンポーネント/コードの動作をオーバーライド/更新することが便利です。

説明

パッチ関数は @web/core/utils/patch にあります。

patch(objToPatch, extension)
引数
  • objToPatch (object()) -- パッチを当てるべき物体は

  • extension (object()) -- それぞれのキーを拡張機能にマッピングする

戻り値

パッチを外す機能

patch 関数は objToPatch オブジェクト (またはクラス) の場所で変更し、extension オブジェクトで説明されているすべてのキー/値を適用します。 unpatch 関数が返されるので、必要に応じて後でパッチを削除するために使用できます。

ほとんどのパッチ操作は、ネイティブの super キーワードを使用して親値へのアクセスを提供します(以下の例を参照)。

単純なオブジェクトにパッチを適用する

以下は、オブジェクトにパッチを当てることができる簡単な例です。

import { patch } from "@web/core/utils/patch";

const object = {
  field: "a field",
  fn() {
    // do something
  },
};

patch(object, {
  fn() {
    // do things
  },
});

関数にパッチを適用する場合、通常は parent 関数にアクセスできるようにしたいと考えています。そのためには、ネイティブの super キーワードを使用するだけです。

patch(object, {
  fn() {
    super.fn(...arguments);
    // do other things
  },
});

警告

super は関数ではないメソッドでのみ使用できます。これは以下の構文が javascript で無効であることを意味します。

const obj = {
  a: function () {
    // Throws: "Uncaught SyntaxError: 'super' keyword unexpected here"
    super.a();
  },
  b: () => {
    // Throws: "Uncaught SyntaxError: 'super' keyword unexpected here"
    super.b();
  },
};

ゲッターとセッターもサポートされています:

patch(object, {
  get number() {
    return super.number / 2;
  },
  set number(value) {
    super.number = value;
  },
});

javascriptクラスにパッチを適用する

patch 関数は、オブジェクトまたはES6クラスと連携するように設計されています。

ただし、javascriptクラスはプロトタイプの継承で動作するので、 クラスから標準メソッドにパッチを適用したい場合、 prototype にパッチを適用する必要があります。

class MyClass {
  static myStaticFn() {...}
  myPrototypeFn() {...}
}

// this will patch static properties!!!
patch(MyClass, {
  myStaticFn() {...},
});

// this is probably the usual case: patching a class method
patch(MyClass.prototype, {
  myPrototypeFn() {...},
});

また、Javascriptは特別なネイティブの方法でコンストラクタを処理するため、パッチを適用することは不可能です。 唯一の回避策は、元のコンストラクタでメソッドを呼び出し、代わりにそのメソッドにパッチを適用することです。

class MyClass {
  constructor() {
    this.setup();
  }
  setup() {
    this.number = 1;
  }
}

patch(MyClass.prototype, {
  setup() {
    super.setup(...arguments);
    this.doubleNumber = this.number * 2;
  },
});

警告

クラスの constructor に直接パッチを適用することはできません。

コンポーネントにパッチを適用しています

コンポーネントは javascript クラスで定義されているため、上記の情報はすべて保持されます。 これらの理由から、Owl コンポーネントは setup メソッドを使用してください。 これらは簡単にパッチを当てることができます( :ref:`ベストプラクティス<frontend/owl/best_practices> `のセクションを参照してください)。

patch(MyComponent.prototype, {
  setup() {
    useMyHook();
  },
});

パッチを削除する

patch 関数は、対応する関数を返します。 これはテストの開始時にパッチを適用し、最後にパッチを外す場合に主にテスト目的に役立ちます。

const unpatch = patch(object, { ... });
// test stuff here
unpatch();

複数のオブジェクトに同じパッチを適用する

It could happen that one wants to apply the same patch to multiple objects but because of the way the super keyword works, the extension can only be used for patching once and cannot be copied/cloned (check the documentation of the keyword). A function returning the object used to patch can be used to make it unique.

const obj1 = {
  method() {
    doSomething();
  },
};

const obj2 = {
  method() {
    doThings();
  },
};

function createExtensionObj() {
  return {
    method() {
      super.method();
      doCommonThings();
    },
  };
}

patch(obj1, createExtensionObj());
patch(obj2, createExtensionObj());

警告

extension が別のエクステンションに基づいている場合、2つのエクステンションは別々に適用されます。エクステンションをコピー/クローンしないでください。

const object = {
  method1() {
    doSomething();
  },
  method2() {
    doAnotherThing();
  },
};

const ext1 = {
  method1() {
    super.method1();
    doThings();
  },
};

const invalid_ext2 = {
  ...ext1, // this will not work: super will not refer to the correct object in methods coming from ext1
  method2() {
    super.method2();
    doOtherThings();
  },
};

patch(object, invalid_ext2);
object.method1(); // throws: Uncaught TypeError: (intermediate value).method1 is not a function

const valid_ext2 = {
  method2() {
    super.method2();
    doOtherThings();
  },
};

patch(object, ext1); // first patch base extension
patch(object, valid_ext2); // then the new one
object.method1(); // works as expected