Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
Sample: Use slashes instead of underscores in PHP namespaces for nest…
Browse files Browse the repository at this point in the history
…ed enums and messages (#2757)
  • Loading branch information
yihanzhen authored May 29, 2019
1 parent 955dd27 commit bc9741c
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@
import com.google.api.codegen.util.TypedValue;
import com.google.api.codegen.util.php.PhpTypeTable;
import com.google.api.tools.framework.model.EnumValue;
import com.google.api.tools.framework.model.MessageType;
import com.google.api.tools.framework.model.ProtoElement;
import com.google.api.tools.framework.model.ProtoFile;
import com.google.api.tools.framework.model.TypeRef;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.stream.Collectors;

public class PhpModelTypeNameConverter extends ModelTypeNameConverter {

Expand Down Expand Up @@ -130,19 +131,9 @@ public TypeName getTypeNameForElementType(TypeRef type) {
}
}

@Override
public TypeName getTypeName(ProtoElement elem) {
try {
return getTypeName(elem, MAX_NESTED_DEPTH);
} catch (IllegalStateException e) {
throw new IllegalStateException("Could not determine type name for elem: " + elem, e);
}
}

/**
* This function recursively determines the PHP type name for a proto message. Recursion is
* required because in PHP nested messages are handled differently from non-nested messages. For
* example, the following proto definition: <code>
* This function determines the PHP type name for a proto message. For example, the following
* proto definition: <code>
* package example;
* message Top {
* message Nested {
Expand All @@ -153,67 +144,45 @@ public TypeName getTypeName(ProtoElement elem) {
*
* <ul>
* <li>\Example\Top
* <li>\Example\Top_Nested
* <li>\Example\Top_Nested_DeepNested
* <li>\Example\Top\Nested
* <li>\Example\Top\Nested\DeepNested
* </ul>
*
* <p>To correctly output these type names, we need to check whether the parent of a proto element
* is a message, and if so use '_' as a separator.
*/
private TypeName getTypeName(ProtoElement elem, int maxDepth) {
ProtoElement parent = elem.getParent();
if (parent != null && parent instanceof MessageType) {
MessageType parentMessage = (MessageType) parent;
if (parentMessage.isCyclic()) {
throw new IllegalStateException(
"Cannot determine type for cyclic message: " + parentMessage);
}
if (maxDepth == 0) {
throw new IllegalStateException("Cannot determine type for deeply nested message");
}

String parentFullName = getTypeName(parent, maxDepth - 1).getFullName();
String fullName = String.format("%s_%s", parentFullName, elem.getSimpleName());
String nickName = fullName.substring(fullName.lastIndexOf("\\") + 1);

return new TypeName(fullName, nickName);
}
return typeNameConverter.getTypeName(getTypeNameString(elem));
}

/**
* This function determines the type name as follows: If the proto type name is in TYPE_NAME_MAP,
* return that value. Else, split on ".", prepend '\' and capitalize each component of the
* namespace except the message name
*/
private static String getTypeNameString(ProtoElement elem) {
@Override
public TypeName getTypeName(ProtoElement elem) {
String fullName = elem.getFullName();
if (TYPE_NAME_MAP.containsKey(fullName)) {
return TYPE_NAME_MAP.get(fullName);
return typeNameConverter.getTypeName(TYPE_NAME_MAP.get(fullName));
}
String[] components = fullName.split("\\.");
String shortName = components[components.length - 1];

StringBuilder builder = new StringBuilder();
LinkedList<String> components = new LinkedList<>();

ProtoElement parentElem = elem.getParent();
if (parentElem != null && parentElem instanceof ProtoFile) {
ProtoFile protoFile = (ProtoFile) parentElem;
while (elem != null && !(elem instanceof ProtoFile)) {
components.addFirst(elem.getSimpleName());
elem = elem.getParent();
}

// Create the type name based on protobuf PHP namespace
if (elem != null && elem instanceof ProtoFile) {
ProtoFile protoFile = (ProtoFile) elem;
String namespace = protoFile.getProto().getOptions().getPhpNamespace();
if (Strings.isNullOrEmpty(namespace)) {
for (int index = 0; index < components.length - 1; index++) {
builder
.append('\\')
.append(components[index].substring(0, 1).toUpperCase())
.append(components[index].substring(1));
}
} else {
builder.append('\\').append(CharMatcher.is('\\').trimFrom(namespace));
if (!Strings.isNullOrEmpty(namespace)) {
components.addFirst(namespace);
fullName =
components
.stream()
.map(PhpModelTypeNameConverter::makeNamespacePieces)
.collect(Collectors.joining(""));
return typeNameConverter.getTypeName(fullName);
}
}

builder.append('\\').append(shortName);
return builder.toString();
// Create the type name based on the element's full name
fullName =
Arrays.stream(fullName.split("\\."))
.map(PhpModelTypeNameConverter::makeNamespacePieces)
.collect(Collectors.joining(""));
return typeNameConverter.getTypeName(fullName);
}

/**
Expand Down Expand Up @@ -285,4 +254,8 @@ public TypeName getTypeNameForResourceNameElementType(
public TypedValue getEnumValue(TypeRef type, EnumValue value) {
return TypedValue.create(getTypeName(type), "%s::" + value.getSimpleName());
}

private static String makeNamespacePieces(String piece) {
return "\\" + piece.substring(0, 1).toUpperCase() + piece.substring(1);
}
}
Loading

0 comments on commit bc9741c

Please sign in to comment.