use super::super::renderers::quoted_key_literal;
use super::super::types::{PathSegment, PhpGetterMap};
use super::{push_key_field_name, push_key_index_suffix};
use heck::ToLowerCamelCase;
use std::collections::HashSet;
pub(in crate::e2e::field_access) fn render_php(segments: &[PathSegment], result_var: &str) -> String {
let mut out = result_var.to_string();
for seg in segments {
match seg {
PathSegment::Field(f) => {
out.push_str("->");
out.push_str(&f.to_lower_camel_case());
}
PathSegment::ArrayField { name, index } => {
if !name.is_empty() {
out.push_str("->");
out.push_str(&name.to_lower_camel_case());
}
out.push_str(&format!("[{index}]"));
}
PathSegment::MapAccess { field, key } => {
out.push_str("->");
out.push_str(&field.to_lower_camel_case());
out.push_str(&format!("[{}]", quoted_key_literal(key)));
}
PathSegment::Length => {
let current = std::mem::take(&mut out);
out = format!("count({current})");
}
}
}
out
}
pub(in crate::e2e::field_access) fn render_php_with_getters(
segments: &[PathSegment],
result_var: &str,
getter_map: &PhpGetterMap,
optional_fields: &HashSet<String>,
) -> String {
render_php_with_getters_from_owner(
segments,
result_var,
getter_map,
optional_fields,
getter_map.root_type.clone(),
)
}
pub(in crate::e2e::field_access) fn render_php_element_with_getters(
segments: &[PathSegment],
element_var: &str,
getter_map: &PhpGetterMap,
optional_fields: &HashSet<String>,
owner_type: Option<String>,
) -> String {
render_php_with_getters_from_owner(segments, element_var, getter_map, optional_fields, owner_type)
}
pub(in crate::e2e::field_access) fn php_element_owner_type(
array_segments: &[PathSegment],
getter_map: &PhpGetterMap,
) -> Option<String> {
let mut current_type = getter_map.root_type.clone();
for segment in array_segments {
let field_name = match segment {
PathSegment::Field(name) | PathSegment::ArrayField { name, .. } => name.as_str(),
PathSegment::MapAccess { field, .. } => field.as_str(),
PathSegment::Length => continue,
};
current_type = getter_map.advance(current_type.as_deref(), field_name);
}
current_type
}
fn push_php_member(out: &mut String, arrow: &str, name: &str, getter_map: &PhpGetterMap, current_type: Option<&str>) {
let camel = name.to_lower_camel_case();
out.push_str(arrow);
if getter_map.needs_getter(current_type, name) {
out.push_str(&format!("get{}", camel.as_str()[..1].to_uppercase() + &camel[1..]));
out.push_str("()");
} else {
out.push_str(&camel);
}
}
fn render_php_with_getters_from_owner(
segments: &[PathSegment],
result_var: &str,
getter_map: &PhpGetterMap,
optional_fields: &HashSet<String>,
owner_type: Option<String>,
) -> String {
let mut out = result_var.to_string();
let mut current_type: Option<String> = owner_type;
let mut path_so_far = String::new();
let mut prev_was_nullable = false;
for seg in segments {
let arrow = if prev_was_nullable { "?->" } else { "->" };
match seg {
PathSegment::Field(f) => {
push_key_field_name(&mut path_so_far, seg);
push_php_member(&mut out, arrow, f, getter_map, current_type.as_deref());
current_type = getter_map.advance(current_type.as_deref(), f.as_str());
prev_was_nullable = prev_was_nullable || optional_fields.contains(&path_so_far);
}
PathSegment::ArrayField { name, index } => {
push_key_field_name(&mut path_so_far, seg);
if !name.is_empty() {
push_php_member(&mut out, arrow, name, getter_map, current_type.as_deref());
current_type = getter_map.advance(current_type.as_deref(), name.as_str());
}
out.push_str(&format!("[{index}]"));
push_key_index_suffix(&mut path_so_far, seg);
prev_was_nullable = prev_was_nullable || optional_fields.contains(&path_so_far);
}
PathSegment::MapAccess { field, key } => {
push_key_field_name(&mut path_so_far, seg);
push_php_member(&mut out, arrow, field, getter_map, current_type.as_deref());
out.push_str(&format!("[{}]", quoted_key_literal(key)));
current_type = getter_map.advance(current_type.as_deref(), field.as_str());
push_key_index_suffix(&mut path_so_far, seg);
prev_was_nullable = prev_was_nullable || optional_fields.contains(&path_so_far);
}
PathSegment::Length => {
let current = std::mem::take(&mut out);
out = format!("count({current})");
}
}
}
out
}