パッチ適用コード¶
場合によっては、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