提交 f16f6deb 编写于 作者: B baiy 提交者: ninecents

#122 json 2 php

上级 bdbcafe7
此差异已折叠。
...@@ -36,6 +36,7 @@ import json2Go from '../json2Go' ...@@ -36,6 +36,7 @@ import json2Go from '../json2Go'
import json2CSharp from '../json2CSharp' import json2CSharp from '../json2CSharp'
import json2Protobuf from '../json2Protobuf' import json2Protobuf from '../json2Protobuf'
import json2Java from '../json2Java' import json2Java from '../json2Java'
import json2php from '../json2php'
import json2Dart from '../json2Dart' import json2Dart from '../json2Dart'
export default { export default {
...@@ -89,6 +90,12 @@ export default { ...@@ -89,6 +90,12 @@ export default {
case "C#": case "C#":
result = json2CSharp.convert(JSON.parse(json), this.options.className, this.options.packageName) result = json2CSharp.convert(JSON.parse(json), this.options.className, this.options.packageName)
break break
case "PHP":
result = json2php(json, {
className:this.options.className,
namespace:this.options.packageName,
})
break
default: default:
throw new Error('language type error') throw new Error('language type error')
} }
...@@ -117,7 +124,8 @@ export default { ...@@ -117,7 +124,8 @@ export default {
"Dart": "dart", "Dart": "dart",
"C#": "csharp", "C#": "csharp",
"Protobuf": "protobuf", "Protobuf": "protobuf",
"Go": "go" "Go": "go",
"PHP": "php"
}, },
} }
}, },
......
import {buildConstructor} from "./constructor";
import {buildGetters, buildSetters} from "./getterSetter";
import {buildProperties, getPropertyInfo} from "./property";
import {isScalarType} from "./types";
import {indent} from "./utils";
function getClassInfo(json, className, config, deps) {
const keys = Object.keys(json);
const properties = keys.map((key) => {
let info = getPropertyInfo(key, json[key]);
if (
isScalarType(info.type) ||
isScalarType(info.subtype) ||
info.subtype === null
)
return info;
let depName = info.type === "array" ? info.subtype : info.type;
if (!deps.has(depName)) {
deps.add({
className: depName,
key: key,
value: info.type === "array" ? json[key][0] : json[key],
});
}
return info;
});
return {
className: className,
properties: properties,
};
}
function buildArraySerialization(properties, config, className) {
if (!(config.arraySerialization || config.includeDeps)) {
return "";
}
return (
buildFromArray(properties, config, className) +
buildToArray(properties, config) +
buildToJson(properties, config)
);
}
function buildFromArray(properties, {typedMethods}, className) {
let result = "\n\n";
let declaration = `public static function fromArray(`;
declaration += typedMethods ? "array $data" : "$data";
declaration += !typedMethods ? ")" : "):" + className;
result += indent(declaration + "\n", 1);
result += indent("{\n", 1);
result += indent(`return new ${className}(\n`, 2);
const propertiesCount = properties.length;
properties.forEach((property, i) => {
let content = "";
let isLast = i >= propertiesCount - 1;
if (isScalarType(property.type) || isScalarType(property.subtype)) {
content = `$data["${property.originalName}"]${isLast ? "" : ","}`;
result += indent(content + "\n", 3);
return;
}
if (property.type === "array" && !isScalarType(property.subtype)) {
content += indent("array_map(function($item){\n", 3);
content += indent(`return ${property.subtype}::fromArray($item);\n`, 4);
content += indent(
`},$data["${property.originalName}"])${isLast ? "" : ","}`,
3
);
result += content + "\n";
return;
}
content = `${property.subtype}::fromArray($data["${
property.originalName
}"])${isLast ? "" : ","}`;
result += indent(content + "\n", 3);
});
result += indent(");\n", 2);
result += indent("}\n", 1);
return result;
}
function buildToArray(properties, {typedMethods}) {
let result = "\n";
let declaration = `public function toArray(`;
declaration += !typedMethods ? ")" : "):array";
result += indent(declaration + "\n", 1);
result += indent("{\n", 1);
result += indent(`return [\n`, 2);
const propertiesCount = properties.length;
properties.forEach((property, i) => {
let content = "";
let isLast = i >= propertiesCount - 1;
if (isScalarType(property.type) || isScalarType(property.subtype)) {
content = `"${property.originalName}"=>$this->${property.name}${
isLast ? "" : ","
}`;
result += indent(content + "\n", 3);
return;
}
if (property.type === "array") {
content += indent(
`"${property.originalName}"=>array_map(function($item){\n`,
3
);
content += indent(`return $item->toArray();\n`, 4);
content += indent(`},$this->${property.name})${isLast ? "" : ","}`, 3);
result += content + "\n";
return;
}
content = `"${property.originalName}"=>$this->${property.name}->toArray()${
isLast ? "" : ","
}`;
result += indent(content + "\n", 3);
});
result += indent("];\n", 2);
result += indent("}\n", 1);
return result;
}
function buildToJson(properties, {typedMethods}) {
let result = "\n";
let declaration = `public function toJson(`;
declaration += !typedMethods ? ")" : "):string";
result += indent(declaration + "\n", 1);
result += indent("{\n", 1);
result += indent(`return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)\n`, 2);
result += indent("}", 1);
return result;
}
export default (config, deps, json, guessedName = null) => {
const {className, properties} = getClassInfo(
json,
guessedName,
config,
deps
);
let classContent =
buildProperties(properties, config) +
buildConstructor(properties, config) +
buildGetters(properties, config) +
buildSetters(properties, config) +
buildArraySerialization(properties, config, className);
return `class ${className}\n{\n${classContent}\n}\n`;
}
import {indent} from "./utils";
function buildParameters(properties, {typedMethods}) {
let result = "";
const propertiesCount = properties.length;
properties.forEach((property, i) => {
if (typedMethods && property.type !== undefined) {
result += property.type + " "
}
result += "$" + property.name;
if (i < (propertiesCount - 1)) {
result += ", ";
}
})
return result;
}
function buildBody(properties) {
let result = "";
const propertiesCount = properties.length;
properties.forEach((property, i) => {
let line = "";
line += `$this->${property.name} = $${property.name};`;
if (i < (propertiesCount - 1)) {
line += "\n";
}
result += indent(line, 2)
})
return result + "\n";
}
export const buildConstructor = (properties, config) => {
if (!(config.arraySerialization)) {
return "";
}
let result = "\n";
let declaration = "";
declaration += "public function __construct(";
declaration += buildParameters(properties, config);
declaration += ")\n";
result += indent(declaration, 1);
result += indent(`{\n`, 1);
result += buildBody(properties, config);
result += indent("}", 1)
return result;
}
export default () => {
let _deps = [];
let _keys = [];
let _index = 0;
const add = (dep) => {
_keys.push(dep.className);
_deps[dep.className] = dep;
return _inner;
}
const has = (className) => _deps.includes(className)
const all = () => _deps;
const get = () => {
if (Object.keys(_deps).length === 0) return null;
const className = _keys[_index];
const val = _deps[className];
delete _deps[className];
_index++;
return val;
}
const _inner = {
add,
has,
all,
get
}
return _inner;
};
import {camelCase, indent} from "./utils";
function buildSetter(property, {typedMethods}) {
const methodName = camelCase("set" + "_" + property.name);
let result = "";
let declaration = `public function ${methodName}`;
declaration += `(${(typedMethods && property.type !== undefined) ? property.type + " " : ""}$${property.name})`;
result += indent(declaration + "\n", 1);
result += indent("{\n", 1);
result += indent(`$this->${property.name} = $${property.name};\n`, 2);
result += indent(`return $this;\n`, 2);
result += indent("}", 1);
return result;
}
function buildGetter(property, {typedMethods}) {
const prefix = property.type === "bool" ? "is" : "get";
const methodName = camelCase(prefix + "_" + property.name);
let result = "";
let declaration = `public function ${methodName}()`;
if (typedMethods && property.type !== undefined) {
declaration += ":" + property.type;
}
result += indent(declaration + "\n", 1);
result += indent("{\n", 1);
result += indent(`return $this->${property.name};\n`, 2);
result += indent("}", 1);
return result;
}
function buildMethod(callback, properties, config) {
if (!config.getters && !config.setters) return "";
let result = "\n";
const l = properties.length;
properties.forEach((p, i) => {
result += "\n";
result += callback(p, config);
if (i < (l - 1)) {
result += "\n";
}
})
return result;
}
export const buildSetters = (properties, config) => {
if (!config.setters) return "";
return buildMethod(buildSetter, properties, config);
}
export const buildGetters = (properties, config) => {
if (!config.getters) return "";
return buildMethod(buildGetter, properties, config);
}
/**
* https://github.com/dani-gouken/json_to_php
*/
import buildClass from "./class";
import {Visibility} from "./property";
import deps from "./deps";
const defaultConfig = {
className: "",
namespace: "",
visibility: Visibility.PRIVATE,
typedProperties: false,
getters: true,
typedMethods: false,
setters: true,
arraySerialization: true,
includeDeps: true
}
function convert(jsonString, config = {}) {
config = {...defaultConfig, ...config}
if (!config.className) {
config.className = 'ClassName'
}
let json = JSON.parse(jsonString);
if (Array.isArray(json)) {
json = json[0];
}
const res = buildDeps(config, deps().add({
className: config.className,
key: null,
value: json
}));
let result = "";
if (config.namespace) {
result = "namespace " + config.namespace + ";\n\n" + result;
}
if (!config.includeDeps) {
return result + res[0];
}
res.forEach((v, i) => {
if (i !== 0) {
result += "\n\n" + v;
} else {
result += v;
}
});
return result;
}
function buildDeps(config, deps, classes = []) {
let classContent = deps.get();
if (classContent == null) {
return classes;
}
classes.push(buildClass(config, deps, classContent.value, classContent.className));
return buildDeps(config, deps, classes);
}
export default convert;
import {guessType, isScalarType} from "./types";
import {camelCase, indent, isEmpty} from "./utils";
export const Visibility = {
PUBLIC: "public",
PRIVATE: "private",
PROTECTED: "protected"
};
export const buildProperties = (properties, {visibility, typedProperties}) => {
let result = "";
properties.forEach((p) => {
if (p.type){
result += indent(`/** @var ${p.type} */\n`, 1);
}
result += indent(`${visibility}${(p.type && typedProperties) ? " " + p.type : ""} $${p.name};\n`, 1);
});
return result;
}
const subtype = (type, value, key) => {
if (isScalarType(type) || isEmpty(value) || (value === {})) return null;
let subKey = key;
if (type === "array") {
return guessType(
value.length > 0 ? value[0] : null,
subKey,
)
}
return guessType(
value,
subKey,
)
}
export const getPropertyInfo = (key, value) => {
let type = guessType(value, key);
return {
name: camelCase(key),
type: type,
originalName: key,
value: value,
subtype: subtype(type, value, key)
}
}
import {pascalCase} from "./utils";
export const guessType = (value, name) => {
const type = typeof value;
switch (type) {
case "object":
if (Array.isArray(value)) {
return "array";
}
if (value === null) {
return undefined;
}
return pascalCase(name);
case "boolean":
return "bool";
case "number":
return Number.isInteger(value) ? "int" : "float";
case "bigint":
return "int";
case "string":
return "string";
default:
return undefined;
}
}
export const isScalarType = (type) => {
return ["bool", "int", "float", "string"].includes(type) || type === null || type === undefined;
}
import {pascalCase as pascalCaseHandle} from "pascal-case"
import {camelCase as camelCaseHandle} from "camel-case"
export const indent = (string, level = 0, spaceCount = 4) => {
let space = " ".repeat(spaceCount * level);
return space + string;
}
export const isEmpty = (val) => {
return Array.isArray(val) && val.length === 0;
}
export const camelCase = (str) => {
return camelCaseHandle(str)
}
export const pascalCase = (str) => {
return pascalCaseHandle(str)
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册