October 07, 2024

Laravel Factories

Spent some time this weekend doing some "house cleaning" on a project we have underway at work. No real heavy dev work, just some quality of life updates that will set us up better down the line. One of the major cleanup items was truly setting up our factory classes. There were 1 or 2 that had some basic definitions but they weren't really being used and didn't provide us all the data we'd want or need. The majority of the work was simply writing out the definitions and using Faker, but I also got to do some pretty neat things with factory states.

For the Invoice model, Invoices can have different "Level Types" (this is essentially how company determines what "Price Level" the Invoice). The business logic is not important but rather how I'm setting these different levels in the factory.

Even though the duplication would have been minimal I wanted to avoid having multiple state methods essentially doing the same thing. So instead I opted for creating Level specific methods for each Level Type that just called a single ofInLevelType state method that takes in the Level Type we'd like to set.

private function ofInLevelType($levelType)
{
    return $this->state([
        'IN_LEVEL' => $levelType
    ]);
}
public function wholesale()
{
    return $this->ofInLevelType('Wholesale');
}
public function cost()
{
    return $this->ofInLevelType('Cost');
}
public function web()
{
    return $this->ofInLevelType('Web');
}
public function list()
{
    return $this->ofInLevelType('List');
}
public function retail()
{
    return $this->ofInLevelType('Retail');
}

Then I had a Customer model that required a little more attention. A Customer has 5 different contact columns, each can contain a different type of contact; Email, Phone, Mobile Phone, Fax, etc. For each contact column there is a corresponding contact type column that describes what type of contact data is stored in the related contact column. Essentially the data looks like this.

{
  "CONTACT_TYPE_1": "Other",
  "CONTACT_TYPE_2": "Contact",
  "CONTACT_TYPE_3": "Phone",
  "CONTACT_TYPE_4": "E-Mail",
  "CONTACT_TYPE_5": "Home Phone",
  "CONTACT_1": "Feest, Quitzon and Lowe",
  "CONTACT_2": "Mrs. Lexie Strosin",
  "CONTACT_3": "+1.210.940.2406",
  "CONTACT_4": "[email protected]",
  "CONTACT_5": "413-503-7367",
}

Full disclosure: we did not define this database. We are working with a company who already had this database structure in place and we're writing an integration that works alongside it.

The unique challenge here was I needed to make sure that whatever contact type was used that the corresponding contact data matched that type. We don't want a contact type of "email" that contains a phone number.

private Collection $contactData;

public function definition()
{
	// get our random Contact Type keys from our Contact Data
	$contactType1 = $this->getContactInfoType();
	$contactType2 = $this->getContactInfoType();
	$contactType3 = $this->getContactInfoType();
	$contactType4 = $this->getContactInfoType();
	$contactType5 = $this->getContactInfoType();

	return [
		'CONTACT_TYPE_1' => $contactType1,
		'CONTACT_TYPE_2' => $contactType2,
		'CONTACT_TYPE_3' => $contactType3,
		'CONTACT_TYPE_4' => $contactType4,
		'CONTACT_TYPE_5' => $contactType5,
		'CONTACT_1' => $this->getContactTypeData($contactType1),
		'CONTACT_2' => $this->getContactTypeData($contactType2),
		'CONTACT_3' => $this->getContactTypeData($contactType3),
		'CONTACT_4' => $this->getContactTypeData($contactType4),
		'CONTACT_5' => $this->getContactTypeData($contactType5),
	];
}

// generate our dummy Contact Data for each possible Contact Type
private function generateContactData()
{
	$this->contactData = collect([
		'Billing Contact' => $this->faker->phoneNumber,
		'Contact' => $this->faker->name,
		'E-Mail' => $this->faker->safeEmail,
		'Extension' => $this->faker->phoneNumberWithExtension,
		'Fax' => $this->faker->phoneNumber,
		'Home Phone' => $this->faker->phoneNumber,
		'Intl. Phone' => $this->faker->e164PhoneNumber,
		'Misc. Phone' => $this->faker->phoneNumber,
		'Mobile Phone' => $this->faker->phoneNumber,
		'Other' => $this->faker->company,
		'Phone' => $this->faker->phoneNumber,
		'Sales Phone' => $this->faker->phoneNumber,
		'Sales Rep' => $this->faker->name,
		'Web Address' => $this->faker->url,
		'Work Phone' => $this->faker->phoneNumber,
	]);
}

// pull a random key from our Contact Data collection 
private function getContactInfoType()
{
	return $this->contactData->keys()->random();
}

// get our contact data based using the Contact Type key provided
private function getContactTypeData(string $contactType)
{
	return $this->contactData->get($contactType);
}

© 2025 Terrence Eisenhower. All rights reserved.